S5PV210(TQ210)学习笔记——Nand flash驱动编写
发布时间:2020-12-15 18:12:25 所属栏目:百科 来源:网络整理
导读:跟裸机程序一样,S5PV210的Nand flash模块跟S3C2440的Nand flash模块非常相似,如果不引入ECC,驱动程序的编写也非常简单,具体的分析及编写过程强烈推荐观看韦东山老师的视频教程,我是使用的Linux-3.8.6(Linux-3.8.3也一样)内核,驱动的API函数有些变化
跟裸机程序一样,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 <linux/module.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> struct s5p_nand_regs{ unsigned long nfconf; unsigned long nfcont; unsigned long nfcmmd; unsigned long nfaddr; unsigned long nfdata; unsigned long nfmeccd0; unsigned long nfmeccd1; unsigned long nfseccd; unsigned long nfsblk; unsigned long nfeblk; unsigned long nfstat; unsigned long nfeccerr0; unsigned long nfeccerr1; unsigned long nfmecc0; unsigned long nfmecc1; unsigned long nfsecc; unsigned long nfmlcbitpt; }; struct s5p_nand_ecc{ unsigned long nfeccconf; unsigned long nfecccont; unsigned long nfeccstat; unsigned long nfeccsecstat; unsigned long nfeccprgecc0; unsigned long nfeccprgecc1; unsigned long nfeccprgecc2; unsigned long nfeccprgecc3; unsigned long nfeccprgecc4; unsigned long nfeccprgecc5; unsigned long nfeccprgecc6; unsigned long nfeccerl0; unsigned long nfeccerl1; unsigned long nfeccerl2; unsigned long nfeccerl3; unsigned long nfeccerl4; unsigned long nfeccerl5; unsigned long nfeccerl6; unsigned long nfeccerl7; unsigned long nfeccerp0; unsigned long nfeccerp1; unsigned long nfeccerp2; unsigned long nfeccerp3; unsigned long nfeccconecc0; unsigned long nfeccconecc1; unsigned long nfeccconecc2; unsigned long nfeccconecc3; unsigned long nfeccconecc4; unsigned long nfeccconecc5; unsigned long nfeccconecc6; }; static struct nand_chip *nand_chip; static struct mtd_info *s5p_mtd_info; static struct s5p_nand_regs *s5p_nand_regs; static struct s5p_nand_ecc *s5p_nand_ecc; static struct clk *s5p_nand_clk; static struct mtd_partition s5p_nand_partions[] = { [0] = { .name = "bootloader",.offset = 0,.size = SZ_1M,},[1] = { .name = "kernel",.offset = MTDPART_OFS_APPEND,.size = 5*SZ_1M,[2] = { .name = "rootfs",.size = MTDPART_SIZ_FULL,}; static void s5p_nand_select_chip(struct mtd_info *mtd,int chipnr){ if(chipnr == -1){ s5p_nand_regs->nfcont |= (1<<1); } else{ s5p_nand_regs->nfcont &= ~(1<<1); } } static void s5p_nand_cmd_ctrl(struct mtd_info *mtd,int cmd,unsigned int ctrl) { if (ctrl & NAND_CLE){ s5p_nand_regs->nfcmmd = cmd; } else{ s5p_nand_regs->nfaddr = cmd; } } static int s5p_nand_ready(struct mtd_info *mtd){ return (s5p_nand_regs->nfstat & 0x1); } static int s5p_nand_probe(struct platform_device *pdev){ int ret = 0; struct resource *mem; //硬件部分初始化 mem = platform_get_resource(pdev,IORESOURCE_MEM,0); if (!mem) { dev_err(&pdev->dev,"can't get I/O resource memn"); return -ENXIO; } s5p_nand_regs = (struct s5p_nand_regs *)ioremap(mem->start,resource_size(mem)); if (s5p_nand_regs == NULL) { dev_err(&pdev->dev,"ioremap failedn"); ret = -EIO; goto err_exit; } s5p_nand_ecc = (struct s5p_nand_ecc *)ioremap(0xB0E20000,sizeof(struct s5p_nand_ecc)); if(s5p_nand_ecc == NULL){ dev_err(&pdev->dev,"ioremap failedn"); ret = -EIO; goto err_iounmap; } s5p_nand_clk = clk_get(&pdev->dev,"nand"); if(s5p_nand_clk == NULL){ dev_dbg(&pdev->dev,"get clk failedn"); ret = -ENODEV; goto err_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 = (struct nand_chip *)kzalloc(sizeof(struct nand_chip),GFP_KERNEL); if(nand_chip == NULL){ dev_err(&pdev->dev,"failed to allocate nand_chip structuren"); ret = -ENOMEM; goto err_clk_put; } s5p_mtd_info = (struct mtd_info *)kzalloc(sizeof(struct mtd_info),GFP_KERNEL); if(s5p_mtd_info == NULL){ dev_err(&pdev->dev,"failed to allocate mtd_info structuren"); ret = -ENOMEM; goto err_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; //扫描Nand flash 设备 if(nand_scan(s5p_mtd_info,1)){ dev_dbg(&pdev->dev,"nand scan errorn"); goto err_free_info; } //添加分区信息 ret = mtd_device_parse_register(s5p_mtd_info,NULL,s5p_nand_partions,ARRAY_SIZE(s5p_nand_partions)); if(!ret) return 0; 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: return ret; } static int s5p_nand_remove(struct platform_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); return 0; } static struct platform_driver s5p_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"); 源码都在上面,具体的原理还是参考视频或者其他资料,这里就不多说了,如果有任何问题,欢迎留言讨论。 本文链接:http://www.voidcn.com/article/p-cfwkrfdf-bbm.html 本文作者:girlkoo (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |