mini2440之nand flash 分析(1)
1:nand falsh 分区信息 可以查看mini2440上面的文件/proc/mtd,/proc/partitions,/dev [@mini2440 /proc]#cat mtd [@mini2440 /proc]#cat partitions ? 31??????? 0??????? 256 mtdblock0 [@mini2440 /dev]#ls -al brw-rw----??? 1 0??????? 0????????? 31,?? 0 Feb 29 18:24 mtdblock0 上面的分区信息有下面的代码所决定: static struct mtd_partition friendly_arm_default_nand_part[] = { [0] = { .name = "supervivi",.size = 0x00040000,.offset = 0,},[1] = { .name = "param",.offset = 0x00040000,.size = 0x00020000,[2] = { .name = "Kernel",.offset = 0x00060000,.size = 0x00500000,[3] = { .name = "root",.offset = 0x00560000,.size = 1024 * 1024 * 1024,// },[4] = { .name = "nand",.offset = 0x00000000,// } }; 在linux内核中nand flash 是以平台设备的方式注册到内核中去的。平台设备的定义如下: struct platform_device s3c_device_nand = { .name = "s3c2410-nand",.id = -1,.num_resources = ARRAY_SIZE(s3c_nand_resource),.resource = s3c_nand_resource,}; 代码中resource 定义如下: static struct resource s3c_nand_resource[] = { [0] = { .start = S3C_PA_NAND,//#define S3C2410_PA_NAND (0x4E000000) .end = S3C_PA_NAND + SZ_1M,.flags = IORESOURCE_MEM,//定义为内存资源,主要用来映射到nand flash 对应的寄存器地址。 } }; ? 其系统中定义的平台设备的信息,可以在/sys目录中找到。 [@mini2440 /sys/devices/platform]#ll 上面目中显示的为注册到内核中的平台设备的信息。 2:重要的数据结构 struct s3c2410_platform_nand { /* timing information for controller,all times in nanoseconds */ int tacls; /* time for active CLE/ALE to nWE/nOE */ int twrph0; /* active time for nWE/nOE */ int twrph1; /* time for release CLE/ALE from nWE/nOE inactive */ unsigned int ignore_unset_ecc:1; int nr_sets; struct s3c2410_nand_set *sets; //定义系统中有几个flash,在mini2440中我们知道,只有一个128M的Nand flash void (*select_chip)(struct s3c2410_nand_set *,int chip); }; struct s3c2410_nand_set { unsigned int disable_ecc:1; unsigned int flash_bbt:1; int nr_chips; int nr_partitions; char *name; int *nr_map; struct mtd_partition *partitions; //分区信息, struct nand_ecclayout *ecc_layout; }; 对每一个分区数据结构的定义。 struct mtd_partition { char *name; /* identifier string */ uint64_t size; /* partition size */ uint64_t offset; /* offset within the master MTD space */ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ }; flash 中的ECC和OBB相关的数据结构。 struct nand_oobfree { __u32 offset; __u32 length; }; #define MTD_MAX_OOBFREE_ENTRIES 8 /* * ECC layout control structure. Exported to userspace for * diagnosis and to allow creation of raw images */ struct nand_ecclayout { __u32 eccbytes; __u32 eccpos[64]; __u32 oobavail; struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; }; 内核中对partition的定义如下: static struct s3c2410_nand_set friendly_arm_nand_sets[] = { [0] = { .name = "NAND",.nr_chips = 1,.nr_partitions = ARRAY_SIZE(friendly_arm_default_nand_part),.partitions = friendly_arm_default_nand_part,}; 其中partitions 就是上面提到的flash的分区信息。 3:mini2440 flash 分析 2440上面的flash 驱动使用的是2410上面的代码,故研究的文件为:?linux/drivers/mtd/nand/s3c2410.c 上面提到过nand flash 是以平台设备的方式注册到linux内核中的,故可以找到平台设备和平台驱动。定义及初始化如下: struct platform_device s3c_device_nand = { .name = "s3c2410-nand",//名字与platform_driver 中的相同 .id = -1,.num_resources = ARRAY_SIZE(s3c_nand_resource),.resource = s3c_nand_resource,}; static struct platform_driver s3c24xx_nand_driver = { .probe = s3c24xx_nand_probe,.remove = s3c24xx_nand_remove,.suspend = s3c24xx_nand_suspend,.resume = s3c24xx_nand_resume,.id_table = s3c24xx_driver_ids,.driver = { .name = "s3c24xx-nand",.owner = THIS_MODULE,}; static int __init s3c2410_nand_init(void) { printk("S3C24XX NAND Driver,(c) 2004 Simtec Electronicsn"); //在系统启动的时候,我们可以看到此信息 return platform_driver_register(&s3c24xx_nand_driver); } static void __exit s3c2410_nand_exit(void) { platform_driver_unregister(&s3c24xx_nand_driver); } 参考博客 在static struct platform_driver平台驱动中可以看到,常见的函数 probe,remove,resume,suspend。 上面提到过nand flash 是以平台设备的方式注册到内核中的,故在系统初始化的时候会在平台设备和平台驱动之间建立起联系,这种联系的建立就是在probe函数中实现。 现在看看函数s3c24xx_nand_probe的定义: 在此之前先看看s3c24xx_nand_probe中涉及到的数据结构:?enum s3c_cpu_type cpu_type; struct s3c2410_nand_info *info;?struct s3c2410_nand_mtd *nmtd; enum s3c_cpu_type { struct s3c2410_nand_info { ?/* device info */ ?enum s3c_cpu_type??cpu_type; #ifdef CONFIG_CPU_FREQ struct s3c2410_nand_mtd { struct nand_chip { uint8_t (*read_byte)(struct mtd_info *mtd); int chip_delay; int page_shift; nand_state_t state; uint8_t *oob_poi; struct nand_ecc_ctrl ecc; struct mtd_oob_ops ops; uint8_t *bbt; struct nand_bbt_descr *badblock_pattern; void *priv; 现在就看看函数static int s3c24xx_nand_probe(struct platform_device *pdev)的定义: static int s3c24xx_nand_probe(struct platform_device *pdev) 而其定义如下:friendly_arm_nand_info; static struct s3c2410_platform_nand friendly_arm_nand_info = { ?pr_debug("s3c2410_nand_probe(%p)n",pdev); //打印信息,可以将打印条件打开,但是打印的信息的将很多。主要在kernel.h中定义来个宏来实现 /*#define DEBUG 1 */ ?info = kmalloc(sizeof(*info),GFP_KERNEL); ?memset(info,sizeof(*info)); ?spin_lock_init(&info->controller.lock); //初始化自旋锁 ?/* get the clock source and enable it */ ?info->clk = clk_get(&pdev->dev,"nand"); ?clk_enable(info->clk); ?/* allocate and map the resource */ ?/* currently we assume we have the one resource */ //其中此函数中参数的传入是在注册平台设备的时候传入的即:platform_add_devices(mini2440_devices,ARRAY_SIZE(mini2440_devices));函数将参数出入此函数的。 /* static struct resource s3c_nand_resource[] = { */ ?info->area = request_mem_region(res->start,size,pdev->name); //申请内存区域,为后面的ioremap()的使用申请空间。 ?if (info->area == NULL) { ?info->device???? = &pdev->dev; ?if (info->regs == NULL) { ?dev_dbg(&pdev->dev,"mapped registers at %pn",info->regs); ?/* initialise the hardware */ ?err = s3c2410_nand_inithw(info); //函数中就有利用虚拟地址对寄存器进行了访问:writel(S3C2440_NFCONT_ENABLE,info->regs + S3C2440_NFCONT); ?sets = (plat != NULL) ? plat->sets : NULL; //判断结构体是否被赋值 ?nr_sets = (plat != NULL) ? plat->nr_sets : 1; //确定nand flash 的个数,在mini2440 中只有一个nand flash 故此值为:1, 信息的确定有下面的定义而得: /* static struct s3c2410_nand_set friendly_arm_nand_sets[] = { /* choose a set of timings which should suit most 512Mbit static struct s3c2410_platform_nand friendly_arm_nand_info = { */ info->mtd_count = nr_sets; ?/* allocate our information */ ?size = nr_sets * sizeof(*info->mtds); ?memset(info->mtds,size); ?/* initialise all possible chips */ ?nmtd = info->mtds; ?for (setno = 0; setno < nr_sets; setno++,nmtd++) { //由上面的信息可知,现在主要是初始化 ??s3c2410_nand_init_chip(info,sets); ??nmtd->scan_res = nand_scan_ident(&nmtd->mtd, ??if (nmtd->scan_res == 0) { ??if (sets != NULL) ?err = s3c2410_nand_cpufreq_register(info); ?if (allow_clk_stop(info)) { ?pr_debug("initialised okn"); ?exit_error: ?if (err == 0) ??err = -EINVAL; ?return err; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |