加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

u-boot移植3:支持 nandflash 的硬件 ECC

发布时间:2020-12-15 20:04:50 所属栏目:百科 来源:网络整理
导读:u-boot 版本:2016.03 用的交叉编译工具:arm-none-linux-gnueabi- 操作的文件:drivers/mtd/nand/s3c2440_nand.c 1. 程序分析: 要知道的几点 : 从s3c2440_nand.c 中知道,要想开启 硬件的ECC ,需要定义一个 CONFIG_S3C2440_NAND_HWECC 的宏,可以放在板
u-boot 版本:2016.03
用的交叉编译工具:arm-none-linux-gnueabi-

操作的文件:drivers/mtd/nand/s3c2440_nand.c

1. 程序分析:


要知道的几点
  • 从s3c2440_nand.c 中知道,要想开启 硬件的ECC ,需要定义一个 CONFIG_S3C2440_NAND_HWECC 的宏,可以放在板子的 .h 文件中 include/configs/lip2440.h?
  • 对板子的 nandflash 的硬件ECC 校验的函数实际的操作的文件是 drivers/mtd/nand/nand_base.c
  • nandflash 的每一页分为 main 区和 spare 区,并同时支持这两个区的硬件 ecc
  • nandFlash是以页为最小单位进行读写操作的

1.1 当定义了 CONFIG_S3C2440_NAND_HWECC 后,在s3c2440_nand.c 中就定义了3个函数:

  • 函数?s3c24x0_nand_enable_hwecc ,作用是 复位ecc,解锁main去ecc
  • 函数?s3c24x0_nand_calculate_ecc ,作用是 计算ecc
  • 函数?s3c24x0_nand_correct_data ,作用是 进行校准

1.2 在?board_nand_init 函数中关联上 nand_chip 结构体中相应的函数指针:

#ifdef CONFIG_S3C2440_NAND_HWECC
    nand->ecc.hwctl = s3c24x0_nand_enable_hwecc;
    nand->ecc.calculate = s3c24x0_nand_calculate_ecc;
    nand->ecc.correct = s3c24x0_nand_correct_data;
    nand->ecc.mode = NAND_ECC_HW;
    nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
    nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
    nand->ecc.strength = 1;
#else
    nand->ecc.mode = NAND_ECC_SOFT;
#endif

1.3 在?drivers/mtd/nand/nand_base.c?中的函数中进行使用:

比如? nand_read_page_hwecc 函数中的:

for (i = 0; eccsteps; eccsteps--,i += eccbytes,p += eccsize) {
        chip->ecc.hwctl(mtd,NAND_ECC_READ);
        chip->read_buf(mtd,p,eccsize);
        chip->ecc.calculate(mtd,&ecc_calc[i]);
    }

支持硬件ECC的读操作最终是由nand_read_page_hwecc函数(在drivers/mtd/nand目录下)来完成的,支持硬件ECC的写操作最终是由nand_write_page_hwecc函数(在drivers/mtd/nand目录下)来完成的。nand_read_page_hwecc函数的流程为先读取main区数据,同时通过调用s3c2440_nand_calculate_ecc函数来得到硬件ECC;再读取spare区数据;然后提取出储存在spare区内的main区ECC;最后通过调用s3c2440_nand_correct_data函数来对刚刚读取的main区数据进行校验。nand_write_page_hwecc函数的流程比较简单,它先写入main区数据,同时通过调用s3c2440_nand_calculate_ecc函数来得到硬件ECC;然后就是把硬件ECC写入到spare区内。
---引用自 赵春江的专栏 博客

在这些函数中关键的 for 循环中所用的参数是我们需要修改的:
for(i = 0; eccsteps; eccsteps--,p += eccsize) {
…… ?……?
}
for循环的作用是适应不同 cpu 的nandflash 控制器一次所能完成的硬件ECC的字节数不同
举例:
? ? ? ? 如果:
  • CPU一次能完成512字节的硬件ECC
  • 开发板上的NandFlash每页有2048个字节
需要分4次来计算ecc,还要注意的是每次ecc产生的结果字节数也有所不同,有的3字节,有的4字节。

eccsize= chip->ecc.size;
eccbytes= chip->ecc.bytes;?
eccsteps= chip->ecc.steps;
我们需要查看的是前两个参数,后边的一个参数是程序中自己计算的

我们的s3c2440:
nand->ecc.size = 2048;
nand->ecc.bytes = 4;

2. 程序修改:


2.1 修改配置文件:include/configs/lip2440.h?

? ??
---?a/include/configs/lip2440.h
+++?b/include/configs/lip2440.h
@@?-147,7?+147,7?@@
?#define?CONFIG_SYS_FLASH_BANKS_LIST?????{?CONFIG_SYS_FLASH_BASE?}
?#define?CONFIG_SYS_MAX_FLASH_SECT??????(35)

-#define?CONFIG_ENV_ADDR????????????????????????(CONFIG_SYS_FLASH_BASE?+?0x070000)
+#define?CONFIG_ENV_ADDR????????????????????????(CONFIG_SYS_FLASH_BASE?+?0x100000)
?#define?CONFIG_ENV_IS_IN_FLASH
?#define?CONFIG_ENV_SIZE????????????????????????0x10000
?/*?allow?to?overwrite?serial?and?ethaddr?*/
@@?-168,8?+168,11?@@
?#ifdef?CONFIG_CMD_NAND
?#define?CONFIG_NAND_S3C2440
?#define?CONFIG_SYS_S3C2440_NAND_HWECC
+#define?CONFIG_S3C2440_NAND_HWECC
?#define?CONFIG_SYS_MAX_NAND_DEVICE?????1
?#define?CONFIG_SYS_NAND_BASE???????????0x4E000000
+#define?CONFIG_SYS_NAND_ECCSIZE?2048
+#define?CONFIG_SYS_NAND_ECCBYTES?4
?#endif

