SFC控制器
1.1 模块功能介绍
SFC 是spi master设备,用来控制spi flash。支持CPU模式和DMA模式传输。
支持CDT命令传输模式。
支持DMA descriptor chain数据传输模式。
支持硬件polling flash的状态。
支持Standard, Dual, Quad, Octal SPI等多种传输协议。
1.2 驱动源码位置
驱动源码所在位置:
module_drivers/drivers/mtd/devices/ingenic_sfc_v2/
├── fmw.h ├── ingenic_sfc_common.c ├── ingenic_sfc_common.h ├── ingenic_sfc_drv.c ├── ingenic_sfc_drv.h ├── ingenic_sfc_nand.c ├── ingenic_sfc_nor.c ├── ingenic_sfc_ops.c ├── Makefile ├── nand_device │ ├── ato_nand.c │ ├── dosilicon_nand.c │ ├── fm_nand.c │ ├── foresee_nand.c │ ├── gd_nand.c │ ├── issi_nand.c │ ├── Makefile │ ├── mxic_nand.c │ ├── nand_common.c │ ├── nand_common.h │ ├── toshiba_nand.c │ ├── winbond_nand.c │ ├── xcsp_nand.c │ ├── xtx_mid0b_nand.c │ ├── xtx_mid2c_nand.c │ ├── xtx_nand.c │ ├── yhy_nand.c │ └── zetta_nand.c ├── nor_device │ ├── Makefile │ ├── nor_device.c │ └── nor_device.h ├── sfc_flash.h ├── sfc.h ├── spinand_cmd.h ├── spinand.h ├── spinor_cmd.h └── spinor.h
1.3 设备树配置
设备树所在位置:
kernel内核(version <= 5.10)dts文件路径:
module_drivers/dts-stage/x1600/x1600.dtsi
kernel内核(version > 5.10)dts文件路径:
module_drivers/dts/x1600/x1600.dtsi
设备树描述:
sfc: sfc@0x13440000 {
compatible = "ingenic,x1600-sfc";
reg = <0x13440000 0x10000>;
interrupt-parent = <&core_intc>;
interrupts = <IRQ_SFC>;
};设备树默认配置
设备树默认编译会产生sfc设备
&sfc {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&sfc_pc>;
ingenic,sfc-init-frequency = <200000000>;
ingenic,sfc-max-frequency = <400000000>;
ingenic,use_ofpart_info = /bits/ 8 <0>;
ingenic,spiflash_param_offset = <0>;
norflash@0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
/* spi nor flash partition */
uboot@0 {
label = "uboot";
reg = <0x0000000 0x40000>;
/*read-only;*/
};
kernel@40000 {
label = "kernel";
reg = <0x40000 0x300000>;
};
rootfs@360000 {
label = "rootfs";
reg = <0x360000 0xca0000>;
};
};
};
nandflash@1 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
/* spi nand flash partition */
partition@0 {
label = "uboot";
reg = <0x0000000 0x100000>;
/*read-only;*/
};
partition@100000 {
label = "kernel";
reg = <0x100000 0x800000>;
};
partition@900000 {
label = "rootfs";
reg = <0x900000 0xf700000>;
};
};
};
};设备树自定义配置
用户可根据实际需求关闭该节点,或进行以下配置:
| 属性名称 | 说明 |
| ingenic,sfc-init-frequency | sfc控制器在初始化阶段设置的时钟频率,因为未经过时序参数的配置,所以频率较低 |
| ingenic,sfc-max-frequency | 配置sfc最大频率,需要经过4分频,实际线上时钟为(sfc-max-frequency / 4) MHz |
| ingenic,use_ofpart_info | 默认情况下,MTD分区由烧录工具传入,当配置该节点为1时,则使用设备树分区信息。 |
| ingenic,spiflash_param_offset | 当使用spi flash存放flash参数和分区信息时, 用于修改spi flash中存放参数的偏移地址。当值为0时,默认偏移为0x5800。 |
1.4 内核编译配置
内核配置INGENIC_SFC,配置说明如下:
Symbol: INGENIC_SFC [=y] Type : tristate Prompt: Ingenic series SFC driver Location: -> Ingenic device-drivers Configurations (1) -> [SFC] (SPI Nand/Nor Flash) Drivers Defined at module_drivers/drivers/mtd/devices/Kconfig:1 Depends on: MACH_XBURST [=y] || MACH_XBURST2 [=n]
内核默认编译配置
默认情况下,内核会配置SFC驱动,如下
Ingenic device-drivers Configurations ---> [SFC] (SPI Nand/Nor Flash) Drivers ---> NAND: <*> Ingenic series SFC driver Select Ingenic series SFC driver version (Use ingenic sfc driver version 2) ---> the SFC external memory (nor or nand) (Support ingenic sfc-nand) ---> [ ] ingenic SN and MAC read write support. NOR: <*> Ingenic series SFC driver Select Ingenic series SFC driver version (Use ingenic sfc driver version 2) ---> the SFC external memory (nor or nand) (Support ingenic sfc-nor) ---> [ ] Use SPI Nor Flash params built in kernel (NEW) --->
内核自定义编译配置
NAND:
预留空间功能,默认不启用。
NAND预留空间,用于存储SN号、MAC地址、License等信息的区域,可配置预留区域的大 小,默认单个区域大小为1MB。
Symbol: INGENIC_SFCNAND_FMW [=y] Type : bool Defined at module_drivers/drivers/mtd/devices/Kconfig:44 Prompt: ingenic SN and MAC read write support. Depends on: INGENIC_SFC [=y] && MTD_INGENIC_SFC_NANDFLASH [=y] Location: -> Ingenic device-drivers Configurations -> [SFC] (SPI Nand/Nor Flash) Drivers -> Ingenic series SFC driver (INGENIC_SFC [=y]) <*> Ingenic series SFC driver Select Ingenic series SFC driver version (Use ingenic sfc driver version 2) ---> the SFC external memory (nor or nand) (Support ingenic sfc-nand) ---> [*] ingenic SN and MAC read write support. 1. SN space size (MB) (NEW) (1) MAC space size (MB) (NEW) (1) LICENSE space size (MB) (NEW)
NOR:
启用内核中包含的NOR flash参数,该功能会优先使用内核中的nor flash参数。
(支持多选,但ID相同的flash只能选一个)
默认不启用该功能。
Symbol: INGENIC_BUILTIN_PARAMS [=y] Type : bool Defined at module_drivers/drivers/mtd/devices/Kconfig:70 Prompt: Use SPI Nor Flash params built in kernel Depends on: INGENIC_SFC [=y] && MTD_INGENIC_SFC_NORFLASH [=y] Location: -> Ingenic device-drivers Configurations -> [SFC] (SPI Nand/Nor Flash) Drivers -> Ingenic series SFC driver (INGENIC_SFC [=y]) --- Use SPI Nor Flash params built in kernel [ ] GD25Q127C 0xc84018 (NEW) [ ] GD25Q256C 0xc84019 (NEW) [ ] GD25S512MD 0xc84019 (NEW)
1.5 设备节点生成
驱动加载成功后生成以下节点:
/dev/mtd*
mtd字符设备节点
/dev/mtdblock*
块设备节点
1.6 应用程序使用说明
1.6.1 flash读写测试
执行脚本: StorageMedia-Test.sh
\#./StorageMedia-Test.sh ********************************************** * * Please input which module you want test . ********************************************** * Enter 1 : Read/Write test in the nand/nor . * Enter 2 : Read/Write test in the sdcard . * Enter 3 : Read/Write test in the ddr . * Enter 4 : Read/Write test between nand/nor and sdcard . * Enter 5 : Read/Write test between nand/nor and ddr . * Enter 6 : Read/Write test between ddr and sdcard .
输入1
You select 1, nand/nor <-> nand/nor *************************************************** * * Please choice which Size you want copy . *************************************************** * Enter 1 : auto random Size * Enter 2 : setting a fix Size
输入1或输入2
选择1:测试随机大小的数据(根据flash剩余空间,自己计算大小)
选择2:测试指定大小的数据(Kbyte)
flash读写测试开始,连续测试一段时间,如果无error异常退出则正常。
1.7 添加新的flash参数
1.7.1 添加NOR flash参数
一、通过cloner烧录工具添加spi nor flash参数(推荐)
1.打开cloner中的Config,在INFO菜单下,选择Board为
x1600_sfc_nor_lpddr2_linux.cfg
2.在SFC菜单下,选择二级菜单norinfo,选择ADD。
3.在弹出的对话框中按照spi nor flash的参数填上保存即可。
注: 烧录工具中id号为红色时,表示存在多个相同ID的flash参数,需要手动删除冲突的flash参数

