summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2015-03-10 11:50:39 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-03-11 23:18:09 +0000
commit27199e7b64659a2db7114c670b903578858f8d50 (patch)
tree71a7332d6b7bbbe3cd9c57ca21b1d736daff8f96
parentd32be0292f1e1aa389da579ea29f7a151ae002e1 (diff)
downloadchrome-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.h1
-rw-r--r--board/npcx_evb/board.h3
-rw-r--r--board/strago/board.h2
-rw-r--r--common/spi_flash.c119
-rw-r--r--include/config.h6
-rw-r--r--include/spi_flash.h6
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