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 <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>
diff --git a/it87spi.c b/it87spi.c
index fb1448a..2b09d64 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -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;
+	int i;
+	int ret = 0;
 
-	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;
-}
+	for (i = 0; i < superio_count; i++) {
+		if (superios[i].vendor != SUPERIO_VENDOR_ITE)
+			continue;
 
-
-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;
+		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 {