New version. I fixed a few return codes not to return an error in case no action was needed, and killed an exit(1).
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.
Please test with boards using - IT8705 MEMW enable for parallel flash - IT8712/IT8716/... SPI flash - IT85* laptops (probably Cr-48)
This patch applies on top of [PATCH] IT85* cleanups/fixes .
WARNING! IT85* support is commented out for now until the improved laptop framework is merged. You must enable it manually by uncommenting the call to it85xx_spi_init(superios[i]) in it87spi.c or flashrom will not work on the Google Cr-48.
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
diff -ru flashrom-it85spi_cleanup/board_enable.c flashrom-register_superio/board_enable.c --- flashrom-it85spi_cleanup/board_enable.c 2011-02-22 18:12:42.000000000 +0100 +++ flashrom-register_superio/board_enable.c 2011-03-04 18:28:32.000000000 +0100 @@ -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 -ru flashrom-it85spi_cleanup/flashrom.c flashrom-register_superio/flashrom.c --- flashrom-it85spi_cleanup/flashrom.c 2011-02-22 18:12:42.000000000 +0100 +++ flashrom-register_superio/flashrom.c 2011-03-04 00:52:42.000000000 +0100 @@ -310,27 +310,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 -ru flashrom-it85spi_cleanup/internal.c flashrom-register_superio/internal.c --- flashrom-it85spi_cleanup/internal.c 2011-02-22 18:54:49.000000000 +0100 +++ flashrom-register_superio/internal.c 2011-03-04 00:33:47.000000000 +0100 @@ -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 -ru flashrom-it85spi_cleanup/it85spi.c flashrom-register_superio/it85spi.c --- flashrom-it85spi_cleanup/it85spi.c 2011-03-04 00:16:48.000000000 +0100 +++ flashrom-register_superio/it85spi.c 2011-03-04 01:40:57.000000000 +0100 @@ -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 -ru flashrom-it85spi_cleanup/it87spi.c flashrom-register_superio/it87spi.c --- flashrom-it85spi_cleanup/it87spi.c 2011-02-22 18:11:33.000000000 +0100 +++ flashrom-register_superio/it87spi.c 2011-03-04 18:33:13.000000000 +0100 @@ -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 { diff -ru flashrom-it85spi_cleanup/programmer.h flashrom-register_superio/programmer.h --- flashrom-it85spi_cleanup/programmer.h 2011-03-01 01:19:58.000000000 +0100 +++ flashrom-register_superio/programmer.h 2011-03-04 00:56:59.000000000 +0100 @@ -53,11 +53,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 @@ -274,7 +269,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); @@ -290,6 +286,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); @@ -585,10 +582,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); @@ -597,9 +592,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);