Add support for more than one Super I/O or EC per machine
Flashrom currently only supports exactly one Super I/O or Embedded
Controller, and this means quite a few notebooks and a small subset of
desktop/server boards cannot be handled reliably and easily.
Allow detection and initialization of up to 3 Super I/O and/or EC chips.
WARNING! If a Super I/O or EC responds on multiple ports (0x2e and
0x4e), the code will do the wrong thing (namely, initialize the hardware
twice). I have no idea if we should handle such situations, and whether
we should ignore the second chip with identical ID or not. Initializing
the hardware twice for the IT87* family is _not_ a problem, but I don't
know how well IT85* can handle it (and whether IT85* would listen at
more than one port anyway).
Corresponding to flashrom svn r1289.
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Thanks to Thomas Schneider for testing on a board with ITE IT87* SPI.
Test report (success) is here: http://paste.flashrom.org/view.php?id=379
Thanks to David Hendricks for testing on a Google Cr-48 laptop with
ITE IT85* EC SPI. Test report (success) is here:
http://www.flashrom.org/pipermail/flashrom/2011-April/006275.html
Acked-by: David Hendricks <dhendrix@google.com>
diff --git a/board_enable.c b/board_enable.c
index 919d055..3b0a4fb 100644
--- a/board_enable.c
+++ b/board_enable.c
@@ -493,7 +493,6 @@
}
} else {
msg_pdbg("No IT8705F flash segment enabled.\n");
- /* Not sure if this is an error or not. */
ret = 0;
}
exit_conf_mode_ite(port);
diff --git a/flashrom.c b/flashrom.c
index 34248ed..d4acb83 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -295,27 +295,6 @@
},
#endif
-#if CONFIG_INTERNAL == 1
-#if defined(__i386__) || defined(__x86_64__)
- {
- .name = "it87spi",
- .init = it87spi_init,
- .shutdown = noop_shutdown,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .chip_readb = noop_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = noop_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
- .delay = internal_delay,
- },
-#endif
-#endif
-
#if CONFIG_FT2232_SPI == 1
{
.name = "ft2232_spi",
diff --git a/internal.c b/internal.c
index c96db99..d3866ba 100644
--- a/internal.c
+++ b/internal.c
@@ -99,17 +99,29 @@
int force_boardmismatch = 0;
#if defined(__i386__) || defined(__x86_64__)
-struct superio superio = {};
-
void probe_superio(void)
{
- superio = probe_superio_ite();
+ 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;
+#define SUPERIO_MAX_COUNT 3
+
+struct superio superios[SUPERIO_MAX_COUNT];
+
+int register_superio(struct superio s)
+{
+ if (superio_count == SUPERIO_MAX_COUNT)
+ return 1;
+ superios[superio_count++] = s;
+ return 0;
+}
+
#endif
int is_laptop = 0;
diff --git a/it85spi.c b/it85spi.c
index d122a18..1710d8e 100644
--- a/it85spi.c
+++ b/it85spi.c
@@ -47,9 +47,6 @@
/* Constants for Logical Device registers */
#define LDNSEL 0x07
-#define CHIP_ID_BYTE1_REG 0x20
-#define CHIP_ID_BYTE2_REG 0x21
-#define CHIP_CHIP_VER_REG 0x22
/* These are standard Super I/O 16-bit base address registers */
#define SHM_IO_BAR0 0x60 /* big-endian, this is high bits */
@@ -86,44 +83,6 @@
unsigned char *ce_high, *ce_low;
static int it85xx_scratch_rom_reenter = 0;
-uint16_t probe_id_ite85(uint16_t port)
-{
- uint16_t id;
-
- id = sio_read(port, CHIP_ID_BYTE1_REG) << 8 |
- sio_read(port, CHIP_ID_BYTE2_REG);
-
- return id;
-}
-
-struct superio probe_superio_ite85xx(void)
-{
- struct superio ret = {};
- uint16_t ite_ports[] = {ITE_SUPERIO_PORT1, ITE_SUPERIO_PORT2, 0};
- uint16_t *i = ite_ports;
-
- ret.vendor = SUPERIO_VENDOR_ITE;
- for (; *i; i++) {
- ret.port = *i;
- ret.model = probe_id_ite85(ret.port);
- switch (ret.model >> 8) {
- case 0x85:
- msg_pdbg("Found EC: ITE85xx (Vendor:0x%02x,ID:0x%02x,"
- "Rev:0x%02x) on sio_port:0x%x.\n",
- ret.model >> 8, ret.model & 0xff,
- sio_read(ret.port, CHIP_CHIP_VER_REG),
- ret.port);
- return ret;
- }
- }
-
- /* No good ID found. */
- ret.vendor = SUPERIO_VENDOR_NONE;
- ret.port = 0;
- ret.model = 0;
- return ret;
-}
-
/* This function will poll the keyboard status register until either
* an expected value shows up, or
* timeout reaches.
@@ -267,20 +226,18 @@
#endif
}
-int it85xx_spi_common_init(void)
+static int it85xx_spi_common_init(struct superio s)
{
chipaddr base;
msg_pdbg("%s():%d superio.vendor=0x%02x\n", __func__, __LINE__,
- superio.vendor);
- if (superio.vendor != SUPERIO_VENDOR_ITE)
- return 1;
+ s.vendor);
#ifdef LPC_IO
/* Get LPCPNP of SHM. That's big-endian */
- sio_write(superio.port, LDNSEL, 0x0F); /* Set LDN to SHM (0x0F) */
- shm_io_base = (sio_read(superio.port, SHM_IO_BAR0) << 8) +
- sio_read(superio.port, SHM_IO_BAR1);
+ sio_write(s.port, LDNSEL, 0x0F); /* Set LDN to SHM (0x0F) */
+ shm_io_base = (sio_read(s.port, SHM_IO_BAR0) << 8) +
+ sio_read(s.port, SHM_IO_BAR1);
msg_pdbg("%s():%d shm_io_base=0x%04x\n", __func__, __LINE__,
shm_io_base);
@@ -311,25 +268,7 @@
return 0;
}
-/* Called by programmer_entry .init */
-int it85xx_spi_init(void)
-{
- int ret;
-
- get_io_perms();
- /* Probe for the Super I/O chip and fill global struct superio. */
- probe_superio();
- ret = it85xx_spi_common_init();
- if (!ret) {
- buses_supported = CHIP_BUSTYPE_SPI;
- } else {
- buses_supported = CHIP_BUSTYPE_NONE;
- }
- return ret;
-}
-
-/* Called by internal_init() */
-int it85xx_probe_spi_flash(void)
+int it85xx_spi_init(struct superio s)
{
int ret;
@@ -337,13 +276,14 @@
msg_pdbg("%s():%d buses not support FWH\n", __func__, __LINE__);
return 1;
}
- ret = it85xx_spi_common_init();
+ ret = it85xx_spi_common_init(s);
msg_pdbg("FWH: %s():%d ret=%d\n", __func__, __LINE__, ret);
if (!ret) {
msg_pdbg("%s():%d buses_supported=0x%x\n", __func__, __LINE__,
buses_supported);
if (buses_supported & CHIP_BUSTYPE_FWH)
msg_pdbg("Overriding chipset SPI with IT85 FWH|SPI.\n");
+ /* Really leave FWH enabled? */
buses_supported |= CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI;
}
return ret;
diff --git a/it87spi.c b/it87spi.c
index fb1448a..2b09d64 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -42,6 +42,7 @@
/* Helper functions for most recent ITE IT87xx Super I/O chips */
#define CHIP_ID_BYTE1_REG 0x20
#define CHIP_ID_BYTE2_REG 0x21
+#define CHIP_VER_REG 0x22
void enter_conf_mode_ite(uint16_t port)
{
OUTB(0x87, port);
@@ -70,31 +71,37 @@
return id;
}
-struct superio probe_superio_ite(void)
+void probe_superio_ite(void)
{
- struct superio ret = {};
+ struct superio s = {};
uint16_t ite_ports[] = {ITE_SUPERIO_PORT1, ITE_SUPERIO_PORT2, 0};
uint16_t *i = ite_ports;
- ret.vendor = SUPERIO_VENDOR_ITE;
+ s.vendor = SUPERIO_VENDOR_ITE;
for (; *i; i++) {
- ret.port = *i;
- ret.model = probe_id_ite(ret.port);
- switch (ret.model >> 8) {
+ s.port = *i;
+ s.model = probe_id_ite(s.port);
+ switch (s.model >> 8) {
case 0x82:
case 0x86:
case 0x87:
- msg_pinfo("Found ITE Super I/O, ID 0x%04hx.\n",
- ret.model);
- return ret;
+ /* FIXME: Print revision for all models? */
+ msg_pdbg("Found ITE Super I/O, ID 0x%04hx on port "
+ "0x%x\n", s.model, s.port);
+ register_superio(s);
+ break;
+ case 0x85:
+ msg_pdbg("Found ITE EC, ID 0x%04hx,"
+ "Rev 0x%02x on port 0x%x.\n",
+ s.model,
+ sio_read(s.port, CHIP_VER_REG),
+ s.port);
+ register_superio(s);
+ break;
}
}
- /* No good ID found. */
- ret.vendor = SUPERIO_VENDOR_NONE;
- ret.port = 0;
- ret.model = 0;
- return ret;
+ return;
}
static uint16_t it87spi_probe(uint16_t port)
@@ -113,7 +120,7 @@
msg_pdbg("No IT87* serial flash segment enabled.\n");
exit_conf_mode_ite(port);
/* Nothing to do. */
- return 1;
+ return 0;
}
msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n",
0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis");
@@ -159,10 +166,7 @@
"port specified.\nPort must be a multiple of "
"0x8 and lie between 0x100 and 0xff8.\n");
free(portpos);
- /* FIXME: Return failure here once it87spi_common_init()
- * can handle the return value sanely.
- */
- exit(1);
+ return 1;
} else {
flashport = (uint16_t)forced_flashport;
msg_pinfo("Forcing serial flash port 0x%04x\n",
@@ -177,44 +181,46 @@
if (buses_supported & CHIP_BUSTYPE_SPI)
msg_pdbg("Overriding chipset SPI with IT87 SPI.\n");
spi_controller = SPI_CONTROLLER_IT87XX;
+ /* FIXME: Add the SPI bus or replace the other buses with it? */
buses_supported |= CHIP_BUSTYPE_SPI;
return 0;
}
int init_superio_ite(void)
{
- if (superio.vendor != SUPERIO_VENDOR_ITE)
- return 1;
+ int i;
+ int ret = 0;
- switch (superio.model) {
- case 0x8705:
- return it8705f_write_enable(superio.port);
- break;
- case 0x8716:
- case 0x8718:
- case 0x8720:
- return it87spi_probe(superio.port);
- break;
- default:
- msg_pdbg("Super I/O ID 0x%04hx is not on the list of flash "
- "capable controllers.\n", superio.model);
- }
- return 1;
-}
+ for (i = 0; i < superio_count; i++) {
+ if (superios[i].vendor != SUPERIO_VENDOR_ITE)
+ continue;
-
-int it87spi_init(void)
-{
- int ret;
-
- get_io_perms();
- /* Probe for the Super I/O chip and fill global struct superio. */
- probe_superio();
- ret = init_superio_ite();
- if (!ret) {
- buses_supported = CHIP_BUSTYPE_SPI;
- } else {
- buses_supported = CHIP_BUSTYPE_NONE;
+ switch (superios[i].model) {
+ case 0x8500:
+ case 0x8502:
+ case 0x8510:
+ case 0x8511:
+ case 0x8512:
+ /* FIXME: This should be enabled, but we need a check
+ * for laptop whitelisting due to the amount of things
+ * which can go wrong if the EC firmware does not
+ * implement the interface we want.
+ */
+ //it85xx_spi_init(superios[i]);
+ break;
+ case 0x8705:
+ ret |= it8705f_write_enable(superios[i].port);
+ break;
+ case 0x8716:
+ case 0x8718:
+ case 0x8720:
+ ret |= it87spi_probe(superios[i].port);
+ break;
+ default:
+ msg_pdbg("Super I/O ID 0x%04hx is not on the list of "
+ "flash capable controllers.\n",
+ superios[i].model);
+ }
}
return ret;
}
@@ -323,10 +329,13 @@
*/
int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int total_size = 1024 * flash->total_size;
fast_spi = 0;
- if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
+ /* FIXME: Check if someone explicitly requested to use IT87 SPI although
+ * the mainboard does not use IT87 SPI translation. This should be done
+ * via a programmer parameter for the internal programmer.
+ */
+ if ((flash->total_size * 1024 > 512 * 1024)) {
spi_read_chunked(flash, buf, start, len, 3);
} else {
read_memmapped(flash, buf, start, len);
@@ -343,9 +352,11 @@
* so page_size > 256 bytes needs a fallback.
* FIXME: Split too big page writes into chunks IT87* can handle instead
* of degrading to single-byte program.
+ * FIXME: Check if someone explicitly requested to use IT87 SPI although
+ * the mainboard does not use IT87 SPI translation. This should be done
+ * via a programmer parameter for the internal programmer.
*/
- if ((programmer == PROGRAMMER_IT87SPI) ||
- (flash->total_size * 1024 > 512 * 1024) ||
+ if ((flash->total_size * 1024 > 512 * 1024) ||
(flash->page_size > 256)) {
spi_chip_write_1(flash, buf, start, len);
} else {
diff --git a/programmer.h b/programmer.h
index b7cebc3..7698ef0 100644
--- a/programmer.h
+++ b/programmer.h
@@ -52,11 +52,6 @@
#if CONFIG_ATAHPT == 1
PROGRAMMER_ATAHPT,
#endif
-#if CONFIG_INTERNAL == 1
-#if defined(__i386__) || defined(__x86_64__)
- PROGRAMMER_IT87SPI,
-#endif
-#endif
#if CONFIG_FT2232_SPI == 1
PROGRAMMER_FT2232_SPI,
#endif
@@ -273,7 +268,8 @@
uint16_t port;
uint16_t model;
};
-extern struct superio superio;
+extern struct superio superios[];
+extern int superio_count;
#define SUPERIO_VENDOR_NONE 0x0
#define SUPERIO_VENDOR_ITE 0x1
struct pci_dev *pci_dev_find_filter(struct pci_filter filter);
@@ -289,6 +285,7 @@
extern int force_boardenable;
extern int force_boardmismatch;
void probe_superio(void);
+int register_superio(struct superio s);
int internal_init(void);
int internal_shutdown(void);
void internal_chip_writeb(uint8_t val, chipaddr addr);
@@ -582,10 +579,8 @@
#endif
/* it85spi.c */
-struct superio probe_superio_ite85xx(void);
-int it85xx_spi_init(void);
+int it85xx_spi_init(struct superio s);
int it85xx_shutdown(void);
-int it85xx_probe_spi_flash(void);
int it85xx_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int it85_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len);
@@ -594,9 +589,8 @@
/* it87spi.c */
void enter_conf_mode_ite(uint16_t port);
void exit_conf_mode_ite(uint16_t port);
-struct superio probe_superio_ite(void);
+void probe_superio_ite(void);
int init_superio_ite(void);
-int it87spi_init(void);
int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);