Patchworkβ Add Winbond SuperI/O detection

login
register
about
Submitter Carl-Daniel Hailfinger
Date 2010-06-30 12:12:45
Message ID <4C2B34BD.8040505@gmx.net>
Download mbox | patch
Permalink /patch/1564/
State Under Review
Headers show

Comments

Carl-Daniel Hailfinger - 2010-06-30 12:12:45
Add Winbond Super I/O detection and hook it up to the generic Super I/O
detection framework.
Incomplete and untested, but at least it shouldn't break anything.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Michael Karcher - 2010-06-30 12:48:52
Am Mittwoch, den 30.06.2010, 14:12 +0200 schrieb Carl-Daniel Hailfinger:

> -static const struct winbond_chip * winbond_superio_detect(uint16_t base)
> +uint8_t probe_id_winbond(uint16_t port)
>  {
>  	uint8_t chipid;
> +
> +	w836xx_ext_enter(port);
> +	chipid = sio_read(port, 0x20);
> +	w836xx_ext_leave(port);
> +
> +	return chipid;
> +}

If this code is to be run on any board, I would like some more checking
in it. For example, you could check that sio_read(port, 0x20) returns
0xFF after the w836xx_ext_leave(). There are ECs that don't need any
enables, so they will respond after the Winbond enable although they are
not Winbond chips. But they still respond after the disable, so they can
be told apart.

I think the kernel has Super I/O detection in the parport-pc driver.
Maybe one could also peek there for safe detection code that has been
tested on thousands of boxes.

> +static const struct winbond_chip *winbond_superio_chipdef(void)
> +{
>  	const struct winbond_chip * chip = NULL;
>  	int i;
>  
> -	w836xx_ext_enter(base);
> -	chipid = sio_read(base, 0x20);
>  	for (i = 0; i < ARRAY_SIZE(winbond_chips); i++)
> -		if (winbond_chips[i].device_id == chipid)
> +		if (winbond_chips[i].device_id == superio.model)
>  		{
>  			chip = &winbond_chips[i];
>  			break;
>  		}
>  	
> -	w836xx_ext_leave(base);
>  	return chip;
>  }
Hmm. Shouldn't you check that superio.vendor is in fact
SUPERIO_VENDOR_WINBOND here?

Regards,
  Michael Karcher
Carl-Daniel Hailfinger - 2010-06-30 14:54:23
On 30.06.2010 14:48, Michael Karcher wrote:
> Am Mittwoch, den 30.06.2010, 14:12 +0200 schrieb Carl-Daniel Hailfinger:
>
>   
>> -static const struct winbond_chip * winbond_superio_detect(uint16_t base)
>> +uint8_t probe_id_winbond(uint16_t port)
>>  {
>>  	uint8_t chipid;
>> +
>> +	w836xx_ext_enter(port);
>> +	chipid = sio_read(port, 0x20);
>> +	w836xx_ext_leave(port);
>> +
>> +	return chipid;
>> +}
>>     
>
> If this code is to be run on any board, I would like some more checking
> in it. For example, you could check that sio_read(port, 0x20) returns
> 0xFF after the w836xx_ext_leave(). There are ECs that don't need any
> enables, so they will respond after the Winbond enable although they are
> not Winbond chips. But they still respond after the disable, so they can
> be told apart.
>   

That's a good idea, but my goal for this patch was to have a quick hack
for discussion. We want to use the discovery code from superiotool or
the Linux kernel to avoid a maintenance headache.


> I think the kernel has Super I/O detection in the parport-pc driver.
> Maybe one could also peek there for safe detection code that has been
> tested on thousands of boxes.
>   

Yes.
http://git.openvz.org/?p=linux-2.6.32-openvz;a=blob;f=drivers/parport/parport_pc.c;h=2597145a066e391fa988ecbbf44921f2f249ef1d;hb=HEAD#l1219

I'm not sure if that code is still tested at all. AFAIK most modern
systems offer Parport discovery via ACPI.


>> +static const struct winbond_chip *winbond_superio_chipdef(void)
>> +{
>>  	const struct winbond_chip * chip = NULL;
>>  	int i;
>>  
>> -	w836xx_ext_enter(base);
>> -	chipid = sio_read(base, 0x20);
>>  	for (i = 0; i < ARRAY_SIZE(winbond_chips); i++)
>> -		if (winbond_chips[i].device_id == chipid)
>> +		if (winbond_chips[i].device_id == superio.model)
>>  		{
>>  			chip = &winbond_chips[i];
>>  			break;
>>  		}
>>  	
>> -	w836xx_ext_leave(base);
>>  	return chip;
>>  }
>>     
> Hmm. Shouldn't you check that superio.vendor is in fact
> SUPERIO_VENDOR_WINBOND here?
>   

