主题 : 分析一下tiny210v2的16bitECC校验(已经实现u-boot for tiny210v2) 复制链接 | 浏览器收藏 | 打印
:)
级别: 骑士
UID: 61588
精华: 5
发帖: 248
金钱: 1500 两
威望: 300 点
贡献值: 5 点
综合积分: 596 分
注册时间: 2012-01-02
最后登录: 2018-03-05
楼主  发表于: 2013-06-05 17:13

 分析一下tiny210v2的16bitECC校验(已经实现u-boot for tiny210v2)

管理提醒: 本帖被 xoom 执行加亮操作(2013-06-05)
提供了:u-boot for tiny210v2 ,源代码回复可见。
本部分内容设定了隐藏,需要回复后才能看到


开发板:tiny210v2
NandFlash:K9GAG08U0F
网上的针对这个板子的u-boot大多都不太好用,很多都是启动的时候从NandFlash往DRAM中拷贝没有进行ECC校验,导致只能启动不完整。
就决定自己做BL1代码,初始化DRAM了什么的都可以从u-boot中提取,没有什么区别。
BL1有代码主要是实现ECC16bit校验,具体用的什么算法,我到目前还不清楚,但是我已经实现了Main区的校验。因为S5PV210的手册上都是傻瓜式的,按照它的做就完全可以实现校验。主要说明步骤在这里:


数据手册转换为代码:


  
测试方法是制作一个里边全是‘A’的bin文件,贴到上边的代码的后边。这个用MiniTools+SuperBoot以下载bootloader的方法下载此程序的时候,这个bin文件会被下载到第4页的地方,然后我的程序从第4页开始拷贝,拷贝到内存中并打印出来。
这中间的拷贝就用了16bit,ECC校验的方式进行读取的。从下图的第4页的OOB区的内容可以推测出来,SuperBoot是怎么放置这些校验码的:


根据这些校验码的位置,和上边三星提供的步骤,得出了上边的代码。

下面实例分析一下出现一位翻转的情况:




  

Main区的修改函数是按照三星提供的第4步进行写的:
/*
* 修复Main区的反转位
*
*/
int fixEcc(uchar* buf, int num, int flag)
{
    uint subst[16];
    uchar pattern[16];
    int i = 0;

    // 数组赋值为0
    for(i=0; i<16; i++)
    {
        subst=pattern=0;
    }
#if 1
    subst[0] = (NFECCERL0_REG>>0) & 0x1ff;
    pattern[0] = (NFECCERP0_REG>>0) & 0xff;

    subst[1] = (NFECCERL0_REG>>16) & 0x1ff;
    pattern[1] = (NFECCERP0_REG>>8) & 0xff;

    subst[2] = (NFECCERL1_REG>>0) & 0x1ff;
    pattern[2] = (NFECCERP0_REG>>16) & 0xff;

    subst[3] = (NFECCERL1_REG>>16) & 0x1ff;
    pattern[3] = (NFECCERP0_REG>>24) & 0xff;

    subst[4] = (NFECCERL2_REG>>0) & 0x1ff;
    pattern[4] = (NFECCERP1_REG>>0) & 0xff;

    subst[5] = (NFECCERL2_REG>>16) & 0x1ff;
    pattern[5] = (NFECCERP1_REG>>8) & 0xff;

    subst[6] = (NFECCERL3_REG>>0) & 0x1ff;
    pattern[6] = (NFECCERP1_REG>>16) & 0xff;

    subst[7] = (NFECCERL3_REG>>16) & 0x1ff;
    pattern[7] = (NFECCERP1_REG>>24) & 0xff;

    subst[8] = (NFECCERL4_REG>>0) & 0x1ff;
    pattern[8] = (NFECCERP2_REG>>0) & 0xff;

    subst[9] = (NFECCERL4_REG>>16) & 0x1ff;
    pattern[9] = (NFECCERP2_REG>>8) & 0xff;

    subst[10] = (NFECCERL5_REG>>0) & 0x1ff;
    pattern[10] = (NFECCERP2_REG>>16) & 0xff;

    subst[11] = (NFECCERL5_REG>>16) & 0x1ff;
    pattern[11] = (NFECCERP2_REG>>24) & 0xff;

    subst[12] = (NFECCERL6_REG>>0) & 0x1ff;
    pattern[12] = (NFECCERP3_REG>>0) & 0xff;

    subst[13] = (NFECCERL6_REG>>16) & 0x1ff;
    pattern[13] = (NFECCERP3_REG>>8) & 0xff;

    subst[14] = (NFECCERL7_REG>>0) & 0x1ff;
    pattern[14] = (NFECCERP3_REG>>16) & 0xff;

    subst[15] = (NFECCERL7_REG>>16) & 0x1ff;
    pattern[15] = (NFECCERP3_REG>>24) & 0xff;

#endif
    if(flag)
    {    
        for(i=0; i<512; i++)
        {
            puthex(buf);
            putc(' ');
        }
    }
    putc('\n');putc('\r');

    for(i=0; i<num; i++)
    {
        buf[subst] ^= pattern;
//        printf("%02X\t", buf[subst]);
        if(flag)
        {    
            put32bits(subst);putc(' ');puthex(pattern);
            putc('\n');putc('\r');
        }
    }
    
    if(flag)
    {    
        for(i=0; i<512; i++)
        {
            puthex(buf);
            putc(' ');
        }
    }
    putc('\n');putc('\r');
    return 0;
}