2.2 更改 s3c2440 的寄存器的:arch/arm/include/asm/arch-s3c24x0/s3c24x0.h


@@?-145,16?+145,16?@@?struct?s3c24x0_nand?{
????????u32?????nfaddr;
????????u32?????nfdata;
?#ifndef?CONFIG_S3C2410
-???????u32?????nfeccd0;
-???????u32?????nfeccd1;
-???????u32?????nfeccd;
+???????u32?????nfmeccd0;
+???????u32?????nfmeccd1;
+???????u32?????nfseccd;
?#endif
????????u32?????nfstat;
?#ifdef?CONFIG_S3C2410
????????u32?????nfecc;
?#else
-???????u32?????nfstat0;
-???????u32?????nfstat1;
+???????u32?????nfestat0;
+???????u32?????nfestat1;
????????u32?????nfmecc0;
????????u32?????nfmecc1;
????????u32?????nfsecc;

2.3 修改关键的3函数:drivers/mtd/nand/s3c2440_nand.c


@@?-82,32?+82,75?@@?void?s3c24x0_nand_enable_hwecc(struct?mtd_info?*mtd,?int?mode)
?{
????????struct?s3c24x0_nand?*nand?=?s3c24x0_get_base_nand();
????????debug("s3c24x0_nand_enable_hwecc(%p,?%d)n",?mtd,?mode);
-???????writel(readl(&nand->nfconf)?|?S3C2440_NFCONF_INITECC,?&nand->nfconf);
+???????writel((readl(&nand->nfcont)?|?S3C2440_NFCONT_INITECC)?&?~S3C2440_NFCONT_MECCL,?&nand->nfcont);
?}

?static?int?s3c24x0_nand_calculate_ecc(struct?mtd_info?*mtd,?const?u_char?*dat,
??????????????????????????????????????u_char?*ecc_code)
?{
????????struct?s3c24x0_nand?*nand?=?s3c24x0_get_base_nand();
-???????ecc_code[0]?=?readb(&nand->nfecc);
-???????ecc_code[1]?=?readb(&nand->nfecc?+?1);
-???????ecc_code[2]?=?readb(&nand->nfecc?+?2);
-???????debug("s3c24x0_nand_calculate_hwecc(%p,):?0x%02x?0x%02x?0x%02xn",
-?????????????mtd?,?ecc_code[0],?ecc_code[1],?ecc_code[2]);
+????u_int32_t?mecc0;
+????writel(readl(&nand->nfcont)|?S3C2440_NFCONT_MECCL,&nand->nfcont);
+????mecc0?=?readl(&nand->nfmecc0);
+???????ecc_code[0]?=?mecc0?&?0xff;
+???????ecc_code[1]?=?(mecc0?>>?8)?&?0xff;
+???????ecc_code[2]?=?(mecc0?>>?16)?&?0xff;
+???????ecc_code[3]?=?(mecc0?>>?24)?&?0xff;
+???????debug("s3c24x0_nand_calculate_hwecc(%p,):?0x%02x?0x%02x?0x%02x?0x%02xn",
+?????????????mtd?,?ecc_code[2],?ecc_code[3]);

????????return?0;
?}

?static?int?s3c24x0_nand_correct_data(struct?mtd_info?*mtd,?u_char?*dat,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u_char?*read_ecc,?u_char?*calc_ecc)

?{
-???????if?(read_ecc[0]?==?calc_ecc[0]?&&
-???????????read_ecc[1]?==?calc_ecc[1]?&&
-???????????read_ecc[2]?==?calc_ecc[2])
-???????????????return?0;

-???????printf("s3c24x0_nand_correct_data:?not?implementedn");
-???????return?-1;
+????struct??s3c24x0_nand?*nand?=?s3c24x0_get_base_nand();
+????u_int32_t??meccdata0,?meccdata1,?estat0,?err_byte_addr;
+????int??ret?=?-1;
+????u_int8_t??repaired;
+
+????meccdata0=?(read_ecc[1]?<<?16)?|?read_ecc[0];
+????meccdata1=?(read_ecc[3]?<<?16)?|?read_ecc[2];
+
+????writel(meccdata0,&nand->nfmeccd0);
+????writel(meccdata1,&nand->nfmeccd1);
+
+????/*?Read?ecc?status?*/
+
+????estat0=?readl(&nand->nfestat0);??
+
+????switch(estat0?&?0x3)?{
+????case??0:?/*?No?error?*/
+????????ret=?0;
+????????break;
+????case??1:
+????????/*
+?????????*?1?bit?error?(Correctable)
+?????????*?(nfestat0?>>?7)?&?0x7ff????:error?byte?number
+?????????*?(nfestat0?>>?4)?&?0x7??????:error?bit?number
+?????????*/
+
+????????err_byte_addr=?(estat0?>>?7)?&?0x7ff;
+????????repaired=?dat[err_byte_addr]?^?(1?<<?((estat0?>>?4)?&?0x7));
+
+????????printf("S3C?NAND:?1?bit?error?detected?at?byte%d.?"
+????????????????"Correcting?from?0x%02x?to0x%02x...OKn",
+????????????????err_byte_addr,?dat[err_byte_addr],repaired);
+
+????????dat[err_byte_addr]=?repaired;
+????????ret=?1;
+????????break;
+????case??2:?/*?Multiple?error?*/
+????case??3:?/*?ECC?area?error?*/
+????????printf("S3C?NAND:?ECC?uncorrectable?errordetected.?"
+????????????????"Not?correctable.n");
+????????ret=?-1;
+????????break;
+????}
+
+????return???ret;
?}
?#endif

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读