Author: hailfinger Date: Wed Apr 27 16:34:08 2011 New Revision: 1289 URL: http://flashrom.org/trac/flashrom/changeset/1289
Log: 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).
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
Modified: trunk/board_enable.c trunk/flashrom.c trunk/internal.c trunk/it85spi.c trunk/it87spi.c trunk/programmer.h
Modified: trunk/board_enable.c ============================================================================== --- trunk/board_enable.c Fri Apr 15 02:03:37 2011 (r1288) +++ trunk/board_enable.c Wed Apr 27 16:34:08 2011 (r1289) @@ -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);
Modified: trunk/flashrom.c ============================================================================== --- trunk/flashrom.c Fri Apr 15 02:03:37 2011 (r1288) +++ trunk/flashrom.c Wed Apr 27 16:34:08 2011 (r1289) @@ -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",
Modified: trunk/internal.c ============================================================================== --- trunk/internal.c Fri Apr 15 02:03:37 2011 (r1288) +++ trunk/internal.c Wed Apr 27 16:34:08 2011 (r1289) @@ -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;
Modified: trunk/it85spi.c ============================================================================== --- trunk/it85spi.c Fri Apr 15 02:03:37 2011 (r1288) +++ trunk/it85spi.c Wed Apr 27 16:34:08 2011 (r1289) @@ -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;
Modified: trunk/it87spi.c ============================================================================== --- trunk/it87spi.c Fri Apr 15 02:03:37 2011 (r1288) +++ trunk/it87spi.c Wed Apr 27 16:34:08 2011 (r1289) @@ -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; - - 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; + int i; + int ret = 0;
- 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; + 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 @@ */ 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 {
Modified: trunk/programmer.h ============================================================================== --- trunk/programmer.h Fri Apr 15 02:03:37 2011 (r1288) +++ trunk/programmer.h Wed Apr 27 16:34:08 2011 (r1289) @@ -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);