diff options
author | Shawn Nematbakhsh <shawnn@chromium.org> | 2015-03-10 11:50:39 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-03-11 23:18:09 +0000 |
commit | 27199e7b64659a2db7114c670b903578858f8d50 (patch) | |
tree | 71a7332d6b7bbbe3cd9c57ca21b1d736daff8f96 | |
parent | d32be0292f1e1aa389da579ea29f7a151ae002e1 (diff) | |
download | chrome-ec-27199e7b64659a2db7114c670b903578858f8d50.tar.gz |
spi_flash: Add protect support for W25X40
W25X40 uses a different protection register encoding than our existing
W25Q64 code. Move the SPI ROM option to a config, and add support for
the new part.
BUG=chrome-os-partner:37688
TEST=`make buildall -j`. W25X40 protection code tested in a subsequent
commit.
BRANCH=None
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Change-Id: Iaaeabf42c6c62c20debc91afd2cf8671c14244c8
Reviewed-on: https://chromium-review.googlesource.com/258440
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | board/fruitpie/board.h | 1 | ||||
-rw-r--r-- | board/npcx_evb/board.h | 3 | ||||
-rw-r--r-- | board/strago/board.h | 2 | ||||
-rw-r--r-- | common/spi_flash.c | 119 | ||||
-rw-r--r-- | include/config.h | 6 | ||||
-rw-r--r-- | include/spi_flash.h | 6 |
6 files changed, 117 insertions, 20 deletions
diff --git a/board/fruitpie/board.h b/board/fruitpie/board.h index 8df61be852..ea5cb59d24 100644 --- a/board/fruitpie/board.h +++ b/board/fruitpie/board.h @@ -33,6 +33,7 @@ #define CONFIG_USB_SWITCH_TSU6721 #define CONFIG_SPI_FLASH #define CONFIG_SPI_FLASH_SIZE 8388608 +#define CONFIG_SPI_FLASH_W25Q64 #define CONFIG_SPI_MASTER_PORT 2 #define CONFIG_SPI_CS_GPIO GPIO_PD_TX_EN #undef CONFIG_WATCHDOG_HELP diff --git a/board/npcx_evb/board.h b/board/npcx_evb/board.h index 1fde31633d..247333b5e2 100644 --- a/board/npcx_evb/board.h +++ b/board/npcx_evb/board.h @@ -20,6 +20,8 @@ /* Optional features */ #define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands for testing */ #define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_SIZE 0x00800000 /* 8MB spi flash */ +#define CONFIG_SPI_FLASH_W25Q64 #define CONFIG_KEYBOARD_BOARD_CONFIG #define CONFIG_KEYBOARD_PROTOCOL_8042 #define CONFIG_POWER_BUTTON @@ -38,7 +40,6 @@ #define CONFIG_UART_HOST 0 #define CONFIG_FANS 1 -#define CONFIG_SPI_FLASH_SIZE 0x00800000 /* 8MB spi flash */ /* Optional feature - used by nuvoton */ #define CONFIG_PWM_INPUT_LFCLK /* PWM use LFCLK for input clock */ diff --git a/board/strago/board.h b/board/strago/board.h index b67d2d2886..6f67928ed4 100644 --- a/board/strago/board.h +++ b/board/strago/board.h @@ -28,6 +28,8 @@ #define CONFIG_SPI_CS_GPIO GPIO_PVT_CS0 #define CONFIG_SPI_FLASH #define CONFIG_SPI_FLASH_SIZE 4194304 +/* TODO: Add flash protect support for the SPI part strago actually has */ +#define CONFIG_SPI_FLASH_W25Q64 /* Modules we want to exclude */ #undef CONFIG_EEPROM #undef CONFIG_EOPTION diff --git a/common/spi_flash.c b/common/spi_flash.c index b68936ef91..53a480daab 100644 --- a/common/spi_flash.c +++ b/common/spi_flash.c @@ -3,7 +3,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * SPI flash driver for Chrome EC, particularly Winbond W25Q64FV. + * SPI flash driver for Chrome EC. */ #include "common.h" @@ -26,7 +26,8 @@ #define SPI_FLASH_TIMEOUT_USEC (800*MSEC) /* - * Registers for the W25Q64FV SPI flash + * Common registers for SPI flash. All registers may not be valid for + * all parts. */ #define SPI_FLASH_SR2_SUS (1 << 7) #define SPI_FLASH_SR2_CMP (1 << 6) @@ -58,6 +59,7 @@ static uint8_t buf[SPI_FLASH_MAX_MESSAGE_SIZE]; * * @return EC_SUCCESS, or non-zero if any error. */ +#ifdef CONFIG_SPI_FLASH_W25Q64 static int reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start, unsigned int *len) { @@ -109,6 +111,40 @@ static int reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start, return EC_SUCCESS; } +#elif defined(CONFIG_SPI_FLASH_W25X40) /* CONFIG_SPI_FLASH_W25Q64 */ +static int reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start, + unsigned int *len) +{ + int blocks; + int size; + uint8_t tb; + uint8_t bp; + + 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; + + /* 64kb block protection granularity */ + size = 32 * 1024; + + /* Determine number of blocks */ + /* Equivalent to pow(2, bp) with pow(2, 0) = 0 */ + /* BP2 set indicates entire 512kb flash protected */ + if (!bp) + blocks = 0; + else + blocks = MIN((1 << 4), (1 << bp)); + *len = size * blocks; + *start = tb ? 0 : + (CONFIG_SPI_FLASH_SIZE - *len) % CONFIG_SPI_FLASH_SIZE; + + return EC_SUCCESS; +} +#endif /* CONFIG_SPI_FLASH_W25X40 */ /** * Computes block write protection registers from range @@ -120,6 +156,7 @@ static int reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start, * * @return EC_SUCCESS, or non-zero if any error. */ +#ifdef CONFIG_SPI_FLASH_W25Q64 static int protect_to_reg(unsigned int start, unsigned int len, uint8_t *sr1, uint8_t *sr2) { @@ -180,6 +217,48 @@ static int protect_to_reg(unsigned int start, unsigned int len, return EC_SUCCESS; } +#elif defined(CONFIG_SPI_FLASH_W25X40) /* CONFIG_SPI_FLASH_W25Q64 */ +static int protect_to_reg(unsigned int start, unsigned int len, + uint8_t *sr1, uint8_t *sr2) +{ + char tb = 0; + char bp = 0; + int blocks; + int size; + + /* 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; + + /* Set bottom/top bit based on start address */ + if (!start && (len % CONFIG_SPI_FLASH_SIZE)) + tb = 1; + + /* 64kb block protection granularity */ + size = 32 * 1024; + + /* Determine number of blocks */ + if (len % size != 0) + return EC_ERROR_INVAL; + blocks = len / size; + + /* Determine bp = log2(blocks) with log2(0) = 0 */ + bp = blocks ? (31 - __builtin_clz(blocks)) : 0; + + /* Clear bits */ + *sr1 &= ~(SPI_FLASH_SR1_TB | SPI_FLASH_SR1_BP2 | SPI_FLASH_SR1_BP1 | + SPI_FLASH_SR1_BP0); + + /* Set bits */ + *sr1 |= (tb ? SPI_FLASH_SR1_TB : 0) | (bp << 2); + + return EC_SUCCESS; +} +#endif /* CONFIG_SPI_FLASH_W25X40 */ /** * Waits for chip to finish current operation. Must be called after @@ -236,6 +315,11 @@ uint8_t spi_flash_get_status2(void) uint8_t cmd = SPI_FLASH_READ_SR2; uint8_t resp; +#ifdef CONFIG_SPI_FLASH_W25X40 + /* Second status register not present */ + return 0; +#endif + if (spi_transaction(&cmd, 1, &resp, 1) != EC_SUCCESS) return -1; @@ -257,15 +341,19 @@ int spi_flash_set_status(int reg1, int reg2) int rv = EC_SUCCESS; /* Register has protection */ - rv = spi_flash_check_wp(); - if (rv) - return rv; + if (spi_flash_check_wp() != SPI_WP_NONE) + return EC_ERROR_ACCESS_DENIED; /* Enable writing to SPI flash */ rv = spi_flash_write_enable(); if (rv) return rv; +#ifdef CONFIG_SPI_FLASH_W25X40 + /* Second status register not present */ + reg2 = -1; +#endif + if (reg2 == -1) rv = spi_transaction(cmd, 2, NULL, 0); else @@ -458,21 +546,22 @@ uint64_t spi_flash_get_unique_id(void) /** * Check for SPI flash status register write protection - * Cannot sample WP pin, will consider hardware WP to be no protection - * - * @param wp Status register write protection mode + * Cannot sample WP pin, so caller should sample it if necessary, if + * SPI_WP_HARDWARE is returned. * - * @return EC_SUCCESS for no protection, or non-zero if error. + * @return enum spi_flash_wp status based on protection */ -int spi_flash_check_wp(void) +enum spi_flash_wp spi_flash_check_wp(void) { - int sr2 = spi_flash_get_status2(); + int sr1_prot = spi_flash_get_status1() & SPI_FLASH_SR1_SRP0; + int sr2_prot = spi_flash_get_status2() & SPI_FLASH_SR2_SRP1; - /* Power cycle or OTP protection */ - if (sr2 & SPI_FLASH_SR2_SRP1) - return EC_ERROR_ACCESS_DENIED; + if (sr2_prot) + return sr1_prot ? SPI_WP_PERMANENT : SPI_WP_POWER_CYCLE; + else if (sr1_prot) + return SPI_WP_HARDWARE; - return EC_SUCCESS; + return SPI_WP_NONE; } /** diff --git a/include/config.h b/include/config.h index c4974dd471..eee74b4389 100644 --- a/include/config.h +++ b/include/config.h @@ -1039,6 +1039,12 @@ /* Support SPI flash */ #undef CONFIG_SPI_FLASH +/* Support W25Q64 SPI flash */ +#undef CONFIG_SPI_FLASH_W25Q64 + +/* Support W25X40 SPI flash */ +#undef CONFIG_SPI_FLASH_W25X40 + /* Size (bytes) of SPI flash memory */ #undef CONFIG_SPI_FLASH_SIZE diff --git a/include/spi_flash.h b/include/spi_flash.h index 9e83ea9e91..9b8a0a64d5 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -141,11 +141,9 @@ uint64_t spi_flash_get_unique_id(void); * Note that this does not check the hardware WP pin as we might not be * able to read the WP pin status. * - * @param wp Status register write protection mode - * - * @return EC_SUCCESS for no protection, or non-zero if error. + * @return enum spi_flash_wp status based on protection */ -int spi_flash_check_wp(void); +enum spi_flash_wp spi_flash_check_wp(void); /** * Set SPI flash status register write protection |