[flashrom] [PATCH] Support more than one EC/SuperIO at a time

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Fri Mar 4 01:54:29 CET 2011


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.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>

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 01:19:52.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)
@@ -183,38 +190,39 @@
 
 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 +331,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 +354,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);


-- 
http://www.hailfinger.org/





More information about the flashrom mailing list