Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2968983
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-10-27 12:50:48

原文地址: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联系起来了。


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

  1. 读分析  
  2.   
  3. MTD 读取数据的入口是 nand_read,然后调用 nand_do_read_ops,此函数主体如下:  
  4.   
  5. 《一》nand_read代码如下:  
  6. static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,  
  7.                      size_tsize_t *retlen, uint8_t *buf)  
  8.   
  9. {  
  10.         struct mtd_oob_ops ops;  
  11.         int ret;  
  12.   
  13.         nand_get_device(mtd, FL_READING);  
  14.         ops.len = len;  
  15.         ops.datbuf = buf;  
  16.         ops.oobbuf = NULL;  
  17.         ops.mode = MTD_OPS_PLACE_OOB;  
  18.         ret = nand_do_read_ops(mtd, from, &ops);  
  19.         *retlen = ops.retlen;  
  20.         nand_release_device(mtd);  
  21.         return ret;  
  22. }  
  23.   
  24. 《二》nand_do_read_ops代码如下:  
  25. static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  
  26. struct mtd_oob_ops *ops)  
  27. {  
  28. /******省略****/  
  29. 。。。。。。。。。。。。。。  
  30. while(1) {  
  31. /******省略****/  
  32. .。。。。。。。。。。。。。。。  
  33. if (likely(sndcmd)) {/*#define NAND_CMD_READ0 0*/  
  34. /*1)***读取数据前肯定要先发送对应的读页命令******/  
  35. chip->cmdfunc(mtd, NAND_CMD_READ00x00, page);  
  36. sndcmd = 0;  
  37. }  
  38. /* Now read the page into the buffer */  
  39. if (unlikely(ops->mode == MTD_OOB_RAW))  
  40. ret = chip->ecc.read_page_raw(mtd, chip,bufpoi, page);  
  41. else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)  
  42. ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);  
  43. else  
  44.   
  45. /******执行到这里read_page函数读取对应的数据了******/  
  46. ret = chip->ecc.read_page(mtd, chip, bufpoi,page);  
  47. if (ret < 0)  
  48. break;  
  49. /* Transfer not aligned data */  
  50. if (!aligned) {  
  51. if (!NAND_SUBPAGE_READ(chip) && !oob)  
  52. chip->pagebuf = realpage;  
  53. memcpy(buf, chip->buffers->databuf + col, bytes);  
  54. }  
  55. buf += bytes;  
  56. 。。。。。。。。。。。。。。。。。。  
  57.   
  58. if (mtd->ecc_stats.failed - stats.failed)  
  59. return -EBADMSG;  
  60. return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;  
  61. }  
  62.   
  63. 上面这些代码都不需要我们去实现的,使用MTD层的自定义代码就行。下面将要分析chip->cmdfunc,我们从probe函数中可以知道  
  64. /* step3. replace NAND command function with large page version */  
  65.         if (mtd->writesize > 512)  
  66.                 chip->cmdfunc = jz4780_nand_command_lp;  
  67.   
  68. jz4780_nand_command_lp的分析  
  69. static void jz4780_nand_command_lp(struct mtd_info *mtd,  
  70.                 unsigned int command, int column, int page_addr)  
  71. {  
  72.         register struct nand_chip *chip = mtd->priv;  
  73.   
  74.         struct jz4780_nand *nand;  
  75.         nand_flash_if_t *nand_if;  
  76.         nand_flash_info_t *nand_info;  
  77.         nand = mtd_to_jz4780_nand(mtd);  
  78.         nand_if = nand->nand_flash_if_table[nand->curr_nand_flash_if];  
  79.         nand_if->curr_command = command;  
  80.         nand_info = nand->curr_nand_flash_info;  
  81.   
  82.         /* Emulate NAND_CMD_READOOB */  
  83.         if (command == NAND_CMD_READOOB) {  
  84.                 column += mtd->writesize;  
  85.                 command = NAND_CMD_READ0;  
  86.         }  
  87.         /* Command latch cycle */  
  88.     /* 此处就是就是发送读命令的第一个周期1st Cycle的命令,即0x00, 对应着上述步骤中的① */  
  89.   
  90.         chip->cmd_ctrl(mtd, command & 0xff,  
  91.                        NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);  
  92.   
  93.         jz4780_nand_delay_after_command(nand, nand_info, command);  
  94.   
  95.         if (column != -1 || page_addr != -1) {  
  96.                 int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;  
  97.   
  98.                 /* Serially input address */  
  99.                 /* 发送两个column列地址,对应着上述步骤中的② */  
  100.   
  101.                 if (column != -1) {  
  102.                         chip->cmd_ctrl(mtd, column, ctrl);  
  103.                         ctrl &= ~NAND_CTRL_CHANGE;  
  104.                         chip->cmd_ctrl(mtd, column >> 8, ctrl);  
  105.                 }  
  106.                 if (page_addr != -1) {  
  107.         /* 接下来是发送三个Row,行地址,对应着上述步骤中的② */  
  108.                         chip->cmd_ctrl(mtd, page_addr, ctrl);  
  109.                         chip->cmd_ctrl(mtd, page_addr >> 8,  
  110.                                       NAND_NCE | NAND_ALE);  
  111.                         /* One more address cycle for devices > 128MiB */  
  112.                         if (chip->chipsize > (128 << 20))  
  113.                                 chip->cmd_ctrl(mtd, page_addr >> 16,  
  114.                                                NAND_NCE | NAND_ALE);  
  115.                 }  
  116.         }  
  117.         jz4780_nand_delay_after_address(nand, nand_info, command);  
  118.         chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  
  119.   
  120.  switch (command) {  
  121. 。。。。。。。。。。。。。。。  
  122.         /******省略****/  
  123. .。。。。。。。。。。。。。。。  
  124.   
  125.   
  126.   
  127.   
  128.     /* 接下来发送读命令的第二个周期2nd Cycle的命令,即0x30,对应着 上述步骤中的④ */   
  129.         case NAND_CMD_READ0:  
  130.                 chip->cmd_ctrl(mtd, NAND_CMD_READSTART,  
  131.                                NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);  
  132.                 chip->cmd_ctrl(mtd, NAND_CMD_NONE,  
  133.                                NAND_NCE | NAND_CTRL_CHANGE);  
  134.                 /* This applies to read commands */  
  135.         default:  
  136.                 /* 
  137.                  * If we don't have access to the busy pin, we apply the given 
  138.                  * command delay. 
  139.                  */  
  140.                 if (!chip->dev_ready) {  
  141.                         nand->udelay(chip->chip_delay);  
  142.                         return;  
  143.                 }  
  144.         }  
  145.         /* 
  146.          * Apply this short delay always to ensure that we do wait tWB in 
  147.          * any case on any machine. 
  148.          */  
  149.        /* 此处是对应着④中的tWB的等待时间*/  
  150.         nand->ndelay(100);  
  151.   
  152. /* 接下来就是要等待一定的时间,使得Nand Flash硬件上准备好数据,以供你之后读取,即对应着步骤⑤ */   
  153.         nand->nand_wait_ready(mtd);  
  154. }  
  155.   
  156.   
  157.   
  158.   
  159.   
  160.   
  161.   
  162.   
  163.   
  164.   
  165.   
  166.   
  167.   
  168.   
  169.   
  170.   
  171. /*还有一个步骤没有实现那就是步骤⑥了一点一点的把数据读出来*/  
  172. nand_read_page_hwecc分析  
  173. static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  
  174.                                 uint8_t *buf, int oob_required, int page)  
  175.   
  176. {  
  177.   
  178.         int i, eccsize = chip->ecc.size;  
  179.         int eccbytes = chip->ecc.bytes;  
  180.         int eccsteps = chip->ecc.steps;  
  181.         uint8_t *p = buf;  
  182.         uint8_t *ecc_calc = chip->buffers->ecccalc;  
  183.         uint8_t *ecc_code = chip->buffers->ecccode;  
  184.         uint32_t *eccpos = chip->ecc.layout->eccpos;  
  185.         unsigned int max_bitflips = 0;  
  186.   
  187.         for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
  188.                 chip->ecc.hwctl(mtd, NAND_ECC_READ);  
  189.                 chip->read_buf(mtd, p, eccsize);//这个函数必须有我们来实现  
  190.                 chip->ecc.calculate(mtd, p, &ecc_calc[i]);  
  191.         }  
  192.         chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);  
  193.         for (i = 0; i < chip->ecc.total; i++)  
  194.                 ecc_code[i] = chip->oob_poi[eccpos[i]];  
  195.         eccsteps = chip->ecc.steps;  
  196.         p = buf;  
  197.         for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
  198.                 int stat;  
  199.                 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);  
  200.                 if (stat < 0) {  
  201.                         mtd->ecc_stats.failed++;  
  202.                 } else {  
  203.                         mtd->ecc_stats.corrected += stat;  
  204.                         max_bitflips = max_t(unsigned int, max_bitflips, stat);  
  205.                 }  
  206.         }  
  207.         return max_bitflips;  
  208. }  
  209. 上面的 read_buf,就是真正的去读取数据的函数了,由于不同的Nand Flash controller 控制器所实现的方式不同,所以这个函数必须在你的 Nand Flash驱动中实现,即MTD 层,能帮我们实现的都实现了,不能实现的,那肯定是我们自己的事情了。。。  

阅读(1172) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~