driver: flash: npcx: introduce npcx flash driver
This CL attempts to implement npcx's flash driver instead of the original one (npcx spi driver plus spi_nor flash driver). Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
This commit is contained in:
parent
7411fbcb5b
commit
f34fff91bc
24 changed files with 1302 additions and 251 deletions
|
@ -38,6 +38,8 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NIOS2_QSPI soc_flash_nios2_qspi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 soc_flash_rv32m1.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_OSPI flash_stm32_ospi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G flash_mcux_flexspi_mx25um51345g.c)
|
||||
|
|
|
@ -118,6 +118,8 @@ source "drivers/flash/Kconfig.mcux"
|
|||
|
||||
source "drivers/flash/Kconfig.nios2_qspi"
|
||||
|
||||
source "drivers/flash/Kconfig.npcx_fiu"
|
||||
|
||||
source "drivers/flash/Kconfig.gecko"
|
||||
|
||||
source "drivers/flash/Kconfig.nor"
|
||||
|
|
34
drivers/flash/Kconfig.npcx_fiu
Normal file
34
drivers/flash/Kconfig.npcx_fiu
Normal file
|
@ -0,0 +1,34 @@
|
|||
# NPCX Flash driver configuration options
|
||||
|
||||
# Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config FLASH_NPCX_FIU_QSPI
|
||||
bool "Nuvoton NPCX QSPI Bus Flash driver"
|
||||
default y
|
||||
depends on DT_HAS_NUVOTON_NPCX_FIU_QSPI_ENABLED
|
||||
help
|
||||
This option enables the QSPI Bus Flash driver for NPCX family of
|
||||
processors.
|
||||
|
||||
config FLASH_NPCX_FIU_NOR
|
||||
bool "Nuvoton NPCX embedded controller (EC) QSPI NOR Flash driver"
|
||||
default y
|
||||
depends on DT_HAS_NUVOTON_NPCX_FIU_NOR_ENABLED
|
||||
depends on FLASH_NPCX_FIU_QSPI
|
||||
select FLASH_HAS_DRIVER_ENABLED
|
||||
select FLASH_HAS_PAGE_LAYOUT
|
||||
select FLASH_JESD216
|
||||
select FLASH_HAS_EX_OP
|
||||
help
|
||||
This option enables the QSPI NOR Flash driver for NPCX family of
|
||||
processors.
|
||||
|
||||
config FLASH_NPCX_FIU_NOR_INIT
|
||||
bool "QSPI NOR flash feature during driver initialization"
|
||||
default y
|
||||
depends on FLASH_NPCX_FIU_NOR
|
||||
help
|
||||
This option enables the QSPI NOR Flash features such as Quad-Enable,
|
||||
4-byte address support and so on during driver initialization. Disable
|
||||
it if QSPI NOR devices are not ready during driver initialization.
|
625
drivers/flash/flash_npcx_fiu_nor.c
Normal file
625
drivers/flash/flash_npcx_fiu_nor.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nuvoton_npcx_fiu_nor
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/flash.h>
|
||||
#include <zephyr/drivers/flash/npcx_flash_api_ex.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
#include <zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h>
|
||||
#include <soc.h>
|
||||
#ifdef CONFIG_USERSPACE
|
||||
#include <zephyr/syscall.h>
|
||||
#include <zephyr/syscall_handler.h>
|
||||
#endif
|
||||
|
||||
#include "flash_npcx_fiu_qspi.h"
|
||||
#include "spi_nor.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(flash_npcx_fiu_nor, CONFIG_FLASH_LOG_LEVEL);
|
||||
|
||||
/* Device config */
|
||||
struct flash_npcx_nor_config {
|
||||
/* QSPI bus device for mutex control and bus configuration */
|
||||
const struct device *qspi_bus;
|
||||
/* Mapped address for flash read via direct access */
|
||||
uintptr_t mapped_addr;
|
||||
/* Size of nor device in bytes, from size property */
|
||||
uint32_t flash_size;
|
||||
/* Minimum size for flash erase */
|
||||
uint32_t min_erase_size;
|
||||
/* Maximum chip erase time-out in ms */
|
||||
uint32_t max_timeout;
|
||||
/* SPI Nor device configuration on QSPI bus */
|
||||
struct npcx_qspi_cfg qspi_cfg;
|
||||
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||
struct flash_pages_layout layout;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Device data */
|
||||
struct flash_npcx_nor_data {
|
||||
/* Specific control operation for Quad-SPI Nor Flash */
|
||||
uint32_t operation;
|
||||
};
|
||||
|
||||
static const struct flash_parameters flash_npcx_parameters = {
|
||||
.write_block_size = 1,
|
||||
.erase_value = 0xff,
|
||||
};
|
||||
|
||||
#define DT_INST_QUAD_EN_PROP_OR(inst) \
|
||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, quad_enable_requirements), \
|
||||
(_CONCAT(JESD216_DW15_QER_VAL_, \
|
||||
DT_INST_STRING_TOKEN(inst, quad_enable_requirements))), \
|
||||
((JESD216_DW15_QER_VAL_NONE)))
|
||||
|
||||
static inline bool is_within_region(off_t addr, size_t size, off_t region_start,
|
||||
size_t region_size)
|
||||
{
|
||||
return (addr >= region_start &&
|
||||
(addr < (region_start + region_size)) &&
|
||||
((addr + size) <= (region_start + region_size)));
|
||||
}
|
||||
|
||||
static int flash_npcx_uma_transceive(const struct device *dev, struct npcx_uma_cfg *cfg,
|
||||
uint32_t flags)
|
||||
{
|
||||
const struct flash_npcx_nor_config *config = dev->config;
|
||||
struct flash_npcx_nor_data *data = dev->data;
|
||||
int ret;
|
||||
|
||||
/* Lock SPI bus and configure it if needed */
|
||||
qspi_npcx_fiu_mutex_lock_configure(config->qspi_bus, &config->qspi_cfg,
|
||||
data->operation);
|
||||
|
||||
/* Execute UMA transaction */
|
||||
ret = qspi_npcx_fiu_uma_transceive(config->qspi_bus, cfg, flags);
|
||||
|
||||
/* Unlock SPI bus */
|
||||
qspi_npcx_fiu_mutex_unlock(config->qspi_bus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* NPCX UMA functions for SPI NOR flash */
|
||||
static int flash_npcx_uma_cmd_only(const struct device *dev, uint8_t opcode)
|
||||
{
|
||||
struct npcx_uma_cfg cfg = { .opcode = opcode};
|
||||
|
||||
return flash_npcx_uma_transceive(dev, &cfg, 0); /* opcode only */
|
||||
}
|
||||
|
||||
static int flash_npcx_uma_cmd_by_addr(const struct device *dev, uint8_t opcode,
|
||||
uint32_t addr)
|
||||
{
|
||||
struct npcx_uma_cfg cfg = { .opcode = opcode};
|
||||
|
||||
cfg.addr.u32 = sys_cpu_to_be32(addr);
|
||||
return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_ADDR);
|
||||
}
|
||||
|
||||
static int flash_npcx_uma_read(const struct device *dev, uint8_t opcode,
|
||||
uint8_t *dst, const size_t size)
|
||||
{
|
||||
struct npcx_uma_cfg cfg = { .opcode = opcode,
|
||||
.rx_buf = dst,
|
||||
.rx_count = size};
|
||||
|
||||
return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_READ);
|
||||
}
|
||||
|
||||
static int flash_npcx_uma_write(const struct device *dev, uint8_t opcode,
|
||||
uint8_t *src, const size_t size)
|
||||
{
|
||||
struct npcx_uma_cfg cfg = { .opcode = opcode,
|
||||
.tx_buf = src,
|
||||
.tx_count = size};
|
||||
|
||||
return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_WRITE);
|
||||
}
|
||||
|
||||
static int flash_npcx_uma_write_by_addr(const struct device *dev, uint8_t opcode,
|
||||
uint8_t *src, const size_t size, uint32_t addr)
|
||||
{
|
||||
struct npcx_uma_cfg cfg = { .opcode = opcode,
|
||||
.tx_buf = src,
|
||||
.tx_count = size};
|
||||
|
||||
cfg.addr.u32 = sys_cpu_to_be32(addr);
|
||||
return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_WRITE |
|
||||
NPCX_UMA_ACCESS_ADDR);
|
||||
}
|
||||
|
||||
/* Local SPI NOR flash functions */
|
||||
static int flash_npcx_nor_wait_until_ready(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
uint8_t reg;
|
||||
const struct flash_npcx_nor_config *config = dev->config;
|
||||
int64_t st = k_uptime_get();
|
||||
|
||||
do {
|
||||
ret = flash_npcx_uma_read(dev, SPI_NOR_CMD_RDSR, ®, sizeof(reg));
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
} else if ((reg & SPI_NOR_WIP_BIT) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} while ((k_uptime_get() - st) < config->max_timeout);
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_read_status_regs(const struct device *dev, uint8_t *sts_reg)
|
||||
{
|
||||
int ret = flash_npcx_uma_read(dev, SPI_NOR_CMD_RDSR, sts_reg, 1);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
return flash_npcx_uma_read(dev, SPI_NOR_CMD_RDSR2, sts_reg + 1, 1);
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_write_status_regs(const struct device *dev, uint8_t *sts_reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = flash_npcx_uma_write(dev, SPI_NOR_CMD_WRSR, sts_reg, 2);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return flash_npcx_nor_wait_until_ready(dev);
|
||||
}
|
||||
|
||||
/* Flash API functions */
|
||||
#if defined(CONFIG_FLASH_JESD216_API)
|
||||
static int flash_npcx_nor_read_jedec_id(const struct device *dev, uint8_t *id)
|
||||
{
|
||||
if (id == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return flash_npcx_uma_read(dev, SPI_NOR_CMD_RDID, id, SPI_NOR_MAX_ID_LEN);
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_read_sfdp(const struct device *dev, off_t addr,
|
||||
void *data, size_t size)
|
||||
{
|
||||
uint8_t sfdp_addr[4];
|
||||
struct npcx_uma_cfg cfg = { .opcode = JESD216_CMD_READ_SFDP,
|
||||
.tx_buf = sfdp_addr,
|
||||
.tx_count = 4,
|
||||
.rx_buf = data,
|
||||
.rx_count = size};
|
||||
|
||||
if (data == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* CMD_READ_SFDP needs a 24-bit address followed by a dummy byte */
|
||||
sfdp_addr[0] = (addr >> 16) & 0xff;
|
||||
sfdp_addr[1] = (addr >> 8) & 0xff;
|
||||
sfdp_addr[2] = addr & 0xff;
|
||||
return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_WRITE |
|
||||
NPCX_UMA_ACCESS_READ);
|
||||
}
|
||||
#endif /* CONFIG_FLASH_JESD216_API */
|
||||
|
||||
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||
static void flash_npcx_nor_pages_layout(const struct device *dev,
|
||||
const struct flash_pages_layout **layout,
|
||||
size_t *layout_size)
|
||||
{
|
||||
const struct flash_npcx_nor_config *config = dev->config;
|
||||
|
||||
*layout = &config->layout;
|
||||
*layout_size = 1;
|
||||
}
|
||||
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
|
||||
|
||||
static int flash_npcx_nor_read(const struct device *dev, off_t addr,
|
||||
void *data, size_t size)
|
||||
{
|
||||
const struct flash_npcx_nor_config *config = dev->config;
|
||||
struct flash_npcx_nor_data *dev_data = dev->data;
|
||||
|
||||
/* Out of the region of nor flash device? */
|
||||
if (!is_within_region(addr, size, 0, config->flash_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Lock/Unlock SPI bus also for DRA mode */
|
||||
qspi_npcx_fiu_mutex_lock_configure(config->qspi_bus, &config->qspi_cfg,
|
||||
dev_data->operation);
|
||||
|
||||
/* Trigger Direct Read Access (DRA) via reading memory mapped-address */
|
||||
memcpy(data, (void *)(config->mapped_addr + addr), size);
|
||||
|
||||
qspi_npcx_fiu_mutex_unlock(config->qspi_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_erase(const struct device *dev, off_t addr,
|
||||
size_t size)
|
||||
{
|
||||
const struct flash_npcx_nor_config *config = dev->config;
|
||||
int ret = 0;
|
||||
uint8_t opcode;
|
||||
|
||||
/* Out of the region of nor flash device? */
|
||||
if (!is_within_region(addr, size, 0, config->flash_size)) {
|
||||
LOG_ERR("Addr %ld, size %d are out of range", addr, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* address must be sector-aligned */
|
||||
if (!SPI_NOR_IS_SECTOR_ALIGNED(addr)) {
|
||||
LOG_ERR("Addr %ld is not sector-aligned", addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* size must be a multiple of sectors */
|
||||
if ((size % config->min_erase_size) != 0) {
|
||||
LOG_ERR("Size %d is not a multiple of sectors", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Select erase opcode by size */
|
||||
if (size == config->flash_size) {
|
||||
flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN);
|
||||
/* Send chip erase command */
|
||||
flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_CE);
|
||||
return flash_npcx_nor_wait_until_ready(dev);
|
||||
} else if (config->min_erase_size == KB(4)) {
|
||||
opcode = SPI_NOR_CMD_SE;
|
||||
} else if (config->min_erase_size == KB(64)) {
|
||||
opcode = SPI_NOR_CMD_BE;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN);
|
||||
/* Send page/block erase command with addr */
|
||||
flash_npcx_uma_cmd_by_addr(dev, opcode, addr);
|
||||
addr += config->min_erase_size;
|
||||
size -= config->min_erase_size;
|
||||
ret = flash_npcx_nor_wait_until_ready(dev);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_write(const struct device *dev, off_t addr,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
const struct flash_npcx_nor_config *config = dev->config;
|
||||
uint8_t *tx_buf = (uint8_t *)data;
|
||||
int ret = 0;
|
||||
size_t sz_write;
|
||||
|
||||
/* Out of the region of nor flash device? */
|
||||
if (!is_within_region(addr, size, 0, config->flash_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Don't write more than a page. */
|
||||
if (size > SPI_NOR_PAGE_SIZE) {
|
||||
sz_write = SPI_NOR_PAGE_SIZE;
|
||||
} else {
|
||||
sz_write = size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Correct the size of first write to not go through page boundary and
|
||||
* make the address of next write to align to page boundary.
|
||||
*/
|
||||
if (((addr + sz_write - 1U) / SPI_NOR_PAGE_SIZE) != (addr / SPI_NOR_PAGE_SIZE)) {
|
||||
sz_write -= (addr + sz_write) & (SPI_NOR_PAGE_SIZE - 1);
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
/* Start to write */
|
||||
flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN);
|
||||
ret = flash_npcx_uma_write_by_addr(dev, SPI_NOR_CMD_PP, tx_buf,
|
||||
sz_write, addr);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait for writing completed */
|
||||
ret = flash_npcx_nor_wait_until_ready(dev);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
size -= sz_write;
|
||||
tx_buf += sz_write;
|
||||
addr += sz_write;
|
||||
|
||||
if (size > SPI_NOR_PAGE_SIZE) {
|
||||
sz_write = SPI_NOR_PAGE_SIZE;
|
||||
} else {
|
||||
sz_write = size;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct flash_parameters *
|
||||
flash_npcx_nor_get_parameters(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return &flash_npcx_parameters;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FLASH_EX_OP_ENABLED
|
||||
static int flash_npcx_nor_ex_exec_uma(const struct device *dev,
|
||||
const struct npcx_ex_ops_uma_in *op_in,
|
||||
const struct npcx_ex_ops_uma_out *op_out)
|
||||
{
|
||||
int flag = 0;
|
||||
struct npcx_uma_cfg cfg;
|
||||
|
||||
if (op_in == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Organize a UMA transaction */
|
||||
cfg.opcode = op_in->opcode;
|
||||
if (op_in->tx_count != 0) {
|
||||
cfg.tx_buf = op_in->tx_buf;
|
||||
cfg.tx_count = op_in->tx_count;
|
||||
flag |= NPCX_UMA_ACCESS_WRITE;
|
||||
}
|
||||
|
||||
if (op_in->addr_count != 0) {
|
||||
cfg.addr.u32 = sys_cpu_to_be32(op_in->addr);
|
||||
flag |= NPCX_UMA_ACCESS_ADDR;
|
||||
}
|
||||
|
||||
if (op_out != NULL && op_in->rx_count != 0) {
|
||||
cfg.rx_buf = op_out->rx_buf;
|
||||
cfg.rx_count = op_in->rx_count;
|
||||
flag |= NPCX_UMA_ACCESS_READ;
|
||||
}
|
||||
|
||||
return flash_npcx_uma_transceive(dev, &cfg, flag);
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_ex_set_spi_spec(const struct device *dev,
|
||||
const struct npcx_ex_ops_qspi_oper_in *op_in)
|
||||
{
|
||||
struct flash_npcx_nor_data *data = dev->data;
|
||||
|
||||
/* Cannot disable write protection of internal flash */
|
||||
if ((data->operation & NPCX_EX_OP_INT_FLASH_WP) != 0) {
|
||||
if ((op_in->mask & NPCX_EX_OP_INT_FLASH_WP) != 0 && !op_in->enable) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (op_in->enable) {
|
||||
data->operation |= op_in->mask;
|
||||
} else {
|
||||
data->operation &= ~op_in->mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_ex_get_spi_spec(const struct device *dev,
|
||||
struct npcx_ex_ops_qspi_oper_out *op_out)
|
||||
{
|
||||
struct flash_npcx_nor_data *data = dev->data;
|
||||
|
||||
op_out->oper = data->operation;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_npcx_nor_ex_op(const struct device *dev, uint16_t code,
|
||||
const uintptr_t in, void *out)
|
||||
{
|
||||
#ifdef CONFIG_USERSPACE
|
||||
bool syscall_trap = z_syscall_trap();
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
switch (code) {
|
||||
case FLASH_NPCX_EX_OP_EXEC_UMA:
|
||||
{
|
||||
struct npcx_ex_ops_uma_in *op_in = (struct npcx_ex_ops_uma_in *)in;
|
||||
struct npcx_ex_ops_uma_out *op_out = (struct npcx_ex_ops_uma_out *)out;
|
||||
#ifdef CONFIG_USERSPACE
|
||||
struct npcx_ex_ops_uma_in in_copy;
|
||||
struct npcx_ex_ops_uma_out out_copy;
|
||||
|
||||
if (syscall_trap) {
|
||||
Z_OOPS(z_user_from_copy(&in_copy, op_in, sizeof(in_copy)));
|
||||
op_in = &in_copy;
|
||||
op_out = &out_copy;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = flash_npcx_nor_ex_exec_uma(dev, op_in, op_out);
|
||||
#ifdef CONFIG_USERSPACE
|
||||
if (ret == 0 && syscall_trap) {
|
||||
Z_OOPS(z_user_to_copy(out, op_out, sizeof(out_copy)));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case FLASH_NPCX_EX_OP_SET_QSPI_OPER:
|
||||
{
|
||||
struct npcx_ex_ops_qspi_oper_in *op_in = (struct npcx_ex_ops_qspi_oper_in *)in;
|
||||
#ifdef CONFIG_USERSPACE
|
||||
struct npcx_ex_ops_qspi_oper_in in_copy;
|
||||
|
||||
if (syscall_trap) {
|
||||
Z_OOPS(z_user_from_copy(&in_copy, op_in, sizeof(in_copy)));
|
||||
op_in = &in_copy;
|
||||
}
|
||||
#endif
|
||||
ret = flash_npcx_nor_ex_set_spi_spec(dev, op_in);
|
||||
break;
|
||||
}
|
||||
case FLASH_NPCX_EX_OP_GET_QSPI_OPER:
|
||||
{
|
||||
struct npcx_ex_ops_qspi_oper_out *op_out =
|
||||
(struct npcx_ex_ops_qspi_oper_out *)out;
|
||||
#ifdef CONFIG_USERSPACE
|
||||
struct npcx_ex_ops_qspi_oper_out out_copy;
|
||||
|
||||
if (syscall_trap) {
|
||||
op_out = &out_copy;
|
||||
}
|
||||
#endif
|
||||
ret = flash_npcx_nor_ex_get_spi_spec(dev, op_out);
|
||||
#ifdef CONFIG_USERSPACE
|
||||
if (ret == 0 && syscall_trap) {
|
||||
Z_OOPS(z_user_to_copy(out, op_out, sizeof(out_copy)));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -ENOTSUP;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct flash_driver_api flash_npcx_nor_driver_api = {
|
||||
.read = flash_npcx_nor_read,
|
||||
.write = flash_npcx_nor_write,
|
||||
.erase = flash_npcx_nor_erase,
|
||||
.get_parameters = flash_npcx_nor_get_parameters,
|
||||
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||
.page_layout = flash_npcx_nor_pages_layout,
|
||||
#endif
|
||||
#if defined(CONFIG_FLASH_JESD216_API)
|
||||
.sfdp_read = flash_npcx_nor_read_sfdp,
|
||||
.read_jedec_id = flash_npcx_nor_read_jedec_id,
|
||||
#endif
|
||||
#ifdef CONFIG_FLASH_EX_OP_ENABLED
|
||||
.ex_op = flash_npcx_nor_ex_op,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int flash_npcx_nor_init(const struct device *dev)
|
||||
{
|
||||
const struct flash_npcx_nor_config *config = dev->config;
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_FLASH_NPCX_FIU_NOR_INIT)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enable quad access of spi NOR flash */
|
||||
if (config->qspi_cfg.qer_type != JESD216_DW15_QER_NONE) {
|
||||
uint8_t qe_idx, qe_bit, sts_reg[2];
|
||||
/* Read status registers first */
|
||||
ret = flash_npcx_nor_read_status_regs(dev, sts_reg);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Enable quad access: read reg failed %d!", ret);
|
||||
return ret;
|
||||
}
|
||||
switch (config->qspi_cfg.qer_type) {
|
||||
case JESD216_DW15_QER_S1B6:
|
||||
qe_idx = 1;
|
||||
qe_bit = 6;
|
||||
break;
|
||||
case JESD216_DW15_QER_S2B1v1:
|
||||
__fallthrough;
|
||||
case JESD216_DW15_QER_S2B1v4:
|
||||
__fallthrough;
|
||||
case JESD216_DW15_QER_S2B1v5:
|
||||
qe_idx = 2;
|
||||
qe_bit = 1;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
/* Set QE bit in status register */
|
||||
sts_reg[qe_idx - 1] |= BIT(qe_bit);
|
||||
ret = flash_npcx_nor_write_status_regs(dev, sts_reg);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Enable quad access: write reg failed %d!", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable 4-byte address of spi NOR flash */
|
||||
if (config->qspi_cfg.enter_4ba != 0) {
|
||||
bool wr_en = (config->qspi_cfg.enter_4ba & 0x02) != 0;
|
||||
|
||||
if (wr_en) {
|
||||
ret = flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Enable 4byte addr: WREN failed %d!", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_4BA);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Enable 4byte addr: 4BA failed %d!", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NPCX_FLASH_NOR_INIT(n) \
|
||||
BUILD_ASSERT(DT_INST_QUAD_EN_PROP_OR(n) == JESD216_DW15_QER_NONE || \
|
||||
DT_INST_STRING_TOKEN(n, rd_mode) == NPCX_RD_MODE_FAST_DUAL, \
|
||||
"Fast Dual IO read must be selected in Quad mode"); \
|
||||
PINCTRL_DT_INST_DEFINE(n); \
|
||||
static const struct flash_npcx_nor_config flash_npcx_nor_config_##n = { \
|
||||
.qspi_bus = DEVICE_DT_GET(DT_PARENT(DT_DRV_INST(n))), \
|
||||
.mapped_addr = DT_INST_PROP(n, mapped_addr), \
|
||||
.flash_size = DT_INST_PROP(n, size) / 8, \
|
||||
.min_erase_size = DT_INST_PROP(n, min_erase_size), \
|
||||
.max_timeout = DT_INST_PROP(n, max_timeout), \
|
||||
.qspi_cfg = { \
|
||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
||||
.flags = DT_INST_PROP(n, qspi_flags), \
|
||||
.enter_4ba = DT_INST_PROP_OR(n, enter_4byte_addr, 0), \
|
||||
.qer_type = DT_INST_QUAD_EN_PROP_OR(n), \
|
||||
.rd_mode = DT_INST_STRING_TOKEN(n, rd_mode), \
|
||||
}, \
|
||||
IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, ( \
|
||||
.layout = { \
|
||||
.pages_count = DT_INST_PROP(n, size) / \
|
||||
(8 * SPI_NOR_PAGE_SIZE), \
|
||||
.pages_size = SPI_NOR_PAGE_SIZE, \
|
||||
},)) \
|
||||
}; \
|
||||
static struct flash_npcx_nor_data flash_npcx_nor_data_##n; \
|
||||
DEVICE_DT_INST_DEFINE(n, flash_npcx_nor_init, NULL, \
|
||||
&flash_npcx_nor_data_##n, &flash_npcx_nor_config_##n, \
|
||||
POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, \
|
||||
&flash_npcx_nor_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(NPCX_FLASH_NOR_INIT)
|
271
drivers/flash/flash_npcx_fiu_qspi.c
Normal file
271
drivers/flash/flash_npcx_fiu_qspi.c
Normal file
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nuvoton_npcx_fiu_qspi
|
||||
|
||||
#include <zephyr/drivers/clock_control.h>
|
||||
#include <zephyr/drivers/flash/npcx_flash_api_ex.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h>
|
||||
#include <soc.h>
|
||||
|
||||
#include "flash_npcx_fiu_qspi.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(npcx_fiu_qspi, LOG_LEVEL_ERR);
|
||||
|
||||
/* Driver convenience defines */
|
||||
#define HAL_INSTANCE(dev) \
|
||||
((struct fiu_reg *)((const struct npcx_qspi_fiu_config *)(dev)->config)->base)
|
||||
|
||||
/* Device config */
|
||||
struct npcx_qspi_fiu_config {
|
||||
/* Flash interface unit base address */
|
||||
uintptr_t base;
|
||||
/* Clock configuration */
|
||||
struct npcx_clk_cfg clk_cfg;
|
||||
/* Enable 2 external SPI devices for direct read on QSPI bus */
|
||||
bool en_direct_access_2dev;
|
||||
};
|
||||
|
||||
/* Device data */
|
||||
struct npcx_qspi_fiu_data {
|
||||
/* mutex of qspi bus controller */
|
||||
struct k_sem lock_sem;
|
||||
/* Current device configuration on QSPI bus */
|
||||
const struct npcx_qspi_cfg *cur_cfg;
|
||||
/* Current Software controlled Chip-Select number */
|
||||
int sw_cs;
|
||||
/* Current QSPI bus operation */
|
||||
uint32_t operation;
|
||||
};
|
||||
|
||||
/* NPCX SPI User Mode Access (UMA) functions */
|
||||
static inline void qspi_npcx_uma_cs_level(const struct device *dev, uint8_t sw_cs, bool level)
|
||||
{
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
|
||||
/* Set chip select to high/low level */
|
||||
if (level) {
|
||||
inst->UMA_ECTS |= BIT(sw_cs);
|
||||
} else {
|
||||
inst->UMA_ECTS &= ~BIT(sw_cs);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qspi_npcx_uma_write_byte(const struct device *dev, uint8_t data)
|
||||
{
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
|
||||
/* Set data to UMA_CODE and trigger UMA */
|
||||
inst->UMA_CODE = data;
|
||||
inst->UMA_CTS = UMA_CODE_CMD_WR_ONLY;
|
||||
/* EXEC_DONE will be zero automatically if a UMA transaction is completed. */
|
||||
while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qspi_npcx_uma_read_byte(const struct device *dev, uint8_t *data)
|
||||
{
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
|
||||
/* Trigger UMA and Get data from DB0 later */
|
||||
inst->UMA_CTS = UMA_CODE_RD_BYTE(1);
|
||||
while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*data = inst->UMA_DB0;
|
||||
}
|
||||
|
||||
/* NPCX SPI Direct Read Access (DRA)/User Mode Access (UMA) configuration functions */
|
||||
static inline void qspi_npcx_config_uma_mode(const struct device *dev,
|
||||
const struct npcx_qspi_cfg *qspi_cfg)
|
||||
{
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
|
||||
if ((qspi_cfg->flags & NPCX_QSPI_SEC_FLASH_SL) != 0) {
|
||||
inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_SEC_CS);
|
||||
} else {
|
||||
inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_SEC_CS);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qspi_npcx_config_dra_mode(const struct device *dev,
|
||||
const struct npcx_qspi_cfg *qspi_cfg)
|
||||
{
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
|
||||
/* Enable quad mode of Direct Read Mode if needed */
|
||||
if (qspi_cfg->qer_type != JESD216_DW15_QER_NONE) {
|
||||
inst->RESP_CFG |= BIT(NPCX_RESP_CFG_QUAD_EN);
|
||||
} else {
|
||||
inst->RESP_CFG &= ~BIT(NPCX_RESP_CFG_QUAD_EN);
|
||||
}
|
||||
|
||||
/* Selects the SPI read access type of Direct Read Access mode */
|
||||
SET_FIELD(inst->SPI_FL_CFG, NPCX_SPI_FL_CFG_RD_MODE, qspi_cfg->rd_mode);
|
||||
|
||||
/* Enable/Disable 4 byte address mode for Direct Read Access (DRA) */
|
||||
#if !defined(CONFIG_SOC_SERIES_NPCX7) /* NPCX7 doesn't support this feature */
|
||||
if (qspi_cfg->enter_4ba != 0) {
|
||||
if ((qspi_cfg->flags & NPCX_QSPI_SEC_FLASH_SL) != 0) {
|
||||
inst->SPI1_DEV |= BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS11);
|
||||
} else {
|
||||
inst->SPI1_DEV |= BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS10);
|
||||
}
|
||||
} else {
|
||||
inst->SPI1_DEV &= ~(BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS11) |
|
||||
BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS10));
|
||||
}
|
||||
#endif /* CONFIG_SOC_SERIES_NPCX7 */
|
||||
}
|
||||
|
||||
static inline void qspi_npcx_fiu_set_operation(const struct device *dev, uint32_t operation)
|
||||
{
|
||||
if ((operation & NPCX_EX_OP_INT_FLASH_WP) != 0) {
|
||||
npcx_pinctrl_flash_write_protect_set();
|
||||
}
|
||||
}
|
||||
|
||||
/* NPCX specific QSPI-FIU controller functions */
|
||||
int qspi_npcx_fiu_uma_transceive(const struct device *dev, struct npcx_uma_cfg *cfg,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct npcx_qspi_fiu_data *const data = dev->data;
|
||||
|
||||
/* UMA transaction is permitted? */
|
||||
if ((data->operation & NPCX_EX_OP_LOCK_UMA) != 0) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Assert chip select */
|
||||
qspi_npcx_uma_cs_level(dev, data->sw_cs, false);
|
||||
|
||||
/* Transmit op-code first */
|
||||
qspi_npcx_uma_write_byte(dev, cfg->opcode);
|
||||
|
||||
if ((flags & NPCX_UMA_ACCESS_ADDR) != 0) {
|
||||
/* 3-byte or 4-byte address? */
|
||||
const int addr_start = (data->cur_cfg->enter_4ba != 0) ? 0 : 1;
|
||||
|
||||
for (size_t i = addr_start; i < 4; i++) {
|
||||
LOG_DBG("addr %d, %02x", i, cfg->addr.u8[i]);
|
||||
qspi_npcx_uma_write_byte(dev, cfg->addr.u8[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & NPCX_UMA_ACCESS_WRITE) != 0) {
|
||||
if (cfg->tx_buf == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
for (size_t i = 0; i < cfg->tx_count; i++) {
|
||||
qspi_npcx_uma_write_byte(dev, cfg->tx_buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & NPCX_UMA_ACCESS_READ) != 0) {
|
||||
if (cfg->rx_buf == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
for (size_t i = 0; i < cfg->rx_count; i++) {
|
||||
qspi_npcx_uma_read_byte(dev, cfg->rx_buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
/* De-assert chip select */
|
||||
qspi_npcx_uma_cs_level(dev, data->sw_cs, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qspi_npcx_fiu_mutex_lock_configure(const struct device *dev,
|
||||
const struct npcx_qspi_cfg *cfg,
|
||||
const uint32_t operation)
|
||||
{
|
||||
struct npcx_qspi_fiu_data *const data = dev->data;
|
||||
|
||||
k_sem_take(&data->lock_sem, K_FOREVER);
|
||||
|
||||
/* If the current device is different from previous one, configure it */
|
||||
if (data->cur_cfg != cfg) {
|
||||
data->cur_cfg = cfg;
|
||||
|
||||
/* Apply pin-muxing and tri-state */
|
||||
pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
||||
|
||||
/* Configure User Mode Access (UMA) settings */
|
||||
qspi_npcx_config_uma_mode(dev, cfg);
|
||||
|
||||
/* Configure for Direct Read Access (DRA) settings */
|
||||
qspi_npcx_config_dra_mode(dev, cfg);
|
||||
|
||||
/* Save SW CS bit used in UMA mode */
|
||||
data->sw_cs = find_lsb_set(cfg->flags & NPCX_QSPI_SW_CS_MASK) - 1;
|
||||
}
|
||||
|
||||
/* Set QSPI bus operation */
|
||||
if (data->operation != operation) {
|
||||
qspi_npcx_fiu_set_operation(dev, operation);
|
||||
data->operation = operation;
|
||||
}
|
||||
}
|
||||
|
||||
void qspi_npcx_fiu_mutex_unlock(const struct device *dev)
|
||||
{
|
||||
struct npcx_qspi_fiu_data *const data = dev->data;
|
||||
|
||||
k_sem_give(&data->lock_sem);
|
||||
}
|
||||
|
||||
static int qspi_npcx_fiu_init(const struct device *dev)
|
||||
{
|
||||
const struct npcx_qspi_fiu_config *const config = dev->config;
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
struct npcx_qspi_fiu_data *const data = dev->data;
|
||||
const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE);
|
||||
int ret;
|
||||
|
||||
if (!device_is_ready(clk_dev)) {
|
||||
LOG_ERR("%s device not ready", clk_dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* initialize mutex for qspi controller */
|
||||
k_sem_init(&data->lock_sem, 1, 1);
|
||||
|
||||
/* Enable direct access for 2 external SPI devices */
|
||||
if (config->en_direct_access_2dev) {
|
||||
if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) {
|
||||
inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_SPI1_2DEV);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NPCX_SPI_FIU_INIT(n) \
|
||||
static const struct npcx_qspi_fiu_config npcx_qspi_fiu_config_##n = { \
|
||||
.base = DT_INST_REG_ADDR(n), \
|
||||
.clk_cfg = NPCX_DT_CLK_CFG_ITEM(n), \
|
||||
.en_direct_access_2dev = DT_INST_PROP(n, en_direct_access_2dev), \
|
||||
}; \
|
||||
static struct npcx_qspi_fiu_data npcx_qspi_fiu_data_##n; \
|
||||
DEVICE_DT_INST_DEFINE(n, qspi_npcx_fiu_init, NULL, \
|
||||
&npcx_qspi_fiu_data_##n, &npcx_qspi_fiu_config_##n, \
|
||||
PRE_KERNEL_1, CONFIG_FLASH_INIT_PRIORITY, NULL);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(NPCX_SPI_FIU_INIT)
|
82
drivers/flash/flash_npcx_fiu_qspi.h
Normal file
82
drivers/flash/flash_npcx_fiu_qspi.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_FLASH_NPCX_FIU_QSPI_H_
|
||||
#define ZEPHYR_DRIVERS_FLASH_NPCX_FIU_QSPI_H_
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include "jesd216.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* UMA operation flags */
|
||||
#define NPCX_UMA_ACCESS_WRITE BIT(0)
|
||||
#define NPCX_UMA_ACCESS_READ BIT(1)
|
||||
#define NPCX_UMA_ACCESS_ADDR BIT(2)
|
||||
|
||||
/* UMA operation configuration for a SPI device */
|
||||
struct npcx_uma_cfg {
|
||||
uint8_t opcode;
|
||||
uint8_t *tx_buf;
|
||||
size_t tx_count;
|
||||
uint8_t *rx_buf;
|
||||
size_t rx_count;
|
||||
union {
|
||||
uint32_t u32;
|
||||
uint8_t u8[4];
|
||||
} addr;
|
||||
};
|
||||
|
||||
/* QSPI bus configuration for a SPI device */
|
||||
struct npcx_qspi_cfg {
|
||||
/* Type of Quad Enable bit in status register */
|
||||
enum jesd216_dw15_qer_type qer_type;
|
||||
/* Pinctrl for QSPI bus */
|
||||
const struct pinctrl_dev_config *pcfg;
|
||||
/* Enter four bytes address mode value */
|
||||
uint8_t enter_4ba;
|
||||
/* SPI read access type of Direct Read Access mode */
|
||||
uint8_t rd_mode;
|
||||
/* Configurations for the Quad-SPI peripherals */
|
||||
int flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Execute UMA transactions on qspi bus
|
||||
*
|
||||
* @param dev Pointer to the device structure for qspi bus controller instance.
|
||||
* @param cfg Pointer to the configuration of UMA transactions.
|
||||
* @param flags Flags to be used during transactions.
|
||||
* @retval 0 on success, -EPERM if an UMA transaction is not permitted.
|
||||
*/
|
||||
int qspi_npcx_fiu_uma_transceive(const struct device *dev, struct npcx_uma_cfg *cfg,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Lock the mutex of npcx qspi bus controller and apply its configuration
|
||||
*
|
||||
* @param dev Pointer to the device structure for qspi bus controller instance.
|
||||
* @param cfg Pointer to the configuration for the device on qspi bus.
|
||||
* @param operation Qspi bus operation for the device.
|
||||
*/
|
||||
void qspi_npcx_fiu_mutex_lock_configure(const struct device *dev,
|
||||
const struct npcx_qspi_cfg *cfg,
|
||||
const uint32_t operation);
|
||||
|
||||
/**
|
||||
* @brief Unlock the mutex of npcx qspi bus controller.
|
||||
*
|
||||
* @param dev Pointer to the device structure for qspi bus controller instance.
|
||||
*/
|
||||
void qspi_npcx_fiu_mutex_unlock(const struct device *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_FLASH_NPCX_FIU_QSPI_H_ */
|
|
@ -27,7 +27,6 @@ zephyr_library_sources_ifdef(CONFIG_SPI_XLNX_AXI_QUADSPI spi_xlnx_axi_quadspi.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_ESP32_SPIM spi_esp32_spim.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_TEST spi_test.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_PSOC6 spi_psoc6.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_FIU spi_npcx_fiu.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_BITBANG spi_bitbang.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI_LDMA spi_xec_qmspi_ldma.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_GD32 spi_gd32.c)
|
||||
|
|
|
@ -107,8 +107,6 @@ source "drivers/spi/Kconfig.test"
|
|||
|
||||
source "drivers/spi/Kconfig.psoc6"
|
||||
|
||||
source "drivers/spi/Kconfig.npcx_fiu"
|
||||
|
||||
source "drivers/spi/Kconfig.bitbang"
|
||||
|
||||
source "drivers/spi/Kconfig.gd32"
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
# NPCX SPI Driver configuration options
|
||||
|
||||
# Copyright (c) 2021 Nuvoton Technology Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SPI_NPCX_FIU
|
||||
bool "Nuvoton NPCX embedded controller (EC) SPI driver for NOR flash"
|
||||
default y
|
||||
depends on DT_HAS_NUVOTON_NPCX_SPI_FIU_ENABLED
|
||||
help
|
||||
Enable the SPI driver for NPCX family of processors. This driver is
|
||||
for the dedicated SPI controller (FIU) to access the NOR flash.
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nuvoton_npcx_spi_fiu
|
||||
|
||||
#include <zephyr/drivers/clock_control.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <soc.h>
|
||||
|
||||
LOG_MODULE_REGISTER(spi_npcx_fiu, LOG_LEVEL_ERR);
|
||||
|
||||
#include "spi_context.h"
|
||||
|
||||
/* Device config */
|
||||
struct npcx_spi_fiu_config {
|
||||
/* flash interface unit base address */
|
||||
uintptr_t base;
|
||||
/* clock configuration */
|
||||
struct npcx_clk_cfg clk_cfg;
|
||||
};
|
||||
|
||||
/* Device data */
|
||||
struct npcx_spi_fiu_data {
|
||||
struct spi_context ctx;
|
||||
};
|
||||
|
||||
/* Driver convenience defines */
|
||||
#define HAL_INSTANCE(dev) \
|
||||
((struct fiu_reg *)((const struct npcx_spi_fiu_config *)(dev)->config)->base)
|
||||
|
||||
static inline void spi_npcx_fiu_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 spi_npcx_fiu_exec_cmd(const struct device *dev, uint8_t code,
|
||||
uint8_t cts)
|
||||
{
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
|
||||
#ifdef CONFIG_ASSERT
|
||||
struct npcx_spi_fiu_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
|
||||
/* Flash mutex must be held while executing UMA commands */
|
||||
__ASSERT((k_sem_count_get(&ctx->lock) == 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))
|
||||
continue;
|
||||
}
|
||||
|
||||
static int spi_npcx_fiu_transceive(const struct device *dev,
|
||||
const struct spi_config *spi_cfg,
|
||||
const struct spi_buf_set *tx_bufs,
|
||||
const struct spi_buf_set *rx_bufs)
|
||||
{
|
||||
struct npcx_spi_fiu_data *data = dev->data;
|
||||
struct fiu_reg *const inst = HAL_INSTANCE(dev);
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
size_t cur_xfer_len;
|
||||
int error = 0;
|
||||
|
||||
spi_context_lock(ctx, false, NULL, NULL, spi_cfg);
|
||||
ctx->config = spi_cfg;
|
||||
|
||||
/*
|
||||
* Configure UMA lock/unlock only if tx buffer set and rx buffer set
|
||||
* are both empty.
|
||||
*/
|
||||
if (tx_bufs == NULL && rx_bufs == NULL) {
|
||||
if (spi_cfg->operation & SPI_LOCK_ON)
|
||||
inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_UMA_LOCK);
|
||||
else
|
||||
inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_UMA_LOCK);
|
||||
spi_context_unlock_unconditionally(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assert chip assert */
|
||||
spi_npcx_fiu_cs_level(dev, 0);
|
||||
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1);
|
||||
if (rx_bufs == NULL) {
|
||||
while (spi_context_tx_buf_on(ctx)) {
|
||||
spi_npcx_fiu_exec_cmd(dev, *ctx->tx_buf,
|
||||
UMA_CODE_CMD_WR_ONLY);
|
||||
spi_context_update_tx(ctx, 1, 1);
|
||||
}
|
||||
} else {
|
||||
cur_xfer_len = spi_context_longest_current_buf(ctx);
|
||||
for (size_t i = 0; i < cur_xfer_len; i++) {
|
||||
spi_npcx_fiu_exec_cmd(dev, *ctx->tx_buf,
|
||||
UMA_CODE_CMD_WR_ONLY);
|
||||
spi_context_update_tx(ctx, 1, 1);
|
||||
spi_context_update_rx(ctx, 1, 1);
|
||||
}
|
||||
while (spi_context_rx_buf_on(ctx)) {
|
||||
inst->UMA_CTS = UMA_CODE_RD_BYTE(1);
|
||||
while (IS_BIT_SET(inst->UMA_CTS,
|
||||
NPCX_UMA_CTS_EXEC_DONE))
|
||||
continue;
|
||||
/* Get read transaction results */
|
||||
*ctx->rx_buf = inst->UMA_DB0;
|
||||
spi_context_update_tx(ctx, 1, 1);
|
||||
spi_context_update_rx(ctx, 1, 1);
|
||||
}
|
||||
}
|
||||
spi_npcx_fiu_cs_level(dev, 1);
|
||||
spi_context_release(ctx, error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int spi_npcx_fiu_release(const struct device *dev,
|
||||
const struct spi_config *config)
|
||||
{
|
||||
struct npcx_spi_fiu_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
|
||||
if (!spi_context_configured(ctx, config)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spi_context_unlock_unconditionally(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spi_npcx_fiu_init(const struct device *dev)
|
||||
{
|
||||
const struct npcx_spi_fiu_config *const config = dev->config;
|
||||
const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE);
|
||||
int ret;
|
||||
|
||||
if (!device_is_ready(clk_dev)) {
|
||||
LOG_ERR("%s device not ready", clk_dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Make sure the context is unlocked */
|
||||
spi_context_unlock_unconditionally(&((struct npcx_spi_fiu_data *)dev->data)->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver_api spi_npcx_fiu_api = {
|
||||
.transceive = spi_npcx_fiu_transceive,
|
||||
.release = spi_npcx_fiu_release,
|
||||
};
|
||||
|
||||
static const struct npcx_spi_fiu_config npcx_spi_fiu_config = {
|
||||
.base = DT_INST_REG_ADDR(0),
|
||||
.clk_cfg = NPCX_DT_CLK_CFG_ITEM(0),
|
||||
};
|
||||
|
||||
static struct npcx_spi_fiu_data npcx_spi_fiu_data = {
|
||||
SPI_CONTEXT_INIT_LOCK(npcx_spi_fiu_data, ctx),
|
||||
};
|
||||
|
||||
DEVICE_DT_INST_DEFINE(0, &spi_npcx_fiu_init, NULL, &npcx_spi_fiu_data,
|
||||
&npcx_spi_fiu_config, POST_KERNEL,
|
||||
CONFIG_SPI_INIT_PRIORITY, &spi_npcx_fiu_api);
|
|
@ -9,6 +9,7 @@
|
|||
/* Macros for device tree declarations of npcx soc family */
|
||||
#include <zephyr/dt-bindings/adc/adc.h>
|
||||
#include <zephyr/dt-bindings/clock/npcx_clock.h>
|
||||
#include <zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h>
|
||||
#include <zephyr/dt-bindings/gpio/gpio.h>
|
||||
#include <zephyr/dt-bindings/i2c/i2c.h>
|
||||
#include <zephyr/dt-bindings/pinctrl/npcx-pinctrl.h>
|
||||
|
@ -510,9 +511,9 @@
|
|||
};
|
||||
};
|
||||
|
||||
/* Dedicated SPI interface to access SPI flashes */
|
||||
spi_fiu0: spi@40020000 {
|
||||
compatible = "nuvoton,npcx-spi-fiu";
|
||||
/* Dedicated Quad-SPI interface to access SPI flashes */
|
||||
qspi_fiu0: quadspi@40020000 {
|
||||
compatible = "nuvoton,npcx-fiu-qspi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x40020000 0x2000>;
|
||||
|
|
|
@ -32,14 +32,19 @@
|
|||
};
|
||||
};
|
||||
|
||||
&spi_fiu0 {
|
||||
&qspi_fiu0 {
|
||||
status = "okay";
|
||||
|
||||
int_flash: w25q80@0 {
|
||||
compatible ="jedec,spi-nor";
|
||||
/* 8388608 bits = 1 Mbytes */
|
||||
size = <0x800000>;
|
||||
compatible ="nuvoton,npcx-fiu-nor";
|
||||
size = <DT_SIZE_K(1024 * 8)>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
status = "okay";
|
||||
jedec-id = [ef 40 14];
|
||||
|
||||
/* quad spi bus configuration of nor flash device */
|
||||
qspi-flags = <NPCX_QSPI_SW_CS1>;
|
||||
mapped-addr = <0x64000000>;
|
||||
pinctrl-0 = <&int_flash_sl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -32,14 +32,19 @@
|
|||
};
|
||||
};
|
||||
|
||||
&spi_fiu0 {
|
||||
&qspi_fiu0 {
|
||||
status = "okay";
|
||||
|
||||
int_flash: w25q40@0 {
|
||||
compatible ="jedec,spi-nor";
|
||||
/* 4194304 bits = 512K Bytes */
|
||||
size = <0x400000>;
|
||||
compatible ="nuvoton,npcx-fiu-nor";
|
||||
size = <DT_SIZE_K(512 * 8)>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
status = "okay";
|
||||
jedec-id = [ef 40 13];
|
||||
|
||||
/* quad spi bus configuration of nor flash device */
|
||||
qspi-flags = <NPCX_QSPI_SW_CS1>;
|
||||
mapped-addr = <0x64000000>;
|
||||
pinctrl-0 = <&int_flash_sl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -36,14 +36,19 @@
|
|||
};
|
||||
};
|
||||
|
||||
&spi_fiu0 {
|
||||
&qspi_fiu0 {
|
||||
status = "okay";
|
||||
|
||||
int_flash: w25q40@0 {
|
||||
compatible ="jedec,spi-nor";
|
||||
/* 4194304 bits = 512K Bytes */
|
||||
size = <0x400000>;
|
||||
compatible ="nuvoton,npcx-fiu-nor";
|
||||
size = <DT_SIZE_K(512 * 8)>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
status = "okay";
|
||||
jedec-id = [ef 40 13];
|
||||
|
||||
/* quad spi bus configuration of nor flash device */
|
||||
qspi-flags = <NPCX_QSPI_SW_CS1>;
|
||||
mapped-addr = <0x64000000>;
|
||||
pinctrl-0 = <&int_flash_sl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,14 +26,19 @@
|
|||
};
|
||||
};
|
||||
|
||||
&spi_fiu0 {
|
||||
&qspi_fiu0 {
|
||||
status = "okay";
|
||||
|
||||
int_flash: w25q40@0 {
|
||||
compatible ="jedec,spi-nor";
|
||||
/* 4194304 bits = 512K Bytes */
|
||||
size = <0x400000>;
|
||||
compatible ="nuvoton,npcx-fiu-nor";
|
||||
size = <DT_SIZE_K(512 * 8)>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
status = "okay";
|
||||
jedec-id = [ef 40 13];
|
||||
|
||||
/* quad spi bus configuration of nor flash device */
|
||||
qspi-flags = <NPCX_QSPI_SW_CS1>;
|
||||
mapped-addr = <0x64000000>;
|
||||
pinctrl-0 = <&int_flash_sl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,14 +26,19 @@
|
|||
};
|
||||
};
|
||||
|
||||
&spi_fiu0 {
|
||||
&qspi_fiu0 {
|
||||
status = "okay";
|
||||
|
||||
int_flash: w25q40@0 {
|
||||
compatible ="jedec,spi-nor";
|
||||
/* 4194304 bits = 512K Bytes */
|
||||
size = <0x400000>;
|
||||
compatible ="nuvoton,npcx-fiu-nor";
|
||||
size = <DT_SIZE_K(512 * 8)>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
status = "okay";
|
||||
jedec-id = [ef 40 13];
|
||||
|
||||
/* quad spi bus configuration of nor flash device */
|
||||
qspi-flags = <NPCX_QSPI_SW_CS1>;
|
||||
mapped-addr = <0x64000000>;
|
||||
pinctrl-0 = <&int_flash_sl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,14 +26,17 @@
|
|||
};
|
||||
};
|
||||
|
||||
&spi_fiu0 {
|
||||
&qspi_fiu0 {
|
||||
int_flash: w25q80@0 {
|
||||
compatible ="jedec,spi-nor";
|
||||
/* 8388608 bits = 1 Mbytes */
|
||||
size = <0x800000>;
|
||||
compatible ="nuvoton,npcx-fiu-nor";
|
||||
size = <DT_SIZE_K(1024 * 8)>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
status = "okay";
|
||||
jedec-id = [ef 40 14];
|
||||
|
||||
/* quad spi bus configuration of nor flash device */
|
||||
qspi-flags = <NPCX_QSPI_SW_CS1>;
|
||||
mapped-addr = <0x64000000>;
|
||||
pinctrl-0 = <&int_flash_sl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
};
|
||||
|
|
56
dts/bindings/flash_controller/nuvoton,npcx-fiu-nor.yaml
Normal file
56
dts/bindings/flash_controller/nuvoton,npcx-fiu-nor.yaml
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
The SPI NOR flash devices accessed by Nuvoton Flash Interface Unit (FIU).
|
||||
|
||||
Representation of a SPI NOR flash on a qspi bus looks like:
|
||||
|
||||
int_flash: w25q40@0 {
|
||||
compatible ="nuvoton,npcx-fiu-nor";
|
||||
size = <DT_SIZE_K(512 * 8)>;
|
||||
reg = <0>;
|
||||
|
||||
qspi-flags = <NPCX_QSPI_SW_CS1>;
|
||||
mapped-addr = <0x64000000>;
|
||||
pinctrl-0 = <&int_flash_sl>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
compatible: "nuvoton,npcx-fiu-nor"
|
||||
|
||||
include: [flash-controller.yaml, pinctrl-device.yaml, "jedec,spi-nor-common.yaml"]
|
||||
|
||||
on-bus: qspi
|
||||
|
||||
properties:
|
||||
mapped-addr:
|
||||
type: int
|
||||
required: true
|
||||
description: Mapped memory address of direct read access for spi nor flash.
|
||||
min-erase-size:
|
||||
type: int
|
||||
default: 0x10000
|
||||
description: Minimum erase size of spi nor flash.
|
||||
enum:
|
||||
- 0x1000 # 4KB (Sector Erase)
|
||||
- 0x10000 # 64KB (Block Erase)
|
||||
max-timeout:
|
||||
type: int
|
||||
default: 10000
|
||||
description: Typically, it equals to max timeout of chip erase in ms.
|
||||
qspi-flags:
|
||||
type: int
|
||||
required: true
|
||||
description: The definitions for configuring the Quad-SPI peripherals.
|
||||
rd-mode:
|
||||
type: string
|
||||
default: "NPCX_RD_MODE_FAST_DUAL"
|
||||
description: |
|
||||
Selects the SPI read access type of Direct Read Access. Usually, we choose
|
||||
Fast Read Dual I/O mode for better performance. If the nor spi flash does
|
||||
not support this mode, please set this property explicitly.
|
||||
enum:
|
||||
- "NPCX_RD_MODE_NORMAL" # Direct read access by command code 03h
|
||||
- "NPCX_RD_MODE_FAST" # Direct read access by command code 0bh
|
||||
- "NPCX_RD_MODE_FAST_DUAL" # Direct read access by command code bbh
|
40
dts/bindings/flash_controller/nuvoton,npcx-fiu-qspi.yaml
Normal file
40
dts/bindings/flash_controller/nuvoton,npcx-fiu-qspi.yaml
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
Properties defining the NPCX Quad-SPI peripheral of Flash Interface Unit (FIU).
|
||||
A npcx quad-spi dt node would typically looks like:
|
||||
|
||||
&qspi_fiu0 {
|
||||
status = "okay";
|
||||
|
||||
int_flash: w25q400@0 {
|
||||
status = "okay";
|
||||
reg = <0>;
|
||||
...
|
||||
};
|
||||
|
||||
ext_flash: w25q256@1 {
|
||||
status = "okay";
|
||||
reg = <1>;
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
`int_flash` and `ext_flash` are the devices accessed by this peripheral.
|
||||
|
||||
compatible: "nuvoton,npcx-fiu-qspi"
|
||||
|
||||
include: [base.yaml, pinctrl-device.yaml]
|
||||
|
||||
bus: qspi
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
clocks:
|
||||
required: true
|
||||
en-direct-access-2dev:
|
||||
type: boolean
|
||||
description: |
|
||||
Two external SPI devices are supported for Direct Read Access (DRA) on QSPI bus.
|
|
@ -1,14 +0,0 @@
|
|||
# Copyright (c) 2021 Nuvoton Technology Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Nuvoton, NPCX-SPI-FIU controller node
|
||||
|
||||
compatible: "nuvoton,npcx-spi-fiu"
|
||||
|
||||
include: [spi-controller.yaml]
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
clocks:
|
||||
required: true
|
75
include/zephyr/drivers/flash/npcx_flash_api_ex.h
Normal file
75
include/zephyr/drivers/flash/npcx_flash_api_ex.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ZEPHYR_INCLUDE_DRIVERS_NPCX_FLASH_API_EX_H__
|
||||
#define __ZEPHYR_INCLUDE_DRIVERS_NPCX_FLASH_API_EX_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <zephyr/drivers/flash.h>
|
||||
|
||||
enum flash_npcx_ex_ops {
|
||||
/*
|
||||
* NPCX User Mode Access (UMA) mode execution.
|
||||
*
|
||||
* Execute a SPI transaction via User Mode Access (UMA) mode. Users can
|
||||
* perform a customized SPI transaction to gread or write the device's
|
||||
* configuration such as status registers of nor flash, power on/off,
|
||||
* and so on.
|
||||
*/
|
||||
FLASH_NPCX_EX_OP_EXEC_UMA = FLASH_EX_OP_VENDOR_BASE,
|
||||
/*
|
||||
* NPCX Configure specific operation for Quad-SPI nor flash.
|
||||
*
|
||||
* It configures specific operation for Quad-SPI nor flash such as lock
|
||||
* or unlock UMA mode, set write protection pin of internal flash, and
|
||||
* so on.
|
||||
*/
|
||||
FLASH_NPCX_EX_OP_SET_QSPI_OPER,
|
||||
/*
|
||||
* NPCX Get specific operation for Quad-SPI nor flash.
|
||||
*
|
||||
* It returns current specific operation for Quad-SPI nor flash.
|
||||
*/
|
||||
FLASH_NPCX_EX_OP_GET_QSPI_OPER,
|
||||
};
|
||||
|
||||
/* Structures used by FLASH_NPCX_EX_OP_EXEC_UMA */
|
||||
struct npcx_ex_ops_uma_in {
|
||||
uint8_t opcode;
|
||||
uint8_t *tx_buf;
|
||||
size_t tx_count;
|
||||
uint32_t addr;
|
||||
size_t addr_count;
|
||||
size_t rx_count;
|
||||
};
|
||||
|
||||
struct npcx_ex_ops_uma_out {
|
||||
uint8_t *rx_buf;
|
||||
};
|
||||
|
||||
/* Structures used by FLASH_NPCX_EX_OP_SET_QSPI_OPER */
|
||||
struct npcx_ex_ops_qspi_oper_in {
|
||||
bool enable;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
/* Structures used by FLASH_NPCX_EX_OP_GET_QSPI_OPER */
|
||||
struct npcx_ex_ops_qspi_oper_out {
|
||||
uint32_t oper;
|
||||
};
|
||||
|
||||
/* Specific NPCX QSPI devices control bits */
|
||||
#define NPCX_EX_OP_LOCK_UMA BIT(0) /* Lock/Unlock UMA mode */
|
||||
#define NPCX_EX_OP_INT_FLASH_WP BIT(1) /* Issue write protection of internal flash */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ZEPHYR_INCLUDE_DRIVERS_NPCX_FLASH_API_EX_H__ */
|
25
include/zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h
Normal file
25
include/zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nuvoton Technology Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NPCK_FIU_QSPI_H_
|
||||
#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NPCK_FIU_QSPI_H_
|
||||
|
||||
#include <zephyr/dt-bindings/dt-util.h>
|
||||
|
||||
/* Software controlled Chip-Select number for UMA transactions */
|
||||
#define NPCX_QSPI_SW_CS0 BIT(0)
|
||||
#define NPCX_QSPI_SW_CS1 BIT(1)
|
||||
#define NPCX_QSPI_SW_CS2 BIT(2)
|
||||
#define NPCX_QSPI_SW_CS_MASK (NPCX_QSPI_SW_CS0 | NPCX_QSPI_SW_CS1 | NPCX_QSPI_SW_CS2)
|
||||
|
||||
/* Supported flash interfaces for UMA transactions */
|
||||
#define NPCX_QSPI_SEC_FLASH_SL BIT(4)
|
||||
|
||||
/* Supported read mode for Direct Read Access */
|
||||
#define NPCX_RD_MODE_NORMAL 0
|
||||
#define NPCX_RD_MODE_FAST 1
|
||||
#define NPCX_RD_MODE_FAST_DUAL 3
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NPCK_FIU_QSPI_H_ */
|
|
@ -1516,11 +1516,23 @@ struct fiu_reg {
|
|||
volatile uint8_t FIU_DMM_CYC;
|
||||
/* 0x033: FIU Extended Configuration */
|
||||
volatile uint8_t FIU_EXT_CFG;
|
||||
#if defined(CONFIG_SOC_SERIES_NPCX9)
|
||||
/* 0x034: UMA address byte 0-3 */
|
||||
volatile uint32_t UMA_AB0_3;
|
||||
/* 0x038-0x3C */
|
||||
volatile uint8_t reserved8[5];
|
||||
/* 0x03D: SPI Device */
|
||||
volatile uint8_t SPI1_DEV;
|
||||
/* 0x03E-0x3F */
|
||||
volatile uint8_t reserved9[2];
|
||||
#endif
|
||||
};
|
||||
|
||||
/* FIU register fields */
|
||||
#define NPCX_RESP_CFG_IAD_EN 0
|
||||
#define NPCX_RESP_CFG_DEV_SIZE_EX 2
|
||||
#define NPCX_RESP_CFG_QUAD_EN 3
|
||||
#define NPCX_SPI_FL_CFG_RD_MODE FIELD(6, 2)
|
||||
#define NPCX_UMA_CTS_A_SIZE 3
|
||||
#define NPCX_UMA_CTS_C_SIZE 4
|
||||
#define NPCX_UMA_CTS_RD_WR 5
|
||||
|
@ -1530,6 +1542,12 @@ struct fiu_reg {
|
|||
#define NPCX_UMA_ECTS_SW_CS1 1
|
||||
#define NPCX_UMA_ECTS_SEC_CS 2
|
||||
#define NPCX_UMA_ECTS_UMA_LOCK 3
|
||||
#define NPCX_SPI1_DEV_FOUR_BADDR_CS10 6
|
||||
#define NPCX_SPI1_DEV_FOUR_BADDR_CS11 7
|
||||
#define NPCX_SPI1_DEV_SPI1_LO_DEV_SIZE FIELD(0, 4)
|
||||
#define NPCX_FIU_EXT_CFG_SPI1_2DEV 7
|
||||
#define NPCX_FIU_EXT_CFG_SET_DMM_EN 2
|
||||
#define NPCX_FIU_EXT_CFG_SET_CMD_EN 1
|
||||
|
||||
/* UMA fields selections */
|
||||
#define UMA_FLD_ADDR BIT(NPCX_UMA_CTS_A_SIZE) /* 3-bytes ADR field */
|
||||
|
|
|
@ -162,7 +162,11 @@ NPCX_REG_OFFSET_CHECK(ps2_reg, PSISIG, 0x008);
|
|||
NPCX_REG_OFFSET_CHECK(ps2_reg, PSIEN, 0x00a);
|
||||
|
||||
/* FIU register structure check */
|
||||
#if defined(CONFIG_SOC_SERIES_NPCX9)
|
||||
NPCX_REG_SIZE_CHECK(fiu_reg, 0x040);
|
||||
#else
|
||||
NPCX_REG_SIZE_CHECK(fiu_reg, 0x034);
|
||||
#endif
|
||||
NPCX_REG_OFFSET_CHECK(fiu_reg, BURST_CFG, 0x001);
|
||||
NPCX_REG_OFFSET_CHECK(fiu_reg, SPI_FL_CFG, 0x014);
|
||||
NPCX_REG_OFFSET_CHECK(fiu_reg, UMA_CTS, 0x01e);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue