300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > NAND FLASH学习笔记之MTD下nand flash驱动(六)

NAND FLASH学习笔记之MTD下nand flash驱动(六)

时间:2018-11-28 11:41:09

相关推荐

NAND FLASH学习笔记之MTD下nand flash驱动(六)

六、驱动层之Flash读操作

MTD对NAND芯片的读写 主要分三部分:

A、struct mtd_info中的读写函数,如read,write_oob等,这是MTD原始设备层与FLASH硬件层之间的接口;

B、struct nand_ecc_ctrl中的读写函数,如read_page_raw,write_page等,主要用来做一些与ecc有关的操作;

C、struct nand_chip中的读写函数,如read_buf,cmdfunc等,与具体的NANDcontroller相关,就是这部分函数与硬件交互,通常需要我们自己来实现。

注: nand_chip中的读写函数虽然与具体的NAND controller相关,但是MTD也为我们提供了默认的读写函数,如果NAND controller比较通用(使用PIO模式),那么对NAND芯片的读写与MTD提供的这些函数一致,就不必自己实现这些函数。

上面三部分读写函数相互配合完成对NAND芯片的读写,具体流程如下:

首先,MTD上层需要读写NAND芯片时,会调用struct mtd_info中的读写函数,接着struct mtd_info中的读写函数就会调用struct nand_chip或struct nand_ecc_ctrl中的读写函数,最后,若调用的是struct nand_ecc_ctrl中的读写函数,那么它又会接着调用struct nand_chip中的读写函数。

以读为例:

MTD上层会调用struct mtd_info中的读page函数,即nand_read函数。

接着nand_read函数会调用struct nand_chip中cmdfunc函数,这个cmdfunc函数与具体的NAND controller相关,它的作用是使NAND controller向NAND芯片发出读命令,NAND芯片收到命令后,就会做好准备等待NAND controller下一步的读取。接着nand_read函数又会调用struct nand_ecc_ctrl中的read_page函数,而read_page函数又会调用struct nand_chip中read_buf函数,从而真正把NAND芯片中的数据读取到buffer中(所以这个read_buf的意思其实应该是read into buffer,另外,这个buffer是struct mtd_info中的nand_read函数传下来的)。

read_buf函数返回后,read_page函数就会对buffer中的数据做一些处理,比如校验ecc,以及若数据有错,就根据ecc对数据修正之类的,最后read_page函数返回到nand_read函数中。

对NAND芯片的其它操作,如写,擦除等,都与读操作类似

JZ4780之NAND FLASH读函数调用流程:

mtd上层选中并调用mtd_info中的读函数

->nand_read(mtd_info)

->nand_do_read_ops

(1)->chip->cmdfunc(mtd,NAND_CMD_READ0, 0x00, page);

(2)->chip->ecc.read_page()

(1) -> read_buf()(read into buffer)

(2) -> 调用一系列函数进行相关的ecc校验

问题:nand_chip(nand flash的描述符)的读写操作是怎么和MTD的读写操作联系起来的呢?

1)probe->scan_tail;

在填充MTD的时候,使用mtd->read = nand_read;这里和mtd挂钩。

2)在nand_read实现中又调用了nand_do_read_ops(mtd,from, &chip->ops);这里和nand_chip联系起来了。

以读为例对代码进行分析如下:

