summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2020-11-25 19:19:32 -0800
committerCommit Bot <commit-bot@chromium.org>2021-01-15 03:56:18 +0000
commitcdb35e70007bca553c6fcf6a88d02433bb0b4c5d (patch)
tree5dc3e8360dbe3804bed1e831abc85d3038255aa9
parentb33a27c9a667b692ac7cd52922df0b6dba70c64d (diff)
downloadchrome-ec-cdb35e70007bca553c6fcf6a88d02433bb0b4c5d.tar.gz
drivers: Add cros_flash driver for npcx chip
Add a driver that implements the cros_flash interface on the npcx chip. BUG=b:174874876 TEST=pass build with related patches. TEST=combine with related patches, use console commands to test all the implemented flash APIs. Change-Id: I435569928ead955079d8299d7d056894066b5929 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/zephyr-chrome/+/2598212 Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Simon Glass <sjg@chromium.org> Commit-Queue: Simon Glass <sjg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2630167 Tested-by: Jack Rosenthal <jrosenth@chromium.org> Commit-Queue: Jack Rosenthal <jrosenth@chromium.org>
-rw-r--r--zephyr/drivers/CMakeLists.txt1
-rw-r--r--zephyr/drivers/Kconfig1
-rw-r--r--zephyr/drivers/cros_flash/CMakeLists.txt3
-rw-r--r--zephyr/drivers/cros_flash/Kconfig13
-rw-r--r--zephyr/drivers/cros_flash/cros_flash_npcx.c525
-rw-r--r--zephyr/dts/bindings/cros_flash/cros-flash-controller.yaml12
-rw-r--r--zephyr/dts/bindings/cros_flash/nuvoton,npcx-cros-flash.yaml24
-rw-r--r--zephyr/include/drivers/cros_flash.h308
-rw-r--r--zephyr/include/soc/nuvoton_npcx/reg_def_cros.h94
-rw-r--r--zephyr/projects/volteer/boards/arm/volteer/volteer.dts9
10 files changed, 990 insertions, 0 deletions
diff --git a/zephyr/drivers/CMakeLists.txt b/zephyr/drivers/CMakeLists.txt
index 7e4a6d94fb..61aebb505e 100644
--- a/zephyr/drivers/CMakeLists.txt
+++ b/zephyr/drivers/CMakeLists.txt
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(cros_kb_raw)
+add_subdirectory(cros_flash)
diff --git a/zephyr/drivers/Kconfig b/zephyr/drivers/Kconfig
index cfffcea226..87237d0ac9 100644
--- a/zephyr/drivers/Kconfig
+++ b/zephyr/drivers/Kconfig
@@ -2,3 +2,4 @@
# SPDX-License-Identifier: Apache-2.0
rsource "cros_kb_raw/Kconfig"
+rsource "cros_flash/Kconfig"
diff --git a/zephyr/drivers/cros_flash/CMakeLists.txt b/zephyr/drivers/cros_flash/CMakeLists.txt
new file mode 100644
index 0000000000..a5d333bb33
--- /dev/null
+++ b/zephyr/drivers/cros_flash/CMakeLists.txt
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: Apache-2.0
+
+zephyr_library_sources_ifdef(CONFIG_CROS_FLASH_NPCX cros_flash_npcx.c)
diff --git a/zephyr/drivers/cros_flash/Kconfig b/zephyr/drivers/cros_flash/Kconfig
new file mode 100644
index 0000000000..e15848f4f6
--- /dev/null
+++ b/zephyr/drivers/cros_flash/Kconfig
@@ -0,0 +1,13 @@
+
+# Copyright 2020 Google LLC
+# SPDX-License-Identifier: Apache-2.0
+
+menuconfig CROS_FLASH_NPCX
+ bool "Nuvoton NPCX flash driver for the Zephyr shim"
+ depends on SOC_FAMILY_NPCX
+ default y
+ help
+ This option enables a flash unit interface (FIU) driver for the NPCX
+ chip. This is used instead of the flash memory interface so we can
+ continue to use most of the existing flash memory processing code in
+ ECOS.
diff --git a/zephyr/drivers/cros_flash/cros_flash_npcx.c b/zephyr/drivers/cros_flash/cros_flash_npcx.c
new file mode 100644
index 0000000000..3fd8f4edb9
--- /dev/null
+++ b/zephyr/drivers/cros_flash/cros_flash_npcx.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT nuvoton_npcx_cros_flash
+
+#include <dt-bindings/clock/npcx_clock.h>
+#include <drivers/cros_flash.h>
+#include <drivers/clock_control.h>
+#include <drivers/gpio.h>
+#include <kernel.h>
+#include <logging/log.h>
+#include <soc.h>
+#include <soc/nuvoton_npcx/reg_def_cros.h>
+#include <sys/__assert.h>
+#include "ec_tasks.h"
+#include "soc_miwu.h"
+#include "task.h"
+#include "../drivers/flash/spi_nor.h"
+
+LOG_MODULE_REGISTER(cros_flash, LOG_LEVEL_ERR);
+
+/* Device config */
+struct cros_flash_npcx_config {
+ /* flash interface unit base address */
+ uintptr_t base;
+ /* clock configuration */
+ struct npcx_clk_cfg clk_cfg;
+ /* Flash size (Unit:bytes) */
+ int size;
+ /* pinmux configuration */
+ const uint8_t alts_size;
+ const struct npcx_alt *alts_list;
+};
+
+/* Device data */
+struct cros_flash_npcx_data {
+ /* flag of flash write protection */
+ bool write_protectied;
+ /* mutex of flash interface controller */
+ struct k_sem lock_sem;
+};
+
+/* TODO: Should we replace them with Kconfig variables */
+#define CONFIG_FLASH_WRITE_SIZE 0x1 /* minimum write size */
+#define CONFIG_FLASH_WRITE_IDEAL_SIZE 256 /* one page size for write */
+
+/* TODO: It should be defined in the spi_nor.h in the zephyr repository */
+#define SPI_NOR_CMD_FAST_READ 0x0B
+
+/* Driver convenience defines */
+#define DRV_CONFIG(dev) ((const struct cros_flash_npcx_config *)(dev)->config)
+#define DRV_DATA(dev) ((struct cros_flash_npcx_data *)(dev)->data)
+#define HAL_INSTANCE(dev) (struct fiu_reg *)(DRV_CONFIG(dev)->base)
+
+/* cros ec flash local inline functions */
+static inline void cros_flash_npcx_mutex_lock(const struct device *dev)
+{
+ struct cros_flash_npcx_data *data = DRV_DATA(dev);
+
+ k_sem_take(&data->lock_sem, K_FOREVER);
+}
+
+static inline void cros_flash_npcx_mutex_unlock(const struct device *dev)
+{
+ struct cros_flash_npcx_data *data = DRV_DATA(dev);
+
+ k_sem_give(&data->lock_sem);
+}
+
+static inline void cros_flash_npcx_set_address(const struct device *dev,
+ uint32_t qspi_addr)
+{
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+ uint8_t *addr = (uint8_t *)&qspi_addr;
+
+ /* Write 3 bytes address to UMA registers */
+ inst->UMA_AB2 = addr[2];
+ inst->UMA_AB1 = addr[1];
+ inst->UMA_AB0 = addr[0];
+}
+
+static inline void cros_flash_npcx_cs_level(const struct device *dev, int level)
+{
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+
+ /* Set chip select to high/low level */
+ if (level == 0)
+ inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_SW_CS1);
+ else
+ inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_SW_CS1);
+}
+
+static inline void cros_flash_npcx_exec_cmd(const struct device *dev,
+ uint8_t code, uint8_t cts)
+{
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+
+#ifdef CONFIG_ASSERT
+ struct cros_flash_npcx_data *data = DRV_DATA(dev);
+
+ /* Flash mutex must be held while executing UMA commands */
+ __ASSERT((k_sem_count_get(&data->lock_sem) == 0), "UMA is not locked");
+#endif
+
+ /* set UMA_CODE */
+ inst->UMA_CODE = code;
+ /* execute UMA flash transaction */
+ inst->UMA_CTS = cts;
+ while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
+ ;
+}
+
+static inline void cros_flash_npcx_burst_read(const struct device *dev,
+ char *dst_data, int dst_size)
+{
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+
+ /* Burst read transaction */
+ for (int idx = 0; idx < dst_size; idx++) {
+ /* 1101 0101 - EXEC, RD, NO CMD, NO ADDR, 4 bytes */
+ inst->UMA_CTS = UMA_CODE_RD_BYTE(1);
+ /* wait for UMA to complete */
+ while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
+ ;
+ /* Get read transaction results*/
+ dst_data[idx] = inst->UMA_DB0;
+ }
+}
+
+static inline int cros_flash_npcx_wait_busy_bit_clear(const struct device *dev)
+{
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+ int wait_period = 10; /* 10 us period t0 check status register */
+ int timeout = (10 * USEC_PER_SEC) / wait_period; /* 10 seconds */
+
+ do {
+ /* Read status register */
+ inst->UMA_CTS = UMA_CODE_RD_BYTE(1);
+ while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
+ ;
+ /* Status bit is clear */
+ if ((inst->UMA_DB0 & SPI_NOR_WIP_BIT) == 0)
+ break;
+ k_usleep(wait_period);
+ } while (--timeout); /* Wait for busy bit clear */
+
+ if (timeout) {
+ return 0;
+ } else {
+ return -ETIMEDOUT;
+ }
+}
+
+/* cros ec flash local functions */
+static int cros_flash_npcx_wait_ready(const struct device *dev)
+{
+ int ret = 0;
+
+ /* Drive CS to low */
+ cros_flash_npcx_cs_level(dev, 0);
+
+ /* Command for Read status register of flash */
+ cros_flash_npcx_exec_cmd(dev, SPI_NOR_CMD_RDSR, UMA_CODE_CMD_ONLY);
+ /* Wait busy bit is clear */
+ ret = cros_flash_npcx_wait_busy_bit_clear(dev);
+ /* Drive CS to low */
+ cros_flash_npcx_cs_level(dev, 1);
+
+ return ret;
+}
+
+static int cros_flash_npcx_set_write_enable(const struct device *dev)
+{
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+ int ret;
+
+ /* Wait for previous operation to complete */
+ ret = cros_flash_npcx_wait_ready(dev);
+ if (ret != 0)
+ return ret;
+
+ /* Write enable command */
+ cros_flash_npcx_exec_cmd(dev, SPI_NOR_CMD_WREN, UMA_CODE_CMD_ONLY);
+
+ /* Wait for flash is not busy */
+ ret = cros_flash_npcx_wait_ready(dev);
+ if (ret != 0)
+ return ret;
+
+ if ((inst->UMA_DB0 & SPI_NOR_WEL_BIT) != 0)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static void cros_flash_npcx_burst_write(const struct device *dev,
+ unsigned int dest_addr,
+ unsigned int bytes,
+ const char *src_data)
+{
+ /* Chip Select down */
+ cros_flash_npcx_cs_level(dev, 0);
+
+ /* Set write address */
+ cros_flash_npcx_set_address(dev, dest_addr);
+ /* Start programming */
+ cros_flash_npcx_exec_cmd(dev, SPI_NOR_CMD_PP, UMA_CODE_CMD_WR_ADR);
+ for (int i = 0; i < bytes; i++) {
+ cros_flash_npcx_exec_cmd(dev, *src_data, UMA_CODE_CMD_WR_ONLY);
+ src_data++;
+ }
+
+ /* Chip Select up */
+ cros_flash_npcx_cs_level(dev, 1);
+}
+
+static int cros_flash_npcx_program_bytes(const struct device *dev,
+ uint32_t offset, uint32_t bytes,
+ const uint8_t *src_data)
+{
+ int write_size;
+ int ret = 0;
+
+ while (bytes > 0) {
+ /* Write length can not go beyond the end of the flash page */
+ write_size = MIN(bytes,
+ CONFIG_FLASH_WRITE_IDEAL_SIZE -
+ (offset &
+ (CONFIG_FLASH_WRITE_IDEAL_SIZE - 1)));
+
+ /* Enable write */
+ ret = cros_flash_npcx_set_write_enable(dev);
+ if (ret != 0)
+ return ret;
+
+ /* Executr UMA burst write transaction */
+ cros_flash_npcx_burst_write(dev, offset, write_size, src_data);
+
+ /* Wait write completed */
+ ret = cros_flash_npcx_wait_ready(dev);
+ if (ret != 0)
+ return ret;
+
+ src_data += write_size;
+ offset += write_size;
+ bytes -= write_size;
+ }
+
+ return ret;
+}
+
+/* cros ec flash api functions */
+static int cros_flash_npcx_init(const struct device *dev)
+{
+ const struct cros_flash_npcx_config *const config = DRV_CONFIG(dev);
+ struct cros_flash_npcx_data *data = DRV_DATA(dev);
+
+ /* initialize mutux for flash interface controller */
+ k_sem_init(&data->lock_sem, 1, 1);
+
+ /* Configure pin-mux for FIU device */
+ npcx_pinctrl_mux_configure(config->alts_list, config->alts_size, 1);
+
+ return 0;
+}
+
+static int cros_flash_npcx_read(const struct device *dev, int offset, int size,
+ char *dst_data)
+{
+ int ret = 0;
+
+ /* Unlock flash interface device during reading flash */
+ cros_flash_npcx_mutex_lock(dev);
+
+ /* Chip Select down */
+ cros_flash_npcx_cs_level(dev, 0);
+
+ /* Set read address */
+ cros_flash_npcx_set_address(dev, offset);
+ /* Start with fast read command (skip one dummy byte) */
+ cros_flash_npcx_exec_cmd(dev, SPI_NOR_CMD_FAST_READ,
+ UMA_CODE_CMD_ADR_WR_BYTE(1));
+ /* Execute burst read */
+ cros_flash_npcx_burst_read(dev, dst_data, size);
+
+ /* Chip Select up */
+ cros_flash_npcx_cs_level(dev, 1);
+
+ /* Unlock flash interface device */
+ cros_flash_npcx_mutex_unlock(dev);
+
+ return ret;
+}
+
+static int cros_flash_npcx_write(const struct device *dev, int offset, int size,
+ const char *src_data)
+{
+ struct cros_flash_npcx_data *const data = DRV_DATA(dev);
+ int ret = 0;
+
+ /* Is write protection enabled? */
+ if (data->write_protectied) {
+ return -EACCES;
+ }
+
+ /* Invalid data pointer? */
+ if (src_data == 0) {
+ return -EINVAL;
+ }
+
+ /* Unlock flash interface device during writing flash */
+ cros_flash_npcx_mutex_lock(dev);
+
+ while (size > 0) {
+ /* First write multiples of 256, then (size % 256) last */
+ int write_len =
+ ((size % CONFIG_FLASH_WRITE_IDEAL_SIZE) == size) ?
+ size :
+ CONFIG_FLASH_WRITE_IDEAL_SIZE;
+
+ ret = cros_flash_npcx_program_bytes(dev, offset, write_len,
+ src_data);
+ if (ret != 0)
+ break;
+
+ src_data += write_len;
+ offset += write_len;
+ size -= write_len;
+ }
+
+ /* Unlock flash interface device */
+ cros_flash_npcx_mutex_unlock(dev);
+
+ return ret;
+}
+
+static int cros_flash_npcx_erase(const struct device *dev, int offset, int size)
+{
+ const struct cros_flash_npcx_config *const config = DRV_CONFIG(dev);
+ struct cros_flash_npcx_data *const data = DRV_DATA(dev);
+ int ret = 0;
+
+ /* Is write protection enabled? */
+ if (data->write_protectied) {
+ return -EACCES;
+ }
+ /* affected region should be within device */
+ if (offset < 0 || (offset + size) > config->size) {
+ LOG_ERR("Flash erase address or size exceeds expected values. "
+ "Addr: 0x%lx size %zu",
+ (long)offset, size);
+ return -EINVAL;
+ }
+
+ /* address must be aligned to erase size */
+ if ((offset % CONFIG_FLASH_ERASE_SIZE) != 0) {
+ return -EINVAL;
+ }
+
+ /* Erase size must be a non-zero multiple of sectors */
+ if ((size == 0) || (size % CONFIG_FLASH_ERASE_SIZE) != 0) {
+ return -EINVAL;
+ }
+
+ /* Unlock flash interface device during erasing flash */
+ cros_flash_npcx_mutex_lock(dev);
+
+ /* Alignment has been checked in upper layer */
+ for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE,
+ offset += CONFIG_FLASH_ERASE_SIZE) {
+
+ /* Enable write */
+ ret = cros_flash_npcx_set_write_enable(dev);
+ if (ret != 0)
+ break;
+
+ /* Set erase address */
+ cros_flash_npcx_set_address(dev, offset);
+ /* Start erasing */
+ cros_flash_npcx_exec_cmd(dev, SPI_NOR_CMD_SE, UMA_CODE_CMD_ADR);
+
+ /* Wait erase completed */
+ ret = cros_flash_npcx_wait_ready(dev);
+ if (ret != 0) {
+ break;
+ }
+ }
+
+ /* Unlock flash interface device */
+ cros_flash_npcx_mutex_unlock(dev);
+
+ return ret;
+}
+
+static int cros_flash_npcx_get_status_reg(const struct device *dev,
+ char cmd_code, char *data)
+{
+ int ret = 0;
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+
+ if (data == 0) {
+ return -EINVAL;
+ }
+
+ /* Lock flash interface device during reading status register */
+ cros_flash_npcx_mutex_lock(dev);
+
+ cros_flash_npcx_exec_cmd(dev, cmd_code, UMA_CODE_CMD_RD_BYTE(1));
+ *data = inst->UMA_DB0;
+ /* Unlock flash interface device */
+ cros_flash_npcx_mutex_unlock(dev);
+
+ return ret;
+}
+
+static int cros_flash_npcx_set_status_reg(const struct device *dev, char *data)
+{
+ int ret = 0;
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+
+ /* Lock flash interface device */
+ cros_flash_npcx_mutex_lock(dev);
+ /* Enable write */
+ ret = cros_flash_npcx_set_write_enable(dev);
+ if (ret != 0)
+ return ret;
+
+ inst->UMA_DB0 = data[0];
+ inst->UMA_DB1 = data[1];
+ /* Write status register 1/2 */
+ cros_flash_npcx_exec_cmd(dev, SPI_NOR_CMD_WRSR,
+ UMA_CODE_CMD_WR_BYTE(2));
+ /* Unlock flash interface device */
+ cros_flash_npcx_mutex_unlock(dev);
+
+ return ret;
+}
+
+static int cros_flash_npcx_write_protection_set(const struct device *dev,
+ bool enable)
+{
+ int ret = 0;
+
+ /* Write protection can be cleared only by core domain reset */
+ if (!enable) {
+ LOG_ERR("WP can be disabled only via core domain reset ");
+ return -ENOTSUP;
+ }
+ /* Lock flash interface device */
+ cros_flash_npcx_mutex_lock(dev);
+ ret = npcx_pinctrl_flash_write_protect_set();
+ /* Unlock flash interface device */
+ cros_flash_npcx_mutex_unlock(dev);
+
+ return ret;
+}
+
+static int cros_flash_npcx_write_protection_is_set(const struct device *dev)
+{
+ return npcx_pinctrl_flash_write_protect_is_set();
+}
+
+static int cros_flash_npcx_uma_lock(const struct device *dev, bool enable)
+{
+ struct fiu_reg *const inst = HAL_INSTANCE(dev);
+
+ if (enable) {
+ inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_UMA_LOCK);
+ } else {
+ inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_UMA_LOCK);
+ }
+
+ return 0;
+}
+
+/* cros ec flash driver registration */
+static const struct cros_flash_driver_api cros_flash_npcx_driver_api = {
+ .init = cros_flash_npcx_init,
+ .physical_read = cros_flash_npcx_read,
+ .physical_write = cros_flash_npcx_write,
+ .physical_erase = cros_flash_npcx_erase,
+ .write_protection = cros_flash_npcx_write_protection_set,
+ .write_protection_is_set = cros_flash_npcx_write_protection_is_set,
+ .get_status_reg = cros_flash_npcx_get_status_reg,
+ .set_status_reg = cros_flash_npcx_set_status_reg,
+ .uma_lock = cros_flash_npcx_uma_lock,
+};
+
+static int flash_npcx_init(const struct device *dev)
+{
+ const struct cros_flash_npcx_config *const config = DRV_CONFIG(dev);
+ const struct device *const clk_dev =
+ device_get_binding(NPCX_CLK_CTRL_NAME);
+
+ int ret;
+
+ /* Turn on device clock first and get source clock freq. */
+ ret = clock_control_on(clk_dev,
+ (clock_control_subsys_t *)&config->clk_cfg);
+ if (ret < 0) {
+ LOG_ERR("Turn on FIU clock fail %d", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct npcx_alt cros_flash_alts[] = NPCX_DT_ALT_ITEMS_LIST(0);
+static const struct cros_flash_npcx_config cros_flash_cfg = {
+ .base = DT_INST_REG_ADDR(0),
+ .clk_cfg = NPCX_DT_CLK_CFG_ITEM(0),
+ .size = DT_INST_PROP(0, size),
+ .alts_size = ARRAY_SIZE(cros_flash_alts),
+ .alts_list = cros_flash_alts,
+};
+
+static struct cros_flash_npcx_data cros_flash_data;
+
+DEVICE_AND_API_INIT(cros_flash_npcx_0, DT_INST_LABEL(0), flash_npcx_init,
+ &cros_flash_data, &cros_flash_cfg, PRE_KERNEL_1,
+ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
+ &cros_flash_npcx_driver_api);
diff --git a/zephyr/dts/bindings/cros_flash/cros-flash-controller.yaml b/zephyr/dts/bindings/cros_flash/cros-flash-controller.yaml
new file mode 100644
index 0000000000..b9c8a9f149
--- /dev/null
+++ b/zephyr/dts/bindings/cros_flash/cros-flash-controller.yaml
@@ -0,0 +1,12 @@
+# Copyright 2020 Google LLC
+# SPDX-License-Identifier: Apache-2.0
+
+# Common fields for Chrome OS flash devices
+
+include: base.yaml
+
+bus: crosflash
+
+properties:
+ label:
+ required: true
diff --git a/zephyr/dts/bindings/cros_flash/nuvoton,npcx-cros-flash.yaml b/zephyr/dts/bindings/cros_flash/nuvoton,npcx-cros-flash.yaml
new file mode 100644
index 0000000000..23c0f92c9c
--- /dev/null
+++ b/zephyr/dts/bindings/cros_flash/nuvoton,npcx-cros-flash.yaml
@@ -0,0 +1,24 @@
+# Copyright 2020 Google LLC
+# SPDX-License-Identifier: Apache-2.0
+
+description: Nuvoton, NPCX-cros-flash node
+
+compatible: "nuvoton,npcx-cros-flash"
+
+include: cros-flash-controller.yaml
+
+properties:
+ reg:
+ required: true
+
+ clocks:
+ required: true
+
+ size:
+ type: int
+ required: true
+
+ pinctrl-0:
+ type: phandles
+ required: true
+ description: configurations of pinmux controllers
diff --git a/zephyr/include/drivers/cros_flash.h b/zephyr/include/drivers/cros_flash.h
new file mode 100644
index 0000000000..fd2a0951e4
--- /dev/null
+++ b/zephyr/include/drivers/cros_flash.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * @brief Chrome OS-specific API for flash memory access
+ * This exists only support the interface expected by the Chrome OS EC. It seems
+ * better to implement this so we can make use of most of the existing code in
+ * its keyboard_scan.c file and thus make sure we operate the same way.
+ *
+ * It provides raw access to flash memory module.
+ */
+
+#ifndef ZEPHYR_INCLUDE_DRIVERS_CROS_FLASH_H_
+#define ZEPHYR_INCLUDE_DRIVERS_CROS_FLASH_H_
+
+#include <kernel.h>
+#include <device.h>
+
+/**
+ * @brief CROS Flash Driver APIs
+ * @defgroup cros_flash_interface CROS Flash Driver APIs
+ * @ingroup io_interfaces
+ * @{
+ */
+
+/**
+ * @cond INTERNAL_HIDDEN
+ *
+ * cros keyboard raw driver API definition and system call entry points
+ *
+ * (Internal use only.)
+ */
+typedef int (*cros_flash_api_init)(const struct device *dev);
+
+typedef int (*cros_flash_api_physical_read)(const struct device *dev,
+ int offset, int size, char *data);
+
+typedef int (*cros_flash_api_physical_write)(const struct device *dev,
+ int offset, int size,
+ const char *data);
+
+typedef int (*cros_flash_api_physical_erase)(const struct device *dev,
+ int offset, int size);
+typedef int (*cros_flash_api_write_protection)(const struct device *dev,
+ bool enable);
+typedef int (*cros_flash_api_write_protection_is_set)(const struct device *dev);
+typedef int (*cros_flash_api_get_status_reg)(const struct device *dev,
+ char cmd_code, char *data);
+typedef int (*cros_flash_api_set_status_reg)(const struct device *dev,
+ char *data);
+typedef int (*cros_flash_api_uma_lock)(const struct device *dev, bool enable);
+
+__subsystem struct cros_flash_driver_api {
+ cros_flash_api_init init;
+ cros_flash_api_physical_read physical_read;
+ cros_flash_api_physical_write physical_write;
+ cros_flash_api_physical_erase physical_erase;
+ cros_flash_api_write_protection write_protection;
+ cros_flash_api_write_protection_is_set write_protection_is_set;
+ cros_flash_api_get_status_reg get_status_reg;
+ cros_flash_api_set_status_reg set_status_reg;
+ cros_flash_api_uma_lock uma_lock;
+};
+
+/**
+ * @endcond
+ */
+
+/**
+ * @brief Initialize physical flash.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_init(const struct device *dev);
+
+static inline int z_impl_cros_flash_init(const struct device *dev)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->init) {
+ return -ENOTSUP;
+ }
+
+ return api->init(dev);
+}
+
+/**
+ * @brief Read from physical flash.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ * @param offset Flash offset to read.
+ * @param size Number of bytes to read.
+ * @param data Destination buffer for data. Must be 32-bit aligned.
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_physical_read(const struct device *dev, int offset,
+ int size, char *data);
+
+static inline int z_impl_cros_flash_physical_read(const struct device *dev,
+ int offset, int size,
+ char *data)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->physical_read) {
+ return -ENOTSUP;
+ }
+
+ return api->physical_read(dev, offset, size, data);
+}
+
+/**
+ * @brief Write to physical flash.
+ *
+ * Offset and size must be a multiple of CONFIG_FLASH_WRITE_SIZE.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ * @param offset Flash offset to write.
+ * @param size Number of bytes to write.
+ * @param data Destination buffer for data. Must be 32-bit aligned.
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_physical_write(const struct device *dev, int offset,
+ int size, const char *data);
+
+static inline int z_impl_cros_flash_physical_write(const struct device *dev,
+ int offset, int size,
+ const char *data)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->physical_write) {
+ return -ENOTSUP;
+ }
+
+ return api->physical_write(dev, offset, size, data);
+}
+
+/**
+ * @brief Erase physical flash.
+ *
+ * Offset and size must be a multiple of CONFIG_FLASH_ERASE_SIZE.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ * @param offset Flash offset to erase.
+ * @param size Number of bytes to erase.
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_physical_erase(const struct device *dev, int offset,
+ int size);
+
+static inline int z_impl_cros_flash_physical_erase(const struct device *dev,
+ int offset, int size)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->physical_erase) {
+ return -ENOTSUP;
+ }
+
+ return api->physical_erase(dev, offset, size);
+}
+
+/**
+ * @brief Enable or disable write protection for a flash memory
+ *
+ * Offset and size must be a multiple of CONFIG_FLASH_ERASE_SIZE.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ * @param enable True to enable it, False to disable it.
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_write_protection_set(const struct device *dev,
+ bool enable);
+
+static inline int
+z_impl_cros_flash_write_protection_set(const struct device *dev, bool enable)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->write_protection) {
+ return -ENOTSUP;
+ }
+
+ return api->write_protection(dev, enable);
+}
+
+/**
+ * @brief Get write protection status of the flash device
+ *
+ * @return 1 If write protection is set, 0 otherwise.
+ */
+__syscall bool cros_flash_write_protection_is_set(const struct device *dev);
+
+static inline bool
+z_impl_cros_flash_write_protection_is_set(const struct device *dev)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->write_protection_is_set) {
+ return -ENOTSUP;
+ }
+
+ return api->write_protection_is_set(dev);
+}
+
+/**
+ * @brief Read status registers of flash.
+ *
+ * cmd_code must be a valid code to read the status register.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ * @param cmd_code instruction code to read status registers.
+ * @param data Buffer to store the value read back
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_get_status_reg(const struct device *dev, char cmd_code,
+ char *data);
+
+static inline int z_impl_cros_flash_get_status_reg(const struct device *dev,
+ char cmd_code, char *data)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->get_status_reg) {
+ return -ENOTSUP;
+ }
+
+ return api->get_status_reg(dev, cmd_code, data);
+}
+
+/**
+ * @brief Write status registers of flash.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ * @param data Buffer to store the value to write
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_set_status_reg(const struct device *dev, char *data);
+
+static inline int z_impl_cros_flash_set_status_reg(const struct device *dev,
+ char *data)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->set_status_reg) {
+ return -ENOTSUP;
+ }
+
+ return api->set_status_reg(dev, data);
+}
+
+/**
+ * @brief Enable or disable UMA module to access the internal flash.
+ *
+ * @param dev Pointer to the device structure for the flash driver instance.
+ * @param enable True to lock it, False to unlock it.
+ *
+ * @return 0 If successful.
+ * @retval -ENOTSUP Not supported api function.
+ */
+__syscall int cros_flash_uma_lock(const struct device *dev, bool enable);
+
+static inline int
+z_impl_cros_flash_uma_lock(const struct device *dev, bool enable)
+{
+ const struct cros_flash_driver_api *api =
+ (const struct cros_flash_driver_api *)dev->api;
+
+ if (!api->uma_lock) {
+ return -ENOTSUP;
+ }
+
+ return api->uma_lock(dev, enable);
+}
+
+/**
+ * @}
+ */
+#include <syscalls/cros_flash.h>
+#endif /* ZEPHYR_INCLUDE_DRIVERS_CROS_FLASH_H_ */
diff --git a/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h b/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h
index 022c58fc24..69d9c37e22 100644
--- a/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h
+++ b/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h
@@ -56,4 +56,98 @@ struct kbs_reg {
#define KBS_CFG_INDX_CNUM 3 /* Keyboard Scan Columns Number */
#define KBS_CFG_INDX_CDIV 4 /* Keyboard Scan Clock Divisor */
+/*
+ * Flash Interface Unit (FIU) device registers
+ */
+struct fiu_reg {
+ /* 0x001: Burst Configuration */
+ volatile uint8_t BURST_CFG;
+ /* 0x002: FIU Response Configuration */
+ volatile uint8_t RESP_CFG;
+ volatile uint8_t reserved1[18];
+ /* 0x014: SPI Flash Configuration */
+ volatile uint8_t SPI_FL_CFG;
+ volatile uint8_t reserved2;
+ /* 0x016: UMA Code Byte */
+ volatile uint8_t UMA_CODE;
+ /* 0x017: UMA Address Byte 0 */
+ volatile uint8_t UMA_AB0;
+ /* 0x018: UMA Address Byte 1 */
+ volatile uint8_t UMA_AB1;
+ /* 0x019: UMA Address Byte 2 */
+ volatile uint8_t UMA_AB2;
+ /* 0x01A: UMA Data Byte 0 */
+ volatile uint8_t UMA_DB0;
+ /* 0x01B: UMA Data Byte 1 */
+ volatile uint8_t UMA_DB1;
+ /* 0x01C: UMA Data Byte 2 */
+ volatile uint8_t UMA_DB2;
+ /* 0x01D: UMA Data Byte 3 */
+ volatile uint8_t UMA_DB3;
+ /* 0x01E: UMA Control and Status */
+ volatile uint8_t UMA_CTS;
+ /* 0x01F: UMA Extended Control and Status */
+ volatile uint8_t UMA_ECTS;
+ /* 0x020: UMA Data Bytes 0-3 */
+ volatile uint32_t UMA_DB0_3;
+ volatile uint8_t reserved3[2];
+ /* 0x026: CRC Control Register */
+ volatile uint8_t CRCCON;
+ /* 0x027: CRC Entry Register */
+ volatile uint8_t CRCENT;
+ /* 0x028: CRC Initialization and Result Register */
+ volatile uint32_t CRCRSLT;
+ volatile uint8_t reserved4[4];
+ /* 0x030: FIU Read Command */
+ volatile uint8_t FIU_RD_CMD;
+ volatile uint8_t reserved5;
+ /* 0x032: FIU Dummy Cycles */
+ volatile uint8_t FIU_DMM_CYC;
+ /* 0x033: FIU Extended Configuration */
+ volatile uint8_t FIU_EXT_CFG;
+};
+
+/* FIU register fields */
+#define NPCX_RESP_CFG_IAD_EN 0
+#define NPCX_RESP_CFG_DEV_SIZE_EX 2
+#define NPCX_UMA_CTS_A_SIZE 3
+#define NPCX_UMA_CTS_C_SIZE 4
+#define NPCX_UMA_CTS_RD_WR 5
+#define NPCX_UMA_CTS_DEV_NUM 6
+#define NPCX_UMA_CTS_EXEC_DONE 7
+#define NPCX_UMA_ECTS_SW_CS0 0
+#define NPCX_UMA_ECTS_SW_CS1 1
+#define NPCX_UMA_ECTS_SEC_CS 2
+#define NPCX_UMA_ECTS_UMA_LOCK 3
+
+/* UMA fields selections */
+#define UMA_FLD_ADDR BIT(NPCX_UMA_CTS_A_SIZE) /* 3-bytes ADR field */
+#define UMA_FLD_NO_CMD BIT(NPCX_UMA_CTS_C_SIZE) /* No 1-Byte CMD field */
+#define UMA_FLD_WRITE BIT(NPCX_UMA_CTS_RD_WR) /* Write transaction */
+#define UMA_FLD_SHD_SL BIT(NPCX_UMA_CTS_DEV_NUM) /* Shared flash selected */
+#define UMA_FLD_EXEC BIT(NPCX_UMA_CTS_EXEC_DONE)
+
+#define UMA_FIELD_DATA_1 0x01
+#define UMA_FIELD_DATA_2 0x02
+#define UMA_FIELD_DATA_3 0x03
+#define UMA_FIELD_DATA_4 0x04
+
+/* UMA code for transaction */
+#define UMA_CODE_CMD_ONLY (UMA_FLD_EXEC | UMA_FLD_SHD_SL)
+#define UMA_CODE_CMD_ADR (UMA_FLD_EXEC | UMA_FLD_ADDR | \
+ UMA_FLD_SHD_SL)
+#define UMA_CODE_CMD_RD_BYTE(n) (UMA_FLD_EXEC | UMA_FIELD_DATA_##n | \
+ UMA_FLD_SHD_SL)
+#define UMA_CODE_RD_BYTE(n) (UMA_FLD_EXEC | UMA_FLD_NO_CMD | \
+ UMA_FIELD_DATA_##n | UMA_FLD_SHD_SL)
+#define UMA_CODE_CMD_WR_ONLY (UMA_FLD_EXEC | UMA_FLD_WRITE | \
+ UMA_FLD_SHD_SL)
+#define UMA_CODE_CMD_WR_BYTE(n) (UMA_FLD_EXEC | UMA_FLD_WRITE | \
+ UMA_FIELD_DATA_##n | UMA_FLD_SHD_SL)
+#define UMA_CODE_CMD_WR_ADR (UMA_FLD_EXEC | UMA_FLD_WRITE | UMA_FLD_ADDR | \
+ UMA_FLD_SHD_SL)
+
+#define UMA_CODE_CMD_ADR_WR_BYTE(n) (UMA_FLD_EXEC | UMA_FLD_WRITE | \
+ UMA_FLD_ADDR | UMA_FIELD_DATA_##n | \
+ UMA_FLD_SHD_SL)
#endif /* _NUVOTON_NPCX_REG_DEF_CROS_H */
diff --git a/zephyr/projects/volteer/boards/arm/volteer/volteer.dts b/zephyr/projects/volteer/boards/arm/volteer/volteer.dts
index 96316db53f..4ba1f97667 100644
--- a/zephyr/projects/volteer/boards/arm/volteer/volteer.dts
+++ b/zephyr/projects/volteer/boards/arm/volteer/volteer.dts
@@ -381,6 +381,15 @@
&wui_io25 &wui_io24 &wui_io23 &wui_io22>;
status = "disabled";
};
+
+ fiu0: cros-flash@40020000 {
+ compatible = "nuvoton,npcx-cros-flash";
+ reg = <0x40020000 0x2000>;
+ clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL1 2>;
+ size = <0x80000>;
+ label = "FLASH_INTERFACE_UNIT0";
+ pinctrl-0 = <>;
+ };
};
};