From cdb35e70007bca553c6fcf6a88d02433bb0b4c5d Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Wed, 25 Nov 2020 19:19:32 -0800 Subject: 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 Tested-by: Simon Glass Commit-Queue: Simon Glass Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2630167 Tested-by: Jack Rosenthal Commit-Queue: Jack Rosenthal --- zephyr/drivers/CMakeLists.txt | 1 + zephyr/drivers/Kconfig | 1 + zephyr/drivers/cros_flash/CMakeLists.txt | 3 + zephyr/drivers/cros_flash/Kconfig | 13 + zephyr/drivers/cros_flash/cros_flash_npcx.c | 525 +++++++++++++++++++++ .../bindings/cros_flash/cros-flash-controller.yaml | 12 + .../cros_flash/nuvoton,npcx-cros-flash.yaml | 24 + zephyr/include/drivers/cros_flash.h | 308 ++++++++++++ zephyr/include/soc/nuvoton_npcx/reg_def_cros.h | 94 ++++ .../volteer/boards/arm/volteer/volteer.dts | 9 + 10 files changed, 990 insertions(+) create mode 100644 zephyr/drivers/cros_flash/CMakeLists.txt create mode 100644 zephyr/drivers/cros_flash/Kconfig create mode 100644 zephyr/drivers/cros_flash/cros_flash_npcx.c create mode 100644 zephyr/dts/bindings/cros_flash/cros-flash-controller.yaml create mode 100644 zephyr/dts/bindings/cros_flash/nuvoton,npcx-cros-flash.yaml create mode 100644 zephyr/include/drivers/cros_flash.h 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include + +/** + * @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 +#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 = <>; + }; }; }; -- cgit v1.2.1