diff options
author | Shawn Nematbakhsh <shawnn@chromium.org> | 2015-03-11 18:09:30 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-03-17 01:42:30 +0000 |
commit | 746debdf20a647fbe0e197f8a6c7b0597bc6a27f (patch) | |
tree | 11f04a0d74e583f71d0e7cab4c6007db52384fbc /common/spi_flash_reg.c | |
parent | fa671e65917b6673250af23e58372bcec272ca0e (diff) | |
download | chrome-ec-746debdf20a647fbe0e197f8a6c7b0597bc6a27f.tar.gz |
spi_flash: Rework protection translation functions
Previously we defined separate functions to map registers to protect
ranges for each supported SPI ROM. This change instead adds a protect range
table + flags for each supported SPI ROM and adds common functions for
translation between ranges + registers. This makes supporting new parts
easier. Since we will never use most supported protection ranges, we can
even simplfy the tables.
The implementation is now similar to flashrom.
BUG=chrome-os-partner:37688
TEST=Manual on Glower.
flashwp disable + spi_flash_rsr --> 0
flashinfo --> shows no protection
spi_flash_prot 0 0x10000 + spi_flash_rsr --> 0x24
flashinfo --> shows 64KB protected
spi_flash_prot 0 0x20000 + spi_flash_rsr --> 0x28
flashinfo --> shows all 96KB protected
spi_flash_prot 0 0x40000 + spi_flash_rsr --> 0x2c
spi_flash_prot 0 0x80000 + spi_flash_rsr --> 0x10
spi_flash_prot 0 0 + spi_flash_rsr --> 0x00
spi_flash_prot 0 0x1000 --> error
spi_flash_prot 0x10000 0x10000 --> error
BRANCH=None
Change-Id: Ie5908ce687b7ff207b09794c7b001a4fbd9e0f5a
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/259310
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'common/spi_flash_reg.c')
-rw-r--r-- | common/spi_flash_reg.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/common/spi_flash_reg.c b/common/spi_flash_reg.c new file mode 100644 index 0000000000..f1261ad823 --- /dev/null +++ b/common/spi_flash_reg.c @@ -0,0 +1,168 @@ +/* + * Copyright 2015 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. + * + * SPI flash protection register translation functions for Chrome OS EC. + */ + +#include "common.h" +#include "spi_flash_reg.h" +#include "util.h" + +/* Bit state for protect range table */ +enum bit_state { + OFF = 0, + ON = 1, + X = -1, /* Don't care */ +}; + +struct protect_range { + enum bit_state cmp; + enum bit_state sec; + enum bit_state tb; + enum bit_state bp[3]; /* Ordered {BP2, BP1, BP0} */ + uint32_t protect_start; + uint32_t protect_len; +}; + +/* Compare macro for (x =? b) for 'X' comparison */ +#define COMPARE_BIT(a, b) ((a) != X && (a) != (b)) +/* Assignment macro where 'X' = 0 */ +#define GET_BIT(a) ((a) == X ? 0 : (a)) + +/* + * Define flags and protect table for each SPI ROM part. It's not necessary + * to define all ranges in the datasheet since we'll usually protect only + * none or half of the ROM. The table is searched sequentially, so ordering + * according to likely configurations improves performance slightly. + */ +#ifdef CONFIG_SPI_FLASH_W25X40 +static const struct protect_range spi_flash_protect_ranges[] = { + { X, X, X, { 0, 0, 0 }, 0, 0 }, /* No protection */ + { X, X, 1, { 0, 1, 1 }, 0, 0x40000 }, /* Lower 1/2 */ + { X, X, 1, { 0, 0, 1 }, 0, 0x10000 }, /* Lower 1/8 */ + { X, X, 1, { 0, 1, 0 }, 0, 0x20000 }, /* Lower 1/4 */ + { X, X, X, { 1, X, X }, 0, 0x80000 }, /* All protected */ +}; + +#elif defined(CONFIG_SPI_FLASH_W25Q64) +static const struct protect_range spi_flash_protect_ranges[] = { + { 0, X, X, { 0, 0, 0 }, 0, 0 }, /* No protection */ + { 0, 0, 1, { 1, 1, 0 }, 0, 0x400000 }, /* Lower 1/2 */ + { 0, 1, 1, { 1, 0, X }, 0, 0x008000 }, /* Lower 1/256 */ + { 0, 0, 1, { 0, 0, 1 }, 0, 0x020000 }, /* Lower 1/64 */ + { 0, 0, 1, { 0, 1, 0 }, 0, 0x040000 }, /* Lower 1/32 */ + { 0, 0, 1, { 0, 1, 1 }, 0, 0x080000 }, /* Lower 1/16 */ + { 0, 0, 1, { 1, 0, 0 }, 0, 0x100000 }, /* Lower 1/8 */ + { 0, 0, 1, { 1, 0, 1 }, 0, 0x200000 }, /* Lower 1/4 */ + { 0, X, X, { 1, 1, 1 }, 0, 0x800000 }, /* All protected */ +}; +#endif + +/** + * Computes block write protection range from registers + * Returns start == len == 0 for no protection + * + * @param sr1 Status register 1 + * @param sr2 Status register 2 + * @param start Output pointer for protection start offset + * @param len Output pointer for protection length + * + * @return EC_SUCCESS, or non-zero if any error. + */ +int spi_flash_reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start, + unsigned int *len) +{ + const struct protect_range *range; + int i; + uint8_t cmp; + uint8_t sec; + uint8_t tb; + uint8_t bp; + + /* Determine flags */ + cmp = (sr2 & SPI_FLASH_SR2_CMP) ? 1 : 0; + sec = (sr1 & SPI_FLASH_SR1_SEC) ? 1 : 0; + tb = (sr1 & SPI_FLASH_SR1_TB) ? 1 : 0; + bp = (sr1 & (SPI_FLASH_SR1_BP2 | SPI_FLASH_SR1_BP1 | SPI_FLASH_SR1_BP0)) + >> 2; + + /* Bad pointers or invalid data */ + if (!start || !len || sr1 == -1 || sr2 == -1) + return EC_ERROR_INVAL; + + for (i = 0; i < ARRAY_SIZE(spi_flash_protect_ranges); ++i) { + range = &spi_flash_protect_ranges[i]; + if (COMPARE_BIT(range->cmp, cmp)) + continue; + if (COMPARE_BIT(range->sec, sec)) + continue; + if (COMPARE_BIT(range->tb, tb)) + continue; + if (COMPARE_BIT(range->bp[0], bp & 0x4)) + continue; + if (COMPARE_BIT(range->bp[1], bp & 0x2)) + continue; + if (COMPARE_BIT(range->bp[2], bp & 0x1)) + continue; + + *start = range->protect_start; + *len = range->protect_len; + return EC_SUCCESS; + } + + /* Invalid range, or valid range missing from our table */ + return EC_ERROR_INVAL; +} + +/** + * Computes block write protection registers from range + * + * @param start Desired protection start offset + * @param len Desired protection length + * @param sr1 Output pointer for status register 1 + * @param sr2 Output pointer for status register 2 + * + * @return EC_SUCCESS, or non-zero if any error. + */ +int spi_flash_protect_to_reg(unsigned int start, unsigned int len, uint8_t *sr1, + uint8_t *sr2) +{ + const struct protect_range *range; + int i; + char cmp = 0; + char sec = 0; + char tb = 0; + char bp = 0; + + /* Bad pointers */ + if (!sr1 || !sr2 || *sr1 == -1 || *sr2 == -1) + return EC_ERROR_INVAL; + + /* Invalid data */ + if ((start && !len) || start + len > CONFIG_SPI_FLASH_SIZE) + return EC_ERROR_INVAL; + + for (i = 0; i < ARRAY_SIZE(spi_flash_protect_ranges); ++i) { + range = &spi_flash_protect_ranges[i]; + if (range->protect_start == start && + range->protect_len == len) { + cmp = GET_BIT(range->cmp); + sec = GET_BIT(range->sec); + tb = GET_BIT(range->tb); + bp = GET_BIT(range->bp[0]) << 2 | + GET_BIT(range->bp[1]) << 1 | + GET_BIT(range->bp[2]); + + *sr1 = (sec ? SPI_FLASH_SR1_SEC : 0) | + (tb ? SPI_FLASH_SR1_TB : 0) | + (bp << 2); + *sr2 = (cmp ? SPI_FLASH_SR2_CMP : 0); + return EC_SUCCESS; + } + } + + /* Invalid range, or valid range missing from our table */ + return EC_ERROR_INVAL; +} |