From bfecef6986b25b630605054680264daf09046f65 Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Wed, 27 Apr 2011 14:34:08 +0000 Subject: 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 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 --- it87spi.c | 121 ++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 66 insertions(+), 55 deletions(-) (limited to 'it87spi.c') diff --git a/it87spi.c b/it87spi.c index fb1448a..2b09d64 100644 --- a/it87spi.c +++ b/it87spi.c @@ -42,6 +42,7 @@ static int fast_spi = 1; /* 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 @@ uint16_t probe_id_ite(uint16_t port) 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 @@ static uint16_t it87spi_probe(uint16_t port) 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 @@ static uint16_t it87spi_probe(uint16_t port) "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 @@ static uint16_t it87spi_probe(uint16_t port) 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; - - 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; -} - - -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; + int i; + int ret = 0; + + for (i = 0; i < superio_count; i++) { + if (superios[i].vendor != SUPERIO_VENDOR_ITE) + continue; + + 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 @@ static int it8716f_spi_page_program(struct flashchip *flash, uint8_t *buf, int s */ 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 @@ int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, * 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 { -- cgit v1.1