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 <[email protected]>

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 <[email protected]>

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);

_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to