/** * @file sdrv_spi_nor.h * @brief SemiDrive SPI Norflash driver header file. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #ifndef SDRV_SPI_NOR_H_ #define SDRV_SPI_NOR_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #undef BIT #define BIT(nr) (1u << (nr)) #define SNOR_READID_DUMMY_LSB (24u) #define SNOR_OPCODE_PROTO_LSB (24u) #define SNOR_DTR_PROTO BIT(16) #define SNOR_INST_LANS_PROTO_LSB (8u) #define SNOR_INST_LANS_PROTO_MASK (0xFu) #define SNOR_INST_SINGLE_LANS (0u << SNOR_INST_LANS_PROTO_LSB) #define SNOR_INST_DUAL_LANS (1u << SNOR_INST_LANS_PROTO_LSB) #define SNOR_INST_QUAD_LANS (2u << SNOR_INST_LANS_PROTO_LSB) #define SNOR_INST_OCTAL_LANS (3u << SNOR_INST_LANS_PROTO_LSB) #define SNOR_INST_LANS(x) (((x) >> SNOR_INST_LANS_PROTO_LSB) & \ (SNOR_INST_LANS_PROTO_MASK)) #define SNOR_ADDR_LANS_PROTO_LSB (4u) #define SNOR_ADDR_LANS_PROTO_MASK (0xFu) #define SNOR_ADDR_SINGLE_LANS (0u << SNOR_ADDR_LANS_PROTO_LSB) #define SNOR_ADDR_DUAL_LANS (1u << SNOR_ADDR_LANS_PROTO_LSB) #define SNOR_ADDR_QUAD_LANS (2u << SNOR_ADDR_LANS_PROTO_LSB) #define SNOR_ADDR_OCTAL_LANS (3u << SNOR_ADDR_LANS_PROTO_LSB) #define SNOR_ADDR_LANS(x) (((x) >> SNOR_ADDR_LANS_PROTO_LSB) & \ (SNOR_ADDR_LANS_PROTO_MASK)) #define SNOR_DATA_LANS_PROTO_LSB (0u) #define SNOR_DATA_LANS_PROTO_MASK (0xFu) #define SNOR_DATA_SINGLE_LANS (0u << SNOR_DATA_LANS_PROTO_LSB) #define SNOR_DATA_DUAL_LANS (1u << SNOR_DATA_LANS_PROTO_LSB) #define SNOR_DATA_QUAD_LANS (2u << SNOR_DATA_LANS_PROTO_LSB) #define SNOR_DATA_OCTAL_LANS (3u << SNOR_DATA_LANS_PROTO_LSB) #define SNOR_DATA_LANS(x) (((x) >> SNOR_DATA_LANS_PROTO_LSB) & \ (SNOR_DATA_LANS_PROTO_MASK)) #define SNOR_PROTO_1_1_1 \ (SNOR_INST_SINGLE_LANS | SNOR_ADDR_SINGLE_LANS | SNOR_DATA_SINGLE_LANS) #define SNOR_PROTO_1_1_2 \ (SNOR_INST_SINGLE_LANS | SNOR_ADDR_SINGLE_LANS | SNOR_DATA_DUAL_LANS) #define SNOR_PROTO_1_1_4 \ (SNOR_INST_SINGLE_LANS | SNOR_ADDR_SINGLE_LANS | SNOR_DATA_QUAD_LANS) #define SNOR_PROTO_1_1_8 \ (SNOR_INST_SINGLE_LANS | SNOR_ADDR_SINGLE_LANS | SNOR_DATA_OCTAL_LANS) #define SNOR_PROTO_1_2_2 \ (SNOR_INST_SINGLE_LANS | SNOR_ADDR_DUAL_LANS | SNOR_DATA_DUAL_LANS) #define SNOR_PROTO_1_4_4 \ (SNOR_INST_SINGLE_LANS | SNOR_ADDR_QUAD_LANS | SNOR_DATA_QUAD_LANS) #define SNOR_PROTO_1_8_8 \ (SNOR_INST_SINGLE_LANS | SNOR_ADDR_OCTAL_LANS | SNOR_DATA_OCTAL_LANS) #define SNOR_PROTO_2_2_2 \ (SNOR_INST_DUAL_LANS | SNOR_ADDR_DUAL_LANS | SNOR_DATA_DUAL_LANS) #define SNOR_PROTO_4_4_4 \ (SNOR_INST_QUAD_LANS | SNOR_ADDR_QUAD_LANS | SNOR_DATA_QUAD_LANS) #define SNOR_PROTO_8_8_8 \ (SNOR_INST_OCTAL_LANS | SNOR_ADDR_OCTAL_LANS | SNOR_DATA_OCTAL_LANS) #define SNOR_PROTO_1_1_1_DTR (SNOR_PROTO_1_1_1 | SNOR_DTR_PROTO) #define SNOR_PROTO_1_2_2_DTR (SNOR_PROTO_1_2_2 | SNOR_DTR_PROTO) #define SNOR_PROTO_1_4_4_DTR (SNOR_PROTO_1_4_4 | SNOR_DTR_PROTO) #define SNOR_PROTO_4_4_4_DTR (SNOR_PROTO_4_4_4 | SNOR_DTR_PROTO) #define SNOR_PROTO_1_1_8_DTR (SNOR_PROTO_1_1_8 | SNOR_DTR_PROTO) #define SNOR_PROTO_1_8_8_DTR (SNOR_PROTO_1_8_8 | SNOR_DTR_PROTO) #define SNOR_PROTO_8_8_8_DTR (SNOR_PROTO_8_8_8 | SNOR_DTR_PROTO) #define SNOR_PROTO_DTR_MASK 0x1ffffu #define SNOR_PROTO_MASK 0xffffu #define SNOR_PROTO_DTR(x) ((x) & SNOR_PROTO_DTR_MASK) #define SNOR_PROTO(x) ((x) & SNOR_PROTO_MASK) #define SPI_NOR_MAX_ID_LEN 6 #define SECTOR_4K_POST (12) #define SECTOR_32K_POST (15) #define SECTOR_64K_POST (16) #define SECTOR_128K_POST (17) #define SECTOR_256K_POST (18) #define SECTOR_POST_TO_SIZE(n) (1U << (n)) #define SPINOR_SECTOR_4K_SIZE (0x1000) #define SPINOR_SECTOR_32K_SIZE (0x8000) #define SPINOR_SECTOR_64K_SIZE (0x10000) #define SPINOR_SECTOR_128K_SIZE (0x20000) #define SPINOR_SECTOR_256K_SIZE (0x40000) #define SWITCH_DEVICE_MAX_NUM (4u) typedef enum { SPI_NOR_SECTOR_4KB = 0, SPI_NOR_SECTOR_32KB, SPI_NOR_SECTOR_64KB, SPI_NOR_SECTOR_128KB, SPI_NOR_SECTOR_256KB, SPI_NOR_SECTOR_TYPE_MAX, } spi_nor_sector_type; #define SECTOR_TYPE_TO_POST(type) ((type) ? (14 + (type)) : 12) #define SECTOR_TYPE_TO_SIZE(type) SECTOR_POST_TO_SIZE(SECTOR_TYPE_TO_POST(type)) /** * @brief flash addr/size use uint64_t. */ typedef uint64_t flash_addr_t; typedef uint64_t flash_size_t; /** * @brief flash operating collection. */ enum flash_opt { FLASH_OPT_NONE, /**< flash none opt */ FLASH_OPT_READ, /**< flash read opt */ FLASH_OPT_WRITE, /**< flash write opt */ FLASH_OPT_ERASE, /**< flash erase opt */ FLASH_OPT_MAX, }; /** * @brief flash operating result collection. */ enum flash_opt_result { FLASH_OPT_COMPLETE = 0, /**< last transfer success flag */ FLASH_OPT_FAILED, /**< last tansfer failed flag */ FLASH_OPT_PENDING, /**< last tansfer not complete flag */ FLASH_OPT_INCONSISTENT, /**< last tansfer data error flag */ FLASH_OPT_INVALID, /**< last tansfer invalid flag */ FLASH_OPT_RESULET_MAX, }; /** * @brief flash transfer collection. */ struct flash_xfer_info { enum flash_opt opt_type; /**< flash r/w/e opt */ enum flash_opt_result opt_result; /**< flash opt result */ flash_addr_t addr; /**< flash address */ uint8_t *buf; /**< flash r/w to buf address */ flash_size_t size; /**< flash opt size */ }; /** * @brief event callback. */ typedef void (*flash_notification)(enum flash_opt type, enum flash_opt_result result); /** * @brief reserve. */ enum xspi_xfer_mode { XSPI_XFER_NONE = 0, XSPI_XFER_READ, XSPI_XFER_WRITE, }; /** * @brief reserve for osEvent interface. */ enum xspi_bus_event_mode { SPI_NOR_XFER_CLEAR, SPI_NOR_XFER_COMPLETE = 1, SPI_NOR_XFER_WAIT, }; /** * @brief xspi config collection */ struct xspi_config { uint8_t id; /**< xspi config id */ addr_t apb_base; /**< xspi config apb address */ addr_t direct_base; /**< xspi config direct transmission base address */ unsigned int irq; /**< xspi config irq number */ unsigned long ref_clk; /**< xspi config reference clk */ bool xip_mode; /**< device is xip mode */ }; /** * @brief xspi private information. */ struct xspi_pdata { uint8_t id; /**< xspi config id */ addr_t apb_base; /**< xspi config apb address */ addr_t direct_base; /**< xspi config direct transmission base address */ unsigned int irq; /**< xspi config irq number */ unsigned long ref_clk_hz; /**< xspi config reference clk */ unsigned int sclk; /**< reverse */ uint8_t dma_bus_width; /**< dma bus width */ uint32_t dma_burst_size; /**< dma burst length */ bool cs_decoded; /**< reverse */ uint8_t current_cs; /**< xspi using cs num */ bool dqs_en; /**< dqs enable for device&&host */ uint8_t fifo_depth; /**< xspi fifo depth */ uint8_t fifo_width; /**< xspi fifo width */ uint32_t direct_range_size; /**ops) { return ((flash_ops_t*)(nor->ops))->fls_wait_idle(nor); } return SDRV_STATUS_INVALID_PARAM; } /** * @brief spi norflash write enable op. * @param[in] nor spi norflash instance contex handle. * @param[in] enable spi norflash write enable or not . * @retval 0: success * @retval other: failed */ static inline int sdrv_spi_nor_write_enable(struct spi_nor *nor, bool enable) { if (nor && nor->ops) { return ((flash_ops_t*)(nor->ops))->fls_write_enable(nor, enable); } return SDRV_STATUS_INVALID_PARAM; } /** * @brief spi norflash host initialize function. * @details This function used for before any other spi nor APIs. * @param[in] host_config spi norflash host config data, will not used after function return, so this param can be in stack. * @return void* The host platform data. * @retval Null: failed * @retval other: success. */ //void *spi_nor_host_init(const struct spi_nor_host_config *host_config); /** * @brief spi norflash instance initialization interface. * @details This function must used after spi_nor_host_init and before other APIs. * @param[in, out] flash_handle spi norflash instance contex handle, the data memory need alloc by user. * @param[in] flash_config spi norflash device config data, will not used after function return, so this param can be in stack. * @return int * @retval 0: success * @retval other: failed */ static inline int sdrv_spi_nor_init(struct spi_nor *flash_handle, struct spi_nor_host *host, const struct spi_nor_config *flash_config) { int ret = -1; if (flash_config->hyperbus_mode) { #if !(CONFIG_DISABLE_HYPERBUS_COMPILE) ret = hyperbus_ops.fls_init(flash_handle, host, flash_config); #endif } else { #if !(CONFIG_DISABLE_SPIBUS_COMPILE) ret = spi_nor_ops.fls_init(flash_handle, host, flash_config); #endif } return ret; } /** * @brief spi norflash instance destruction interface. * @param[in] flash_handle spi norflash instance contex handle. */ static inline void sdrv_spi_nor_deinit(struct spi_nor *flash_handle) { ssdk_printf(SSDK_CRIT, "sdrv_spi_nor_deinit!\r\n"); // ssdk_printf(SSDK_INFO,"flash_handle: %d,flash_handle->ops: %d \r\n", flash_handle, flash_handle->ops); ssdk_printf(SSDK_CRIT, "flash_handle :0x%x,handle->ops: :0x%x,\r\n",flash_handle, flash_handle->ops); if (flash_handle && flash_handle->ops) { ((flash_ops_t*)(flash_handle->ops))->fls_deinit(flash_handle); } } /** * @brief spi norflash read interface. * @details When the buffer and read size aligned with cacheline size will provide best performance. * @param[in] flash_handle spi norflash instance contex handle. * @param[in] addr spi norflash addr. * @param[in] buf Read buffer, alloc by user. * @param[in] size Read size, need aligned with 4bytes for dma limit. * @return int * @retval 0: success * @retval other: failed */ static inline int sdrv_spi_nor_read(struct spi_nor *flash_handle, flash_addr_t addr, uint8_t *buf, flash_size_t size) { if (flash_handle && flash_handle->ops) { return ((flash_ops_t*)(flash_handle->ops))->fls_read(flash_handle, addr, buf, size); } return SDRV_STATUS_INVALID_PARAM; } /** * @brief spi norflash write interface. * @details When the buffer and write size aligned with cacheline size will provide best performance. * @param[in] flash_handle spi norflash instance contex handle. * @param[in] addr spi norflash addr. * @param[in] buf Write buffer, alloc by user. * @param[in] size Read size, need aligned with 4bytes for dma limit. * @return int * @retval 0: success * @retval other: failed */ static inline int sdrv_spi_nor_write(struct spi_nor *flash_handle, flash_addr_t addr, const uint8_t *buf, flash_size_t size) { if (flash_handle && flash_handle->ops) { return ((flash_ops_t*)(flash_handle->ops))->fls_write(flash_handle, addr, buf, size); } return SDRV_STATUS_INVALID_PARAM; } /** * @brief spi norflash erase interface. * @param[in] flash_handle spi norflash instance contex handle. * @param[in] addr spi norflash addr. * @param[in] size Erase size, need aligned with sector_size what get by sdrv_spi_nor_get_info API. * @return int * @retval 0: success * @retval other: failed */ static inline int sdrv_spi_nor_erase(struct spi_nor *flash_handle, flash_addr_t addr, flash_size_t size) { if (flash_handle && flash_handle->ops) { return ((flash_ops_t*)(flash_handle->ops))->fls_erase(flash_handle, addr, size); } return SDRV_STATUS_INVALID_PARAM; } /** * @brief spi norflash async cancel interface. * @details Used for cancel the last tansfer what like read write or erase. * @param[in] flash_handle spi norflash instance contex handle. * @return int * @retval 0: success * @retval other: failed */ static inline int sdrv_spi_nor_cancel(struct spi_nor *flash_handle) { if (flash_handle && flash_handle->ops) { return ((flash_ops_t*)(flash_handle->ops))->fls_cancel(flash_handle); } return SDRV_STATUS_INVALID_PARAM; } /** * @brief spi norflash async main function interface. * @details When use async mode, this function need be called cyclically. * @param[in] flash_handle spi norflash instance contex handle. */ static inline void sdrv_spi_nor_main_function(struct spi_nor *flash_handle) { if (flash_handle && flash_handle->ops) { ((flash_ops_t*)(flash_handle->ops))->fls_main_function(flash_handle); } } /** * @brief Used for setup spi norflash async mode notification handler. * @details When use async mode, user can selet passive notification mode or active query mode. * @param[in] flash_handle spi norflash instance contex handle. * @param[in] handler flash notification handler. */ static inline void sdrv_spi_nor_setup_handler(struct spi_nor *flash_handle, flash_notification handler) { flash_handle->event_handler = handler; return; } /** * @brief Used for get spi norflash async tansfer result. * @param[in] flash_handle spi norflash instance contex handle. * @return enum flash_opt_result * @retval FLASH_OPT_COMPLETE: last transfer success * @retval FLASH_OPT_FAILED: last tansfer failed * @retval FLASH_OPT_PENDING: last tansfer not complete * @retval FLASH_OPT_INCONSISTENT: last tansfer data error * @retval FLASH_OPT_INVALID: last tansfer invalid */ static inline enum flash_opt_result sdrv_spi_nor_get_result( struct spi_nor *flash_handle) { if (flash_handle) { return flash_handle->xfer_info.opt_result; } else { return FLASH_OPT_INVALID; } } /** * @brief Used for get spi norflash info what like sector size, page size, and ect. * @param[in] flash_handle spi norflash instance contex handle. * @return struct flash_info* Norflash info data. */ static inline struct flash_info *sdrv_spi_nor_get_info(struct spi_nor *flash_handle) { if (flash_handle) { return &(flash_handle->info); } else { return NULL; } } static inline int sdrv_spi_nor_enable_rfd(struct spi_nor *flash_handle, uint8_t mask) { int ret; if (flash_handle && flash_handle->host->ops->enable_rfd) { flash_handle->host->ops->prepare(flash_handle, SPI_NOR_OPS_LOCK); ret = flash_handle->host->ops->enable_rfd(flash_handle, mask); flash_handle->host->ops->unprepare(flash_handle, SPI_NOR_OPS_LOCK); if (ret) { return SDRV_STATUS_FAIL; } } else { return SDRV_STATUS_INVALID_PARAM; } return SDRV_STATUS_OK; } static inline const struct flash_info *sdrv_spi_nor_get_flash_table( bool is_hyperbus, uint32_t *num) { const struct flash_info *ret = NULL; if (!num) { return NULL; } if (is_hyperbus) { #if !(CONFIG_DISABLE_HYPERBUS_COMPILE) ret = hyperbus_ops.fls_get_flash_table(num); #endif } else { #if !(CONFIG_DISABLE_SPIBUS_COMPILE) ret = spi_nor_ops.fls_get_flash_table(num); #endif } return ret; } static inline struct spi_nor *sdrv_get_flash_handle(struct spi_nor_host *host, flash_addr_t addr, flash_size_t size) { struct spi_nor *nor; for (uint8_t i = 0; i < SWITCH_DEVICE_MAX_NUM ; i++) { nor = host->nor_tab[i]; if (!nor) { continue; } if ((addr >= nor->offset_address) && (addr + size) <= (nor->offset_address + nor->info.size)) { return nor; } } return NULL; } static inline int sdrv_host_read(struct spi_nor_host *host, flash_addr_t addr, uint8_t *buf, flash_size_t size) { struct spi_nor *flash_handle = sdrv_get_flash_handle(host, addr, size); if (flash_handle) { addr -= flash_handle->offset_address; return sdrv_spi_nor_read(flash_handle, addr, buf, size); } return SDRV_STATUS_FAIL; } static inline int sdrv_host_erase(struct spi_nor_host *host, flash_addr_t addr, flash_size_t size) { struct spi_nor *flash_handle = sdrv_get_flash_handle(host, addr, size); if (flash_handle) { addr -= flash_handle->offset_address; return sdrv_spi_nor_erase(flash_handle, addr, size); } return SDRV_STATUS_FAIL; } static inline int sdrv_host_write(struct spi_nor_host *host, flash_addr_t addr, const uint8_t *buf, flash_size_t size) { struct spi_nor *flash_handle = sdrv_get_flash_handle(host, addr, size); if (flash_handle) { addr -= flash_handle->offset_address; return sdrv_spi_nor_write(flash_handle, addr, buf, size); } return SDRV_STATUS_FAIL; } #ifdef __cplusplus } #endif #endif /* SDRV_SPI_NOR_H_ */