diff options
author | Randall Spangler <rspangler@chromium.org> | 2011-12-07 18:51:09 +0000 |
---|---|---|
committer | Vincent Palatin <vpalatin@chromium.org> | 2011-12-07 19:10:02 +0000 |
commit | bdf7da5b082f6d18dd27f1e5d8cca0b12154a28c (patch) | |
tree | 6f14312a6cc70d056efc2bede8728c0868266719 /chip/lm4/eeprom.c | |
parent | abe5786058f4b60dc6d30e7d7c964aae850caa1f (diff) | |
download | chrome-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.c | 256 |
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; +} |