设计说明
12 Nov 2024
Read time: 12 minute(s)
源码说明
相关模块 | 源码路径 |
---|---|
PSRAM Driver | bsp/artinchip/drv_bare/psram |
HAL | bsp/artinchip/hal/xspi |
模块架构
ArtInChip 提供了 XSPI HAL 层,并且实现了对接 DRV_BARE 的驱动层。 由于 XSPI 传输需要使用 SYSCFG 和 CMU,因此 SYSCFG HAL 和 CMU HAL 是相关模块。
HAL 与 DRV
ArtInChip 的 PSRAM 驱动按照 HAL 层 + Driver 层的结构进行设计,其中 HAL 层为硬件抽象层, 提供系统无关的硬件驱动实现;在 HAL 层之上,可根据不同 RTOS 的驱动框架,实现对应的 PSRAM DRV 层进行对接。
XSPI HAL 的特点:
-
无状态
-
支持 XIP,AHB 模式
XSPI HAL 相关的设备操作都需要通过 Handle 的方式进行。 由于 HAL 其内部无状态,不会进行空间分配,因此 Handle 的空间需要外部申请并且传入, 由 HAL 层进行使用。
关键流程设计
在 bootloader 板级初始化过程中,会调用 aic_xspi_psram_init() 函数,对 XSPI
控制器、PSRAM 设备初始化, 并开启 XIP 模式,系统可以通过 PSRAM 映射地址进行内存访问
0x40000000-0x5FFFFFFF
。aic_xspi_psram_init(); // application\baremetal\bootloader\main.c
|-> hal_xspi_init(); // bsp\artinchip\drv_bare\psram\xspi_psram.c
|-> aic_xspi_psram_dev_init(); // bsp\artinchip\drv_bare\psram\xspi_psram.c
|-> hal_xspi_set_boudary(); // bsp\artinchip\drv_bare\psram\xspi_psram.c
|-> aic_xspi_psram_xip(); // bsp\artinchip\drv_bare\psram\xspi_psram.c
|-> hal_xspi_dll_training() // bsp\artinchip\drv_bare\psram\xspi_psram.c
|-> hal_xspi_set_parallel_mode(); // bsp\artinchip\drv_bare\psram\xspi_psram.c
数据结构设计
Driver 层主要数据接口
struct aic_xspi
{
char *name;
u32 idx;
u32 clk_id;
u32 clk_in_hz;
u32 dma_port_id;
u32 irq_num;
hal_xspi_handle handle;
bool inited;
};
提示:
name,idx,clk_id,clk_in_hz
属性需要有相应的值, 其中
clk_id
使用 aic_clk_id.h
文件的宏定义,
clk_in_hz
从配置文件中获取
HAL
层主要数据结构
struct hal_xspi_config {
u32 idx;
u32 clk_in_hz;
u32 clk_id;
u32 cs0_port;
u32 cs1_port;
bool bit_mode;
bool wire3_en;
bool lsb_en;
bool cs_auto;
u8 cs_polarity;
u8 cpol;
u8 cpha;
};
struct hal_xspi_transfer {
u8 *tx_data;
u8 *rx_data;
u32 data_len;
};
struct hal_xspi_proto_cfg {
u8 mode;
u8 clk_mode;
u8 parallel_mode;
u8 wr_cmd_clk_mode;
u8 wr_cmd_lines;
u8 wr_cmd_val;
u8 rd_cmd_clk_mode;
u8 rd_cmd_lines;
u8 rd_cmd_val;
u8 addr_clk_mode;
u8 addr_lines;
u8 addr_width;
u8 wr_dummy;
u8 rd_dummy;
u8 wr_cnt_lines;
u32 wr_cnt;
u8 rd_cnt_lines;
u32 rd_cnt;
};
struct hal_xspi_state {
u32 idx;
hal_xspi_async_cb cb;
void *cb_priv;
u32 status;
u32 clk_id;
u32 bus_hz;
u32 bus_width;
struct hal_xspi_dma_config dma_cfg;
void *dma_tx;
void *dma_rx;
u8 *async_tx; /* Used in Async Non-DMA mode */
u8 *async_rx; /* Used in Async Non-DMA mode */
u32 async_tx_remain; /* Used in Async Non-DMA mode */
u32 async_rx_remain; /* Used in Async Non-DMA mode */
u32 work_mode;
u32 done_mask;
};
接口设计
Driver 接口设计
函数原型 | static struct aic_xspi *aic_get_xspi_by_index(u32 idx) |
功能说明 | 获取具体 XSPI 控制设备 |
参数定义 |
u32 idx
XSPI 控制器编号,XSPI 当前只有 0 可选择。
|
返回值 |
NULL: 失败
aic_xspi 实例: 成功
|
注意事项 | - |
函数原型 | static u32 aic_xspi_psram_dev_reset(hal_xspi_handle *handle) |
功能说明 | reset PSRAM 模块,当前只支持 APS3208K |
参数定义 |
hal_xspi_handle *handle
XSPI 控制器句柄, 经过 hal_xspi_init 初始化后可得到。
|
返回值 |
0: 操作完成
|
注意事项 | - |
函数原型 | static u32 aic_xspi_psram_dev_init(hal_xspi_handle *handle) |
功能说明 | 初始化 PSRAM 设备 |
参数定义 |
hal_xspi_handle *handle
XSPI 控制器句柄, 经过 hal_xspi_init 初始化后可得到。
|
返回值 |
0: 操作完成
|
注意事项 | - |
函数原型 | static u32 aic_xspi_psram_read_id(hal_xspi_handle *handle) |
功能说明 | 读取 PSRAM 的 ID |
参数定义 |
hal_xspi_handle *handle
XSPI 控制器句柄, 经过 hal_xspi_init 初始化后可得到。
|
返回值 |
0: 操作完成
|
注意事项 | 该接口只是读取一遍,没有实际作用,仅作为调试使用 |
函数原型 | static u32 aic_xspi_psram_xip(hal_xspi_handle *handle, hal_xspi_proto_cfg_t proto) |
功能说明 | 读取 PSRAM 的 ID |
参数定义 |
hal_xspi_handle *handle
XSPI 控制器句柄, 经过 hal_xspi_init 初始化后可得到。
hal_xspi_proto_cfg_t proto
关于 XIP 的相关配置
|
返回值 |
0: 操作完成
|
注意事项 | - |
函数原型 | u32 aic_xspi_psram_icp_calc(u32 clk_in_hz) |
功能说明 | 根据配置的 clock,获取 ICP 时钟等级 |
参数定义 |
u32 clk_in_hz
配置给 XSPI 的时钟值
|
返回值 |
0: AIC_XSPI_ICP_50_100M
1:AIC_XSPI_ICP_100_150M
2: AIC_XSPI_ICP_150_200M
|
注意事项 | 返回结果一般作为 aic_xspi_psram_training 接口的 reg_icp 参数。 |
函数原型 | static u8 aic_xspi_psram_mem_test(long address, u32 size) |
功能说明 | PSRAM 的 training 使用的 memtest |
参数定义 |
long address
training buffer 的起始地址
u32 size
training buffer 的空间大小
|
返回值 |
0: 成功完成
1:失败
|
注意事项 | 需要判断是否成功 |
函数原型 | u32 aic_xspi_psram_training(hal_xspi_handle *h, u8 sel, u8 reg_icp, void *psram_buf, u32 len) |
功能说明 | PSRAM 的 training |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 sel
XSPI 的 CS 选择,0, 1
u8 reg_icp
XSPI 的时钟范围选择,ICP__50_100M = 0x0, ICP_100_150M =
0x1,
ICP_150_200M = 0x2, ICP_200_266M = 0x3.
void *psram_buf
psram 的 training 地址,取 psram 的地址空间
u32 len
地址空间大小,建议 256KB 以上
|
返回值 |
0: 传输成功完成
1:传输失败
|
注意事项 | 需要判断是否 traning 成功 |
函数原型 | u32 aic_xspi_psram_init(void) |
功能说明 | 读取 PSRAM 的 ID |
参数定义 |
无
|
返回值 |
0: 操作完成
|
注意事项 | training 失败时,会打印 trainning failed, 并停止系统启动。 |
HAL 接口设计
函数原型 | int hal_xspi_init(hal_xspi_handle *h, struct hal_xspi_config *cfg) |
功能说明 | XSPI 控制器的初始化函数 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
struct hal_xspi_config *cfg
XSPI 控制器的初始化配置参数
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | 初始化时,Handle 的空间由使用者负责分配和释放 |
函数原型 | int hal_xspi_set_cmd_width(hal_xspi_handle *h, u8 ddr_sdr_mode, u8 lines) |
功能说明 | 设置 CMD 传输所使用的模式和总线位宽 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 ddr_sdr_mode
cmd 数据设置 ddr,sdr 模式
u8 lines
cmd 数据设置 1/2/4/8 线传输
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | - |
函数原型 | int hal_xspi_set_cmd(hal_xspi_handle *h, u8 ddr_sdr_mode, u8 cmd) |
功能说明 | 设置 CMD 的模式和 opcode |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 ddr_sdr_mode
cmd 数据设置 ddr,sdr 模式
u8 cmd
设置 CMD 的 opcode
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | - |
函数原型 | int hal_xspi_set_addr_width(hal_xspi_handle *h, u8 ddr_sdr_mode, u8 lines, u8 bw_3_4_bytes) |
功能说明 | 设置 addr 的模式,传输线数,地址宽度 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 ddr_sdr_mode
ADDR 数据设置 ddr,sdr 模式, 0x0 是 sdr, 0x01 是 ddr
u8 lines
ADDR 数据设置 1/2/4/8 线传输, 可取值 0, 1, 2, 3
u8 bw_3_4_bytes
ADDR 数据的宽度,可取值 3、4
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | - |
函数原型 | int hal_xspi_set_addr(hal_xspi_handle *h, u8 addr) |
功能说明 | 设置 addr 的 opcode |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 addr
addr 的 opcode
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | - |
函数原型 | int hal_xspi_set_dummy(hal_xspi_handle *h, u8 lines, u8 dummy) |
功能说明 | 配置 read dummy |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 lines
设置 1/2/4/8 线传输, 可取值 0, 1, 2, 3(可固定任意值)
u8 dummy
dummy 个数
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | line 可以设置任意值,dummy 不受传输线限制 |
函数原型 | int hal_xspi_set_write_cnt(hal_xspi_handle *h, u8 ddr_sdr_mode, u8 lines, u32 count) |
功能说明 | 配置写 data 的个数 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 ddr_sdr_mode
写数据设置 ddr,sdr 模式, 0x0 是 sdr, 0x01 是 ddr
u8 lines
设置 1/2/4/8 线传输, 可取值 0, 1, 2, 3
u32 count
设置写入 data 的个数,bytes 为单位
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | u8 lines 需要根据实际配置,传入的 lines 和 count 硬件会控制输出的 cycle |
函数原型 | int hal_xspi_set_read_cnt(hal_xspi_handle *h, u8 ddr_sdr_mode, u8 lines, u32 count) |
功能说明 | 配置读 data 的个数 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 ddr_sdr_mode
读数据设置 ddr,sdr 模式, 0x0 是 sdr, 0x01 是 ddr
u8 lines
设置 1/2/4/8 线传输, 可取值 0, 1, 2, 3
u32 count
设置读入 data 的个数,bytes 为单位
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | u8 lines 需要根据实际配置,传入的 lines 和 count 硬件会控制输出的 cycle |
函数原型 | int hal_xspi_start_transfer(hal_xspi_handle *h) |
功能说明 | 开始传输使能 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
|
返回值 |
0: 成功
其他: 失败
|
注意事项 | - |
函数原型 | int hal_xspi_transfer_cpu_sync(hal_xspi_handle *h, struct hal_xspi_transfer *t) |
功能说明 | 数据传输配置,写入 fifo。 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
struct hal_xspi_transfer *t
数据结构体
|
返回值 |
0: 传输成功完成
|
注意事项 | - |
函数原型 | int hal_xspi_xip_cfg(hal_xspi_handle *h, hal_xspi_proto_cfg_t xip_proto_cfg) |
功能说明 | XSPI 的 XIP 配置,根据实际的 psram 设备协议写入 XIP 指令 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
hal_xspi_proto_cfg_t xip_proto_cfg
psram 设备协议 XIP 指令
|
返回值 |
0: 设置完成
|
注意事项 | - |
函数原型 | int hal_xspi_xip_enable( hal_xspi_handle *h) |
功能说明 | XSPI 的 XIP 使能 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
|
返回值 |
0: 设置完成
|
注意事项 | 在 hal_xspi_xip_cfg()后调用 |
函数原型 | int hal_xspi_set_cs(hal_xspi_handle *h, u8 sel) |
功能说明 | 数据传输配置,写入 fifo。 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 sel
XSPI 的 CS 选择,0, 1
|
返回值 |
0: 设置完成
|
注意事项 | - |
函数原型 | int hal_xspi_set_boudary(hal_xspi_handle *h, u8 by) |
功能说明 | 数据切割,根据具体 psram 配置 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 by
数据长度切割,可选 xspi_2k = 0x0, xspi_1k = 0x1,
|
返回值 |
0: 设置完成
|
注意事项 | - |
函数原型 | int hal_xspi_set_parallel_mode(hal_xspi_handle *h, u8 mode) |
功能说明 | 使用双/单片 PSRAM 配置。 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 mode
单片或双片配置,可选 single_mode = 0x0, parellel_mode =
0x1
|
返回值 |
0: 设置完成
|
注意事项 | - |
函数原型 | int hal_xspi_set_dll_ctl(hal_xspi_handle *h, u8 sel, u8 reg_icp, u8 phase_sel) |
功能说明 | 时钟采样相位和时钟频率等级配置,需要传入与时钟频率等级和相位值,一般在 training 得到稳定相位时传入。 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 sel
XSPI 的 CS 选择,0, 1
u8 reg_icp
时钟频率等级,ICP_50_100M,ICP_100_150M,
ICP_150_200M。
u8 phase_sel
相位等级配置(0x00-0x0f)
|
返回值 |
0: 设置完成
|
注意事项 | - |
函数原型 | int hal_xspi_set_phase_sel(hal_xspi_handle *h, u8 sel, u8 phase_sel) |
功能说明 | 时钟采样相位配置,需要传入相位值,一般在 training 过程尝试不同相位时配置。 |
参数定义 |
hal_xspi_handle *h
XSPI 控制器 Handle
u8 sel
XSPI 的 CS 选择,0, 1
u8 phase_sel
相位等级配置(0x00-0x0f)
|
返回值 |
0: 设置完成
|
注意事项 | - |