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

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, p, &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--, i += eccbytes, 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%02x\n",

-             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%02x\n",

+             mtd , ecc_code[0], ecc_code[1], 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 implemented\n");

-       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...OK\n",

+                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

时间: 2024-11-01 12:03:34

u-boot移植3:支持 nandflash 的硬件 ECC的相关文章

u-boot-2016.03 在mini2440上移植之nandflash 硬件ecc

MINI2440 开发板使用的是8bit,256M blocksize= 128k,pagesize =2k的nandflash. 宽带为8bit ,由S3C2440 datasheet 可知硬件生产的ecc为4byte. S3C2440 硬件ecc 操作流程: 1.先读出NFMECC0寄存器中由硬件生产的ecc data. 2.将读出的ecc数据,进行处理之后,分别写入NFMECCD0和NFMECCD1寄存器, 硬件自动检测,检测结果可从NFESTAT0 寄存器读取. 3. 读取NFESTAT

STM32 下 FatFs的移植,实现了擦写均衡,坏块管理,硬件 ECC,ECC纠错

最近因项目需要,做一个数据采集的单片机平台.需要移植 FatFs .现在把最后成果贴上来. 在 STM32 单片机上,成功移植 FatFs 0.12b,使用的 Nand Flash 芯片为 K9F2G08 . 特点: 系统配合 FatFs 实现了擦写均衡,坏块管理,硬件ECC,软件 ECC 纠错 文件组成: FatFs 目录 +---- ffconf.h 对 FatFs 进行配置的文件 +---- ff.h +---- ff.c 是 FatFs 的实现文件,擦写均衡 在 f_getfree 函数

为一个支持GPRS的硬件设备搭建一台高并发服务器用什么开发比较容易?

高并发服务器开发,硬件socket发送数据至服务器,服务器对数据进行判断,需要实现心跳以保持长连接. 同时还要接收另外一台服务器的消支付成功消息,接收到消息后控制硬件执行操作. 查了一些资料,java的netty,go,或者是用C/C++不知道该用哪个,想问一下哪个比较适合,学习更容易一些. 为一个支持GPRS的硬件设备搭建一台高并发服务器用什么开发比较容易? >> golang 这个答案描述的挺清楚的:http://www.goodpm.net/postreply/golang/101000

Spring Boot 添加JSP支持【转】

Spring Boot 添加JSP支持 大体步骤: (1)            创建Maven web project: (2)            在pom.xml文件添加依赖: (3)            配置application.properties支持jsp (4)            编写测试Controller (5)          编写JSP页面 (6)          编写启动类App.Java 1,FreeMarker2,Groovy3,Thymeleaf (s

Spring Boot 之FilterRegistrationBean --支持web Filter 排序的使用(转)

Spring Boot 之FilterRegistrationBean  --支持web Filter 排序的使用Spring 提供了FilterRegistrationBean类,此类提供setOrder方法,可以为filter设置排序值,让spring在注册web filter之前排序后再依次注册. 写一个普通的filter: package com.sdcuike.practice.web2; import java.io.IOException; import javax.annotat

Nand Flash 控制器中的硬件 ECC 介绍

ECC 产生方法 ECC 是用于对存储器之间传送数据正确进行校验的一种算法,分硬件 ECC 和软件 ECC 算法两种,在 S3C2410 的 Nand Flash 控制器中实现了由硬件电路(ECC 生成器)实现的硬件 ECC. ECC 生成器工作过程 当写入数据到 Nand flash 存储空间时, ECC 生成器会在写入数据完毕后自动生成 ECC 码,将其放入到 ECC0-ECC2.当读出数据时 Nand Flash 同样会在读数据完毕后,自动生成 ECC 码将其放到 ECC0-ECC2 当

(笔记)CanOpen协议【CanFestival】移植方法 支持VC、QT、STM32

转自http://bbs.21ic.com/icview-878522-1-1.html 前段时间学习了CanOpen协议,到网上下载的CanFestival3-10源码,移植到VC.QT.STM32等平台,由于网上的资源较少,走了不少弯路,移植好使用过程中才逐渐暴露出各种问题,比如OD字符串传输.心跳时间不准确等等,现在已经解决了遇到的所有问题,移植出来的工程能够完好支持CanOpen协议,花了点时间,整理出一个简单易用的移植方法说明,也写了一些比较实用的调试工具,本来还想整理SDO.PDO.

Spring Mvc和Spring Boot配置Tomcat支持Https

SpringBoot配置支持https spring boot因为是使用内置的tomcat,所以只需要一些简单的配置即可. 1.首先打开命令行工具,比如cmd,输入以下命令 keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650 2.然后在你的根目录下面会看到一个.p12的文件,如下图所示: 3.将它移到你的spring boot

全球首款支持华为鲲鹏硬件架构,GaussDB T数据库云服务上线华为云

近日,全球首款支持鲲鹏硬件架构的企业级 OLTP 数据库 GaussDB T 的云服务,正式上线华为云.意味着 GaussDB T 除了为企业提供本地部署外,同时具备了在云上为更多企业提供高效.稳定.易用和高价值的 OLTP 数据库服务能力. 华为 GaussDB T 基于创新性数据库内核,提供高性能事务实时处理能力.金融级高可用能力,可以用于金融.政府.运营商.大企业等行业场景,如金融互联网交易.政府或企业自动化办公(OA)等管理支撑系统业务. 华为 GaussDB T 数据库云服务具有如下特