| /* |
| * 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> |
| #if defined(CONFIG_FLASH_NPCX_FIU_USE_DMA) |
| #include <zephyr/drivers/dma.h> |
| #include <zephyr/drivers/dma/dma_npcx_gdma.h> |
| #endif |
| #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, CONFIG_FLASH_LOG_LEVEL); |
| |
| /* Driver convenience defines */ |
| #define HAL_INSTANCE(dev) \ |
| ((struct fiu_reg *)((const struct npcx_qspi_fiu_config *)(dev)->config)->base) |
| |
| #if defined(CONFIG_ESPI_TAF) |
| static const struct device *const espi_dev = DEVICE_DT_GET(DT_NODELABEL(espi0)); |
| #endif |
| |
| /* 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; |
| bool base_flash_inv; |
| }; |
| |
| #if defined(CONFIG_FLASH_NPCX_FIU_USE_DMA) |
| /* DMA data */ |
| struct gdma_data { |
| const struct device *dev; |
| uint32_t channel; |
| struct dma_config dma_cfg; |
| struct k_sem dma_sem; |
| }; |
| #endif /* CONFIG_FLASH_NPCX_FIU_USE_DMA */ |
| |
| /* 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; |
| #if defined(CONFIG_FLASH_NPCX_FIU_USE_DMA) |
| struct gdma_data dma; |
| #endif /* CONFIG_FLASH_NPCX_FIU_USE_DMA */ |
| }; |
| |
| /* 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 npcx_uma_start(const struct device *dev, uint8_t code) |
| { |
| struct fiu_reg *const inst = HAL_INSTANCE(dev); |
| |
| #if defined(CONFIG_FLASH_NPCX_FIU_UMA_EX) |
| code &= ~BIT(NPCX_UMA_CTS_DEV_NUM); |
| inst->UMA_CTS = (inst->UMA_CTS & BIT(NPCX_UMA_CTS_DEV_NUM)) | code; |
| #else |
| inst->UMA_CTS = code; |
| #endif |
| } |
| |
| 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; |
| npcx_uma_start(dev, 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 */ |
| npcx_uma_start(dev, 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 defined(CONFIG_FLASH_NPCX_FIU_UMA_EX) |
| if ((qspi_cfg->flags & NPCX_QSPI_SHD_FLASH_SL) != 0) { |
| inst->UMA_CTS |= BIT(NPCX_UMA_CTS_DEV_NUM); |
| inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_UMA_DEV_BKP); |
| } else if ((qspi_cfg->flags & NPCX_QSPI_PVT_FLASH_SL) != 0) { |
| inst->UMA_CTS &= ~BIT(NPCX_UMA_CTS_DEV_NUM); |
| inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_UMA_DEV_BKP); |
| } else if ((qspi_cfg->flags & NPCX_QSPI_BKP_FLASH_SL) != 0) { |
| inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_UMA_DEV_BKP); |
| } |
| #else |
| 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); |
| } |
| #endif /* CONFIG_FLASH_NPCX_FIU_UMA_EX */ |
| } |
| |
| static inline void qspi_npcx_config_dra_4byte_mode(const struct device *dev, |
| const struct npcx_qspi_cfg *qspi_cfg) |
| { |
| #if defined(CONFIG_FLASH_NPCX_FIU_SUPP_DRA_4B_ADDR) |
| struct fiu_reg *const inst = HAL_INSTANCE(dev); |
| |
| #if defined(CONFIG_FLASH_NPCX_FIU_DRA_V1) |
| 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)); |
| } |
| #elif defined(CONFIG_FLASH_NPCX_FIU_DRA_V2) |
| if (qspi_cfg->enter_4ba != 0) { |
| SET_FIELD(inst->SPI_DEV, NPCX_SPI_DEV_NADDRB, NPCX_DEV_NUM_ADDR_4BYTE); |
| } |
| #elif defined(CONFIG_FLASH_NPCX_FIU_DRA_EX) |
| if (qspi_cfg->enter_4ba != 0) { |
| if ((qspi_cfg->flags & NPCX_QSPI_SHD_FLASH_SL) != 0) { |
| inst->FIU_4B_EN |= BIT(NPCX_MSR_FIU_4B_EN_SHD_4B); |
| } else if ((qspi_cfg->flags & NPCX_QSPI_PVT_FLASH_SL) != 0) { |
| inst->FIU_4B_EN |= BIT(NPCX_MSR_FIU_4B_EN_PVT_4B); |
| } else if ((qspi_cfg->flags & NPCX_QSPI_BKP_FLASH_SL) != 0) { |
| inst->FIU_4B_EN |= BIT(NPCX_MSR_FIU_4B_EN_BKP_4B); |
| } |
| } |
| #endif |
| #endif /* CONFIG_FLASH_NPCX_FIU_SUPP_DRA_4B_ADDR */ |
| } |
| |
| 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); |
| |
| /* Select SPI device number for DRA mode in npcx4 series */ |
| if (IS_ENABLED(CONFIG_FLASH_NPCX_FIU_DRA_V2)) { |
| int spi_dev_num = (qspi_cfg->flags & NPCX_QSPI_SEC_FLASH_SL) != 0 ? 1 : 0; |
| |
| SET_FIELD(inst->BURST_CFG, NPCX_BURST_CFG_SPI_DEV_SEL, spi_dev_num); |
| } |
| |
| /* 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) */ |
| qspi_npcx_config_dra_4byte_mode(dev, qspi_cfg); |
| } |
| |
| 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; |
| } |
| |
| #if defined(CONFIG_FLASH_NPCX_FIU_USE_DMA) |
| static void dma_callback(const struct device *dev, void *arg, |
| uint32_t channel, int status) |
| { |
| struct npcx_qspi_fiu_data *const data = arg; |
| struct gdma_data *dma = &data->dma; |
| |
| if (status == DMA_STATUS_COMPLETE) { |
| k_sem_give(&dma->dma_sem); |
| } |
| } |
| |
| static int qspi_npcx_fiu_dma_transfer(const struct device *dev, uint8_t *src, uint8_t *dest, |
| size_t size) |
| { |
| struct npcx_qspi_fiu_data *const data = dev->data; |
| struct gdma_data *dma = &data->dma; |
| struct dma_config dma_cfg; |
| struct dma_status status; |
| |
| #if defined(CONFIG_NPCX_SOC_VARIANT_NPCKN) |
| struct fiu_reg *const inst = HAL_INSTANCE(dev); |
| |
| /* |
| * Check the address is 16 byte alignment when Read burst size is set to 16 bytes |
| */ |
| if (GET_FIELD(inst->BURST_CFG, NPCX_BURST_CFG_R_BURST) == NPCX_BURST_MODE_16_BYTE) { |
| if ((((uint32_t)src) & NPCX_DMA_ADDR_16B_ALIGN) != 0) { |
| LOG_ERR("Source address is not aligned to 16 Bytes"); |
| return -EINVAL; |
| } |
| } |
| #endif |
| |
| /* Configure user setting */ |
| dma_cfg = dma->dma_cfg; |
| |
| dma_cfg.head_block->block_size = size; |
| dma_cfg.head_block->source_address = (uint32_t)src; |
| dma_cfg.head_block->dest_address = (uint32_t)dest; |
| dma_cfg.user_data = (void *)data; |
| |
| if (dma_request_channel(dma->dev, (void *)&dma->channel) < 0) { |
| LOG_ERR("No available GDMA channel"); |
| return -EINVAL; |
| } |
| |
| if (dma_get_status(dma->dev, dma->channel, &status)) { |
| LOG_ERR("Get GDMA channel failed"); |
| return -EINVAL; |
| } |
| |
| if (status.busy) { |
| LOG_ERR("GDMA channel busy"); |
| return -EBUSY; |
| } |
| |
| if (dma_config(dma->dev, dma->channel, &dma_cfg)) { |
| LOG_ERR("GDMA configuration failed"); |
| return -EINVAL; |
| } |
| |
| if (dma_start(dma->dev, dma->channel)) { |
| LOG_ERR("GDMA transaction failed"); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static int qspi_npcx_fiu_dma_transfer_stop(const struct device *dev) |
| { |
| struct npcx_qspi_fiu_data *const data = dev->data; |
| struct gdma_data *dma = &data->dma; |
| |
| dma_stop(dma->dev, dma->channel); |
| |
| dma_release_channel(dma->dev, dma->channel); |
| |
| return 0; |
| } |
| |
| int qspi_npcx_fiu_dma_transceive(const struct device *dev, uint8_t *src, uint8_t *dest, size_t size) |
| { |
| struct npcx_qspi_fiu_data *const data = dev->data; |
| struct gdma_data *dma = &data->dma; |
| int ret; |
| |
| if (dma->dev == NULL) { |
| LOG_ERR("GDMA transaction not supported!"); |
| return -EINVAL; |
| } |
| |
| ret = qspi_npcx_fiu_dma_transfer(dev, src, dest, size); |
| |
| if (ret != 0) { |
| LOG_ERR("GDMA transaction failed"); |
| return ret; |
| } |
| |
| k_sem_take(&dma->dma_sem, K_FOREVER); |
| |
| qspi_npcx_fiu_dma_transfer_stop(dev); |
| |
| return ret; |
| } |
| #endif /* CONFIG_FLASH_NPCX_FIU_USE_DMA */ |
| |
| void qspi_npcx_fiu_mutex_lock(const struct device *dev) |
| { |
| struct npcx_qspi_fiu_data *const data = dev->data; |
| |
| k_sem_take(&data->lock_sem, K_FOREVER); |
| } |
| |
| 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); |
| } |
| |
| void qspi_npcx_fiu_apply_cfg(const struct device *dev, |
| const struct npcx_qspi_cfg *cfg, |
| const uint32_t operation) |
| { |
| struct npcx_qspi_fiu_data *data = dev->data; |
| |
| if (cfg == NULL) { |
| LOG_ERR("Invalid QSPI configuration"); |
| return; |
| } |
| |
| /* 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; |
| } |
| |
| /* Updates the cur_cfg pointer to the new QSPI configuration */ |
| data->cur_cfg = cfg; |
| } |
| |
| void qspi_npcx_fiu_mutex_lock_configure(const struct device *dev, |
| const struct npcx_qspi_cfg *cfg, |
| const uint32_t operation) |
| { |
| qspi_npcx_fiu_mutex_lock(dev); |
| qspi_npcx_fiu_apply_cfg(dev, cfg, operation); |
| } |
| |
| #if defined(CONFIG_FLASH_NPCX_FIU_DRA_V2) |
| void qspi_npcx_fiu_set_spi_size(const struct device *dev, const struct npcx_qspi_cfg *cfg) |
| { |
| struct fiu_reg *const inst = HAL_INSTANCE(dev); |
| uint8_t flags = cfg->flags; |
| |
| if (cfg->spi_dev_sz <= NPCX_SPI_DEV_SIZE_128M) { |
| if ((flags & NPCX_QSPI_SEC_FLASH_SL) == 0) { |
| SET_FIELD(inst->BURST_CFG, NPCX_BURST_CFG_SPI_DEV_SEL, NPCX_SPI_F_CS0); |
| } else { |
| SET_FIELD(inst->BURST_CFG, NPCX_BURST_CFG_SPI_DEV_SEL, NPCX_SPI_F_CS1); |
| } |
| inst->SPI_DEV_SIZE = BIT(cfg->spi_dev_sz); |
| } else { |
| LOG_ERR("Invalid setting of low device size"); |
| } |
| } |
| #endif |
| |
| int qspi_npcx_fiu_uma_block(const struct device *dev, bool lock_en) |
| { |
| #if defined(CONFIG_FLASH_NPCX_FIU_UMA_EX) |
| /* uma block for npck */ |
| struct fiu_reg *const inst = HAL_INSTANCE(dev); |
| |
| if (lock_en) { |
| inst->FIU_MSR_IE_CFG |= BIT(NPCX_MSR_IE_CFG_UMA_BLOCK); |
| } else { |
| inst->FIU_MSR_IE_CFG &= ~BIT(NPCX_MSR_IE_CFG_UMA_BLOCK); |
| } |
| #endif |
| |
| #if defined(CONFIG_ESPI_TAF) |
| if (espi_taf_npcx_block(espi_dev, lock_en) != 0) { |
| LOG_ERR("TAF block timeout, lock_en:%d", lock_en); |
| return -ETIMEDOUT; |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| static int qspi_npcx_fiu_init(const struct device *dev) |
| { |
| const struct npcx_qspi_fiu_config *const config = dev->config; |
| 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); |
| |
| #if defined(CONFIG_FLASH_NPCX_FIU_USE_DMA) |
| struct gdma_data *dma = &data->dma; |
| |
| if (!device_is_ready(dma->dev)) { |
| LOG_ERR("GDMA device not ready"); |
| return -EINVAL; |
| } |
| |
| k_sem_init(&dma->dma_sem, 0, 1); |
| #endif |
| |
| /* Enable direct access for 2 external SPI devices */ |
| if (config->en_direct_access_2dev) { |
| #if defined(CONFIG_FLASH_NPCX_FIU_SUPP_DRA_2_DEV) |
| struct fiu_reg *const inst = HAL_INSTANCE(dev); |
| |
| inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_SPI1_2DEV); |
| #if defined(CONFIG_FLASH_NPCX_FIU_SUPP_LOW_DEV_SWAP) |
| if (config->base_flash_inv) { |
| inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_LOW_DEV_NUM); |
| } |
| #endif |
| #endif |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_FLASH_NPCX_FIU_USE_DMA) |
| #define QSPI_DMA_BLOCK_CONFIG(inst, name) \ |
| .source_addr_adj = NPCX_GDMA_CONFIG_SRCADDR_ADJ(NPCX_GDMA_CHANNEL_CONFIG(inst, name)), \ |
| .dest_addr_adj = NPCX_GDMA_CONFIG_DSTADDR_ADJ(NPCX_GDMA_CHANNEL_CONFIG(inst, name)), |
| |
| #define QSPI_DMA_CHANNEL_INIT(inst, name) \ |
| .dma = { \ |
| .dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(inst, name)), \ |
| .channel = DT_INST_DMAS_CELL_BY_NAME(inst, name, channel), \ |
| .dma_cfg = \ |
| { \ |
| .channel_direction = NPCX_GDMA_CONFIG_DIRECTION( \ |
| NPCX_GDMA_CHANNEL_CONFIG(inst, name)), \ |
| .source_burst_length = NPCX_GDMA_CONFIG_BURST_LENGTH( \ |
| NPCX_GDMA_CHANNEL_CONFIG(inst, name)), \ |
| .dest_burst_length = NPCX_GDMA_CONFIG_BURST_LENGTH( \ |
| NPCX_GDMA_CHANNEL_CONFIG(inst, name)), \ |
| .head_block = &npcx_dma_config_##inst, \ |
| .dma_callback = dma_callback, \ |
| }, \ |
| } |
| |
| #define QSPI_DMA_CHANNEL(inst, name) \ |
| COND_CODE_1(DT_INST_DMAS_HAS_NAME(inst, name), (QSPI_DMA_CHANNEL_INIT(inst, name)), (EMPTY)) |
| |
| #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), \ |
| .base_flash_inv = DT_INST_PROP(n, flash_dev_inv), \ |
| }; \ |
| static struct dma_block_config npcx_dma_config_##n = {QSPI_DMA_BLOCK_CONFIG(n, fiu_dma)}; \ |
| static struct npcx_qspi_fiu_data npcx_qspi_fiu_data_##n = {QSPI_DMA_CHANNEL(n, fiu_dma)}; \ |
| 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); |
| #else |
| #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), \ |
| .base_flash_inv = DT_INST_PROP(n, flash_dev_inv), \ |
| }; \ |
| 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); |
| #endif |
| |
| DT_INST_FOREACH_STATUS_OKAY(NPCX_SPI_FIU_INIT) |