summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunLin <CHLin56@nuvoton.com>2020-12-28 17:16:50 +0800
committerCommit Bot <commit-bot@chromium.org>2020-12-29 22:16:49 +0000
commit9da76bf112b451ca3e294100f5c24d188c7860e9 (patch)
tree42cdb6479084fdce00f5318e66ece82146e9d3a1
parent373c310c8e78650d644b038530a34a5433412870 (diff)
downloadchrome-ec-9da76bf112b451ca3e294100f5c24d188c7860e9.tar.gz
zephyr: shim the flash access
Implement the flash_physical* APIs by wrapping the cros_flash device driver APIs in zephyr-chrome BRANCH=none BUG=b:174874876 TEST=pass build with related patches. TEST=combine with related patches, use console commands to test all the implemented flash APIs. Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: JunLin <CHLin56@nuvoton.com> Cq-Depend: chromium:2601823, chromium:2598212 Change-Id: I72543fe6290e24b74f7c6bf133599e577c529f08 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2600809
-rw-r--r--zephyr/CMakeLists.txt3
-rw-r--r--zephyr/shim/include/config_chip.h1
-rw-r--r--zephyr/shim/src/flash.c333
3 files changed, 330 insertions, 7 deletions
diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt
index 1f72e715be..78fc2bc86b 100644
--- a/zephyr/CMakeLists.txt
+++ b/zephyr/CMakeLists.txt
@@ -64,7 +64,8 @@ zephyr_sources_ifdef(CONFIG_PLATFORM_EC_ESPI "${PLATFORM_EC}/common/espi.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC "${PLATFORM_EC}/common/extpower_common.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_EXTPOWER_GPIO
"${PLATFORM_EC}/common/extpower_gpio.c")
-zephyr_sources_ifdef(CONFIG_PLATFORM_EC_FLASH "${PLATFORM_EC}/common/flash.c")
+zephyr_sources_ifdef(CONFIG_PLATFORM_EC_FLASH "${PLATFORM_EC}/common/flash.c"
+ "${PLATFORM_EC}/common/spi_flash_reg.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_HOSTCMD "${PLATFORM_EC}/common/host_command.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_HOSTCMD "${PLATFORM_EC}/common/host_event_commands.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_I2C "${PLATFORM_EC}/common/i2c_controller.c")
diff --git a/zephyr/shim/include/config_chip.h b/zephyr/shim/include/config_chip.h
index 8015dc9193..8bd5cbce67 100644
--- a/zephyr/shim/include/config_chip.h
+++ b/zephyr/shim/include/config_chip.h
@@ -94,6 +94,7 @@ enum battery_type {
#undef CONFIG_CMD_FLASHINFO
#undef CONFIG_CMD_FLASH
#define CONFIG_FLASH
+#define CONFIG_SPI_FLASH_W25Q80 /* Internal SPI flash type. */
#define CONFIG_FLASH_SIZE 0x80000
/* TODO(b:176490413): use DT_PROP(DT_INST(inst, DT_DRV_COMPAT), size) ? */
#define CONFIG_MAPPED_STORAGE_BASE 0x64000000
diff --git a/zephyr/shim/src/flash.c b/zephyr/shim/src/flash.c
index 83d210f270..12824753e7 100644
--- a/zephyr/shim/src/flash.c
+++ b/zephyr/shim/src/flash.c
@@ -5,35 +5,356 @@
#include <flash.h>
#include <kernel.h>
+#include <logging/log.h>
+
+#include "console.h"
+#include "drivers/cros_flash.h"
+#include "gpio.h"
+#include "registers.h"
+#include "spi_flash_reg.h"
+#include "util.h"
+
+LOG_MODULE_REGISTER(shim_flash, LOG_LEVEL_ERR);
+
+#define CROS_FLASH_DEV DT_LABEL(DT_NODELABEL(fiu0))
+static const struct device *cros_flash_dev;
+
+static int all_protected; /* Has all-flash protection been requested? */
+static int addr_prot_start;
+static int addr_prot_length;
+static uint8_t flag_prot_inconsistent;
+static uint8_t saved_sr1;
+static uint8_t saved_sr2;
+
+#define CMD_READ_STATUS_REG 0x05
+#define CMD_READ_STATUS_REG2 0x35
+
+static int flash_get_status1(void)
+{
+ uint8_t reg;
+
+ if (all_protected)
+ return saved_sr1;
+
+ cros_flash_get_status_reg(cros_flash_dev, CMD_READ_STATUS_REG, &reg);
+ return reg;
+}
+
+static int flash_get_status2(void)
+{
+ uint8_t reg;
+
+ if (all_protected)
+ return saved_sr1;
+
+ cros_flash_get_status_reg(cros_flash_dev, CMD_READ_STATUS_REG2, &reg);
+ return reg;
+}
+
+static int flash_write_status_reg(uint8_t *data)
+{
+ return cros_flash_set_status_reg(cros_flash_dev, data);
+}
+
+static int is_int_flash_protected(void)
+{
+ return cros_flash_write_protection_is_set(cros_flash_dev);
+}
+
+static void flash_protect_int_flash(int enable)
+{
+ /*
+ * Please notice the type of WP_IF bit is R/W1S. Once it's set,
+ * only rebooting EC can clear it.
+ */
+ if (enable)
+ cros_flash_write_protection_set(cros_flash_dev, enable);
+}
+
+static void flash_uma_lock(int enable)
+{
+ if (enable && !all_protected) {
+ /*
+ * Store SR1 / SR2 for later use since we're about to lock
+ * out all access (including read access) to these regs.
+ */
+ saved_sr1 = flash_get_status1();
+ saved_sr2 = flash_get_status2();
+ }
+
+ cros_flash_uma_lock(cros_flash_dev, enable);
+ all_protected = enable;
+}
+
+static int flash_set_status_for_prot(int reg1, int reg2)
+{
+ uint8_t regs[2];
+
+ /*
+ * Writing SR regs will fail if our UMA lock is enabled. If WP
+ * is deasserted then remove the lock and allow the write.
+ */
+ if (all_protected) {
+ if (is_int_flash_protected())
+ return EC_ERROR_ACCESS_DENIED;
+
+ if (flash_get_protect() & EC_FLASH_PROTECT_GPIO_ASSERTED)
+ return EC_ERROR_ACCESS_DENIED;
+ flash_uma_lock(0);
+ }
+
+ /*
+ * If WP# is active and ec doesn't protect the status registers of
+ * internal spi-flash, protect it now before setting them.
+ */
+#ifdef CONFIG_WP_ACTIVE_HIGH
+ flash_protect_int_flash(gpio_get_level(GPIO_WP));
+#else
+ flash_protect_int_flash(!gpio_get_level(GPIO_WP_L));
+#endif /*_CONFIG_WP_ACTIVE_HIGH_*/
+
+ regs[0] = reg1;
+ regs[1] = reg2;
+ flash_write_status_reg(regs);
+
+ spi_flash_reg_to_protect(reg1, reg2, &addr_prot_start,
+ &addr_prot_length);
+
+ return EC_SUCCESS;
+}
+
+static int flash_check_prot_range(unsigned int offset, unsigned int bytes)
+{
+ /* Invalid value */
+ if (offset + bytes > CONFIG_FLASH_SIZE)
+ return EC_ERROR_INVAL;
+
+ /* Check if ranges overlap */
+ if (MAX(addr_prot_start, offset) <
+ MIN(addr_prot_start + addr_prot_length, offset + bytes))
+ return EC_ERROR_ACCESS_DENIED;
+
+ return EC_SUCCESS;
+}
+
+static int flash_check_prot_reg(unsigned int offset, unsigned int bytes)
+{
+ unsigned int start;
+ unsigned int len;
+ uint8_t sr1, sr2;
+ int rv = EC_SUCCESS;
+
+ /*
+ * If WP# is active and ec doesn't protect the status registers of
+ * internal spi-flash, protect it now.
+ */
+#ifdef CONFIG_WP_ACTIVE_HIGH
+ flash_protect_int_flash(gpio_get_level(GPIO_WP));
+#else
+ flash_protect_int_flash(!gpio_get_level(GPIO_WP_L));
+#endif /* CONFIG_WP_ACTIVE_HIGH */
+
+ sr1 = flash_get_status1();
+ sr2 = flash_get_status2();
+
+ /* Invalid value */
+ if (offset + bytes > CONFIG_FLASH_SIZE)
+ return EC_ERROR_INVAL;
+
+ /* Compute current protect range */
+ rv = spi_flash_reg_to_protect(sr1, sr2, &start, &len);
+ if (rv)
+ return rv;
+
+ /* Check if ranges overlap */
+ if (MAX(start, offset) < MIN(start + len, offset + bytes))
+ return EC_ERROR_ACCESS_DENIED;
+
+ return EC_SUCCESS;
+}
+
+static int flash_write_prot_reg(unsigned int offset, unsigned int bytes,
+ int hw_protect)
+{
+ int rv;
+ uint8_t sr1 = flash_get_status1();
+ uint8_t sr2 = flash_get_status2();
+
+ /* Invalid values */
+ if (offset + bytes > CONFIG_FLASH_SIZE)
+ return EC_ERROR_INVAL;
+
+ /* Compute desired protect range */
+ rv = spi_flash_protect_to_reg(offset, bytes, &sr1, &sr2);
+ if (rv)
+ return rv;
+
+ if (hw_protect)
+ sr1 |= SPI_FLASH_SR1_SRP0;
+
+ return flash_set_status_for_prot(sr1, sr2);
+}
/* TODO(b/174873770): Add calls to Zephyr code here */
int flash_physical_write(int offset, int size, const char *data)
{
- return -ENOSYS;
+ /* Fail if offset, size, and data aren't at least word-aligned */
+ if ((offset | size | (uint32_t)(uintptr_t)data) &
+ (CONFIG_FLASH_WRITE_SIZE - 1))
+ return EC_ERROR_INVAL;
+
+ /* check protection */
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* check protection */
+ if (flash_check_prot_range(offset, size))
+ return EC_ERROR_ACCESS_DENIED;
+
+ return cros_flash_physical_write(cros_flash_dev, offset, size, data);
}
int flash_physical_erase(int offset, int size)
{
- return -ENOSYS;
+ /* check protection */
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* check protection */
+ if (flash_check_prot_range(offset, size))
+ return EC_ERROR_ACCESS_DENIED;
+
+ return cros_flash_physical_erase(cros_flash_dev, offset, size);
}
int flash_physical_get_protect(int bank)
{
- return -ENOSYS;
+ uint32_t addr = bank * CONFIG_FLASH_BANK_SIZE;
+
+ return flash_check_prot_reg(addr, CONFIG_FLASH_BANK_SIZE);
}
uint32_t flash_physical_get_protect_flags(void)
{
- return -ENOSYS;
+ uint32_t flags = 0;
+
+ /* Check if WP region is protected in status register */
+ if (flash_check_prot_reg(WP_BANK_OFFSET * CONFIG_FLASH_BANK_SIZE,
+ WP_BANK_COUNT * CONFIG_FLASH_BANK_SIZE))
+ flags |= EC_FLASH_PROTECT_RO_AT_BOOT;
+
+ /*
+ * TODO: If status register protects a range, but SRP0 is not set,
+ * flags should indicate EC_FLASH_PROTECT_ERROR_INCONSISTENT.
+ */
+ if (flag_prot_inconsistent)
+ flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
+
+ /* Read all-protected state from our shadow copy */
+ if (all_protected)
+ flags |= EC_FLASH_PROTECT_ALL_NOW;
+
+ return flags;
}
int flash_physical_protect_at_boot(uint32_t new_flags)
{
- return -ENOSYS;
+ int ret;
+
+ if ((new_flags & (EC_FLASH_PROTECT_RO_AT_BOOT |
+ EC_FLASH_PROTECT_ALL_AT_BOOT)) == 0) {
+ /* Clear protection bits in status register */
+ return flash_set_status_for_prot(0, 0);
+ }
+
+ ret = flash_write_prot_reg(CONFIG_WP_STORAGE_OFF,
+ CONFIG_WP_STORAGE_SIZE, 1);
+
+ /*
+ * Set UMA_LOCK bit for locking all UMA transaction.
+ * But we still can read directly from flash mapping address
+ */
+ if (new_flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
+ flash_uma_lock(1);
+
+ return ret;
}
int flash_physical_protect_now(int all)
{
- return -ENOSYS;
+ if (all) {
+ /*
+ * Set UMA_LOCK bit for locking all UMA transaction.
+ * But we still can read directly from flash mapping address
+ */
+ flash_uma_lock(1);
+ } else {
+ /* TODO: Implement RO "now" protection */
+ }
+
+ return EC_SUCCESS;
+}
+
+int flash_physical_read(int offset, int size, char *data)
+{
+ return cros_flash_physical_read(cros_flash_dev, offset, size, data);
+}
+
+static int flash_dev_init(const struct device *unused)
+{
+ ARG_UNUSED(unused);
+
+ cros_flash_dev = device_get_binding(CROS_FLASH_DEV);
+ if (!cros_flash_dev) {
+ LOG_ERR("Fail to find %s", CROS_FLASH_DEV);
+ return -ENODEV;
+ }
+ cros_flash_init(cros_flash_dev);
+
+ /*
+ * Protect status registers of internal spi-flash if WP# is active
+ * during ec initialization.
+ */
+#ifdef CONFIG_WP_ACTIVE_HIGH
+ flash_protect_int_flash(gpio_get_level(GPIO_WP));
+#else
+ flash_protect_int_flash(!gpio_get_level(GPIO_WP_L));
+#endif /*CONFIG_WP_ACTIVE_HIGH */
+
+ /* Initialize UMA to unlocked */
+ flash_uma_lock(0);
+
+ return 0;
}
+
+uint32_t flash_physical_get_valid_flags(void)
+{
+ return EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW |
+ EC_FLASH_PROTECT_ALL_NOW;
+}
+
+uint32_t flash_physical_get_writable_flags(uint32_t cur_flags)
+{
+ uint32_t ret = 0;
+
+ /* If RO protection isn't enabled, its at-boot state can be changed. */
+ if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW))
+ ret |= EC_FLASH_PROTECT_RO_AT_BOOT;
+
+ /*
+ * If entire flash isn't protected at this boot, it can be enabled if
+ * the WP GPIO is asserted.
+ */
+ if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) &&
+ (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED))
+ ret |= EC_FLASH_PROTECT_ALL_NOW;
+
+ return ret;
+}
+
+/*
+ * The priority flash_dev_init should be lower than GPIO initialization because
+ * it calls gpio_get_level function.
+ */
+SYS_INIT(flash_dev_init, PRE_KERNEL_1, 51);