Yes, thanks for pointing this out.

We should try to decide which exernal superio detection code we want
before we proceed.

Regards,
Carl-Daniel

Patch

Index: flashrom-winbond_superio_detect/flash.h
===================================================================
--- flashrom-winbond_superio_detect/flash.h	(Revision 1064)
+++ flashrom-winbond_superio_detect/flash.h	(Arbeitskopie)
@@ -350,6 +350,7 @@ 
 /* board_enable.c */
 void w836xx_ext_enter(uint16_t port);
 void w836xx_ext_leave(uint16_t port);
+struct superio probe_superio_winbond(void);
 uint8_t sio_read(uint16_t port, uint8_t reg);
 void sio_write(uint16_t port, uint8_t reg, uint8_t data);
 void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask);
@@ -388,7 +389,8 @@ 
 };
 extern struct superio superio;
 #define SUPERIO_VENDOR_NONE	0x0
-#define SUPERIO_VENDOR_ITE	0x1
+#define SUPERIO_VENDOR_WINBOND	0x1
+#define SUPERIO_VENDOR_ITE	0x2
 struct pci_dev *pci_dev_find_filter(struct pci_filter filter);
 struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class);
 struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device);
Index: flashrom-winbond_superio_detect/internal.c
===================================================================
--- flashrom-winbond_superio_detect/internal.c	(Revision 1064)
+++ flashrom-winbond_superio_detect/internal.c	(Arbeitskopie)
@@ -104,12 +104,14 @@ 
 
 void probe_superio(void)
 {
-	superio = probe_superio_ite();
+	superio = probe_superio_winbond();
 #if 0
-	/* Winbond Super I/O code is not yet available. */
+	/* ITE probe causes SMSC LPC47N217 to power off the serial UART. */
 	if (superio.vendor == SUPERIO_VENDOR_NONE)
-		superio = probe_superio_winbond();
+		superio = probe_superio_smsc();
 #endif
+	if (superio.vendor == SUPERIO_VENDOR_NONE)
+		superio = probe_superio_ite();
 }
 #endif
 
Index: flashrom-winbond_superio_detect/board_enable.c
===================================================================
--- flashrom-winbond_superio_detect/board_enable.c	(Revision 1064)
+++ flashrom-winbond_superio_detect/board_enable.c	(Arbeitskopie)
@@ -229,22 +229,59 @@ 
    address, but takes no effort to make sure the chip is really a
    Winbond Super I/O */
 
-static const struct winbond_chip * winbond_superio_detect(uint16_t base)
+uint8_t probe_id_winbond(uint16_t port)
 {
 	uint8_t chipid;
+
+	w836xx_ext_enter(port);
+	chipid = sio_read(port, 0x20);
+	w836xx_ext_leave(port);
+
+	return chipid;
+}
+
+#define WINBOND_SUPERIO_PORT1	0x2e
+#define WINBOND_SUPERIO_PORT2	0x4e
+
+struct superio probe_superio_winbond(void)
+{
+	struct superio ret = {};
+	uint16_t winbond_ports[] = {WINBOND_SUPERIO_PORT1, WINBOND_SUPERIO_PORT2, 0};
+	uint16_t *i = winbond_ports;
+
+	ret.vendor = SUPERIO_VENDOR_WINBOND;
+	for (; *i; i++) {
+		ret.port = *i;
+		ret.model = probe_id_winbond(ret.port);
+		switch (ret.model) {
+		case WINBOND_W83627HF_ID:
+		case WINBOND_W83627EHF_ID:
+		case WINBOND_W83627THF_ID:
+			msg_pinfo("Found Winbond Super I/O, id %02hx\n",
+				  ret.model);
+			return ret;
+		}
+	}
+
+	/* No good ID found. */
+	ret.vendor = SUPERIO_VENDOR_NONE;
+	ret.port = 0;
+	ret.model = 0;
+	return ret;
+}
+
+static const struct winbond_chip *winbond_superio_chipdef(void)
+{
 	const struct winbond_chip * chip = NULL;
 	int i;
 
-	w836xx_ext_enter(base);
-	chipid = sio_read(base, 0x20);
 	for (i = 0; i < ARRAY_SIZE(winbond_chips); i++)
-		if (winbond_chips[i].device_id == chipid)
+		if (winbond_chips[i].device_id == superio.model)
 		{
 			chip = &winbond_chips[i];
 			break;
 		}
 	
-	w836xx_ext_leave(base);
 	return chip;
 }
 
@@ -259,7 +296,7 @@ 
 	int port = pin / 10;
 	int bit = pin % 10;
 
-	chip = winbond_superio_detect(base);
+	chip = winbond_superio_chipdef();
 	if (!chip) {
 		msg_perr("\nERROR: No supported Winbond Super I/O found\n");
 		return -1;