Hello Carl-Daniel Hailfinger,
I'd like you to do a code review. Please visit
https://review.coreboot.org/25112
to review the following change.
Change subject: SMSC SuperI/O detection ......................................................................
SMSC SuperI/O detection
Add SMSC SuperI/O detection. Avoid probing for SuperI/O at a port where we already know the SuperI/O.
Change-Id: I6e9f6d99193ee539e1fcc268dc3b489983052f96 Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net --- M board_enable.c M internal.c M it87spi.c M programmer.h 4 files changed, 86 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/12/25112/1
diff --git a/board_enable.c b/board_enable.c index 56d3081..370d9aa 100644 --- a/board_enable.c +++ b/board_enable.c @@ -45,6 +45,13 @@ OUTB(0xAA, port); }
+void smsc_enter_conf_mode(uint16_t port) +{ + /* Most SMSC Super I/Os require only one 0x55, but the second one does not hurt. */ + OUTB(0x55, port); + OUTB(0x55, port); +} + /* Generic Super I/O helper functions */ uint8_t sio_read(uint16_t port, uint8_t reg) { @@ -299,7 +306,10 @@ 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. */ + /* Skip if we already know the Super I/O on this port. */ + if (superio_port_detected(s.port)) + continue; + /* If we're already in Super I/O config mode, 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. */ @@ -582,6 +592,63 @@ return 0; }
+#define SMSC_SUPERIO_PORT1 0x2e +#define SMSC_SUPERIO_PORT2 0x4e + +enum smsc_id { + SMSC_LPC47N217_ID = 0x7a, + SMSC_LPC47N227_ID = 0x5a, + SMSC_LPC47N237_ID = 0x13, +}; + +void probe_superio_smsc(void) +{ + struct superio s = {}; + uint16_t smsc_ports[] = {SMSC_SUPERIO_PORT1, SMSC_SUPERIO_PORT2, 0}; + uint16_t *i = smsc_ports; + uint8_t model1; + uint8_t model2; + + s.vendor = SUPERIO_VENDOR_SMSC; + for (; *i; i++) { + s.port = *i; + /* Skip if we already know the Super I/O on this port. */ + if (superio_port_detected(s.port)) + continue; + /* If we're already in Super I/O config mode, the SMSC enter sequence won't hurt. */ + smsc_enter_conf_mode(s.port); + /* Older SMSC chips have their ID in register 0x0d. */ + model1 = sio_read(s.port, 0x0d); + /* Newer SMSC chips have their ID in register 0x20. */ + model2 = sio_read(s.port, 0x20); + /* No response, no point leaving the config mode. */ + if ((model1 == 0xff) && (model2 == 0xff)) + continue; + /* Try to leave config mode. If the ID register is still readable, it's not a SMSC chip. */ + w836xx_ext_leave(s.port); + if ((model1 == sio_read(s.port, 0x0d)) && (model2 == sio_read(s.port, 0x20))) { + msg_pdbg("SMSC enter config mode worked or we were already in config mode. SMSC " + "leave config mode had no effect.\n"); + continue; + } + switch (model1) { + case SMSC_LPC47N217_ID: + case SMSC_LPC47N227_ID: + case SMSC_LPC47N237_ID: + /* Encode ID register location in the model. */ + s.model = (0x0d << 8) | model1 ; + msg_pdbg("Found SMSC Super I/O, ID 0x%02x (reg %02x) on port 0x%x\n", s.model & 0xff, + s.model >> 8, s.port); + register_superio(s); + continue; + break; + } + msg_pdbg("Found SMSC Super I/O, ID 0x%02x (reg 0x0d), ID 0x%02x (reg 0x20) on port 0x%x\n", + model1, model2, s.port); + msg_pdbg("Not registering.\n"); + } +} + /* * Suited for all boards with ITE IT8705F. * The SIS950 Super I/O probably requires a similar flash write enable. diff --git a/internal.c b/internal.c index 5b24577..9112708 100644 --- a/internal.c +++ b/internal.c @@ -107,7 +107,7 @@ * 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_smsc(); probe_superio_ite(); }
@@ -116,6 +116,17 @@
struct superio superios[SUPERIO_MAX_COUNT];
+/* Check if a Super I/O chip has already been detected on this port. */ +int superio_port_detected(uint16_t port) +{ + int i; + + for (i = 0; i < superio_count; i++) + if (superios[i].port == port) + return 1; + return 0; +} + int register_superio(struct superio s) { if (superio_count == SUPERIO_MAX_COUNT) diff --git a/it87spi.c b/it87spi.c index 8119289..0d9e983 100644 --- a/it87spi.c +++ b/it87spi.c @@ -80,6 +80,9 @@ s.vendor = SUPERIO_VENDOR_ITE; for (; *i; i++) { s.port = *i; + /* Skip if we already know the Super I/O on this port. */ + if (superio_port_detected(s.port)) + continue; s.model = probe_id_ite(s.port); switch (s.model >> 8) { case 0x82: diff --git a/programmer.h b/programmer.h index 6f9ea8f..718f3fa 100644 --- a/programmer.h +++ b/programmer.h @@ -247,6 +247,7 @@ void w836xx_ext_enter(uint16_t port); void w836xx_ext_leave(uint16_t port); void probe_superio_winbond(void); +void probe_superio_smsc(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); @@ -292,6 +293,7 @@ #define SUPERIO_VENDOR_NONE 0x0 #define SUPERIO_VENDOR_ITE 0x1 #define SUPERIO_VENDOR_WINBOND 0x2 +#define SUPERIO_VENDOR_SMSC 0x3 #endif #if NEED_PCI == 1 struct pci_dev *pci_dev_find_filter(struct pci_filter filter); @@ -308,6 +310,7 @@ extern int force_boardenable; extern int force_boardmismatch; void probe_superio(void); +int superio_port_detected(uint16_t port); int register_superio(struct superio s); extern enum chipbustype internal_buses_supported; int internal_init(void);