转自http://blog.csdn.net/wang_zheng_kai/article/details/19039273
六、驱动层之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_tsize_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)) {
-
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
- sndcmd = 0;
- }
-
- 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
-
-
- ret = chip->ecc.read_page(mtd, chip, bufpoi,page);
- if (ret < 0)
- break;
-
- 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函数中可以知道
-
- 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;
-
-
- if (command == NAND_CMD_READOOB) {
- column += mtd->writesize;
- command = NAND_CMD_READ0;
- }
-
-
-
- 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;
-
-
-
-
- if (column != -1) {
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
- if (page_addr != -1) {
-
- chip->cmd_ctrl(mtd, page_addr, ctrl);
- chip->cmd_ctrl(mtd, page_addr >> 8,
- NAND_NCE | NAND_ALE);
-
- 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) {
- 。。。。。。。。。。。。。。。
-
- .。。。。。。。。。。。。。。。
-
-
-
-
-
- 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);
-
- default:
-
-
-
-
- if (!chip->dev_ready) {
- nand->udelay(chip->chip_delay);
- return;
- }
- }
-
-
-
-
-
- nand->ndelay(100);
-
-
- 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 层,能帮我们实现的都实现了,不能实现的,那肯定是我们自己的事情了。。。
0 0