Update the ITE IT8500 EC support to match the current state of the flashrom-chromium tree

This code has been deployed and tested to work on the Cr-48.
There are a few caveats, though:
- The boot BIOS straps register must be modified to select LPC. This
  can be done with the "select_bbs.sh" script (Install iotools at
  http://code.google.com/p/iotools/ before using select_bbs).
- It is very important to disable power management daemons before
  running flashrom on this EC. I commented out the brute force method
  we use in the Chromium OS branch that disables powerd, since IIRC
  Carl-Daniel has a better approach in the works.
- Due to dependencies which may be introduced by the OEM/ODM EC
  firmware, the code is not guaranteed to work for anything other than
  the Cr-48.

Corresponding to flashrom svn r1263.

Signed-off-by: David Hendricks <dhendrix@google.com>

Carl-Daniel comments:
Code is not hooked up yet because probing needs to be sorted out.

Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
diff --git a/Makefile b/Makefile
index 9225204..6028485 100644
--- a/Makefile
+++ b/Makefile
@@ -184,7 +184,7 @@
 FEATURE_CFLAGS += -D'CONFIG_INTERNAL=1'
 PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o
 # FIXME: The PROGRAMMER_OBJS below should only be included on x86.
-PROGRAMMER_OBJS += it87spi.o ichspi.o sb600spi.o wbsio_spi.o mcp6x_spi.o
+PROGRAMMER_OBJS += it87spi.o it85spi.o ichspi.o sb600spi.o wbsio_spi.o mcp6x_spi.o
 NEED_PCI := yes
 endif
 
diff --git a/it85spi.c b/it85spi.c
index 8fac3ea..6d5b1d1 100644
--- a/it85spi.c
+++ b/it85spi.c
@@ -27,18 +27,23 @@
 #if defined(__i386__) || defined(__x86_64__)
 
 #include <string.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include "flash.h"
 #include "chipdrivers.h"
 #include "spi.h"
 #include "programmer.h"
 
+#define MAX_TIMEOUT 100000
+#define MAX_TRY 5
+
 /* Constans for I/O ports */
 #define ITE_SUPERIO_PORT1	0x2e
 #define ITE_SUPERIO_PORT2	0x4e
 
 /* Legacy I/O */
-#define LEGACY_KBC_PORT		0x64
+#define LEGACY_KBC_PORT_DATA	0x60
+#define LEGACY_KBC_PORT_CMD	0x64
 
 /* Constants for Logical Device registers */
 #define LDNSEL			0x07
@@ -50,6 +55,13 @@
 #define SHM_IO_BAD0		0x60  /* big-endian, this is high bits */
 #define SHM_IO_BAD1		0x61
 
+/* 8042 keyboard controller uses an input buffer and an output buffer to
+ * communicate with host CPU. Both buffers are 1-byte depth. That means the
+ * IBF is set to 1 when host CPU sends a command to input buffer (standing on
+ * the EC side). IBF is cleared to 0 once the command is read by EC. */
+#define KB_IBF 			(1 << 1)  /* Input Buffer Full */
+#define KB_OBF 			(1 << 0)  /* Output Buffer Full */
+
 /* IT8502 supports two access modes:
  *   LPC_MEMORY: through the memory window in 0xFFFFFxxx (follow mode)
  *   LPC_IO: through I/O port (so called indirect memory)
@@ -95,11 +107,11 @@
 		ret.model = probe_id_ite85(ret.port);
 		switch (ret.model >> 8) {
 		case 0x85:
-			msg_pinfo("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);
+			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;
 		}
 	}
@@ -111,20 +123,147 @@
 	return ret;
 }
 
-/* IT8502 employs a scratch rom when flash is updating. Call the following two
- * functions before/after flash erase/program. */
+/* This function will poll the keyboard status register until either
+ *   an expected value shows up, or
+ *   timeout reaches.
+ *
+ * Returns: 0 -- the expected value has shown.
+ *          1 -- timeout reached.
+ */
+static int wait_for(
+		const unsigned int mask,
+		const unsigned int expected_value,
+		const int timeout,  /* in usec */
+		const char* error_message,
+		const char* function_name,
+		const int lineno
+) {
+	int time_passed;
+
+	for (time_passed = 0;; ++time_passed) {
+		if ((INB(LEGACY_KBC_PORT_CMD) & mask) == expected_value)
+			return 0;
+		if (time_passed >= timeout)
+			break;
+		programmer_delay(1);
+	}
+	if (error_message)
+		msg_perr("%s():%d %s", function_name, lineno, error_message);
+	return 1;
+}
+
+/* IT8502 employs a scratch ram when flash is being updated. Call the following
+ * two functions before/after flash erase/program. */
 void it85xx_enter_scratch_rom()
 {
+	int ret;
+	int tries;
+
+	msg_pdbg("%s():%d was called ...\n", __FUNCTION__, __LINE__);
 	if (it85xx_scratch_rom_reenter > 0) return;
-	it85xx_scratch_rom_reenter++;
-	OUTB(0xb4, LEGACY_KBC_PORT);
+
+#if 0
+	/* FIXME: this a workaround for the bug that SMBus signal would
+	 *        interfere the EC firmware update. Should be removed if
+	 *        we find out the root cause. */
+	ret = system("stop powerd >&2");
+	if (ret) {
+		msg_perr("Cannot stop powerd.\n");
+	}
+#endif
+
+	for (tries = 0; tries < MAX_TRY; ++tries) {
+		/* Wait until IBF (input buffer) is not full. */
+		if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+		             "* timeout at waiting for IBF==0.\n",
+		             __FUNCTION__, __LINE__))
+			continue;
+
+		/* Copy EC firmware to SRAM. */
+		OUTB(0xb4, LEGACY_KBC_PORT_CMD);
+
+		/* Confirm EC has taken away the command. */
+		if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+		             "* timeout at taking command.\n",
+		             __FUNCTION__, __LINE__))
+			continue;
+
+		/* Waiting for OBF (output buffer) has data.
+		 * Note sometimes the replied command might be stolen by kernel
+		 * ISR so that it is okay as long as the command is 0xFA. */
+		if (wait_for(KB_OBF, KB_OBF, MAX_TIMEOUT, NULL, NULL, 0))
+			msg_pdbg("%s():%d * timeout at waiting for OBF.\n",
+			         __FUNCTION__, __LINE__);
+		if ((ret = INB(LEGACY_KBC_PORT_DATA)) == 0xFA) {
+			break;
+		} else {
+			msg_perr("%s():%d * not run on SRAM ret=%d\n",
+			         __FUNCTION__, __LINE__, ret);
+			continue;
+		}
+	}
+
+	if (tries < MAX_TRY) {
+		/* EC already runs on SRAM */
+		it85xx_scratch_rom_reenter++;
+		msg_pdbg("%s():%d * SUCCESS.\n", __FUNCTION__, __LINE__);
+	} else {
+		msg_perr("%s():%d * Max try reached.\n",
+		         __FUNCTION__, __LINE__);
+	}
 }
 
 void it85xx_exit_scratch_rom()
 {
+#if 0
+	int ret;
+#endif
+	int tries;
+
+	msg_pdbg("%s():%d was called ...\n", __FUNCTION__, __LINE__);
 	if (it85xx_scratch_rom_reenter <= 0) return;
-	it85xx_scratch_rom_reenter = 0;
-	OUTB(0xfe, LEGACY_KBC_PORT);
+
+	for (tries = 0; tries < MAX_TRY; ++tries) {
+		/* Wait until IBF (input buffer) is not full. */
+		if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+		             "* timeout at waiting for IBF==0.\n",
+		             __FUNCTION__, __LINE__))
+			continue;
+
+		/* Exit SRAM. Run on flash. */
+		OUTB(0xFE, LEGACY_KBC_PORT_CMD);
+
+		/* Confirm EC has taken away the command. */
+		if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
+		             "* timeout at taking command.\n",
+		             __FUNCTION__, __LINE__)) {
+			/* We cannot ensure if EC has exited update mode.
+			 * If EC is in normal mode already, a further 0xFE
+			 * command will reboot system. So, exit loop here. */
+			tries = MAX_TRY;
+			break;
+		}
+
+		break;
+	}
+
+	if (tries < MAX_TRY) {
+		it85xx_scratch_rom_reenter = 0;
+		msg_pdbg("%s():%d * SUCCESS.\n", __FUNCTION__, __LINE__);
+	} else {
+		msg_perr("%s():%d * Max try reached.\n",
+		         __FUNCTION__, __LINE__);
+	}
+
+#if 0
+	/* FIXME: this a workaround for the bug that SMBus signal would
+	 *        interfere the EC firmware update. Should be removed if
+	 *        we find out the root cause. */
+	ret = system("start powerd >&2");
+	if (ret) {
+		msg_perr("Cannot start powerd again.\n");
+	}
+#endif
 }
 
 int it85xx_spi_common_init(void)
