Author: hailfinger Date: Tue Mar 1 00:58:15 2011 New Revision: 1263 URL: http://flashrom.org/trac/flashrom/changeset/1263
Log: 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.
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
Modified: trunk/Makefile trunk/it85spi.c trunk/programmer.h trunk/spi.c
Modified: trunk/Makefile ============================================================================== --- trunk/Makefile Tue Feb 22 18:16:34 2011 (r1262) +++ trunk/Makefile Tue Mar 1 00:58:15 2011 (r1263) @@ -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
Modified: trunk/it85spi.c ============================================================================== --- trunk/it85spi.c Tue Feb 22 18:16:34 2011 (r1262) +++ trunk/it85spi.c Tue Mar 1 00:58:15 2011 (r1263) @@ -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; }
Modified: trunk/programmer.h ============================================================================== --- trunk/programmer.h Tue Feb 22 18:16:34 2011 (r1262) +++ trunk/programmer.h Tue Mar 1 00:58:15 2011 (r1263) @@ -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);
Modified: trunk/spi.c ============================================================================== --- trunk/spi.c Tue Feb 22 18:16:34 2011 (r1262) +++ trunk/spi.c Tue Mar 1 00:58:15 2011 (r1263) @@ -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,