首页 MTD原始设备与FLASH硬件驱动的对话_luofuchong

MTD原始设备与FLASH硬件驱动的对话_luofuchong

举报
开通vip

MTD原始设备与FLASH硬件驱动的对话_luofuchong MTD原始设备与FLASH硬件驱动的对话 luofuchong 看了>后对以MTD的分层结构以及各层的分工情况有了大致的了 解,然而各层之间是如何进行对话的呢,对于这个问题,>上没有 详细的去说明。 小弟抽空研究了一下,打算从下到上,在从上到下,分两条主线来研究一下 MTD 原始设备与 FLASH硬件驱动的对话(MTD原始设备与更上层的对话留待以后再研究)。 以下是第一部分,从下到上的介绍 FLASH硬件驱动与MTD原始设备是如何建立联系的。 1、首先从入口函数开始: stati...

MTD原始设备与FLASH硬件驱动的对话_luofuchong
MTD原始设备与FLASH硬件驱动的对话 luofuchong 看了<>后对以MTD的分层结构以及各层的分工情况有了大致的了 解,然而各层之间是如何进行对话的呢,对于这个问题,<>上没有 详细的去说明。 小弟抽空研究了一下,打算从下到上,在从上到下,分两条主线来研究一下 MTD 原始设备与 FLASH硬件驱动的对话(MTD原始设备与更上层的对话留待以后再研究)。 以下是第一部分,从下到上的介绍 FLASH硬件驱动与MTD原始设备是如何建立联系的。 1、首先从入口函数开始: static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) { struct platform_device *pdev = to_platform_device(dev); struct s3c2410_platform_nand *plat = to_nand_plat(dev); //获取 nand flash配置用结构体数据(dev.c中定义,详细见附录部分) struct s3c2410_nand_info *info; struct s3c2410_nand_mtd *nmtd; struct s3c2410_nand_set *sets; struct resource *res; int err = 0; int size; int nr_sets; int setno; pr_debug("s3c2410_nand_probe(%p)\n", dev); info = kmalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { printk(KERN_ERR PFX "no memory for flash info\n"); err = -ENOMEM; goto exit_error; } memzero(info, sizeof(*info)); dev_set_drvdata(dev, info); //以后有用 spin_lock_init(&info->controller.lock); //初始化自旋锁 init_waitqueue_head(&info->controller.wq); //初始化等待队列 /* get the clock source and enable it */ info->clk = clk_get(dev, "nand"); if (IS_ERR(info->clk)) { printk(KERN_ERR PFX "failed to get clock"); err = -ENOENT; goto exit_error; } clk_use(info->clk); clk_enable(info->clk); /* allocate and map the resource */ /* currently we assume we have the one resource */ res = pdev->resource; //提取 dev.c中定义的与设备相关的资源 size = res->end - res->start + 1; info->area = request_mem_region(res->start, size, pdev->name); if (info->area == NULL) { printk(KERN_ERR PFX "cannot reserve register region\n"); err = -ENOENT; goto exit_error; } info->device = dev; info->platform = plat; //保存好 struct s3c2410_platform_nand 结构数据 info->regs = ioremap(res->start, size);//映射 nand flash用到的寄存器 info->is_s3c2440 = is_s3c2440; if (info->regs == NULL) { printk(KERN_ERR PFX "cannot reserve register region\n"); err = -EIO; goto exit_error; } printk(KERN_INFO PFX "mapped registers at %p\n", info->regs); /* initialise the hardware */ err = s3c2410_nand_inithw(info, dev); //初始化 s3c2410 nand flash控制,主要是配置 S3C2410_NFCONF寄存器 if (err != 0) goto exit_error; sets = (plat != NULL) ? plat->sets : NULL; nr_sets = (plat != NULL) ? plat->nr_sets : 1; info->mtd_count = nr_sets; //我的板上只有一块 nand flash,配置信息见 plat-sets,数目为 1。 /* allocate our information */ size = nr_sets * sizeof(*info->mtds); info->mtds = kmalloc(size, GFP_KERNEL); if (info->mtds == NULL) { printk(KERN_ERR PFX "failed to allocate mtd storage\n"); err = -ENOMEM; goto exit_error; } memzero(info->mtds, size); /* initialise all possible chips */ nmtd = info->mtds; for (setno = 0; setno < nr_sets; setno++, nmtd++) { pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info); s3c2410_nand_init_chip(info, nmtd, sets); nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1);//为什么使用 set->nr_chips(还没配置 的东西)? if (nmtd->scan_res == 0) { s3c2410_nand_add_partition(info, nmtd, sets); } if (sets != NULL) sets++; } pr_debug("initialised ok\n"); return 0; exit_error: s3c2410_nand_remove(dev); if (err == 0) err = -EINVAL; return err; } //初始化代 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 一片 flash的 struct nand_chip结构 static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *nmtd, struct s3c2410_nand_set *set) { struct nand_chip *chip = &nmtd->chip; chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; //读地址 chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; //写地址 chip->hwcontrol = s3c2410_nand_hwcontrol; chip->dev_ready = s3c2410_nand_devready; //ready状态查询 chip->write_buf = s3c2410_nand_write_buf; //写函数 chip->read_buf = s3c2410_nand_read_buf; //读函数 chip->select_chip = s3c2410_nand_select_chip; //片选函数 chip->chip_delay = 50; chip->priv = nmtd; chip->options = 0; chip->controller = &info->controller; if (info->is_s3c2440) { chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; chip->hwcontrol = s3c2440_nand_hwcontrol; } nmtd->info = info; nmtd->mtd.priv = chip; //nand_scan 函数中会调用 struct nand_chip *this = mtd->priv 取出该 struct nand_chip结构 nmtd->set = set; if (hardware_ecc) { chip->correct_data = s3c2410_nand_correct_data; chip->enable_hwecc = s3c2410_nand_enable_hwecc; chip->calculate_ecc = s3c2410_nand_calculate_ecc; chip->eccmode = NAND_ECC_HW3_512; chip->autooob = &nand_hw_eccoob; if (info->is_s3c2440) { chip->enable_hwecc = s3c2440_nand_enable_hwecc; chip->calculate_ecc = s3c2440_nand_calculate_ecc; } } else { chip->eccmode = NAND_ECC_SOFT; //ECC的类型 } } /* command and control functions * * Note, these all use tglx's method of changing the IO_ADDR_W field * to make the code simpler, and use the nand layer's code to issue the * command and address sequences via the proper IO ports. * */ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct nand_chip *chip = mtd->priv; switch (cmd) { case NAND_CTL_SETNCE: case NAND_CTL_CLRNCE: printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); break; case NAND_CTL_SETCLE: chip->IO_ADDR_W = info->regs + S3C2410_NFCMD;//写命令 break; case NAND_CTL_SETALE: chip->IO_ADDR_W = info->regs + S3C2410_NFADDR;//写地址 break; /* NAND_CTL_CLRCLE: */ /* NAND_CTL_CLRALE: */ default: chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;//写数据 break; } } /* s3c2410_nand_devready() * * returns 0 if the nand is busy, 1 if it is ready */ static int s3c2410_nand_devready(struct mtd_info *mtd) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); if (info->is_s3c2440) return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;//返回 nand flash都忙标志 } static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; writesb(this->IO_ADDR_W, buf, len);//写操作 } static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; readsb(this->IO_ADDR_R, buf, len);//读操作 } /* select chip */ /* * 根据 chip都值设置 nand flash都片选信号: * chip = -1 -- 禁用 nand flash * chip !=-1 -- 选择对应的 nand flash */ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) { struct s3c2410_nand_info *info; struct s3c2410_nand_mtd *nmtd; struct nand_chip *this = mtd->priv; void __iomem *reg; unsigned long cur; unsigned long bit; nmtd = this->priv; info = nmtd->info; bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF); cur = readl(reg); if (chip == -1) { cur |= bit; } else { if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { printk(KERN_ERR PFX "chip %d out of range\n", chip); return; } if (info->platform != NULL) { if (info->platform->select_chip != NULL) (info->platform->select_chip)(nmtd->set, chip); } cur &= ~bit; } writel(cur, reg); } 注: s3c2410_nand_init_chip 填充 struct nand_chip 的一部分成员,nand_scan 以通用 nand flash的标准进行检测,并填充 struct nand_chip的其它成员,必要时根据检测结果进 行取舍。 int nand_scan (struct mtd_info *mtd, int maxchips) { int i, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; //取出 struct nand_chip结构 /* Get buswidth to select the correct functions*/ busw = this->options & NAND_BUSWIDTH_16; //nand flash的位宽 /* check for proper chip_delay setup, set 20us if not */ if (!this->chip_delay) this->chip_delay = 20; /* check, if a user supplied command function given */ if (this->cmdfunc == NULL) //填充命令函数 this->cmdfunc = nand_command; /* check, if a user supplied wait function given */ if (this->waitfunc == NULL) //填充等待函数 this->waitfunc = nand_wait; if (!this->select_chip) //s3c2410_nand_init_chip中已定义 this->select_chip = nand_select_chip; if (!this->write_byte) //使用默认的 this->write_byte = busw ? nand_write_byte16 : nand_write_byte; if (!this->read_byte) //使用默认的 this->read_byte = busw ? nand_read_byte16 : nand_read_byte; if (!this->write_word) //使用默认的 this->write_word = nand_write_word; if (!this->read_word) //使用默认的 this->read_word = nand_read_word; if (!this->block_bad) //使用默认的 this->block_bad = nand_block_bad; if (!this->block_markbad) //使用默认的 this->block_markbad = nand_default_block_markbad; if (!this->write_buf) //s3c2410_nand_init_chip中已定义 this->write_buf = busw ? nand_write_buf16 : nand_write_buf; if (!this->read_buf) //s3c2410_nand_init_chip中已定义 this->read_buf = busw ? nand_read_buf16 : nand_read_buf; if (!this->verify_buf) //使用默认的 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; if (!this->scan_bbt) //使用默认的 this->scan_bbt = nand_default_bbt; /* Select the device */ this->select_chip(mtd, 0); //片选,可惜在 s3c2410 nand flash控制器中此操作 为空 /* Send the command for reading device ID */ this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);//发送读 ID命令 /* Read manufacturer and device IDs */ nand_maf_id = this->read_byte(mtd); //读取生产商 ID nand_dev_id = this->read_byte(mtd); //读取设备 ID /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { //保存着 nand flash资料的 nand_flash_ids表在 include/linux/mtd/nand_ids.c文件中, 详细见附录 if (nand_dev_id != nand_flash_ids[i].id) //比较设备 ID continue; if (!mtd->name) mtd->name = nand_flash_ids[i].name; //填充设备名 this->chipsize = nand_flash_ids[i].chipsize << 20; //填充设备大小 /* New devices have all the information in additional id bytes */ if (!nand_flash_ids[i].pagesize) { int extid; /* The 3rd id byte contains non relevant data ATM */ extid = this->read_byte(mtd); /* The 4th id byte is the important one */ extid = this->read_byte(mtd); /* Calc pagesize */ mtd->oobblock = 1024 << (extid & 0x3); extid >>= 2; /* Calc oobsize */ mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; } else { /* Old devices have this data hardcoded in the * device id table */ mtd->erasesize = nand_flash_ids[i].erasesize; //填充檫除单元大小(16k) mtd->oobblock = nand_flash_ids[i].pagesize; //填充页大小(512) mtd->oobsize = mtd->oobblock / 32; //oob大小(512/32=16) busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;//获取 nand flash表中定义的位宽 } /* Try to identify manufacturer */ //比较生产商 ID for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) { if (nand_manuf_ids[maf_id].id == nand_maf_id) break; } /* Check, if buswidth is correct. Hardware drivers should set * this correct ! */ /用户定义的位宽与芯片实际的位宽不一致,取消 nand flash的片选 if (busw != (this->options & NAND_BUSWIDTH_16)) { printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[maf_id].name , mtd->name); printk (KERN_WARNING "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); this->select_chip(mtd, -1);//在 s3c2410 nand flash控制器驱动中,此操作为 空操作 return 1; } /* Calculate the address shift from the page size */ //计算页、可檫除单元、nand flash大小的偏移值 this->page_shift = ffs(mtd->oobblock) - 1; this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; this->chip_shift = ffs(this->chipsize) - 1; /* Set the bad block position */ //标注此 nand flash为大页还是小页? this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ //用户没指定的选项从 nand flash表中获取补上 this->options &= ~NAND_CHIPOPTIONS_MSK; this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK; /* Set this as a default. Board drivers can override it, if neccecary */ this->options |= NAND_NO_AUTOINCR; /* Check if this is a not a samsung device. Do not clear the options * for chips which are not having an extended id. */ if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) this->options &= ~NAND_SAMSUNG_LP_OPTIONS; /* Check for AND chips with 4 page planes */ if (this->options & NAND_4PAGE_ARRAY) this->erase_cmd = multi_erase_cmd; else this->erase_cmd = single_erase_cmd; /* Do not replace user supplied command function ! */ if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); break; }//好的,检测结束^_^ if (!nand_flash_ids[i].name) { printk (KERN_WARNING "No NAND device found!!!\n"); this->select_chip(mtd, -1); return 1; } //统计一下同种类型的 nand flash有多少块(我板上只有一块) for (i=1; i < maxchips; i++) { this->select_chip(mtd, i); /* Send the command for reading device ID */ this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != this->read_byte(mtd) || nand_dev_id != this->read_byte(mtd)) break; } if (i > 1) printk(KERN_INFO "%d NAND chips detected\n", i); /* Allocate buffers, if neccecary */ if (!this->oob_buf) { size_t len; //求出一个檫除单元 64K中 oob所占用的总空间 len = mtd->oobsize << (this->phys_erase_shift - this->page_shift); this->oob_buf = kmalloc (len, GFP_KERNEL); if (!this->oob_buf) { printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n"); return -ENOMEM; } this->options |= NAND_OOBBUF_ALLOC;//oob空间已分配,置相应的标志位 } if (!this->data_buf) { size_t len; len = mtd->oobblock + mtd->oobsize;//512+16=128 this->data_buf = kmalloc (len, GFP_KERNEL); if (!this->data_buf) { if (this->options & NAND_OOBBUF_ALLOC) kfree (this->oob_buf); printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); return -ENOMEM; } this->options |= NAND_DATABUF_ALLOC;//数据空间已分配,置相应的标志位 } /* Store the number of chips and calc total size for mtd */ this->numchips = i;//记录 nand flash片数 mtd->size = i * this->chipsize;//计算出 nand flash总大小 /* Convert chipsize to number of pages per chip -1. */ this->pagemask = (this->chipsize >> this->page_shift) - 1;//(64M>>9)-1=128k-1=0x1ffff /* Preset the internal oob buffer */ //oob_buf全部置为 0xff memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); /* If no default placement scheme is given, select an * appropriate one */ if (!this->autooob) { //我们选用的是 NAND_ECC_SOFT,autooob未设置 /* Select the appropriate default oob placement scheme for * placement agnostic filesystems */ switch (mtd->oobsize) { case 8: this->autooob = &nand_oob_8; break; case 16: this->autooob = &nand_oob_16;//我们的 nand flash属于这一类 break; case 64: this->autooob = &nand_oob_64; break; default: printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize); BUG(); } } 注: ECC的东西不是很懂,先跳过^_^ /* The number of bytes available for the filesystem to place fs dependend * oob data */ mtd->oobavail = 0; for (i = 0; this->autooob->oobfree[i][1]; i++) mtd->oobavail += this->autooob->oobfree[i][1]; /* * check ECC mode, default to software * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize * fallback to software ECC */ this->eccsize = 256; /* set default eccsize */ this->eccbytes = 3; switch (this->eccmode) { case NAND_ECC_HW12_2048: if (mtd->oobblock < 2048) { printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", mtd->oobblock); this->eccmode = NAND_ECC_SOFT; this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; } else this->eccsize = 2048; break; case NAND_ECC_HW3_512: case NAND_ECC_HW6_512: case NA
本文档为【MTD原始设备与FLASH硬件驱动的对话_luofuchong】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_952678
暂无简介~
格式:pdf
大小:208KB
软件:PDF阅读器
页数:0
分类:互联网
上传时间:2013-03-20
浏览量:21