Nand Flash驱动程序分析
发布时间:2020-12-15 17:26:42 所属栏目:百科 来源:网络整理
导读:/*Nand Flash驱动分析*//*首先: 市面上的开发板很多,Nand Flash差不多都一样。先说说Nand Flash的特性*//* 上图是OK6410开发板的Nand Flash原理图,从上图可知:1. 数据线和地址线明显是公用的。因为只看见了DATA0-DATA7没看见地址线。作为一个存储芯片当
/*Nand Flash驱动分析*/ /*首先: 市面上的开发板很多,Nand Flash差不多都一样。先说说Nand Flash的特性*/ /* 上图是OK6410开发板的Nand Flash原理图,从上图可知: 1. 数据线和地址线明显是公用的。因为只看见了DATA0-DATA7没看见地址线。作为一个存储芯片当然要写数据,读数据。当然需要地址线。 2. DATA0-DATA7在好多地址被使用了,那怎么区分当前是那个芯片。那当然要CSN2和CSN3来控制当前选中那个芯片,也就是让那个芯片工作。 3. FWEN和FREN是写使能信号,和读使能信息。来控制读写的操作 4. 当FCLE为高电平时传输的是命令, FALE为高电平时传输的是地址,当FCLE和FALE都为低电平时传输的是数据。(可以从Nand Flash芯片手册上获取到) 既然了解这么多,就该知道Nand Flash一般的工作流程了: 1. 先发命令, 2. 再发地址(可能需要发送好几个周期), 3. 发出数据或者读取数据 */ /*其次,我们来分析三星公司自带的Nand Flash驱动程序。路径: drivers/mtd/nand/s3c2410.c*/ //老套路了还是平台驱动程序,既然是平台驱动程序,就有平台设备的存在 static int __init s3c2410_nand_init(void) { printk("S3C24XX NAND Driver,(c) 2004 Simtec Electronicsn"); return platform_driver_register(&s3c24xx_nand_driver); } //平台设备与驱动想匹配时,就会调用probe函数 /* s3c24xx_nand_probe //注释写的是多么的清楚 * * called by device layer when it finds a device matching //先是当发现设备后调用设备层,接着代码检测是否能分配足够的资源 * one our driver can handled. This code checks to see if //然后调用Nand 层去寻找设备。 * it can allocate all necessary resources then calls the //注释中出现了Device 层和 Nand层的概念,以后会说到 * nand layer to look for devices */ static int s3c24xx_nand_probe(struct platform_device *pdev) { struct s3c2410_nand_info *info; //分配info结构 info = kzalloc(sizeof(*info),GFP_KERNEL); platform_set_drvdata(pdev,info); //设置时钟,使能时钟 info->clk = clk_get(&pdev->dev,"nand"); s3c2410_nand_clk_set_state(info,CLOCK_ENABLE); //初始化硬件 s3c2410_nand_inithw(info); //初始化所有可能的芯片 s3c2410_nand_init_chip //nand 寻找设备 nand_scan_ident(); //如果没有找到, if (nmtd->scan_res == 0) { s3c2410_nand_update_chip(info,nmtd); nand_scan_tail(&nmtd->mtd);//寻找设备 s3c2410_nand_add_partition(info,nmtd,sets);//增加分区 } } //寻找Nand Flash设备 int nand_scan_ident(struct mtd_info *mtd,int maxchips,struct nand_flash_dev *table) { /* Get buswidth to select the correct functions */ busw = chip->options & NAND_BUSWIDTH_16; //设置总线宽度 /* Set the default functions */ nand_set_defaults(chip,busw); //设置一些默认的函数 /* Read the flash type */ type = nand_get_flash_type(mtd,chip,busw,//读取flash的类型 &nand_maf_id,&nand_dev_id,table); } /*所谓设置默认函数,就是设置flash的读,写,发送命令,发送数据,等待等函数。*/ static void nand_set_defaults(struct nand_chip *chip,int busw) { /* check for proper chip_delay setup,set 20us if not */ if (!chip->chip_delay) //如果没有设置延迟时间,那就设置 chip->chip_delay = 20; /* check,if a user supplied command function given */ if (chip->cmdfunc == NULL) //如果没有设置发送命令的函数,那就需要我们自己设置 chip->cmdfunc = nand_command; /* check,if a user supplied wait function given */ if (chip->waitfunc == NULL) //如果没有设置等待函数,那就需要在驱动程序中设置 chip->waitfunc = nand_wait; if (!chip->select_chip) chip->select_chip = nand_select_chip; //片选函数设置 if (!chip->read_byte) chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; //读flash函数 if (!chip->read_word) chip->read_word = nand_read_word; if (!chip->block_bad) chip->block_bad = nand_block_bad; if (!chip->block_markbad) chip->block_markbad = nand_default_block_markbad; if (!chip->write_buf) chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; //写flash函数 if (!chip->read_buf) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; if (!chip->verify_buf) chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; if (!chip->scan_bbt) chip->scan_bbt = nand_default_bbt; } } /* 取得Flash和厂家id,寻找是否支持该设备 * Get the flash and manufacturer id and lookup if the type is supported */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,struct nand_chip *chip,int busw,int *maf_id,int *dev_id,struct nand_flash_dev *type) { /* Select the device */ chip->select_chip(mtd,0); //先选中芯片 /* * Reset the chip,required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up */ chip->cmdfunc(mtd,NAND_CMD_RESET,-1,-1); //reset芯片 /* Send the command for reading device ID */ chip->cmdfunc(mtd,NAND_CMD_READID,0x00,-1); //发送读取ID的命令90h, /* Read manufacturer and device IDs */ *maf_id = chip->read_byte(mtd); //读取厂家ID *dev_id = chip->read_byte(mtd); //读取设备ID } s3c2410_nand_add_partition -> mtd_device_register ->add_mtd_partitions -> add_mtd_device-> { list_for_each_entry(not,&mtd_notifiers,list)//遍历mtd_notifiers中每个调用add函数 not->add(mtd); } //那mtd_notifiers在那里设置了? void register_mtd_user (struct mtd_notifier *new) { list_add(&new->list,&mtd_notifiers);//在这里设置了mtd_notifiers __module_get(THIS_MODULE); mtd_for_each_device(mtd) new->add(mtd); } //看看谁调用register_mtd_user函数 //一个文件在: drivers/mtd/mtdchar.c register_mtd_user(&mtdchar_notifier); //一个文件在: drivers/mtd/mtd_blkdevs.c register_mtd_user(&blktrans_notifier); //先看mtdchar_notifier中的add函数 static void mtd_notify_add(struct mtd_info *mtd) { } //再看blktrans_notifier中的add函数 static void blktrans_notify_add(struct mtd_info *mtd) { //遍历blktrans_majors链表,调用add_mtd函数 list_for_each_entry(tr,&blktrans_majors,list) tr->add_mtd(tr,mtd); } //看blktrans_majors链表在那里设置? int register_mtd_blktrans(struct mtd_blktrans_ops *tr) { list_add(&tr->list,&blktrans_majors); //此函数中有设置 } //init_mtdblock函数调用了register_mtd_blktrans函数 static int __init init_mtdblock(void) { mutex_init(&mtdblks_lock); return register_mtd_blktrans(&mtdblock_tr); } //看mtdblock_tr结构中的add_mtd函数 static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr,struct mtd_info *mtd) { } int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) { //穿件gendisk结构 gd = alloc_disk(1 << tr->part_bits); //初始化gendisk new->disk = gd; gd->private_data = new; gd->major = tr->major; gd->first_minor = (new->devnum) << tr->part_bits; gd->fops = &mtd_blktrans_ops; set_capacity(gd,(new->size * tr->blksize) >> 9); //初始化请求队列 new->rq = blk_init_queue(mtd_blktrans_request,&new->queue_lock); //注册gendisk add_disk(gd); } /*在这里可以发现,是不是块设备的基本操作等。 其实是内核帮我们已经做好了这些东西。 这样做的好处是把Nand Flash相关的操作都抽象出来,放在nand层。 而把和硬件相关的, 经常需要变化的留给设备层,而设备层就是由我们程序员编写,因为设备层的差别各异, 很难抽象成统一的整体。 所以我们编写块设备的话,只需要做设备层相关的操作,其余的操作内核已经帮我们做好了。 */ /*上面的分析是对自带的程序分析: 那我们如何写驱动程序同时也能融合到内核为我们提供好的nand层*/ /* 1. 分配一个nand_chip结构 2. 设置nand_chip结构 设置cmdfunc, waitfunc, select_chip等函数 3. 硬件相关的代码 使能时钟, 设置时钟,选择芯片 4. 使用nand_scan识别nand flash 5. 添加分区(这样就会将nand flash驱动加到内核中) */ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- 检查一个postgresql表是否存在于python(可能是Psycopg2)
- c# – 如何让CopyFileEx报告回来以便取消文件复制操作?
- 2015-04-08---cocos2dx一个都不能死(含源码)
- c# – Asp.Net Core 2.0 ArgumentNullException:值不能为n
- flex中TitleWindow滚动条问题
- ruby-on-rails – Rails’link_to’立即下载图像,而不是在浏
- ruby-on-rails – Rails 4.2从活动作业中获得延迟的作业ID
- ruby – Gem :: Ext :: BuildError:错误:无法构建gem原生
- Swift语法基础: 20 - Swift的定义和调用函数, 函数形参名
- c – 专用于私有成员类的std :: hash