1,参数适配
struct SPI_NAND_READ_ECC_CHECK_T {
const u8 type;
const u8 ecc_threhsold_value[SPI_NAND_FLASH_THRESHOLD_VALUE_MAX];
const u8 ext_data[SPI_NAND_FLASH_EXT_DATA_MAX];
};
typedef enum{
SPI_NAND_FLASH_READ_DUMMY_BYTE_PREPEND,
SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND,
SPI_NAND_FLASH_READ_DUMMY_BYTE_DEF_NO
} SPI_NAND_FLASH_READ_DUMMY_BYTE_T;
typedef enum{
SPI_NAND_FLASH_READ_SPEED_MODE_SINGLE =0,
SPI_NAND_FLASH_READ_SPEED_MODE_DUAL,
SPI_NAND_FLASH_READ_SPEED_MODE_QUAD,
SPI_NAND_FLASH_READ_SPEED_MODE_DEF_NO
} SPI_NAND_FLASH_READ_SPEED_MODE_T;
typedef enum{
SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE =0,
SPI_NAND_FLASH_WRITE_SPEED_MODE_QUAD,
SPI_NAND_FLASH_WRITE_SPEED_MODE_DEF_NO
} SPI_NAND_FLASH_WRITE_SPEED_MODE_T;
struct spi_nand_flash_oobfree{
u32 offset;
u32 len;
};
struct spi_nand_flash_ooblayout
{
unsigned int oobsize;
struct spi_nand_flash_oobfree oobfree[SPI_NAND_FLASH_OOB_FREE_ENTRY_MAX];
};
struct SPI_NAND_ECC_FAIL_CHECK_INFO_T {
u8 ecc_check_mask;
u8 ecc_uncorrected_value;
};
struct SPI_NAND_QUAD_EN_INFO_T {
u8 quad_en_mask;
u8 quad_en_value;
};
struct SPI_NAND_ECC_EN_INFO_T {
u8 ecc_en_addr;
u8 ecc_en_mask;
u8 ecc_en_value;
};
struct SPI_NAND_EXTEND_ID_T {
const u8 extend_len;
const u8 extend_id[3];
};
struct SPI_NAND_READ_ECC_CHECK_T {
const u8 type;
const u8 ecc_threhsold_value[SPI_NAND_FLASH_THRESHOLD_VALUE_MAX];
const u8 ext_data[SPI_NAND_FLASH_EXT_DATA_MAX];
};
typedef enum{
SPI_NAND_FLASH_WRITE_LOAD_FIRST =0,
SPI_NAND_FLASH_WRITE_EN_FIRST,
} SPI_NAND_FLASH_WRITE_EN_TYPE_T;
struct SPI_NAND_FLASH_INFO_T {
#if defined(TCSUPPORT_BL2_OPTIMIZATION) && defined(IMAGE_BL2)
u8 mfr_id;
u8 dev_id;
const u8 *ptr_name;
#else
const u8 mfr_id;
const u8 dev_id;
const u8 *ptr_name;
#endif
u32 device_size; /* Flash total Size */
u32 page_size; /* Page Size */
u32 erase_size; /* Block Size */
u32 oob_size; /* Spare Area (OOB) Size */
SPI_NAND_FLASH_READ_DUMMY_BYTE_T dummy_mode;
SPI_NAND_FLASH_READ_SPEED_MODE_T read_mode;
struct spi_nand_flash_ooblayout *oob_free_layout;
u8 die_num;
SPI_NAND_FLASH_WRITE_SPEED_MODE_T write_mode;
u32 feature;
struct SPI_NAND_ECC_FAIL_CHECK_INFO_T ecc_fail_check_info;
SPI_NAND_FLASH_WRITE_EN_TYPE_T write_en_type;
struct SPI_NAND_UNLOCK_BLOCK_INFO_T unlock_block_info;
struct SPI_NAND_QUAD_EN_INFO_T quad_en;
struct SPI_NAND_ECC_EN_INFO_T ecc_en;
char otp_page_num;
#if defined(TCSUPPORT_PARALLEL_NAND)
u32 ext_id;
u32 timing_setting;
u8 min_ecc_req;
u8 addr_cycle;
#endif
struct SPI_NAND_EXTEND_ID_T extend_dev_id;
u8 soc_ecc_ability;
struct SPI_NAND_READ_ECC_CHECK_T read_ecc_ceck;
};
参数说明
mfr_id/dev_id/extend_dev_id
-
含义:制造商 ID、设备 ID 和扩展 ID,用于唯一识别 Flash 芯片。
-
获取方式 :发送
Read JEDEC ID (9Fh)命令,返回 1 字节制造商 ID、1 字节设备 ID,之后可能跟扩展 ID 字节。F35SQB512M 的 JEDEC ID 为0xCD 0x70 0x70(制造商0xCD,设备第一字节0x70,扩展字节0x70)。注意 B 款扩展 ID 长度为 2(0x70,0x70),A 款长度为 1。 -
代码使用 :
scan_spi_nand_table()中比较mfr_id和dev_id,然后调用check_extend_dev_id()逐字节比较扩展 ID,完全匹配才使用该表项。这解决了同 ID 不同型号的区分问题。
-
ptr_name -
device_size
-
含义 :Flash 总容量(字节)。F35SQB512M 为 512Mbit = 64MB =
0x04000000。 -
代码使用 :用于边界检查(
spi_nand_boundary_check)和 MTD 设备大小设置。
page_size
- 含义 :每页主数据区大小。F35SQB512M 为 2KB =
0x800。
注意 :芯片物理页包含主区 + 备用区,但驱动中page_size仅指主区。

