热度 16
2014-12-10 10:54
786 次阅读|
0 个评论
大家好,又到了天嵌【嵌入式分享】的时间,相对于前几期【嵌入式分享】做的主要是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 = { .name = "bootloader", .offset = 0, .size = SZ_1M, }, = { .name = "kernel", .offset = MTDPART_OFS_APPEND, .size = 5*SZ_1M, }, = { .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 |= (11); } else{ s5p_nand_regs-nfcont = ~(11); } } 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 = (312)|(58)|(34)|(11); 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"); 上述源码为嵌入式爱好者分享,如有更新,请咨询相关客服与销售人员,以便更新与开发。 操作所使用的硬件: TQ210V6开发板