|
大家好,又到了天嵌【嵌入式分享】的时间,相对于前几期【嵌入式分享】做的主要是TQ335X开发板的技术分享,本期决定做同是cortex-a8系列的TQ210开发板的技术分享。本期是关于TQ210开发板的Nand flash驱动编写,可能源码部分会比较多,本文由博主girlkoo编写,感谢他的分享。
跟裸机程序一样,S5PV210(TQ210)的Nand flash模块跟S3C2440(TQ2440)的Nand flash模块非常相似,如果不引入ECC,驱动程序的编写也非常简单,我是使用的Linux-3.8.6(Linux-3.8.3也一样)内核,驱动的API函数有些变化,不过原理是相通的,稍微看一下内核源码并参考下其他平台的相关代码就可以自己写出Nand flash驱动了,下面是Nand flash驱动的源码,没有启用ECC,当然,你也可以改成软件ECC,但是我的觉得既然软件ECC不如HWECC快,我就采用硬件ECC吧。
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- 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",
- .offset = MTDPART_OFS_APPEND,
- .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 mem\n");
- 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 failed\n");
- 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 failed\n");
- ret = -EIO;
- goto err_iounmap;
- }
-
- s5p_nand_clk = clk_get(&pdev->dev, "nand");
- if(s5p_nand_clk == NULL){
- dev_dbg(&pdev->dev, "get clk failed\n");
- 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 structure\n");
- 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 structure\n");
- 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 error\n");
- goto err_free_info;
- }
-
- //添加分区信息
- ret = mtd_device_parse_register(s5p_mtd_info, NULL, 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");
复制代码 上述源码为嵌入式爱好者分享,如有更新,请咨询相关客服与销售人员,以便更新与开发。
|
|