跟裸机程序相同,S5PV210的Nand flash模块跟S3C2440的Nand flash模块十分类似,假如不引进ECC,驱动程序的编写也十分简略,详细的剖析及编写进程强烈推荐观看韦东山教师的视频教程,我是运用的Linux-3.8.6(Linux-3.8.3也相同)内核,驱动的API函数有些改变,不过原理是相通的,略微看一下内核源码并参阅下其他渠道的相关代码就能够自己写出Nand flash驱动了,下面是Nand flash驱动的源码,没有启用ECC,当然,你也能够改成软件ECC,可是我的觉得已然软件ECC不如HWECC快,我就选用硬件ECC吧,我会鄙人篇文章中参加HWECC。
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- structs5p_nand_regs{
- unsignedlongnfconf;
- unsignedlongnfcont;
- unsignedlongnfcmmd;
- unsignedlongnfaddr;
- unsignedlongnfdata;
- unsignedlongnfmeccd0;
- unsignedlongnfmeccd1;
- unsignedlongnfseccd;
- unsignedlongnfsblk;
- unsignedlongnfeblk;
- unsignedlongnfstat;
- unsignedlongnfeccerr0;
- unsignedlongnfeccerr1;
- unsignedlongnfmecc0;
- unsignedlongnfmecc1;
- unsignedlongnfsecc;
- unsignedlongnfmlcbitpt;
- };
- structs5p_nand_ecc{
- unsignedlongnfeccconf;
- unsignedlongnfecccont;
- unsignedlongnfeccstat;
- unsignedlongnfeccsecstat;
- unsignedlongnfeccprgecc0;
- unsignedlongnfeccprgecc1;
- unsignedlongnfeccprgecc2;
- unsignedlongnfeccprgecc3;
- unsignedlongnfeccprgecc4;
- unsignedlongnfeccprgecc5;
- unsignedlongnfeccprgecc6;
- unsignedlongnfeccerl0;
- unsignedlongnfeccerl1;
- unsignedlongnfeccerl2;
- unsignedlongnfeccerl3;
- unsignedlongnfeccerl4;
- unsignedlongnfeccerl5;
- unsignedlongnfeccerl6;
- unsignedlongnfeccerl7;
- unsignedlongnfeccerp0;
- unsignedlongnfeccerp1;
- unsignedlongnfeccerp2;
- unsignedlongnfeccerp3;
- unsignedlongnfeccconecc0;
- unsignedlongnfeccconecc1;
- unsignedlongnfeccconecc2;
- unsignedlongnfeccconecc3;
- unsignedlongnfeccconecc4;
- unsignedlongnfeccconecc5;
- unsignedlongnfeccconecc6;
- };
- staticstructnand_chip*nand_chip;
- staticstructmtd_info*s5p_mtd_info;
- staticstructs5p_nand_regs*s5p_nand_regs;
- staticstructs5p_nand_ecc*s5p_nand_ecc;
- staticstructclk*s5p_nand_clk;
- staticstructmtd_partitions5p_nand_partions[]={
- [0]={
- .name=”bootloader”,
- .offset=0,
- .size=SZ_1M,
- },
- [1]={
- .name=”kernel”,
- .offset=MTDPART_OFS_APPEND,
- .size=5*SZ_1M,
- },
- [2]={
- .name=”rootfs”,
- .offset=MTDPART_OFS_APPEND,
- .size=MTDPART_SIZ_FULL,
- },
- };
- staticvoids5p_nand_select_chip(structmtd_info*mtd,intchipnr){
- if(chipnr==-1){
- s5p_nand_regs->nfcont|=(1<<1);
- }
- else{
- s5p_nand_regs->nfcont&=~(1<<1);
- }
- }
- staticvoids5p_nand_cmd_ctrl(structmtd_info*mtd,intcmd,unsignedintctrl)
- {
- if(ctrl&NAND_CLE){
- s5p_nand_regs->nfcmmd=cmd;
- }
- else{
- s5p_nand_regs->nfaddr=cmd;
- }
- }
- staticints5p_nand_ready(structmtd_info*mtd){
- return(s5p_nand_regs->nfstat&0x1);
- }
- staticints5p_nand_probe(structplatform_device*pdev){
- intret=0;
- structresource*mem;
- //硬件部分初始化
- mem=platform_get_resource(pdev,IORESOURCE_MEM,0);
- if(!mem){
- dev_err(&pdev->dev,”cantgetI/Oresourcemem”);
- return-ENXIO;
- }
- s5p_nand_regs=(structs5p_nand_regs*)ioremap(mem->start,resource_size(mem));
- if(s5p_nand_regs==NULL){
- dev_err(&pdev->dev,”ioremapfailed“);
- ret=-EIO;
- gotoerr_exit;
- }
- s5p_nand_ecc=(structs5p_nand_ecc*)ioremap(0xB0E20000,sizeof(structs5p_nand_ecc));
- if(s5p_nand_ecc==NULL){
- dev_err(&pdev->dev,”ioremapfailed”);
- ret=-EIO;
- gotoerr_iounmap;
- }
- s5p_nand_clk=clk_get(&pdev->dev,”nand”);
- if(s5p_nand_clk==NULL){
- dev_dbg(&pdev->dev,”getclkfailed”);
- ret=-ENODEV;
- gotoerr_iounmap;
- }
- clk_enable(s5p_nand_clk);
- s5p_nand_regs->nfconf=(3<<12)|(5<<8)|(3<<4)|(1<<1);
- s5p_nand_regs->nfcont|=3;
- //分配驱动相关结构体
- nand_chip=(structnand_chip*)kzalloc(sizeof(structnand_chip),GFP_KERNEL);
- if(nand_chip==NULL){
- dev_err(&pdev->dev,”failedtoallocatenand_chipstructure”);
- ret=-ENOMEM;
- gotoerr_clk_put;
- }
- s5p_mtd_info=(structmtd_info*)kzalloc(sizeof(structmtd_info),GFP_KERNEL);
- if(s5p_mtd_info==NULL){
- dev_err(&pdev->dev,”failedtoallocatemtd_infostructure”);
- ret=-ENOMEM;
- gotoerr_free_chip;
- }
- //设置驱动相关结构体
- nand_chip->select_chip=s5p_nand_select_chip;
- nand_chip->cmd_ctrl=s5p_nand_cmd_ctrl;
- nand_chip->IO_ADDR_R=&s5p_nand_regs->nfdata;
- nand_chip->IO_ADDR_W=&s5p_nand_regs->nfdata;
- nand_chip->dev_ready=s5p_nand_ready;
- nand_chip->ecc.mode=NAND_ECC_SOFT;
- s5p_mtd_info->priv=nand_chip;
- s5p_mtd_info->owner=THIS_MODULE;
- //扫描Nandflash设备
- if(nand_scan(s5p_mtd_info,1)){
- dev_dbg(&pdev->dev,”nandscanerror”);
- gotoerr_free_info;
- }
- //增加分区信息
- ret=mtd_device_parse_register(s5p_mtd_info,NULL,NULL,s5p_nand_partions,ARRAY_SIZE(s5p_nand_partions));
- if(!ret)
- return0;
- err_free_info:
- kfree(s5p_mtd_info);
- err_free_chip:
- kfree(nand_chip);
- err_clk_put:
- clk_disable(s5p_nand_clk);
- clk_put(s5p_nand_clk);
- err_iounmap:
- //if(s5p_nand_ecc==NULL)
- //iounmap(s5p_nand_ecc);
- if(s5p_nand_regs==NULL)
- iounmap(s5p_nand_regs);
- err_exit:
- returnret;
- }
- staticints5p_nand_remove(structplatform_device*pdev){
- nand_release(s5p_mtd_info);
- kfree(s5p_mtd_info);
- kfree(nand_chip);
- clk_disable(s5p_nand_clk);
- clk_put(s5p_nand_clk);
- if(s5p_nand_regs==NULL)
- iounmap(s5p_nand_regs);
- return0;
- }
- staticstructplatform_drivers5p_nand_drv={
- .driver={
- .owner=THIS_MODULE,
- .name=”s5p-nand”,
- },
- .probe=s5p_nand_probe,
- .remove=s5p_nand_remove,
- };
- module_platform_driver(s5p_nand_drv);
- MODULE_LICENSE(“GPL”);
源码都在上面,详细的原理仍是参阅视频或许其他材料,这儿就不多说了,假如有任何问题,欢迎留言评论。