diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-06-22 09:24:01 -0700 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-06-22 11:34:16 -0700 |
commit | 232363bac25dc6af5d2ff580fded6baff9546398 (patch) | |
tree | 72e86f0d464fd0fd7f3d06a94f24eedfb7ab5a2b /chip | |
parent | 23d9defb2bfa3bbe5b35609be30dfce98b54c9a4 (diff) | |
download | chrome-ec-232363bac25dc6af5d2ff580fded6baff9546398.tar.gz |
Revise EEPROM init and write routines
They now more closely resemble TI's recommended flow.
BUG=chrome-os-partner:10764
TEST=manual:
eewrite 1 12 0x1000
eeread 1 12 --> should be 0x1000
eewrite 1 12 0
eewrite 1 12 1
...
eewrite 1 12 100
eewrite 1 12 0xabcd
eeread 1 12 --> should be 0xabcd
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Change-Id: I309caea2774615518e68a0d01d33b052d6945c0f
Reviewed-on: https://gerrit.chromium.org/gerrit/25941
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/lm4/eeprom.c | 73 | ||||
-rw-r--r-- | chip/lm4/registers.h | 2 |
2 files changed, 53 insertions, 22 deletions
diff --git a/chip/lm4/eeprom.c b/chip/lm4/eeprom.c index 03768d2c13..ff414ede24 100644 --- a/chip/lm4/eeprom.c +++ b/chip/lm4/eeprom.c @@ -5,8 +5,9 @@ /* EEPROM module for Chrome EC */ -#include "eeprom.h" +#include "clock.h" #include "console.h" +#include "eeprom.h" #include "registers.h" #include "timer.h" #include "util.h" @@ -19,16 +20,26 @@ static int block_count; -/* Waits for the current EEPROM operation to finish; all operations but write - * should normally finish in 4 system clocks. eeprom_write() has its own - * delay loop for the longer delay. */ +/* + * Wait for the current EEPROM operation to finish; all operations but write + * should normally finish in 4 system clocks, but worst case is up to + * 1800ms if the EEPROM needs to do an internal page erase/copy. We must + * spin-wait for this delay, because EEPROM operations will fail if the chip + * drops to sleep mode. + */ static int wait_for_done(void) { - int i; - for (i = 0; i < 1000; i++) { - if (!(LM4_EEPROM_EEDONE & 0x01)) - return EC_SUCCESS; + int j; + + for (j = 0; j < 20; j++) { /* 20 * 100 ms = 2000 ms */ + uint64_t tstop = get_time().val + 100000; /* 100ms from now */ + while (get_time().val < tstop) { + if (!(LM4_EEPROM_EEDONE & 0x01)) + return EC_SUCCESS; + } + watchdog_reload(); } + return EC_ERROR_UNKNOWN; } @@ -75,7 +86,7 @@ int eeprom_read(int block, int offset, int size, char *data) int eeprom_write(int block, int offset, int size, const char *data) { uint32_t *d = (uint32_t *)data; - int rv, i; + int rv; if (block < 0 || block >= block_count || offset < 0 || offset > EEPROM_BLOCK_SIZE || offset & 3 || @@ -96,18 +107,17 @@ int eeprom_write(int block, int offset, int size, const char *data) for ( ; size; size -= sizeof(uint32_t)) { LM4_EEPROM_EERDWRINC = *(d++); - /* Writes nominally take ~110us, but can take up to 1800 ms - * worst-case (near endurance limit and need erase/copy). */ - for (i = 0; i < 2000 && (LM4_EEPROM_EEDONE & 0x01); i++) { - /* First few delays are smaller for nominal case */ - usleep(i < 20 ? 100 : 1000); - /* Reload the watchdog timer in case we're called - * before task scheduling starts. */ - watchdog_reload(); - } + rv = wait_for_done(); + if (rv) + return rv; - if (LM4_EEPROM_EEDONE) + if (LM4_EEPROM_EEDONE & 0x10) { + /* Failed due to write protect */ + return EC_ERROR_ACCESS_DENIED; + } else if (LM4_EEPROM_EEDONE & 0x100) { + /* Failed due to program voltage level */ return EC_ERROR_UNKNOWN; + } } return EC_SUCCESS; @@ -231,14 +241,33 @@ DECLARE_CONSOLE_COMMAND(eehide, command_eeprom_hide, int eeprom_init(void) { - volatile uint32_t scratch __attribute__((unused)); - /* Enable the EEPROM module and delay a few clocks */ LM4_SYSTEM_RCGCEEPROM = 1; - scratch = LM4_SYSTEM_RCGCEEPROM; + clock_wait_cycles(6); + /* Wait for internal EEPROM init to finish */ wait_for_done(); + + /* Store block count */ block_count = LM4_EEPROM_EESIZE >> 16; + /* + * Handle resetting the EEPROM module to clear state from a previous + * error condition. + */ + if (LM4_EEPROM_EESUPP & 0xc0) { + LM4_SYSTEM_SREEPROM = 1; + clock_wait_cycles(200); + LM4_SYSTEM_SREEPROM = 0; + + /* Wait again for internal init to finish */ + clock_wait_cycles(6); + wait_for_done(); + + /* Fail if error condition didn't clear */ + if (LM4_EEPROM_EESUPP & 0xc0) + return EC_ERROR_UNKNOWN; + } + return EC_SUCCESS; } diff --git a/chip/lm4/registers.h b/chip/lm4/registers.h index dccd86e179..18a75b6027 100644 --- a/chip/lm4/registers.h +++ b/chip/lm4/registers.h @@ -240,6 +240,7 @@ static inline int lm4_fan_addr(int ch, int offset) /* Note: USER_REG3 is used to hold pre-programming process data and should not * be modified by EC code. See crosbug.com/p/8889. */ #define LM4_SYSTEM_USER_REG3 LM4REG(0x400fe1ec) +#define LM4_SYSTEM_SREEPROM LM4REG(0x400fe558) #define LM4_SYSTEM_RCGCWD LM4REG(0x400fe600) #define LM4_SYSTEM_RCGCTIMER LM4REG(0x400fe604) #define LM4_SYSTEM_RCGCGPIO LM4REG(0x400fe608) @@ -254,6 +255,7 @@ static inline int lm4_fan_addr(int ch, int offset) #define LM4_SYSTEM_RCGCFAN LM4REG(0x400fe654) #define LM4_SYSTEM_RCGCEEPROM LM4REG(0x400fe658) #define LM4_SYSTEM_RCGCWTIMER LM4REG(0x400fe65c) +#define LM4_SYSTEM_PREEPROM LM4REG(0x400fea58) #define LM4_DMA_DMACFG LM4REG(0x400ff004) #define LM4_DMA_DMACTLBASE LM4REG(0x400ff008) |