Nand Flash驱动程序分析

来源:互联网 发布:excel数据可视化工具 编辑:程序博客网 时间:2024/06/10 04:22
/*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 Electronics\n");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.cregister_mtd_user(&mtdchar_notifier);//一个文件在: drivers/mtd/mtd_blkdevs.cregister_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);//初始化gendisknew->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);//注册gendiskadd_disk(gd);}/*在这里可以发现,是不是块设备的基本操作等。 其实是内核帮我们已经做好了这些东西。  这样做的好处是把Nand Flash相关的操作都抽象出来,放在nand层。 而把和硬件相关的,  经常需要变化的留给设备层,而设备层就是由我们程序员编写,因为设备层的差别各异,  很难抽象成统一的整体。    所以我们编写块设备的话,只需要做设备层相关的操作,其余的操作内核已经帮我们做好了。*//*上面的分析是对自带的程序分析: 那我们如何写驱动程序同时也能融合到内核为我们提供好的nand层*//*1. 分配一个nand_chip结构  2. 设置nand_chip结构   设置cmdfunc, waitfunc, select_chip等函数3. 硬件相关的代码 使能时钟, 设置时钟,选择芯片4. 使用nand_scan识别nand flash5. 添加分区(这样就会将nand flash驱动加到内核中)*/


0 0
原创粉丝点击