大家好,又到了天嵌【嵌入式分享】的時間,相對于前幾期【嵌入式分享】做的主要是TQ335X開發(fā)板的技術(shù)分享,本期決定做同是cortex-a8系列的TQ210開發(fā)板的技術(shù)分享。本期是關(guān)于TQ210開發(fā)板的Nand flash驅(qū)動編寫,可能源碼部分會比較多,本文由博主girlkoo編寫,感謝他的分享。 跟裸機程序一樣,S5PV210(TQ210)的Nand flash模塊跟S3C2440(TQ2440)的Nand flash模塊非常相似,如果不引入ECC,驅(qū)動程序的編寫也非常簡單,我是使用的Linux-3.8.6(Linux-3.8.3也一樣)內(nèi)核,驅(qū)動的API函數(shù)有些變化,不過原理是相通的,稍微看一下內(nèi)核源碼并參考下其他平臺的相關(guān)代碼就可以自己寫出Nand flash驅(qū)動了,下面是Nand flash驅(qū)動的源碼,沒有啟用ECC,當(dāng)然,你也可以改成軟件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;
-
- //分配驅(qū)動相關(guān)結(jié)構(gòu)體
- 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;
- }
-
- //設(shè)置驅(qū)動相關(guān)結(jié)構(gòu)體
- 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 設(shè)備
- if(nand_scan(s5p_mtd_info, 1)){
- dev_dbg(&pdev->dev, "nand scan error\n");
- goto err_free_info;
- }
-
- //添加分區(qū)信息
- 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");
上述源碼為嵌入式愛好者分享,如有更新,請咨詢相關(guān)客服與銷售人員,以便更新與開發(fā)。 操作所使用的硬件: TQ210V6開發(fā)板
|