diff options
author | Rong Chang <rongchang@google.com> | 2011-12-09 14:34:54 +0800 |
---|---|---|
committer | Rong Chang <rongchang@google.com> | 2011-12-12 18:21:08 +0800 |
commit | 1eb5417847831c9dda4c8609af67ad21f9bfba42 (patch) | |
tree | 1f94c726cb5d72397a66c765981d46ad8dd0aa6d /chip/lm4/flash.c | |
parent | 82f89a25373e0e614d3d1e94c91b1455242467ab (diff) | |
download | chrome-ec-1eb5417847831c9dda4c8609af67ad21f9bfba42.tar.gz |
Add flash write protect range command
This CL add host command to enable, get/set flash write protect range.
BUG=None
TEST=Use flashrom utility to set write protect range, enable write
protect and get status.
Change-Id: I345f1eb65944d8cf8028e6fdb7e43c40cc742a6d
Signed-off-by: Rong Chang <rongchang@chromium.org>
Diffstat (limited to 'chip/lm4/flash.c')
-rw-r--r-- | chip/lm4/flash.c | 126 |
1 files changed, 122 insertions, 4 deletions
diff --git a/chip/lm4/flash.c b/chip/lm4/flash.c index 115747d7d9..10a07343d2 100644 --- a/chip/lm4/flash.c +++ b/chip/lm4/flash.c @@ -11,6 +11,10 @@ #include "registers.h" #include "util.h" +#define BANK_SHIFT 5 /* bank registers have 32bits each, 2^32 */ +#define BANK_MASK ((1 << BANK_SHIFT) - 1) /* 5 bits */ +#define F_BANK(b) ((b) >> BANK_SHIFT) +#define F_BIT(b) (1 << ((b) & BANK_MASK)) static int usable_flash_size; @@ -151,22 +155,136 @@ int flash_erase(int offset, int size) return EC_SUCCESS; } +/* Get write protect status of single flash block + * return value: + * 0 - WP + * non-zero - writable + */ +static uint32_t get_block_wp(int block) +{ + return LM4_FLASH_FMPPE[F_BANK(block)] & F_BIT(block); +} -int flash_get_write_protect_range(int *offset, int *size) +static void set_block_wp(int block) { - return EC_ERROR_UNIMPLEMENTED; + LM4_FLASH_FMPPE[F_BANK(block)] &= ~F_BIT(block); } +static int find_first_wp_block(void) +{ + int block; + for (block = 0; block < LM4_FLASH_FSIZE; block++) + if (get_block_wp(block) == 0) + return block; + return -1; +} + +static int find_last_wp_block(void) +{ + int block; + for (block = LM4_FLASH_FSIZE - 1; block >= 0; block--) + if (get_block_wp(block) == 0) + return block; + return -1; +} + +static int get_wp_range(int *start, int *nblock) +{ + int start_blk, end_blk; + + start_blk = find_first_wp_block(); + + if (start_blk < 0) { + /* Flash is not write protected */ + *start = 0; + *nblock = 0; + return EC_SUCCESS; + } + + /* TODO: Sanity check the shadow value? */ + + end_blk = find_last_wp_block(); + *nblock = end_blk - start_blk + 1; + *start = start_blk; + return EC_SUCCESS; +} + + +static int set_wp_range(int start, int nblock) +{ + int end_blk, block; + + if (nblock == 0) + return EC_SUCCESS; + + end_blk = (start + nblock - 1); + + for (block = start; block <= end_blk; block++) + set_block_wp(block); + + return EC_SUCCESS; +} + +int flash_get_write_protect_range(int *offset, int *size) +{ + int start, nblock; + int rv; + + rv = get_wp_range(&start, &nblock); + if (rv) + return rv; + + *size = nblock * FLASH_PROTECT_BYTES; + *offset = start * FLASH_PROTECT_BYTES; + return EC_SUCCESS; +} int flash_set_write_protect_range(int offset, int size) { - return EC_ERROR_UNIMPLEMENTED; + int start, nblock; + int rv; + + if ((offset < 0) || (size < 0) || ((offset + size) > + (LM4_FLASH_FSIZE * FLASH_PROTECT_BYTES))) + return EC_ERROR_UNKNOWN; /* Invalid range */ + + rv = flash_get_write_protect_status(); + + if (rv & EC_FLASH_WP_RANGE_LOCKED) { + if (size == 0) { + /* TODO: Clear shadow if system WP is asserted */ + /* TODO: Reboot EC */ + return EC_SUCCESS; + } + + return EC_ERROR_UNKNOWN; /* Range locked */ + } + + start = offset / FLASH_PROTECT_BYTES; + nblock = ((offset + size - 1) / FLASH_PROTECT_BYTES) - start + 1; + rv = set_wp_range(start, nblock); + if (rv) + return rv; + + return EC_SUCCESS; } int flash_get_write_protect_status(void) { - return EC_ERROR_UNIMPLEMENTED; + int start, nblock; + int rv; + + rv = get_wp_range(&start, &nblock); + if (rv) + return rv; + + rv = 0; + if (nblock) + rv |= EC_FLASH_WP_RANGE_LOCKED; + /* TODO: get WP gpio*/ + + return rv; } |