oob_size
- 含义 :备用区(OOB)总大小。F35SQB512M 在 ECC 使能时,OOB 为 64 字节(其中一部分用于存储 ECC 校验码,剩余给用户)。
注意 :oob_size是物理 OOB 总大小,而不是用户可用大小(用户可用大小由oob_free_layout定义)。
erase_size
- 含义 :物理块大小 = 页数 × 页大小。F35SQB512M 每块 64 页,块大小 = 64 × 2KB = 128KB =
0x20000。

die_num
- 含义:芯片封装内 Die 数量。单片封装为 1。
-
dummy_modetypedef enum {
SPI_NAND_FLASH_READ_DUMMY_BYTE_PREPEND, // Dummy 放在地址之前
SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND, // Dummy 放在地址之后
} ... ;struct SPI_NAND_QUAD_EN_INFO_T {
u8 quad_en_mask; // 配置寄存器中 Quad 使能位掩码
u8 quad_en_value; // 写入的使能值(通常为掩码本身)
};
-
取值 :
SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND或PREPEND。 -
含义 :读命令中假周期(dummy bytes)的位置。大多数芯片在地址之后附加 dummy 字节,因此选择
APPEND。
代码使用 :在spi_nand_protocol_read_from_cache()中根据此值决定发送 dummy 字节的位置。
dummy mode,append mode和append mode的差异对比
read_mode/write_mode
- 含义 :默认读写速度模式(SINGLE/DUAL/QUAD)。为提高性能,通常读选用 DUAL 或 QUAD,写一般仅支持 SINGLE(部分芯片支持 QUAD 写入)。
代码使用 :在spi_nand_read_internal()和spi_nand_write_internal()中传递给底层协议函数。
标准、dual,quad spi 访问区别
-
oob_free_layoutstruct spi_nand_flash_oobfree {
u32 offset; // 在 OOB 中的起始偏移
u32 len; // 连续可用字节数
};struct spi_nand_flash_ooblayout {
unsigned int oobsize; // 总 OOB 大小(通常等于 oob_size)
struct spi_nand_flash_oobfree oobfree[SPI_NAND_FLASH_OOB_FREE_ENTRY_MAX];
};
-
含义 :描述 OOB 中用户可用的区域(偏移和长度)。驱动预定义了多种布局(
ooblayout_type1~type23)。 -
示例 :
ooblayout_type1=.oobsize = 24, .oobfree = {``{4,4}, {16,8}, {32,8}, {48,4}}表示物理 OOB 的字节偏移 4~7(4字节)、16~23(8字节)、32~39(8字节)、48~51(4字节)共 24 字节可供用户使用。其余字节(如偏移 0~3、8~15 等)被 ECC 校验码或坏块标记占用。
-

