开始准备0718的nandflash的前提工作了。
看了一下三星的K9GA08X0M,虽然是MLC的,但是还只是1page = (4K + 128)Bytes的配置
虽然我们的nandflash控制器的硬件ECC校验————可选16、24、30bits BCH 校验(1024+4字节)
但是BCH编码 1024字节生成 14*T比特的ECC校验码
这样的话30 bits BCH校验2K页的话会生成14*30*2= 840 bits = 105 bytes > 64 bytes
同样,暂时24 bits BCH检验也用不了,只能选择16 bits BCH校验
即使是16 bits BCH校验,也会生成16*14*2 = 56 bytes 的ECC校验码
这样与linux中的标准定义:
static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 2,
.length = 38}}
};不符
(1)所以工作一是要重新定义一个满足SEP0718 nandflash控制器的 ecc分布
由于我们的硬件ECC校验是1024+4字节,也就是所必须向FLASH控制器写入1028个字节的数据,才会生成ECC校验码,要不然就会一直等待。但是输入连续的1028个字节的数据与传统的nandflash不相符
所以这4个字节仍然属于OOB区,这样就要在写/读操作中用到了Random data input/output来来回的变换读/写位置
(2)所以工作二是要处理好这些变换过程的关系
(3)由于2K是要分1K*2来输入,这样ECC校验码就要分2次生成,这样ECC校验需要在驱动中需要重新组合
其他如chip->ecc.calculate,chip->ecc.correct可以参照2.6.32中三星的nandflash完成
5.10:
以前一直不知道eccsteps是干嘛的,今天看了一下eccsize和eccbytes的打印信息:
eccsize = 256,eccbytes = 3,才知道,是分前半页和后半页来生成ECC校验码,这样的
sep0718的nandflash也是分两次来生成校验码的,以前还以为一次搞定呢 =。=!!
鉴于我们1024+4 bytes 这种奇怪的模式,有麻烦了
5.12:
完成write_buf,read_buf函数。
在读函数中要保持ecc_status以及error_addr的内容,这些内容在后面的correct_data中会用到。
完成correct_data函数。
5.24:
前些日因为NANDFLASH控制器连ID都读不出来,所以拖延了几天
前天在rvds上实现了整页(4K)的擦除,读写(NAND_ECC_HW)。
今天编写完成了linux上的nandflash驱动(采用platform架构的)并将以前写做了大幅修改,
但是出现了让人摸不着北的错误:
drivers/built-in.o: In function `sep0718_nand_probe':
rtc-lib.c:(.text+0x2e2cc): undefined reference to `add_mtd_partitions'
make: *** [.tmp_vmlinux1] 错误 1
5.25:
上面的错误是因为有一个内核选项没选
V3版镜像的模块的基地址变了,又悲剧了半天
5.27:
将read_buf函数中的read_reg(info->regs + NAND_SDATA)误写为read_reg(NAND_SDATA),又悲剧了好长时间
终于可以probe完成了,并且成功添加了4个分区,但是不知道为什么在/dev目录下为
mtd0 mtd0ro(为什么不是mtdblock0 ??)
mtd1 mtd1ro
mtd2 mtd2ro
mtd3 mtd3ro
这是什么东东?
5.28:
(1)#if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE)
#define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
#else
#define MTD_DEVT(index) 0
#endif
由于一个内核选项没选,导致没注册进去
(2) 今天又悲剧了一个下午,被自己因为写的很酷的一句语句搞死了。
mtd = kmalloc( sizeof(struct mtd_info) + sizeof(struct nand_chip) + sizeof(struct sep0718_nand_info),GFP_KERNEL);
if(!mtd)
{
printk ("Unable to allocate MTD device structure.\n");
return -ENOMEM;
}
memset((char*)mtd,0,sizeof(struct mtd_info)+sizeof(struct nand_chip)+sizeof(struct sep0718_nand_info));
sep0718_nand->mtd = mtd;
this = (struct nand_chip*)(&mtd[1]);
sep0718_nand->chip = this;
info = (struct sep0718_nand_info *)(&mtd[1]+sizeof(struct nand_chip)); |
结果就悲剧了,本意是很好的,但是其中这样一句:
info = (struct sep0718_nand_info *)(&mtd[1]+sizeof(struct nand_chip)); |
就让我死的很惨。哎,,指针啊指针
改成:
info = (struct sep0718_nand_info *)((char*)&mtd[1]+sizeof(struct nand_chip)); |
就好了。。。
5.31:
又走了一些弯路。
现在想用jffs2来测试一下,但是会有一些页会ECC校验失败,不知道是不是因为nandflash没有擦,明天用
rvds写个小程序来擦除一下再继续尝试挂载jffs2
6.1:
今天又重新用rvds来调程序了,发现读写时好时坏。最后发现时DDR的配置对nandflash读写会造成影响,所以在SD boot启动代码中将DDR配置删除了。
今天挂jffs2的时候老是出现ECC fail的情况,后来才发现貌似ECC模块对空页(全是0xff)生成的ECC校验码并不是0xff,所以难怪读空页会出错(囧了),向5楼反应上去了,希望是我搞错了,要不然程序没法搞了
6.4
原来以为nand_scan中扫描坏块是用的nand_block_bad,结果今天发现不是,不过差不多,对于大页,检查OOB区的前两个字节,看是否是0xff,建立bbt(bad block table)。
一直发现NANDFLASH中的一个很奇怪的情况,有些页的OOB区,前16字节为0xff,但是后面就不是了。所以扫描的时候并不能检查出。所以我将函数改了,改成检查前20个字符=.=
最后在挂了一次jffs2文件系统,没有报错,小兴奋了一下,但是发现没有,创建的文件夹貌似没写进去,而且挂上去居然不能umount下来,汗。。。。
6.8
哈哈,今天真是走运啊,SDK3.6的时候的UBIFS不是白调的,今天终于用上了。
以前不知道jffs2其实也用到了OOB区,所以像我们这样使用特殊硬件ECC的控制器是不能用的。所以果断换。
所以今天使用了ubifs文件系统,果然一次搞定。哈哈哈。。。。
7.2
继续崩溃中,DMA啊,调了这么多天终于将scatterlist的DMA使用在nandflash上实现了。
扩展板的设计真让人蛋疼,SD卡启动的开关同时又是NANDFLASH 8/16 bits的选择开关,难怪调了那么长时间,在RVDS上可以,在linux上就是不行。
原来以为已经搞定的。但是天不如人愿。对于Vmalloc分配的空间,我DMA搬运就会出问题。所以必须通过页表找到该地址对应的物理地址。
所以在DMA搬运代码中加了这样一段:
/*判断该buffer空间是否是由vmalloc分配的*/
if(((unsigned int)buffer <= VMALLOC_END) && ((unsigned int)buffer >= VMALLOC_START))
{
page = vmalloc_to_page(buffer);/*获得该buffer的页描述符*/
sg_init_table(&info->sg, 1);
sg_set_page(&info->sg, page, len, offset_in_page(buffer));
} |
在UBIFS上拷贝零碎文件的时候会卡死(陷入DMA等待),发现是在搬运一个虚地址为0xc1cdc028的内存时卡死的。
fuck,FPGA镜像有问题。。。前端修改掉了
07.14
这几天添加了对于NANDFLASH WIDTH 16bit的支持,这样的16bit与linux中的NAND_BUSWIDTH_16有很大的区别,根本不是一个概念。linux中的是指dma的burst宽度为16bit。
现在一般nandflash芯片的I/O都是8bit,也就是说最小输入输出是以字节为最小单元。如果将2块芯片并联,那么I/O口宽度就会达到16bit,这样对于NANDFLASH控制而言,页大小就会变成原来的2倍。
比如单个芯片是4K页,如果使用flashwidth 16bit,那么页大小就变成8K。这8K的数据分别保存在2个flash芯片的同一页上(即页地址是一样的)。
所以在nand_base.c的nand_get_flash_type函数中添加了下面的代码:
#ifdef CONFIG_MTD_NAND_SEP0718_WIDTH16
mtd->writesize <<= 1;
mtd->oobsize <<= 1;
mtd->erasesize <<= 1;
chip->chipsize <<= 1;
// printk("mtd->writesize :%d ;mtd->oobsize %d ;mtd->erasesize 0x%x ;chip->chipsize :0x%012llx \n",mtd->writesize,mtd->oobsize,mtd->erasesize,(unsigned long long )chip->chipsize);
#endif |
一直以来觉得TCC8900的NANDFLASH驱动的设计太过于复杂,感觉没必要。但是突然感觉到其实很有必要,因为linux的MTD层中不能很好的发挥MLC芯片的性能,而且现在的产品对FLASH的读写性能要求很高,所以必须充分的利用mlc的优势。
既然MTD层不能利用MLC的一些新特性,那么只能在驱动中实现喽,所以才那么复杂。
阅读(3241) | 评论(2) | 转发(1) |