18.9 硬件 ecc 适配
18.9.1 配置修改
根据前面的内容,修改配置:
查看代码,还需要配置几个选项,在 Kconfig 中没有添加,所以需要添加进去。
先看下 size、bytes 是做什么用的:
- CONFIG_SYS_NAND_ECCSIZE:定义了数据的长度,即每多少字节进行 1 次 ECC 校验
- CONFIG_SYS_NAND_ECCBYTES:生成的 ECC 的字节个数,对于 512 字节可以生成 3 个字节,2048 字节可以生成 4 个字节
确定一下 nandflash 的每一页的大小:
可以看到每一页是 2 x 1024 字节,那么CONFIG_SYS_NAND_ECCSIZE 设置成2048, CONFIG_SYS_NAND_ECCBYTES 设置成 4 个字节
先添加 drivers/mtd/nand/Kconfig 中的代码:
修改配置:
18.9.2 代码修改
硬件 ECC 主要由 nand 控制器进行控制,所以我们只需要操作寄存器即可。先修改一下硬件控制 ECC 的宏:
1 /** ecc 初始化, 一个是硬件 ECC 校验,一个是软件 ECC 校验 */ 2 #ifdef CONFIG_NAND_HW_ECC 3 nand->ecc.hwctl = s3c24x0_nand_enable_hwecc; 4 nand->ecc.calculate = s3c24x0_nand_calculate_ecc; 5 nand->ecc.correct = s3c24x0_nand_correct_data; 6 nand->ecc.mode = NAND_ECC_HW; 7 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; 8 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; 9 nand->ecc.strength = 1; 10 #else 11 nand->ecc.mode = NAND_ECC_SOFT; 12 #endif
接下来来看看芯片手册给我们提供的硬件 ECC 的操作步骤:
在步骤 1 中很明确的说明需要对 MainECCCLock 开锁,我们放在硬件初始化函数中进行:
之后就是计算 s3c24x0_nand_calculate_ecc :
对 ECC 进行校验:
1 /** 该函数首先把 read_ecc 数组内的 ECC 存入寄存器 NFMECCD0 和寄存器 NFMECCD1 中,这样系统就会自动校验数据, 2 * 并把状态放入寄存器 NFESTAT0 中,然后读取该寄存器的后 4 位,当为 0 时表示校验正确; 3 * 当为 1 时表示发生了 1 位错误(该类错误可以校正), 4 * 我们把它校正过来;当为 2 和 3 时表示发生其他类型的错误,这类错误是无法校正的。 5 */ 6 static int s3c24x0_nand_correct_data(struct mtd_info *mtd, u_char *dat, 7 u_char *read_ecc, u_char *calc_ecc) 8 { 9 #if CONFIG_S3C2440_NAND_HWECC 10 struct s3c24x0_nand *nand = s3c24x0_get_base_nand(); 11 12 uint meccdata0, meccdata1, estat0, err_byte_addr; 13 uchar repaired; 14 int ret = -1; 15 16 meccdata0 = (read_ecc[1] << 16) | read_ecc[0]; 17 meccdata1 = (read_ecc[3] << 16) | read_ecc[2]; 18 19 writel(meccdata0, &nand->nfeccd0); 20 writel(meccdata1, &nand->nfeccd1); 21 22 /** 读取 ecc 得状态 */ 23 estat0 = readl(&nand->nfstat0); 24 switch (estat0 & 0x3) 25 { 26 case 0: /*no error*/ 27 ret = 0; 28 break; 29 case 1: 30 /* 31 *1bit error(correctable) 32 *(nfestat0 >> 7) & 0x7ff error byte number 33 *(nfestat0 >> 4) & 0x7 error bit number 34 */ 35 err_byte_addr = (estat0 >>7 ) & 0x7ff; 36 repaired = dat[err_byte_addr] ^ (1 << ((estat0 >> 4) & 0x7)); 37 printf("S3C NAND: 1 bit error detected at byte %u. Correcting from 0x%02x to0x%02x...OK ", 38 err_byte_addr, dat[err_byte_addr], repaired); 39 dat[err_byte_addr] = repaired; 40 ret = 1; 41 break; 42 case 2: /* Multiple error */ 43 case 3: /* ECC area error */ 44 printf("S3C NAND: ECC uncorrectable errordetected. Not correctable. "); 45 ret= -1; 46 break; 47 } 48 49 return ret; 50 #else 51 if (read_ecc[0] == calc_ecc[0] && 52 read_ecc[1] == calc_ecc[1] && 53 read_ecc[2] == calc_ecc[2]) 54 return 0; 55 56 printf("s3c24x0_nand_correct_data: not implemented "); 57 return -EBADMSG; 58 #endif 59 }
18.9.3 编译测试
烧写进去后,读写都是 OK 的,但是在擦除的时候报了错,如下:
追踪代码发现是 BBT,即进行擦除的过程中,会进行坏块检查,会去读取每一页的数据,然后进行 ecc 校验,开 debug 进行测试,测试结果如下:
加入打印测试:
nandflash 中有坏块,所以这个问题是非问题。