/** * @file fls.c * * Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. * * Description: * * Revision History: * ----------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if CONFIG_XSPI_ENABLE_DMA #include "sdrv_dma.h" #endif #include "fls.h" extern sdrv_scr_t g_scr_ctrl; #define XSPI_SWITCH_DEVICE_MAX_NUM (2u) typedef struct { Fls_Controller_ID_t id; struct spi_nor_host spi_nor_host; struct xspi_pdata xspi; struct spi_nor flash[XSPI_SWITCH_DEVICE_MAX_NUM]; uint8_t flash_num; #if CONFIG_XSPI_ENABLE_DMA sdrv_dma_t g_dma_instance; sdrv_dma_channel_t g_channel; volatile uint8_t dma_xspi_done_flag; uint8_t dma_xspi_init_dmac_flag; #endif bool is_locksetp_mode; bool is_parallel_mode; bool is_xip_mode; uint8_t flag; } Fls_Context_t; #if defined(APB_XSPI2PORTA_BASE) && defined(APB_XSPI2PORTB_BASE) #define XSPI_RESOURE_NUM (2u) #else #define XSPI_RESOURE_NUM (1u) #endif #define XSPI_PORT_MAX_NUM (XSPI_RESOURE_NUM * 2) static Fls_Context_t fls_context[XSPI_PORT_MAX_NUM]; static sdrv_ckgen_node_t *clk_node_tab[FLS_CONTROLLER_ID_MAX] = { [FLS_XSPI1_PORTA] = CLK_NODE(g_ckgen_ip_xspi1a), [FLS_XSPI1_PORTB] = CLK_NODE(g_ckgen_ip_xspi1b), #if (XSPI_RESOURE_NUM >= 2) [FLS_XSPI2_PORTA] = CLK_NODE(g_ckgen_ip_xspi2a), [FLS_XSPI2_PORTB] = CLK_NODE(g_ckgen_ip_xspi2b), #endif }; static struct xspi_config host_config[FLS_CONTROLLER_ID_MAX] = { [FLS_XSPI1_PORTA] = { .id = FLS_XSPI1_PORTA, .irq = XSPI1_IRQ0_INTR_NUM, .apb_base = APB_XSPI1PORTA_BASE, .direct_base = XSPI1_XSPI1PORTA_BASE, }, [FLS_XSPI1_PORTB] = { .id = FLS_XSPI1_PORTB, .irq = XSPI1_IRQ1_INTR_NUM, .apb_base = APB_XSPI1PORTB_BASE, .direct_base = XSPI1_XSPI1PORTB_BASE, }, #if (XSPI_RESOURE_NUM >= 2) [FLS_XSPI2_PORTA] = { .id = FLS_XSPI2_PORTA, .irq = XSPI2_IRQ0_INTR_NUM, .apb_base = APB_XSPI2PORTA_BASE, .direct_base = XSPI2_XSPI2PORTA_BASE, }, [FLS_XSPI2_PORTB] = { .id = FLS_XSPI2_PORTB, .irq = XSPI2_IRQ1_INTR_NUM, .apb_base = APB_XSPI2PORTB_BASE, .direct_base = XSPI2_XSPI2PORTB_BASE, }, #endif }; #ifndef SCR_SF_XSPI1_SRC_CFG_LOCKSTEP_MODE_N #define SCR_SF_XSPI1_SRC_CFG_LOCKSTEP_MODE_N SCR_SF_XSPI1_LOCKSTEP_DISABLE #endif static void sdrv_xspi_lockstep_enable(bool flag, uint8_t id) { scr_signal_t signal; sdrv_rstgen_sig_t *xspi_porta, *xspi_portb; switch (id) { case FLS_XSPI1_PORTA: signal = (scr_signal_t)SCR_SF_XSPI1_SRC_CFG_LOCKSTEP_MODE_N; xspi_porta = &rstsig_xspi1a; xspi_portb = &rstsig_xspi1b; break; #if (XSPI_RESOURE_NUM >= 2) case FLS_XSPI2_PORTA: signal = (scr_signal_t)SCR_SF_XSPI2_SRC_CFG_LOCKSTEP_MODE_N; xspi_porta = &rstsig_xspi2a; xspi_portb = &rstsig_xspi2b; break; #endif default: ssdk_printf(SSDK_ERR, "xspi %d unsupport lockstep mode", id); return; } sdrv_rstgen_assert(xspi_portb); sdrv_rstgen_assert(xspi_porta); DSB; udelay(10); scr_set(&g_scr_ctrl, &signal, !flag); udelay(10); DSB; sdrv_rstgen_deassert(xspi_porta); sdrv_rstgen_deassert(xspi_portb); } static void sdrv_xspi_parallel_enable(bool flag, uint8_t id) { scr_signal_t signal; sdrv_rstgen_sig_t *xspi_porta, * xspi_portb; switch (id) { case FLS_XSPI1_PORTA: signal = (scr_signal_t)SCR_SF_XSPI1_SRC_CFG_PARALLEL_MODE; xspi_porta = &rstsig_xspi1a; xspi_portb = &rstsig_xspi1b; break; #if (XSPI_RESOURE_NUM >= 2) case FLS_XSPI2_PORTA: signal = (scr_signal_t)SCR_SF_XSPI2_SRC_CFG_PARALLEL_MODE; xspi_porta = &rstsig_xspi2a; xspi_portb = &rstsig_xspi2b; break; #endif default: ssdk_printf(SSDK_ERR, "xspi %d unsupport parallel mode", id); return; } sdrv_rstgen_assert(xspi_portb); sdrv_rstgen_assert(xspi_porta); DSB; udelay(10); scr_set(&g_scr_ctrl, &signal, flag); udelay(10); DSB; sdrv_rstgen_deassert(xspi_porta); sdrv_rstgen_deassert(xspi_portb); } #if CONFIG_XSPI_ENABLE_DMA static void sdrv_dma_transfer_every_mad_done(uint32_t status, uint32_t param, void *context) { Fls_Context_t *pCtx = context; ssdk_printf(SSDK_INFO, " xspi set dma transfer done\r\n"); if (status == SDRV_DMA_COMPLETED) { pCtx->dma_xspi_done_flag = 1; } } static void sdrv_xspi_dma_config(struct spi_nor *nor, flash_addr_t addr, uint8_t *buf, uint32_t len, bool is_read_flag, uint32_t burst_len) { uint32_t burst_width; struct xspi_pdata *xspi = nor->host->priv_data; sdrv_dma_channel_config_t xspi_dma_cfg; Fls_Context_t *pCtx = &fls_context[nor->id]; burst_width = SDRV_DMA_BUSWIDTH_4_BYTES; ssdk_printf(SSDK_INFO, "burst lens is %d\n", burst_len); if (pCtx->dma_xspi_init_dmac_flag == 0) { ssdk_printf(SSDK_INFO, "dma init controller\r\n"); /* 1.init dma controller (only one time) */ sdrv_dma_init_dmac(APB_DMA_SF0_BASE); /* 2.create dma instance */ sdrv_dma_create_instance(&pCtx->g_dma_instance, APB_DMA_SF0_BASE); pCtx->dma_xspi_init_dmac_flag = 1; } /* 3.get default config */ sdrv_dma_init_channel_config(&xspi_dma_cfg, &pCtx->g_dma_instance); /* 4.modify config param */ xspi_dma_cfg.channel_id = SDRV_DMA_CHANNEL_1; /* select channel */ xspi_dma_cfg.xfer_mode = SDRV_DMA_TRANSFER_MODE_SINGLE; /* single or continuous or linklist */ xspi_dma_cfg.buffer_mode = SDRV_DMA_SINGLE_BUFFER; /* buffer mode */ xspi_dma_cfg.loop_mode = SDRV_DMA_LOOP_MODE_2; /* mem2mem(MODE_0) mem2dev/dev2mem(MODE_1,MODE_2) */ xspi_dma_cfg.interrupt_type = SDRV_DMA_LAST_MAD_DONE; /* set interrupt type */ xspi_dma_cfg.trig_mode = SDRV_DMA_TRIGGER_BY_HARDWARE; /* by hardware trig */ if (is_read_flag) { ssdk_printf(SSDK_INFO, "dev2mem\r\n"); xspi_dma_cfg.xfer_type = SDRV_DMA_DIR_DEV2MEM; xspi_dma_cfg.src_addr = (addr_t)xspi->apb_base + XSPI_INDIRECT_RDATA; xspi_dma_cfg.dst_addr = (addr_t)buf; xspi_dma_cfg.src_inc = SDRV_DMA_ADDR_NO_INC; /* source address increase or not */ xspi_dma_cfg.dst_inc = SDRV_DMA_ADDR_INC; /* destination address increase or not */ xspi_dma_cfg.src_port_sel = SDRV_DMA_PORT_AHB32; /* periph -> SDRV_DMA_PORT_AHB32 */ } else { ssdk_printf(SSDK_INFO, "mem2dev\r\n"); xspi_dma_cfg.xfer_type = SDRV_DMA_DIR_MEM2DEV; xspi_dma_cfg.dst_addr = (addr_t)xspi->apb_base + XSPI_INDIRECT_WDATA; xspi_dma_cfg.src_addr = (addr_t)buf; xspi_dma_cfg.src_inc = SDRV_DMA_ADDR_INC; /* source address increase or not */ xspi_dma_cfg.dst_inc = SDRV_DMA_ADDR_NO_INC; /* destination address increase or not */ xspi_dma_cfg.dst_port_sel = SDRV_DMA_PORT_AHB32; /* periph -> SDRV_DMA_PORT_AHB32 */ } xspi_dma_cfg.xfer_bytes = len; xspi_dma_cfg.src_width = (sdrv_dma_bus_width_e)burst_width; xspi_dma_cfg.dst_width = (sdrv_dma_bus_width_e)burst_width; xspi_dma_cfg.src_burst_len = burst_len; xspi_dma_cfg.dst_burst_len = burst_len; /* 5.init channel config */ sdrv_dma_init_channel(&pCtx->g_channel, &xspi_dma_cfg); /* 6.set interrupt callback */ pCtx->g_channel.irq_callback = sdrv_dma_transfer_every_mad_done; pCtx->g_channel.irq_context = (void *)pCtx; /* 7.start channel transfer */ pCtx->dma_xspi_done_flag = 0; sdrv_dma_start_channel_xfer(&pCtx->g_channel); } static void sdrv_xspi_dma_stop(struct spi_nor *nor) { Fls_Context_t *pCtx = &fls_context[nor->id]; sdrv_dma_stop_channel_xfer(&pCtx->g_channel); return; } static void spi_nor_register_dma_handler(struct spi_nor *flash_handle) { flash_handle->dma_xfer_config = sdrv_xspi_dma_config; flash_handle->dma_stop = sdrv_xspi_dma_stop; return; } #endif struct spi_nor_host* sdrv_norflash_init(struct spi_nor_config *config, uint8_t num, bool xip_en) { bool locksetp_mode = false; bool parallel_mode = false; Fls_Context_t *pCtx = NULL; if (config->id >= XSPI_PORT_MAX_NUM) { ssdk_printf(SSDK_CRIT, "config id(%d) Cross the line(%d)!\r\n", config->id, XSPI_PORT_MAX_NUM); return NULL; } pCtx = &fls_context[config->id]; /* config dev spi nor dev single mode */ switch (config->dev_mode) { case SPI_NOR_DEV_LOCKSTEP_MODE: locksetp_mode = true; break; case SPI_NOR_DEV_PARALLEL_MODE: parallel_mode = true; break; default: break; } if (pCtx->flag) { // host has been initialized if ((locksetp_mode != pCtx->is_locksetp_mode) || (parallel_mode != pCtx->is_parallel_mode) || (xip_en != pCtx->is_xip_mode)) { ssdk_printf(SSDK_CRIT, "This controller(%d) has been initialized to (lockstep:%d parallel%d xip:%d) mode!\r\n", config->id, pCtx->is_locksetp_mode, pCtx->is_parallel_mode, pCtx->is_xip_mode); return NULL; } else if ((pCtx->flash_num + num) > XSPI_SWITCH_DEVICE_MAX_NUM) { ssdk_printf(SSDK_CRIT, "This controller(%d) unsupport %d devices be connected at the same time!\r\n", config->id, pCtx->flash_num + num); return NULL; } } else { sdrv_ckgen_node_t *clk = clk_node_tab[config->id]; struct xspi_config host_cfg; memcpy(&host_cfg, &host_config[config->id], sizeof(struct xspi_config)); if (!xip_en) { /* close locksetp/parallel mode */ sdrv_xspi_lockstep_enable(locksetp_mode, config->id); sdrv_xspi_parallel_enable(parallel_mode, config->id); } /* initializes xspi host */ host_cfg.ref_clk = sdrv_ckgen_get_rate(clk); host_cfg.xip_mode = xip_en; if (config->xfer_mode == SPI_NOR_XFER_POLLING_MODE) { host_cfg.irq = 0; } sdrv_xspi_host_init(&(pCtx->spi_nor_host), &(pCtx->xspi), &host_cfg); pCtx->spi_nor_host.clk = clk; sdrv_ckgen_set_rate(clk, config->baudrate); pCtx->is_locksetp_mode = locksetp_mode; pCtx->is_parallel_mode = parallel_mode; pCtx->is_xip_mode = xip_en; pCtx->flag = 1; pCtx->id = (Fls_Controller_ID_t)config->id; ssdk_printf(SSDK_CRIT, "xspi(%d) init (lockstep:%d parallel%d) sucessfully! clock rate is %u!\r\n", pCtx->id, pCtx->is_locksetp_mode, pCtx->is_parallel_mode, sdrv_ckgen_get_rate(clk)); } for (uint8_t i = 0; i < num; i++) { config->cs = pCtx->flash_num; /* initializes spi nor device */ if (sdrv_spi_nor_init(&(pCtx->flash[pCtx->flash_num]), &(pCtx->spi_nor_host), config)) { ssdk_printf(SSDK_CRIT, "spinor(id:%d cs:%d) init failed!\r\n", pCtx->id, pCtx->flash_num); return NULL; } #if CONFIG_XSPI_ENABLE_DMA spi_nor_register_dma_handler(&(pCtx->flash[pCtx->flash_num])); #endif ssdk_printf(SSDK_CRIT, "spinor(id:%d cs:%d) size = 0x%llx, sector_size = 0x%x \r\n", pCtx->id, pCtx->flash_num, pCtx->flash[pCtx->flash_num].info.size, pCtx->flash[pCtx->flash_num].info.sector_size); pCtx->flash_num++; } return &pCtx->spi_nor_host; } void sdrv_norflash_deinit(struct spi_nor_host* host) { uint32_t j; Fls_Context_t *pCtx = &fls_context[host->id]; if (!pCtx->flag) { return; } for (j = 0; j < pCtx->flash_num; j++) { struct spi_nor *flash = &pCtx->flash[j]; /* soft reset flash */ sdrv_spi_nor_deinit(flash); /* soft reset xspi host */ sdrv_spi_nor_drv_deinit(flash); } memset(pCtx, 0, sizeof(Fls_Context_t)); } void sdrv_norflash_deinit_all(void) { uint32_t i; for (i = 0; i < FLS_CONTROLLER_ID_MAX; i++) { sdrv_norflash_deinit(&(fls_context[i].spi_nor_host)); } return; } struct spi_nor* get_flashhandler_by_id(Fls_Controller_ID_t port_id, uint8_t cs_id) { if (port_id >= FLS_CONTROLLER_ID_MAX) { ssdk_printf(SSDK_CRIT, "xspi port id %s cross!\r\n", port_id); return NULL; } else if (!fls_context[port_id].flag) { ssdk_printf(SSDK_CRIT, "xspi host %d uninitialized id\r\n", port_id); return NULL; } else if (cs_id >= fls_context[port_id].flash_num) { ssdk_printf(SSDK_CRIT, "xspi host %d cs %d uninitialized id\r\n", port_id, cs_id); return NULL; } return &(fls_context[port_id].flash[cs_id]); } int sdrv_norflash_enable_rfd(struct spi_nor_host* host, uint8_t mask) { if (!host || !host->nor_tab[0]) { return -1; } return sdrv_spi_nor_enable_rfd(host->nor_tab[0], mask); } int get_norflash_direct_base(struct spi_nor_host* host, addr_t *direct_base) { if (!host || !direct_base) { return -1; } *direct_base = ((struct xspi_pdata*)(host->priv_data))->direct_base; return 0; } int sdrv_norflash_swap_cs(struct spi_nor_host* host, bool is_reverse) { uint32_t reg; uint8_t cs_order = (is_reverse) ? 0x89 : 0x98; if (!host) { return -1; } reg = readl(((struct xspi_pdata*)(host->priv_data))->apb_base + 0x44); reg = (reg & (~0xffu)) | (cs_order); writel(reg, ((struct xspi_pdata*)(host->priv_data))->apb_base + 0x44); return 0; } int sdrv_norflash_get_flash_info(struct spi_nor_host* host, uint8_t cs_id, Fls_Flash_Info_t* info) { if (!host || !info) { return -1; } else if (!host->nor_tab[cs_id]) { return -2; } info->octal_dtr_en = host->nor_tab[cs_id]->octal_dtr_en; info->cinst_type = (host->nor_tab[cs_id]->info.read_proto >> 8) & 0xf; return 0; }