-
重要性:必须与芯片实际 OOB 分配匹配,否则上层文件系统(UBI)会读到错误数据。
-
ECC 关联 :当芯片内部 ECC 开启时,ECC 校验码会占用 OOB 的特定区域(通常每 512 字节扇区对应 13~16 字节 ECC 数据),
oob_free_layout必须避开这些区域。 -

外部ecc和内部ecc对比

使用举例:
oobsize = 20, oobfree = {{0,4}, {4,4}, {20,4}, {36,4}, {52,4}}
feature
-
类型:位掩码,定义芯片支持的高级功能。常见位:
-
SPI_NAND_FLASH_ERASE_STATISTICS:支持擦除统计(在 OOB 中记录擦除次数)。 -
SPI_NAND_FLASH_READ_ECC_ERROR_BIT_CHECK:支持读取时检测 ECC 超阈值(即位翻转过多但仍可纠正),触发 BMT 迁移。 -
SPI_NAND_FLASH_BLANK_PAGE_FIXUP:需要空白页 ECC 修复(某些 Winbond 芯片)。 -
SPI_NAND_FLASH_OOB_RESERVE_FOR_BMT:OOB 中预留区域给 BMT 存储映射信息。 -
其他:
SPI_NAND_FLASH_PLANE_SELECT_HAVE、SPI_NAND_FLASH_DIE_SELECT_1_HAVE等。
-
write_en_type
-
取值 :
SPI_NAND_FLASH_WRITE_EN_FIRST或SPI_NAND_FLASH_WRITE_LOAD_FIRST。 -
含义 :某些芯片要求先发写使能再发数据加载,有些顺序相反。绝大多数芯片采用
WRITE_EN_FIRST。
-
unlock_block_infostruct SPI_NAND_UNLOCK_BLOCK_INFO_T {
u8 unlock_block_mask; // 保护寄存器中的掩码
u8 unlock_block_value; // 要写入的值(0 表示全部解锁)
};
-
通过 Set Feature 写保护寄存器(地址
0xA0),清除块保护。 -
示例 :
{0x7C, 0x00}表示将保护寄存器的 bit2~bit6 清零(解除保护)。
代码使用 :spi_nand_manufacute_init()中调用spi_nand_protocol_set_feature(_SPI_NAND_ADDR_PROTECTION, feature)。
-
quad_enstruct SPI_NAND_QUAD_EN_INFO_T {
u8 quad_en_mask; // 配置寄存器中 Quad 使能位掩码
u8 quad_en_value; // 写入的使能值(通常为掩码本身)
};
- 如果芯片支持 Quad SPI,需设置 Feature 寄存器(地址
0xB0)的 QE 位。若芯片默认支持 Quad 或不需要使能,填{0x0, 0x0}。
-
ecc_enstruct SPI_NAND_ECC_EN_INFO_T {
u8 ecc_en_addr; // 特性寄存器地址(如 _SPI_NAND_ADDR_FEATURE = 0xB0)
u8 ecc_en_mask; // ECC 使能位掩码
u8 ecc_en_value; // 使能值(掩码与上具体位)
};
-
含义:配置芯片内部 ECC 的使能寄存器和位。
-
地址
ecc_en_addr:通常为_SPI_NAND_ADDR_FEATURE(0xB0)。 -
掩码
ecc_en_mask:一般为0x10(bit4)。 -
使能值
ecc_en_value:使能时该位应设为1,即0x10。
-
-
代码使用 :
SPI_NAND_Flash_Enable_OnDie_ECC()读取该寄存器,若当前值未使能,则设置并写回。 -
默认状态:大多数 SPI NAND 上电后 ECC 默认使能,但驱动仍会主动设置以确保状态。
-
ecc_fail_check_infostruct SPI_NAND_ECC_FAIL_CHECK_INFO_T {
u8 ecc_check_mask; // 状态寄存器中需要检查的位掩码
u8 ecc_uncorrected_value; // 掩码后该值表示不可纠正错误
};
-
含义 :从状态寄存器(地址
0xC0)中读取 ECC 状态时,使用ecc_check_mask提取相关位,并与ecc_uncorrected_value比较,若相等表示发生了不可纠正的 ECC 错误。 -
典型值 :
{0x30, 0x20}-
掩码
0x30(bit4-5)表示 ECC 状态位。 -
值
0x20(bit5=1, bit4=0)表示"不可纠正错误"。
-
-
数据手册验证:F35SQB512M 的状态寄存器 bit5-4 定义为 ECCS1-0:
-
00:无错误 -
01:1-bit 错误并纠正 -
1x:>1-bit 错误且不可纠正因此
0x20(二进制10 0000)对应 bit5=1, bit4=0,属于不可纠正类。
-
-
代码使用 :
ecc_fail_check()函数读取状态寄存器后,执行:status &= ecc_check_mask; if (status == ecc_uncorrected_value) return DETECTED_BAD_BLOCK;




-
read_ecc_ceckstruct SPI_NAND_READ_ECC_CHECK_T {
const u8 type; // 检测类型
const u8 ecc_threhsold_value[3]; // 阈值对应的 ECC 状态值
const u8 ext_data[3]; // 扩展数据(如第二个寄存器地址)
};
-
含义 :用于检测 ECC 错误超过阈值(即可纠正但位翻转过多,预示块可能即将损坏)。当检测到这种状态时,驱动会主动触发 BMT 迁移,将数据移到好块,避免未来数据丢失。
-
类型:
-
_SPI_NAND_CHECK_ECC_THROSHOLD_BY_FLASH:芯片内部有专门的阈值寄存器,通过 Set Feature 配置。 -
_SPI_NAND_CHECK_ECC_THROSHOLD_BY_REG:直接通过状态寄存器的某个值判断阈值(如0x10表示超过阈值)。 -
_SPI_NAND_CHECK_ECC_THROSHOLD_BY_2REG:需要读取两个寄存器组合判断。
-
-
示例(来自代码中 Winbond W25N02KV):
read_ecc_ceck: {_SPI_NAND_CHECK_ECC_THROSHOLD_BY_FLASH, {0x30, 0x0, 0x0}, {_SPI_NAND_ADDR_EXTEND_BFD, 0x60, 0x0}}表示通过 Flash 内部阈值检测,地址
0x10设置阈值,状态寄存器值0x30表示超过阈值。 -
代码使用 :在
ecc_fail_check()中,如果芯片支持SPI_NAND_FLASH_READ_ECC_ERROR_BIT_CHECK,则读取状态寄存器后,将状态值与ecc_threhsold_value[0]比较,若相等则返回ECC_EXCEEDED_THRESHOLD,进而触发update_bmt()。
soc_ecc_ability
-
含义:当使用 SoC 控制器 ECC(而非芯片内部 ECC)时,指示控制器需要提供的 ECC 纠错能力(如 4-bit, 8-bit, 12-bit)。若使用芯片内部 ECC,该字段设为 0。
-
代码使用 :在
SPI_NAND_Flash_Init()中,若isSpiNandAndCtrlECC为真,则根据soc_ecc_ability配置 NFI 的 ECC 引擎(encode_ecc_abiliry,decode_ecc_abiliry等)。
19. otp_page_num
- 含义 :OTP(One Time Programmable)页数量。F35SQB512M 提供 62 页 OTP,可用于存储一次性数据。若芯片不支持 OTP,填
-1。
2,新增一款nand flash
spi_nand_flash_tables里面新增自己的nand flash
struct spi_nand_flash_ooblayout ooblayout_type1 = {
.oobsize = 24,
.oobfree = {{4,4}, {16,8}, {32,8}, {48,4}, {0, 0}}
};
{
mfr_id: _SPI_NAND_MANUFACTURER_ID_FORESEE,
dev_id: _SPI_NAND_DEVICE_ID_F35SQA512M,
ptr_name: (const u8 *) "_SPI_NAND_DEVICE_ID_F35SQA512M",
device_size: _SPI_NAND_CHIP_SIZE_512MBIT,
page_size: _SPI_NAND_PAGE_SIZE_2KBYTE,
oob_size: _SPI_NAND_OOB_SIZE_64BYTE,
erase_size: _SPI_NAND_BLOCK_SIZE_128KBYTE,
dummy_mode: SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND,
read_mode: SPI_NAND_FLASH_READ_SPEED_MODE_DUAL,
write_mode: SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE,
oob_free_layout: &ooblayout_type1,
feature: SPI_NAND_FLASH_ERASE_STATISTICS,
die_num: 1,
ecc_fail_check_info: {0x30, 0x20},
write_en_type: SPI_NAND_FLASH_WRITE_EN_FIRST,
unlock_block_info: {0x7C, 0x0},
quad_en: {0x01, 0x01},
ecc_en: {_SPI_NAND_ADDR_FEATURE, 0x10, 0x10},
#ifdef TCSUPPORT_NAND_FLASH_OTP
otp_page_num: -1,
#endif
extend_dev_id: _SPI_NAND_DEVICE_ID_F35SQA512M_EXTEND,
},
| 成员 | 类型 | 说明 | 江波龙 F35SQA512M |
|---|---|---|---|
mfr_id |
u8 | 制造商 ID,从数据手册获取 | 0xCD (Foresee) |
dev_id |
u8 | 设备 ID | 0x70 |
ptr_name |
const u8* | 设备名称字符串 | "F35SQA512M" |
device_size |
u32 | 总容量(字节) | 0x04000000 (512 Mbit = 64 MB) |
page_size |
u32 | 页大小(字节) | 0x0800 (2048) |
oob_size |
u32 | OOB 大小(字节) | 0x40 (64) |
erase_size |
u32 | 块大小(字节) | 0x20000 (128 KB) |
dummy_mode |
enum | Dummy 字节插入位置 | SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND |
read_mode |
enum | 读操作 SPI 速度模式 | SPI_NAND_FLASH_READ_SPEED_MODE_DUAL |
write_mode |
enum | 写操作 SPI 速度模式 | SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE |
oob_free_layout |
struct* | OOB 空闲区域布局指针 | &ooblayout_type1 |
die_num |
u8 | 芯片内 Die 数量 | 1 |
feature |
u32 | 特性标志位(如擦除统计、OTP等) | SPI_NAND_FLASH_ERASE_STATISTICS |
ecc_fail_check_info |
struct | ECC 错误检测掩码和值 | {0x70, 0x70} |
write_en_type |
enum | 写使能顺序 | SPI_NAND_FLASH_WRITE_LOAD_FIRST |
unlock_block_info |
struct | 解锁所有块的寄存器配置 | {0x38, 0x0} |
quad_en |
struct | Quad 模式使能掩码和值 | {0x01, 0x01} |
ecc_en |
struct | ECC 使能寄存器地址、掩码、值 | {_SPI_NAND_ADDR_ECC, 0x10, 0x10} |
otp_page_num |
char | OTP 页数量,-1 表示不支持 | -1 |
extend_dev_id |
struct | 扩展设备 ID(长度和字节数组) | {1, {0x70,0,0}} |
soc_ecc_ability |
u8 | 控制器 ECC 能力(如 4/8/12 bits) | 未使用(0) |
read_ecc_ceck |
struct | ECC 阈值检测配置 | 未配置 |