读分析MTD 读取数据的入口是 nand_read,然后调用 nand_do_read_ops,此函数主体如下:《一》nand_read代码如下:static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,size_t *retlen, uint8_t *buf){struct mtd_oob_ops ops;int ret;nand_get_device(mtd, FL_READING);ops.len = len;ops.datbuf = buf;ops.oobbuf = NULL;ops.mode = MTD_OPS_PLACE_OOB;ret = nand_do_read_ops(mtd, from, &ops);*retlen = ops.retlen;nand_release_device(mtd);return ret;}《二》nand_do_read_ops代码如下:static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,struct mtd_oob_ops *ops){/******省略****/。。。。。。。。。。。。。。while(1) {/******省略****/.。。。。。。。。。。。。。。。if (likely(sndcmd)) {/*#define NAND_CMD_READ0 0*//*1)***读取数据前肯定要先发送对应的读页命令******/chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);sndcmd = 0;}/* Now read the page into the buffer */if (unlikely(ops->mode == MTD_OOB_RAW))ret = chip->ecc.read_page_raw(mtd, chip,bufpoi, page);else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);else/******执行到这里read_page函数读取对应的数据了******/ret = chip->ecc.read_page(mtd, chip, bufpoi,page);if (ret < 0)break;/* Transfer not aligned data */if (!aligned) {if (!NAND_SUBPAGE_READ(chip) && !oob)chip->pagebuf = realpage;memcpy(buf, chip->buffers->databuf + col, bytes);}buf += bytes;。。。。。。。。。。。。。。。。。。if (mtd->ecc_stats.failed - stats.failed)return -EBADMSG;return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;}上面这些代码都不需要我们去实现的,使用MTD层的自定义代码就行。下面将要分析chip->cmdfunc,我们从probe函数中可以知道/* step3. replace NAND command function with large page version */if (mtd->writesize > 512)chip->cmdfunc = jz4780_nand_command_lp;jz4780_nand_command_lp的分析static void jz4780_nand_command_lp(struct mtd_info *mtd,unsigned int command, int column, int page_addr){register struct nand_chip *chip = mtd->priv;struct jz4780_nand *nand;nand_flash_if_t *nand_if;nand_flash_info_t *nand_info;nand = mtd_to_jz4780_nand(mtd);nand_if = nand->nand_flash_if_table[nand->curr_nand_flash_if];nand_if->curr_command = command;nand_info = nand->curr_nand_flash_info;/* Emulate NAND_CMD_READOOB */if (command == NAND_CMD_READOOB) {column += mtd->writesize;command = NAND_CMD_READ0;}/* Command latch cycle *//* 此处就是就是发送读命令的第一个周期1st Cycle的命令,即0x00,对应着上述步骤中的① */chip->cmd_ctrl(mtd, command & 0xff,NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);jz4780_nand_delay_after_command(nand, nand_info, command);if (column != -1 || page_addr != -1) {int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;/* Serially input address *//* 发送两个column列地址,对应着上述步骤中的② */if (column != -1) {chip->cmd_ctrl(mtd, column, ctrl);ctrl &= ~NAND_CTRL_CHANGE;chip->cmd_ctrl(mtd, column >> 8, ctrl);}if (page_addr != -1) {/* 接下来是发送三个Row,行地址,对应着上述步骤中的② */chip->cmd_ctrl(mtd, page_addr, ctrl);chip->cmd_ctrl(mtd, page_addr >> 8,NAND_NCE | NAND_ALE);/* One more address cycle for devices > 128MiB */if (chip->chipsize > (128 << 20))chip->cmd_ctrl(mtd, page_addr >> 16,NAND_NCE | NAND_ALE);}}jz4780_nand_delay_after_address(nand, nand_info, command);chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);switch (command) {。。。。。。。。。。。。。。。/******省略****/.。。。。。。。。。。。。。。。/* 接下来发送读命令的第二个周期2nd Cycle的命令,即0x30,对应着上述步骤中的④ */ case NAND_CMD_READ0:chip->cmd_ctrl(mtd, NAND_CMD_READSTART,NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd, NAND_CMD_NONE,NAND_NCE | NAND_CTRL_CHANGE);/* This applies to read commands */default:/** If we don't have access to the busy pin, we apply the given* command delay.*/if (!chip->dev_ready) {nand->udelay(chip->chip_delay);return;}}/** Apply this short delay always to ensure that we do wait tWB in* any case on any machine.*//* 此处是对应着④中的tWB的等待时间*/nand->ndelay(100);/* 接下来就是要等待一定的时间,使得Nand Flash硬件上准备好数据,以供你之后读取,即对应着步骤⑤ */ nand->nand_wait_ready(mtd);}/*还有一个步骤没有实现那就是步骤⑥了一点一点的把数据读出来*/nand_read_page_hwecc分析static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,uint8_t *buf, int oob_required, int page){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *p = buf;uint8_t *ecc_calc = chip->buffers->ecccalc;uint8_t *ecc_code = chip->buffers->ecccode;uint32_t *eccpos = chip->ecc.layout->eccpos;unsigned int max_bitflips = 0;for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {chip->ecc.hwctl(mtd, NAND_ECC_READ);chip->read_buf(mtd, p, eccsize);//这个函数必须有我们来实现chip->ecc.calculate(mtd, p, &ecc_calc[i]);}chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);for (i = 0; i < chip->ecc.total; i++)ecc_code[i] = chip->oob_poi[eccpos[i]];eccsteps = chip->ecc.steps;p = buf;for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {int stat;stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);if (stat < 0) {mtd->ecc_stats.failed++;} else {mtd->ecc_stats.corrected += stat;max_bitflips = max_t(unsigned int, max_bitflips, stat);}}return max_bitflips;}上面的 read_buf,就是真正的去读取数据的函数了,由于不同的Nand Flash controller 控制器所实现的方式不同,所以这个函数必须在你的 Nand Flash驱动中实现,即MTD 层,能帮我们实现的都实现了,不能实现的,那肯定是我们自己的事情了。。。

个人观点,有问题请斧正!!

转载请注明出处:/wang_zheng_kai

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。