在读者学习本章之前,最好了解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函数中,看看它是如何初始化
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 }