@@ -256,6 +395,14 @@
 		readarr[i] = *ce_low;
 #endif
 	}
+#ifdef LPC_IO
+	INDIRECT_A1(shm_io_base, (((unsigned long int)ce_high) >> 8) & 0xff);
+	INDIRECT_WRITE(shm_io_base, 0xFF);  /* Write anything to this address.*/
+#endif
+#ifdef LPC_MEMORY
+	*ce_high = 0;
+#endif
+
 	return 0;
 }
 
diff --git a/programmer.h b/programmer.h
index da49096..7a497f8 100644
--- a/programmer.h
+++ b/programmer.h
@@ -523,6 +523,7 @@
 #if defined(__i386__) || defined(__x86_64__)
 	SPI_CONTROLLER_ICH7,
 	SPI_CONTROLLER_ICH9,
+	SPI_CONTROLLER_IT85XX,
 	SPI_CONTROLLER_IT87XX,
 	SPI_CONTROLLER_SB600,
 	SPI_CONTROLLER_VIA,
@@ -583,6 +584,14 @@
 int ich_spi_send_multicommand(struct spi_command *cmds);
 #endif
 
+/* it85spi.c */
+struct superio probe_superio_ite85xx(void);
+int it85xx_spi_init(void);
+int it85xx_shutdown(void);
+int it85xx_probe_spi_flash(const char *name);
+int it85xx_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, unsigned char *readarr);
+
 /* it87spi.c */
 void enter_conf_mode_ite(uint16_t port);
 void exit_conf_mode_ite(uint16_t port);
diff --git a/spi.c b/spi.c
index 7d76120..8106360 100644
--- a/spi.c
+++ b/spi.c
@@ -55,6 +55,13 @@
 		.write_256 = ich_spi_write_256,
 	},
 
+	{ /* SPI_CONTROLLER_IT85XX */
+		.command = it85xx_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = ich_spi_read,
+		.write_256 = ich_spi_write_256,
+	},
+
 	{ /* SPI_CONTROLLER_IT87XX */
 		.command = it8716f_spi_send_command,
 		.multicommand = default_spi_send_multicommand,