Am 07.05.2012 00:08 schrieb Michael Karcher:
On Sun, 2012-05-06 at 23:51 +0200, Carl-Daniel Hailfinger wrote:
Am 06.05.2012 21:13 schrieb Carl-Daniel Hailfinger:
New version, this time with extremely paranoid checks.
Even more paranoid checks... and we now handle IT8707F and IT8710F in the Winbond detection routine.
As these chips share the config mode init sequence, this makes sense.
Please note that this is only SuperI/O detection, we don't call any write enable functions.
IT8707F and IT8710F write enable needs to be hooked up in it87spi.c, the W836xx write enable functions need to be hooked up somewhere.
- /* Set HBACS=1. */
- sio_mask_alzheimer(hwmport, 0x4e, 0x80, 0x80);
- /* Read upper byte of vendor ID. */
- OUTB(0x4f, hwmport);
- hwm_vendorid = INB(hwmport + 1) << 8;
Why don't you use sio_read to read from the hardware monitor? (three times)
Good point. Fixed.
tmp = w836xx_deviceid_hwmon(s.port);
/* FIXME: This might be too paranoid... */
if (!tmp) {
msg_pdbg("Probably not a Winbond Super I/O\n");
break;
}
I think this *is* too paranoid, but maybe you are right being paranoid.
I also think this is too paranoid, but hey... we can still disable it later.
Acked-by: Michael Karcher flashrom@mkarcher.dialup.fu-berlin.de
Thanks, I have attached the new version with sio_read for hwm accesses.
Thanks for working through the mess of detecting chip generically that were never meant for that.
Thanks.
New patch, changed to use sio_read in w836xx_deviceid_hwmon().
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net Acked-by: Michael Karcher flashrom@mkarcher.dialup.fu-berlin.de
Index: flashrom-winbond_superio_detect/internal.c =================================================================== --- flashrom-winbond_superio_detect/internal.c (Revision 1530) +++ flashrom-winbond_superio_detect/internal.c (Arbeitskopie) @@ -101,12 +101,14 @@ #if defined(__i386__) || defined(__x86_64__) void probe_superio(void) { + probe_superio_winbond(); + /* ITE probe causes SMSC LPC47N217 to power off the serial UART. + * Always probe for SMSC first, and if a SMSC Super I/O is detected + * at a given I/O port, do _not_ probe that port with the ITE probe. + * This means SMSC probing must be done before ITE probing. + */ + //probe_superio_smsc(); probe_superio_ite(); -#if 0 - /* Winbond Super I/O code is not yet available. */ - if (superio.vendor == SUPERIO_VENDOR_NONE) - superio = probe_superio_winbond(); -#endif }
int superio_count = 0; Index: flashrom-winbond_superio_detect/programmer.h =================================================================== --- flashrom-winbond_superio_detect/programmer.h (Revision 1530) +++ flashrom-winbond_superio_detect/programmer.h (Arbeitskopie) @@ -246,6 +246,7 @@ /* board_enable.c */ void w836xx_ext_enter(uint16_t port); void w836xx_ext_leave(uint16_t port); +void probe_superio_winbond(void); int it8705f_write_enable(uint8_t port); uint8_t sio_read(uint16_t port, uint8_t reg); void sio_write(uint16_t port, uint8_t reg, uint8_t data); @@ -290,6 +291,7 @@ extern int superio_count; #define SUPERIO_VENDOR_NONE 0x0 #define SUPERIO_VENDOR_ITE 0x1 +#define SUPERIO_VENDOR_WINBOND 0x2 #endif #if NEED_PCI == 1 struct pci_dev *pci_dev_find_filter(struct pci_filter filter); Index: flashrom-winbond_superio_detect/board_enable.c =================================================================== --- flashrom-winbond_superio_detect/board_enable.c (Revision 1530) +++ flashrom-winbond_superio_detect/board_enable.c (Arbeitskopie) @@ -67,6 +67,17 @@ OUTB(tmp | (data & mask), port + 1); }
+/* Winbond W83697 documentation indicates that the index register has to be written for each access. */ +void sio_mask_alzheimer(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask) +{ + uint8_t tmp; + + OUTB(reg, port); + tmp = INB(port + 1) & ~mask; + OUTB(reg, port); + OUTB(tmp | (data & mask), port + 1); +} + /* Not used yet. */ #if 0 static int enable_flash_decode_superio(void) @@ -163,6 +174,7 @@ WINBOND_W83627HF_ID = 0x52, WINBOND_W83627EHF_ID = 0x88, WINBOND_W83627THF_ID = 0x82, + WINBOND_W83697HF_ID = 0x60, };
static const struct winbond_mux w83627hf_port2_mux[8] = { @@ -227,28 +239,154 @@ {WINBOND_W83627THF_ID, ARRAY_SIZE(w83627thf), w83627thf}, };
-/* - * Detects which Winbond Super I/O is responding at the given base address, - * but takes no effort to make sure the chip is really a Winbond Super I/O. +#define WINBOND_SUPERIO_PORT1 0x2e +#define WINBOND_SUPERIO_PORT2 0x4e + +/* We don't really care about the hardware monitor, but it offers better (more specific) device ID info than + * the simple device ID in the normal configuration registers. + * Note: This function expects to be called while the Super I/O is in config mode. */ -static const struct winbond_chip *winbond_superio_detect(uint16_t base) +static uint8_t w836xx_deviceid_hwmon(uint16_t sio_port) { - uint8_t chipid; - const struct winbond_chip *chip = NULL; - int i; + uint16_t hwmport; + uint16_t hwm_vendorid; + uint8_t hwm_deviceid;
- w836xx_ext_enter(base); - chipid = sio_read(base, 0x20); + sio_write(sio_port, 0x07, 0x0b); /* Select LDN 0xb (HWM). */ + if ((sio_read(sio_port, 0x30) & (1 << 0)) != (1 << 0)) { + msg_pinfo("W836xx hardware monitor disabled or does not exist.\n"); + return 0; + } + /* Get HWM base address (stored in LDN 0xb, index 0x60/0x61). */ + hwmport = sio_read(sio_port, 0x60) << 8; + hwmport |= sio_read(sio_port, 0x61); + /* HWM address register = HWM base address + 5. */ + hwmport += 5; + msg_pdbg2("W836xx Hardware Monitor at port %04x\n", hwmport); + /* FIXME: This busy check should happen before each HWM access. */ + if (INB(hwmport) & 0x80) { + msg_pinfo("W836xx hardware monitor busy, ignoring it.\n"); + return 0; + } + /* Set HBACS=1. */ + sio_mask_alzheimer(hwmport, 0x4e, 0x80, 0x80); + /* Read upper byte of vendor ID. */ + hwm_vendorid = sio_read(hwmport, 0x4f) << 8; + /* Set HBACS=0. */ + sio_mask_alzheimer(hwmport, 0x4e, 0x00, 0x80); + /* Read lower byte of vendor ID. */ + hwm_vendorid |= sio_read(hwmport, 0x4f); + if (hwm_vendorid != 0x5ca3) { + msg_pinfo("W836xx hardware monitor vendor ID weirdness: expected 0x5ca3, got %04x\n", + hwm_vendorid); + return 0; + } + /* Set Bank=0. */ + sio_mask_alzheimer(hwmport, 0x4e, 0x00, 0x07); + /* Read "chip" ID. We call this one the device ID. */ + hwm_deviceid = sio_read(hwmport, 0x58); + return hwm_deviceid; +}
- for (i = 0; i < ARRAY_SIZE(winbond_chips); i++) { - if (winbond_chips[i].device_id == chipid) { - chip = &winbond_chips[i]; +void probe_superio_winbond(void) +{ + struct superio s = {}; + uint16_t winbond_ports[] = {WINBOND_SUPERIO_PORT1, WINBOND_SUPERIO_PORT2, 0}; + uint16_t *i = winbond_ports; + uint8_t model; + uint8_t tmp; + + s.vendor = SUPERIO_VENDOR_WINBOND; + for (; *i; i++) { + s.port = *i; + /* If we're already in Super I/O config more, the W836xx enter sequence won't hurt. */ + w836xx_ext_enter(s.port); + model = sio_read(s.port, 0x20); + /* No response, no point leaving the config mode. */ + if (model == 0xff) + continue; + /* Try to leave config mode. If the ID register is still readable, it's not a Winbond chip. */ + w836xx_ext_leave(s.port); + if (model == sio_read(s.port, 0x20)) { + msg_pdbg("W836xx enter config mode worked or we were already in config mode. W836xx " + "leave config mode had no effect.\n"); + if (model == 0x87) { + /* ITE IT8707F and IT8710F are special: They need the W837xx enter sequence, + * but they want the ITE exit sequence. Handle them here. + */ + tmp = sio_read(s.port, 0x21); + switch (tmp) { + case 0x07: + case 0x10: + s.vendor = SUPERIO_VENDOR_ITE; + s.model = (0x87 << 8) | tmp ; + msg_pdbg("Found ITE Super I/O, ID 0x%04hx on port " + "0x%x\n", s.model, s.port); + register_superio(s); + /* Exit ITE config mode. */ + exit_conf_mode_ite(s.port); + /* Restore vendor for next loop iteration. */ + s.vendor = SUPERIO_VENDOR_WINBOND; + continue; + } + } + msg_pinfo("Active config mode, unknown reg 0x20 ID: %02x.\n", model); + msg_pinfo("Please send the output of "flashrom -V" to \n" + "flashrom@flashrom.org with W836xx: your board name: flashrom -V\n" + "as the subject to help us finish support for your Super I/O. Thanks.\n"); + continue; + } + /* The Super I/O reacts to W836xx enter and exit config mode, it's probably Winbond. */ + w836xx_ext_enter(s.port); + s.model = sio_read(s.port, 0x20); + switch (s.model) { + case WINBOND_W83627HF_ID: + case WINBOND_W83627EHF_ID: + case WINBOND_W83627THF_ID: + msg_pdbg("Found Winbond Super I/O, id %02hx\n", s.model); + register_superio(s); break; + case WINBOND_W83697HF_ID: + /* This code is extremely paranoid. */ + tmp = sio_read(s.port, 0x26) & 0x40; + if (((tmp == 0x00) && (s.port != WINBOND_SUPERIO_PORT1)) || + ((tmp == 0x40) && (s.port != WINBOND_SUPERIO_PORT2))) { + msg_pdbg("Winbond Super I/O probe weirdness: Port mismatch for ID " + "%02x at port %04x\n", s.model, s.port); + break; + } + tmp = w836xx_deviceid_hwmon(s.port); + /* FIXME: This might be too paranoid... */ + if (!tmp) { + msg_pdbg("Probably not a Winbond Super I/O\n"); + break; + } + if (tmp != s.model) { + msg_pinfo("W83 series hardware monitor device ID weirdness: expected %02x, " + "got %02x\n", WINBOND_W83697HF_ID, tmp); + break; + } + msg_pinfo("Found Winbond Super I/O, id %02hx\n", s.model); + register_superio(s); + break; } + w836xx_ext_leave(s.port); } + return; +}
- w836xx_ext_leave(base); - return chip; +static const struct winbond_chip *winbond_superio_chipdef(void) +{ + int i, j; + + for (i = 0; i < superio_count; i++) { + if (superios[i].vendor != SUPERIO_VENDOR_WINBOND) + continue; + for (j = 0; j < ARRAY_SIZE(winbond_chips); j++) + if (winbond_chips[j].device_id == superios[i].model) + return &winbond_chips[j]; + } + return NULL; }
/* @@ -264,7 +402,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;