summaryrefslogtreecommitdiff
path: root/chip/lm4/eeprom.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2011-12-07 18:51:09 +0000
committerVincent Palatin <vpalatin@chromium.org>2011-12-07 19:10:02 +0000
commitbdf7da5b082f6d18dd27f1e5d8cca0b12154a28c (patch)
tree6f14312a6cc70d056efc2bede8728c0868266719 /chip/lm4/eeprom.c
parentabe5786058f4b60dc6d30e7d7c964aae850caa1f (diff)
downloadchrome-ec-bdf7da5b082f6d18dd27f1e5d8cca0b12154a28c.tar.gz
Initial sources import 1/3
source files mainly done by Randall. Signed-off-by: Randall Spangler <rspangler@chromium.org> Change-Id: Iaff83a842b17f3350fb6f2a3f1597ad4c29bd12a
Diffstat (limited to 'chip/lm4/eeprom.c')
-rw-r--r--chip/lm4/eeprom.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/chip/lm4/eeprom.c b/chip/lm4/eeprom.c
new file mode 100644
index 0000000000..266dbe3d44
--- /dev/null
+++ b/chip/lm4/eeprom.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* EEPROM module for Chrome EC */
+
+#include "eeprom.h"
+#include "console.h"
+#include "uart.h"
+#include "registers.h"
+#include "util.h"
+
+/* Size of EEPROM block in bytes */
+#define EEPROM_BLOCK_SIZE 64
+
+/* Count of EEPROM blocks */
+static int block_count;
+
+
+/* Waits for the current EEPROM operation to finish. */
+static int wait_for_done(void)
+{
+ /* TODO: how long is a reasonable timeout? */
+ int i;
+ for (i = 0; i < 1000000; i++) {
+ if (!(LM4_EEPROM_EEDONE & 0x01))
+ return EC_SUCCESS;
+ }
+ return EC_ERROR_UNKNOWN;
+}
+
+
+int eeprom_get_block_count(void)
+{
+ return block_count;
+}
+
+
+int eeprom_get_block_size(void)
+{
+ return EEPROM_BLOCK_SIZE;
+}
+
+
+int eeprom_read(int block, int offset, int size, char *data)
+{
+ uint32_t *d = (uint32_t *)data;
+ int rv;
+
+ if (block < 0 || block >= block_count ||
+ offset < 0 || offset > EEPROM_BLOCK_SIZE || offset & 3 ||
+ size < 0 || offset + size >= EEPROM_BLOCK_SIZE || size & 3)
+ return EC_ERROR_UNKNOWN;
+
+ rv = wait_for_done();
+ if (rv)
+ return rv;
+
+ LM4_EEPROM_EEBLOCK = block;
+ if (LM4_EEPROM_EEBLOCK != block)
+ return EC_ERROR_UNKNOWN; /* Error setting block */
+
+ LM4_EEPROM_EEOFFSET = offset >> 2;
+
+ for ( ; size; size -= sizeof(uint32_t))
+ *(d++) = LM4_EEPROM_EERDWRINC;
+
+ return EC_SUCCESS;
+}
+
+
+int eeprom_write(int block, int offset, int size, const char *data)
+{
+ uint32_t *d = (uint32_t *)data;
+ int rv;
+
+ if (block < 0 || block >= block_count ||
+ offset < 0 || offset > EEPROM_BLOCK_SIZE || offset & 3 ||
+ size < 0 || offset + size >= EEPROM_BLOCK_SIZE || size & 3)
+ return EC_ERROR_UNKNOWN;
+
+ rv = wait_for_done();
+ if (rv)
+ return rv;
+
+ LM4_EEPROM_EEBLOCK = block;
+ if (LM4_EEPROM_EEBLOCK != block)
+ return EC_ERROR_UNKNOWN; /* Error setting block */
+
+ LM4_EEPROM_EEOFFSET = offset >> 2;
+
+ /* Write 32 bits at a time; wait for each write to complete */
+ for ( ; size; size -= sizeof(uint32_t)) {
+ LM4_EEPROM_EERDWRINC = *(d++);
+ rv = wait_for_done();
+ if (rv)
+ return rv;
+ if (LM4_EEPROM_EEDONE)
+ return EC_ERROR_UNKNOWN;
+ }
+
+ return EC_SUCCESS;
+}
+
+
+int eeprom_hide(int block)
+{
+ /* Block 0 can't be hidden */
+ if (block <= 0 || block >= block_count)
+ return EC_ERROR_UNKNOWN;
+
+ LM4_EEPROM_EEHIDE |= 1 << block;
+ return EC_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/* Console commands */
+
+static int command_eeprom_info(int argc, char **argv)
+{
+ uart_printf("EEPROM: %d blocks of %d bytes\n",
+ eeprom_get_block_count(), eeprom_get_block_size());
+ uart_printf(" Block-hide flags: 0x%08x\n", LM4_EEPROM_EEHIDE);
+ return EC_SUCCESS;
+}
+
+
+static int command_eeprom_read(int argc, char **argv)
+{
+ int block = 0;
+ int offset = 0;
+ char *e;
+ int rv;
+ uint32_t d;
+
+ if (argc < 2) {
+ uart_puts("Usage: eeread <block> [offset]\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ block = strtoi(argv[1], &e, 0);
+ if (*e) {
+ uart_puts("Invalid block\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ if (argc > 2) {
+ offset = strtoi(argv[2], &e, 0);
+ if (*e) {
+ uart_puts("Invalid offset\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ }
+
+ rv = eeprom_read(block, offset, sizeof(d), (char *)&d);
+ if (rv == EC_SUCCESS)
+ uart_printf("Block %d offset %d = 0x%08x\n",
+ block, offset, d);
+ return rv;
+}
+
+
+static int command_eeprom_write(int argc, char **argv)
+{
+ int block = 0;
+ int offset = 0;
+ char *e;
+ int rv;
+ uint32_t d;
+
+ if (argc < 4) {
+ uart_puts("Usage: eeread <block> <offset> <data>\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ block = strtoi(argv[1], &e, 0);
+ if (*e) {
+ uart_puts("Invalid block\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ offset = strtoi(argv[2], &e, 0);
+ if (*e) {
+ uart_puts("Invalid offset\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ d = strtoi(argv[3], &e, 0);
+ if (*e) {
+ uart_puts("Invalid data\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ uart_printf("Writing 0x%08x to block %d offset %d...\n",
+ d, block, offset);
+ rv = eeprom_write(block, offset, sizeof(d), (char *)&d);
+ if (rv == EC_SUCCESS)
+ uart_puts("done.\n");
+ return rv;
+}
+
+
+static int command_eeprom_hide(int argc, char **argv)
+{
+ int block = 0;
+ char *e;
+ int rv;
+
+ if (argc < 2) {
+ uart_puts("Usage: eehide <block>\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ block = strtoi(argv[1], &e, 0);
+ if (*e) {
+ uart_puts("Invalid block\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ uart_printf("Hiding EEPROM block %d...\n", block);
+ rv = eeprom_hide(block);
+ if (rv == EC_SUCCESS)
+ uart_printf("Done.\n");
+ return rv;
+}
+
+
+static const struct console_command console_commands[] = {
+ {"eeinfo", command_eeprom_info},
+ {"eeread", command_eeprom_read},
+ {"eewrite", command_eeprom_write},
+ {"eehide", command_eeprom_hide},
+};
+static const struct console_group command_group = {
+ "EEPROM", console_commands, ARRAY_SIZE(console_commands)
+};
+
+
+/*****************************************************************************/
+/* Initialization */
+
+
+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;
+
+ wait_for_done();
+ block_count = LM4_EEPROM_EESIZE >> 16;
+
+ console_register_commands(&command_group);
+ return EC_SUCCESS;
+}