在读者学习本章之前,最好了解Nand Flash读写过程和操作,可以参考:Nand Flash裸机操作

 

一开始想在本章写eMMC框架和设备驱动,但是没有找到关于eMMC设备驱动具体写法,所以本章仍继续完成Nand Flash设备驱动,eMMC这个坑留在以后填。如果读者开发板为eMMC,本节驱动可能无法正常执行。

 

 

在裸机操作中,读者应了解Nand Flash时序图、Nand Flash片选、读写和擦除等操作,在此不再赘述。

Nand Flash设备驱动放在drivers/mtd/nand目录下,mtd(memory technology device,存储技术设备)是用于访问存储设备(ROM、flash)的子系统。mtd的主要目的是为了使新的存储设备的驱动更加简单,因此它在硬件和顶层之间提供了一个抽象的接口。

读者可在此目录下任意选择一个单板驱动文件进行分析,我选择的是davinci_nand.c文件。

Nand Flash和Nor Flash文件链接:

https://files.cnblogs.com/files/Lioker/18_nand_nor.zip

 

首先来看它的入口函数:

1 static int __init nand_davinci_init(void)
2 {
3     return platform_driver_probe(&nand_davinci_driver, nand_davinci_probe);
4 }

我们进入platform_driver的probe函数中,看看它是如何初始化

18、Nand Flash驱动和Nor Flash驱动
  1 static int __init nand_davinci_probe(struct platform_device *pdev)
  2 {
  3     struct davinci_nand_pdata    *pdata = pdev->dev.platform_data;
  4     struct davinci_nand_info    *info;
  5     struct resource            *res1;
  6     struct resource            *res2;
  7     void __iomem            *vaddr;
  8     void __iomem            *base;
  9     int                ret;
 10     uint32_t            val;
 11     nand_ecc_modes_t        ecc_mode;
 12     struct mtd_partition        *mtd_parts = NULL;
 13     int                mtd_parts_nb = 0;
 14 
 15 ...
 16     /* 初始化硬件,如设置TACLS、TWRPH0、TWRPH1等 */
 17     platform_set_drvdata(pdev, info);
 18 ...
 19     /* 配置mtd_info结构体,它是nand_chip的抽象 */
 20     info->mtd.priv        = &info->chip;
 21     info->mtd.name        = dev_name(&pdev->dev);
 22     info->mtd.owner        = THIS_MODULE;
 23 
 24     info->mtd.dev.parent    = &pdev->dev;
 25 
 26     /* 配置nand_chip结构体 */
 27     info->chip.IO_ADDR_R    = vaddr;
 28     info->chip.IO_ADDR_W    = vaddr;
 29     info->chip.chip_delay    = 0;
 30     info->chip.select_chip    = nand_davinci_select_chip;
 31 ...
 32     /* Set address of hardware control function */
 33     info->chip.cmd_ctrl    = nand_davinci_hwcontrol;
 34     info->chip.dev_ready    = nand_davinci_dev_ready;
 35 
 36     /* Speed up buffer I/O */
 37     info->chip.read_buf     = nand_davinci_read_buf;
 38     info->chip.write_buf    = nand_davinci_write_buf;
 39 
 40     /* Use board-specific ECC config */
 41     ecc_mode        = pdata->ecc_mode;
 42 
 43     ret = -EINVAL;
 44     switch (ecc_mode) {
 45     case NAND_ECC_NONE:
 46     case NAND_ECC_SOFT:        /* 启动软件ECC */
 47         pdata->ecc_bits = 0;
 48         break;
 49     case NAND_ECC_HW:        /* 启动硬件ECC */
 50 ...
 51         break;
 52     default:
 53         ret = -EINVAL;
 54         goto err_ecc;
 55     }
 56     info->chip.ecc.mode = ecc_mode;
 57 
 58     /* 使能nand clk */
 59     info->clk = clk_get(&pdev->dev, "aemif");
 60 ...
 61     ret = clk_enable(info->clk);
 62 ...
 63     val = davinci_nand_readl(info, A1CR_OFFSET + info->core_chipsel * 4);
 64 ...
 65     /* 扫描Nand Flash */
 66     ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL);
 67 ...
 68     /* second phase scan */
 69     ret = nand_scan_tail(&info->mtd);
 70     /* 以上nand_scan_ident()和nand_scan_tail()两步可以使用nand_scan()代替 */
 71     
 72     if (mtd_has_cmdlinepart()) {
 73         static const char *probes[] __initconst = {
 74             "cmdlinepart", NULL
 75         };
 76     /* 设置分区 */
 77         mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes,
 78                             &mtd_parts, 0);
 79     }
 80 
 81     if (mtd_parts_nb <= 0) {
 82         mtd_parts = pdata->parts;
 83         mtd_parts_nb = pdata->nr_parts;
 84     }
 85 
 86     /* Register any partitions */
 87     if (mtd_parts_nb > 0) {
 88         ret = mtd_device_register(&info->mtd, mtd_parts,
 89                       mtd_parts_nb);
 90         if (ret == 0)
 91             info->partitioned = true;
 92     }
 93 
 94     /* If there's no partition info, just package the whole chip
 95      * as a single MTD device.
 96      */
 97     if (!info->partitioned)
 98         ret = mtd_device_register(&info->mtd, NULL, 0) ? -ENODEV : 0;
 99 ...
100     return ret;
101 }
View Code

相关文章: