新增4轮4转-补丁代码
This commit is contained in:
460
e3_176_ref-补丁/middleware/flash/fls.c
Normal file
460
e3_176_ref-补丁/middleware/flash/fls.c
Normal file
@@ -0,0 +1,460 @@
|
||||
/**
|
||||
* @file fls.c
|
||||
*
|
||||
* Copyright (c) 2022 Semidrive Semiconductor.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Revision History:
|
||||
* -----------------
|
||||
*/
|
||||
#include <armv7-r/barriers.h>
|
||||
#include <armv7-r/cache.h>
|
||||
#include <clock_cfg.h>
|
||||
#include <clock_ip.h>
|
||||
#include <debug.h>
|
||||
#include <irq.h>
|
||||
#include <irq_num.h>
|
||||
#include <param.h>
|
||||
#include <pinmux_cfg.h>
|
||||
#include <regs_base.h>
|
||||
#include <reset_cfg.h>
|
||||
#include <scr_hw.h>
|
||||
#include <sdrv_ckgen.h>
|
||||
#include <sdrv_rstgen.h>
|
||||
#include <sdrv_scr.h>
|
||||
#include <sdrv_spi_nor.h>
|
||||
#include <sdrv_xspi.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <types.h>
|
||||
#include <udelay/udelay.h>
|
||||
#include <reset_ip.h>
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user