summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-06-22 09:24:01 -0700
committerGerrit <chrome-bot@google.com>2012-06-22 11:34:16 -0700
commit232363bac25dc6af5d2ff580fded6baff9546398 (patch)
tree72e86f0d464fd0fd7f3d06a94f24eedfb7ab5a2b /chip
parent23d9defb2bfa3bbe5b35609be30dfce98b54c9a4 (diff)
downloadchrome-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.c73
-rw-r--r--chip/lm4/registers.h2
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)