二、在内核中添加NOR flash参数
如果需要添加自定义型号的flash,添加流程如下:
根据flash型号, 添加base params、cdt params、private params参数。参考如下:
module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.c
添加config配置,参考如下:
module_drivers/drivers/mtd/devices/Kconfig
1.7.2 添加NAND flash参数
一、添加NAND flash厂商支持
各厂商NAND flash参数配置文件位置
module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/
若存在该厂商的配置文件,则跳过此步骤;
若不存在,则需要参照其他厂商的参数配置文件,编写自己的配置文件。例如:
$ cp gd_nand.c myflash_nand.c && vi myflash_nand.c
flash参数配置文件主要构成(例如gd_nand.c)
/ 1. flash支持型号的个数 /
#define GD_DEVICES_NUM 7
/ 2. flash的基础参数 /
static struct ingenic_sfcnand_base_param gd_param[GD_DEVICES_NUM] = {
[0] = { ...},
}/ 3. flash的id和参数建立关联 /
static struct device_id_struct device_id[GD_DEVICES_NUM] = {
DEVICE_ID_STRUCT(0xD1, "GD5F1GQ4UB",&gd_param[0]),
...
}/ 4. flash获取默认的cdt参数,并根据id更新参数/**
static cdt_params_t *gd_get_cdt_params(struct sfc_flash *flash, uint8_t device_id){
...
}/ 5. 使用通用的get feature接口,需要定义处理ecc的接口 /
static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status){
...
}/ 6.注册flash参数 /
static int __init gd_nand_init(void) {
...
}二、添加nand flash型号支持
需要对照flash手册,完成以下步骤
添加flash基础参数.
[6] = {.pagesize = 2 * 1024, ... },建立flash与参数的关联
DEVICE_ID_STRUCT(0xA1, "GD5F1GQ4RF",&gd_param[6]),
根据id,更新默认参数
case 0xA1: gd_nand->cdt_params.standard_r.addr_nbyte = 3; gd_nand->cdt_params.quad_r.addr_nbyte = 3; break;
在处理ecc的接口中添加对应型号的处理
switch(device_id) {
case 0xA1:
...
}将支持flash总数+1
#define GD_DEVICES_NUM 7
三、对照flash手册比较默认参数,更新参数
默认command参数文件:
module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h
制作参数接口说明:
控制flash相关:
/CMD_INFO(_CMD, flash命令, dummy bits, 地址长度, 传输协议)/
读flash状态的参数
/ST_INFO(_ST, flash命令, status偏移bit, status状态位的mask, status状态位的期望值, 传输长度, dummy bits)/
例如:
| Command Name | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte N |
| Read From Cache x 4 | 6BH | dummy (2) | A15-A8 | A7-A0 | dummy (2) | (D7-D0)x4 |
/dummy 8bit, 地址长度3,传输协议对应sfc手册:TM_QI_QO_SPI/
CMD_INFO(cdt_params.quad_r, SPINAND_CMD_RDCH_X4, 8, 2, TM_QI_QO_SPI);
| Register | Addr | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Status | C0H | Reserved | ECCS2 | ECCS1 | ECCS0 | P_FAIL | E_FAIL | WEL | OIP |
/OIP偏移 bit是0, status状态位mask是0x1, 期望值0x0,传输长度1byte, get feature dummy 0bit/
ST_INFO(cdt_params.oip, SPINAND_CMD_GET_FEATURE, 0, 0x1, 0x0, 1, 0);
默认command参数如下
/*
* cdt params
*/
#define CDT_PARAMS_INIT(cdt_params) { \
/* read to cache */ \
CMD_INFO(cdt_params.r_to_cache, SPINAND_CMD_PARD, 0, 3, TM_STD_SPI); \
/* standard read from cache */ \
CMD_INFO(cdt_params.standard_r, SPINAND_CMD_FRCH, 8, 2, TM_STD_SPI); \
/* quad read from cache*/ \
CMD_INFO(cdt_params.quad_r, SPINAND_CMD_RDCH_X4, 8, 2, TM_QI_QO_SPI); \
/* standard write to cache*/ \
CMD_INFO(cdt_params.standard_w_cache, SPINAND_CMD_PRO_LOAD, 0, 2, TM_STD_SPI); \
/* quad write to cache*/ \
CMD_INFO(cdt_params.quad_w_cache, SPINAND_CMD_PRO_LOAD_X4, 0, 2, TM_QI_QO_SPI); \
/* write exec */ \
CMD_INFO(cdt_params.w_exec, SPINAND_CMD_PRO_EN, 0, 3, TM_STD_SPI); \
/* block erase */ \
CMD_INFO(cdt_params.b_erase, SPINAND_CMD_ERASE_128K, 0, 3, TM_STD_SPI); \
/* write enable */ \
CMD_INFO(cdt_params.w_en, SPINAND_CMD_WREN, 0, 0, TM_STD_SPI); \
/* get frature wait oip not busy */ \
ST_INFO(cdt_params.oip, SPINAND_CMD_GET_FEATURE, 0, 0x1, 0x0, 1, 0); \
}参数更新(例如gd_nand.c)
static cdt_params_t *gd_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) {
switch(device_id) {
...
case 0xA1:
gd_nand->cdt_params.standard_r.addr_nbyte = 3; /*地址长度更新为3byte*/
gd_nand->cdt_params.quad_r.addr_nbyte = 3;/*地址长度更新为3byte*/
break;
...
}四、配置get_feature接口
默认get_feature接口位置:
module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c
可以使用默认的get_feature接口,特殊情况下需要自定义ECC的处理接口
static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) {
switch(device_id) {
case 0xA1:
case 0xB1 ... 0xB4:
switch((ecc_status >> 4) & 0x7) {
case 0x7:
ret = -EBADMSG;
break;
case 0x6:
ret = 0x8;
break;
case 0x5:
ret = 0x7;
break;
default:
ret = 0;
}
...
break;
}
}自定义get_feature接口:
在flash参数的配置文件中定义自己的get_feature接口
将自己定义的接口注册到参数中
int32_t my_get_feature(struct sfc_flash *flash, uint8_t flag) {
...
}
static int __init gd_nand_init(void) {
...
/* use private get feature interface, please define it in this document */
//gd_nand->ops.get_feature = NULL;
gd_nand->ops.get_feature = my_get_feature();
...
}1.8 注意事项
1.Nand Flash ECC方案
使用nand flash自带的硬件ECC, 基于MTD框架,在内存中建立BBT。
2.已经支持过的参数位置
NAND: 目录module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/下。
NOR: 见烧录工具norinfo 界面。
3.Kernel可以使用u-boot内置参数,详细参考uboot文档。
需要依赖u-boot,kernel使用默认配置即可。
4.支持多Die的SPI NOR Flash
spl: 暂不支持多Die切换。
参数: 当flash参数使用烧录方式时,必须存放于Die0。
启动: 支持重启异常时reset flash切换Die0。