其实到这里已经完整的实现了Main区的16bit的ECC校验,但是还有一个问题是校验码也是从NandFlash中读取的,校验码也会发生翻转,这就需要进行数据手册上的第6步检验SPACE区的ECC
下边给一下ECC码也发生的翻转的实例:



同样是全是‘A’,这个校验码读错了,造成原来对的就会改成了错误的(高亮那Byte正确的应该是‘03’)。
(可以看到它把原来的第6Byte的‘AA’,根据错误的校验码改成了‘BA’)  
[ 此帖被kangear在2013-06-27 17:17重新编辑 ]
级别: 新手上路
UID: 93759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
贡献值: 0 点
综合积分: 40 分
注册时间: 2013-06-30
最后登录: 2014-03-26
1楼  发表于: 2013-07-23 16:30
看看
级别: 新手上路
UID: 93759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
贡献值: 0 点
综合积分: 40 分
注册时间: 2013-06-30
最后登录: 2014-03-26
2楼  发表于: 2013-07-23 19:12

 回 2楼(kangear) 的帖子

楼主说oob区翻转会导致出现错误的校正,这与我做的测试不符。
也和手册里的描述不符:
The parity codes have self-correctable information including parity code itself.

大致看了下楼主的代码,发现了问题所在。

手册中对翻转位置寄存器的描述如下
MLC ECC Error Byte Location Status Register (NFECCERL0~7, R, Address = 0xB0E2_00C0 ~ 0xB0E2_00DC)
ErrByteLoc1
[9:0]
Error byte location of 1st bit error
0x000

可以看到手册里描述的 ErrByteLoc 长度是10位,也就是Mask应该是0x3FF, 而楼主代码中用的mask为0x1FF。
这会有什么问题呢?

这个ECC引擎,不仅用来纠正数据错误,也用来纠正ECC错误,如果ECC本身发生翻转,ErrByteLoc 就会指向出错的ECC字节。
楼主用的这个MASK,屏蔽掉了最高1位,当数据长度为512时,导致把指向ECC的位置误认为指向数据的位置。
在ECC出错时错误地纠正了数据,这才出现了楼主描述的这种奇怪的现象。
                             ErrByteLoc
                                           |
                                          V
0 1 2 。。。 511 |  ECC0 ECC1 。。。 ECCLast
    DATA                             ECC
级别: 新手上路
UID: 93759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
贡献值: 0 点
综合积分: 40 分
注册时间: 2013-06-30
最后登录: 2014-03-26
3楼  发表于: 2013-07-29 21:15

 回 34楼(kangear) 的帖子

因为ecc能自我纠正,所以oob里ecc那部分就不用再用ecc校验了。
所以友善的OOB校验码只校验了第4到35字节,也就是OOB的空闲部分。
因为你测试的那几个页面那部分都是空闲的FF,所以校验码总是不变。
oob开头字节是坏块标记。

ECC的自我纠正我也是看了你提出的现象以后看了文档,然后实验验证才弄明白的,以前我写的代码是oob里前480多字节全部参与校验的。
级别: 新手上路
UID: 93759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
贡献值: 0 点
综合积分: 40 分
注册时间: 2013-06-30
最后登录: 2014-03-26
4楼  发表于: 2013-08-08 17:47
我写了个驱动把ECC功能导出到用户态来,做各种测试就方便多了。

512个AA,16位ECC
复制代码
  1. [root@alarm ~]# python2 -c 'print "\xAA"*512' |./ecc -l 512 -s 16|hexdump -C
  2. 00000000  dc e7 f0 25 d2 d5 03 f8  57 43 61 20 6d b6 e5 79  |...%....WCa m..y|
  3. 00000010  ab 0b 9d f5 09 3e a0 b5  7a b0                    |.....>..z.|
  4. 0000001a


512个FF,16位ECC
复制代码
  1. [root@alarm ~]# python2 -c 'print "\xFF"*512' |./ecc -l 512 -s 16|hexdump -C  
  2. 00000000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
  3. 00000010  ff ff ff ff ff ff ff ff  ff ff                    |..........|
  4. 0000001a


32个FF,16位ECC
复制代码
  1. [root@alarm ~]# python2 -c 'print "\xFF"*32' |./ecc -l 32 -s 16|hexdump -C      
  2. 00000000  e2 3e fe b5 6f f2 cd 78  a9 6e cd 57 09 f4 0e d8  |.>..o..x.n.W....|
  3. 00000010  9e 2e 8f 77 90 a9 85 e9  0a 74                    |...w.....t|
  4. 0000001a
级别: 新手上路
UID: 93759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
贡献值: 0 点
综合积分: 40 分
注册时间: 2013-06-30
最后登录: 2014-03-26
5楼  发表于: 2013-08-09 18:11
还是先在linux上调试通过,再移植到u-boot上比较方便