注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之五  

2012-01-15 17:28:24|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之五

周日干活,是为了春节休息,不懂得休息的人就不懂得战斗。

nand_command这个函数按说应该好好讲讲,毕竟真正的命令在这里,但是这个要和具体的硬件相结合,手头又暂时没有,抄别人也没太大意思,大家如果有兴趣可以去看arm-linux东东之nand里面讲的,比我讲的好,其实我的这些博客好多的内容也是抄的人家的,呵呵,再次感谢一下。

不管怎么样,重点是要把知识和技术学会,这才是真正的王道。话不多说,接着向下讲nand_get_flash_type这个函数。

/* Read manufacturer and device IDs */

       *maf_id = chip->read_byte(mtd);

       dev_id = chip->read_byte(mtd);

 

       /* Try again to make sure, as some systems the bus-hold or other

        * interface concerns can cause random data which looks like a

        * possibly credible NAND flash to appear. If the two results do

        * not match, ignore the device completely.

        */

 

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

 

       /* Read manufacturer and device IDs */

 

       tmp_manf = chip->read_byte(mtd);

       tmp_id = chip->read_byte(mtd);

 

       if (tmp_manf != *maf_id || tmp_id != dev_id) {

              printk(KERN_INFO "%s: second ID read did not match "

                     "%02x,%02x against %02x,%02x\n", __func__,

                     *maf_id, dev_id, tmp_manf, tmp_id);

              return ERR_PTR(-ENODEV);

       }

命令发完了就可以读了.然后再发一次同样的命令.如果两次获得的ID不同就说明出错了.没用的NAND.

……………………….

       /* Lookup the flash id */

       for (i = 0; nand_flash_ids[i].name != NULL; i++) {

              if (dev_id == nand_flash_ids[i].id) {

                     type =  &nand_flash_ids[i];

                     break;

              }

       }

 

       if (!type)

              return ERR_PTR(-ENODEV);

 

       if (!mtd->name)

              mtd->name = type->name;

 

       chip->chipsize = type->chipsize << 20;

………………………………………

Nand_flash_id就是这些:

/*

*     Chip ID list

*

*     Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,

*     options

*

*     Pagesize; 0, 256, 512

*     0     get this information from the extended chip ID

+     256 256 Byte page size

*     512 512 Byte page size

*/

struct nand_flash_dev nand_flash_ids[] = {

 

#ifdef CONFIG_MTD_NAND_MUSEUM_IDS

       {"NAND 1MiB 5V 8-bit",             0x6e, 256, 1, 0x1000, 0},

       {"NAND 2MiB 5V 8-bit",             0x64, 256, 2, 0x1000, 0},

       {"NAND 4MiB 5V 8-bit",             0x6b, 512, 4, 0x2000, 0},

       {"NAND 1MiB 3,3V 8-bit",   0xe8, 256, 1, 0x1000, 0},

       {"NAND 1MiB 3,3V 8-bit",   0xec, 256, 1, 0x1000, 0},

       {"NAND 2MiB 3,3V 8-bit",   0xea, 256, 2, 0x1000, 0},

       {"NAND 4MiB 3,3V 8-bit",   0xd5, 512, 4, 0x2000, 0},

       {"NAND 4MiB 3,3V 8-bit",   0xe3, 512, 4, 0x2000, 0},

       {"NAND 4MiB 3,3V 8-bit",   0xe5, 512, 4, 0x2000, 0},

       {"NAND 8MiB 3,3V 8-bit",   0xd6, 512, 8, 0x2000, 0},

 

       {"NAND 8MiB 1,8V 8-bit",   0x39, 512, 8, 0x2000, 0},

       {"NAND 8MiB 3,3V 8-bit",   0xe6, 512, 8, 0x2000, 0},

       {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},

       {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},

#endif

 

       {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},

       {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},

       {"NAND 16MiB 1,8V 16-bit",      0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},

       {"NAND 16MiB 3,3V 16-bit",      0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},

 

       {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},

       {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},

       {"NAND 32MiB 1,8V 16-bit",      0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},

       {"NAND 32MiB 3,3V 16-bit",      0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},

 

       {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},

       {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},

       {"NAND 64MiB 1,8V 16-bit",      0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},

       {"NAND 64MiB 3,3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},

 

       {"NAND 128MiB 1,8V 8-bit",      0x78, 512, 128, 0x4000, 0},

       {"NAND 128MiB 1,8V 8-bit",      0x39, 512, 128, 0x4000, 0},

       {"NAND 128MiB 3,3V 8-bit",      0x79, 512, 128, 0x4000, 0},

       {"NAND 128MiB 1,8V 16-bit",    0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},

       {"NAND 128MiB 1,8V 16-bit",    0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},

       {"NAND 128MiB 3,3V 16-bit",    0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},

       {"NAND 128MiB 3,3V 16-bit",    0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},

 

       {"NAND 256MiB 3,3V 8-bit",      0x71, 512, 256, 0x4000, 0},

 

       /*

        * These are the new chips with large page size. The pagesize and the

        * erasesize is determined from the extended id bytes

        */

#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)

#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)

 

       /*512 Megabit */

       {"NAND 64MiB 1,8V 8-bit", 0xA2, 0,  64, 0, LP_OPTIONS},

       {"NAND 64MiB 3,3V 8-bit", 0xF2, 0,  64, 0, LP_OPTIONS},

       {"NAND 64MiB 1,8V 16-bit",      0xB2, 0,  64, 0, LP_OPTIONS16},

       {"NAND 64MiB 3,3V 16-bit",      0xC2, 0,  64, 0, LP_OPTIONS16},

 

       /* 1 Gigabit */

       {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, LP_OPTIONS},

       {"NAND 128MiB 3,3V 8-bit",      0xF1, 0, 128, 0, LP_OPTIONS},

       {"NAND 128MiB 1,8V 16-bit",    0xB1, 0, 128, 0, LP_OPTIONS16},

       {"NAND 128MiB 3,3V 16-bit",    0xC1, 0, 128, 0, LP_OPTIONS16},

 

       /* 2 Gigabit */

       {"NAND 256MiB 1,8V 8-bit",      0xAA, 0, 256, 0, LP_OPTIONS},

       {"NAND 256MiB 3,3V 8-bit",      0xDA, 0, 256, 0, LP_OPTIONS},

       {"NAND 256MiB 1,8V 16-bit",    0xBA, 0, 256, 0, LP_OPTIONS16},

       {"NAND 256MiB 3,3V 16-bit",    0xCA, 0, 256, 0, LP_OPTIONS16},

 

       /* 4 Gigabit */

       {"NAND 512MiB 1,8V 8-bit",      0xAC, 0, 512, 0, LP_OPTIONS},

       {"NAND 512MiB 3,3V 8-bit",      0xDC, 0, 512, 0, LP_OPTIONS},

       {"NAND 512MiB 1,8V 16-bit",    0xBC, 0, 512, 0, LP_OPTIONS16},

       {"NAND 512MiB 3,3V 16-bit",    0xCC, 0, 512, 0, LP_OPTIONS16},

 

       /* 8 Gigabit */

       {"NAND 1GiB 1,8V 8-bit",    0xA3, 0, 1024, 0, LP_OPTIONS},

       {"NAND 1GiB 3,3V 8-bit",    0xD3, 0, 1024, 0, LP_OPTIONS},

       {"NAND 1GiB 1,8V 16-bit",  0xB3, 0, 1024, 0, LP_OPTIONS16},

       {"NAND 1GiB 3,3V 16-bit",  0xC3, 0, 1024, 0, LP_OPTIONS16},

 

       /* 16 Gigabit */

       {"NAND 2GiB 1,8V 8-bit",    0xA5, 0, 2048, 0, LP_OPTIONS},

       {"NAND 2GiB 3,3V 8-bit",    0xD5, 0, 2048, 0, LP_OPTIONS},

       {"NAND 2GiB 1,8V 16-bit",  0xB5, 0, 2048, 0, LP_OPTIONS16},

       {"NAND 2GiB 3,3V 16-bit",  0xC5, 0, 2048, 0, LP_OPTIONS16},

 

       /*

        * Renesas AND 1 Gigabit. Those chips do not support extended id and

        * have a strange page/block layout !  The chosen minimum erasesize is

        * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page

        * planes 1 block = 2 pages, but due to plane arrangement the blocks

        * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would

        * increase the eraseblock size so we chose a combined one which can be

        * erased in one go There are more speed improvements for reads and

        * writes possible, but not implemented now

        */

       {"AND 128MiB 3,3V 8-bit",  0x01, 2048, 128, 0x4000,

        NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |

        BBT_AUTO_REFRESH

       },

 

       {NULL,}

};//这个新版本里更全了,比老的多多了厂商和类型

每一种类NAND在这里都有个表.如果在这里找不到属于你NAND的表就game over了

struct nand_flash_dev {

       char *name;

       int id;

       unsigned long pagesize;

       unsigned long chipsize;

       unsigned long erasesize;

       unsigned long options;

};来看一下上面这个结构体.pagesize 就是一页的大小.一般就是512.注意呀不是528.chipsize就是容量.64M的就是64.erasesize就是咱们前面说的块大小.NAND是以块为erase单位的.

Options 就是一些宏的组合.

{"AND 128MiB 3,3V 8-bit",  0x01, 2048, 128, 0x4000,

        NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |

        BBT_AUTO_REFRESH

       },

看到这个比较变态的NAND没有??属于options的宏都用上了.这里不说这个NAND,因为主流不是它.

chip->chipsize = type->chipsize << 20;

这句计算容量.1<<20就是1M.64<<20就是64M.

 

…………………………

f (!type->pagesize) {

              int extid;

              /* The 3rd id byte holds MLC / multichip data */

              chip->cellinfo = chip->read_byte(mtd);

              /* The 4th id byte is the important one */

              extid = chip->read_byte(mtd);

              /* Calc pagesize */

              mtd->writesize = 1024 << (extid & 0x3);

              extid >>= 2;

              /* Calc oobsize */

              mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);

              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 chip data hardcoded in the device id table

               */

              mtd->erasesize = type->erasesize;

              mtd->writesize = type->pagesize;

              mtd->oobsize = mtd->writesize / 32;

              busw = type->options & NAND_BUSWIDTH_16;

       }

………………………………………

Pagesize我们是有的.所以跳到else来了.

来说下这个:

mtd->oobsize = mtd->writesize / 32;

512/32就是16.就是上面说的C区.

 

for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {

              if (nand_manuf_ids[maf_idx].id == *maf_id)

                     break;

       }

 

/*

*     Manufacturer ID list

*/

struct nand_manufacturers nand_manuf_ids[] = {

       {NAND_MFR_TOSHIBA, "Toshiba"},

       {NAND_MFR_SAMSUNG, "Samsung"},

       {NAND_MFR_FUJITSU, "Fujitsu"},

       {NAND_MFR_NATIONAL, "National"},

       {NAND_MFR_RENESAS, "Renesas"},

       {NAND_MFR_STMICRO, "ST Micro"},

       {NAND_MFR_HYNIX, "Hynix"},

       {NAND_MFR_MICRON, "Micron"},

       {NAND_MFR_AMD, "AMD"},

       {0x0, "Unknown"}

};

这个没有问题.就是找厂商吗!!!!

       if (busw != (chip->options & NAND_BUSWIDTH_16)) {

              printk(KERN_INFO "NAND device: Manufacturer ID:"

                     " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,

                     dev_id, nand_manuf_ids[maf_idx].name, mtd->name);

              printk(KERN_WARNING "NAND bus width %d instead %d bit\n",

                     (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,

                     busw ? 16 : 8);

              return ERR_PTR(-EINVAL);

       }

 

       /* Calculate the address shift from the page size */

       chip->page_shift = ffs(mtd->writesize) - 1;

       /* Convert chipsize to number of pages per chip -1. */

       chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;

 

       chip->bbt_erase_shift = chip->phys_erase_shift =

              ffs(mtd->erasesize) - 1;

       chip->chip_shift = ffs(chip->chipsize) - 1;

 

       /* Set the bad block position */

       chip->badblockpos = mtd->writesize > 512 ?

              NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;

 

       /* Get chip options, preserve non chip based options */

       chip->options &= ~NAND_CHIPOPTIONS_MSK;

       chip->options |= type->options & NAND_CHIPOPTIONS_MSK;

………………………………………………….

Busw是传进来的参数.如果传进来的参数与表中的不一致就出错.

chip->page_shift = ffs(mtd->writesize) - 1;

后面会看到当给定一个32的地址.add>>chip->page_shift.因为NAND是页寻址的.512的页就是右移9位. Pagemask就是用来限制地址高位.64M的就只用17位有效地址所以高于17就mask了.chip_shift是用于多NAND中的.其他的我们用到的时候再说.好吧!!

……………………………

if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)

              chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;

 

       /* Check for AND chips with 4 page planes */

       if (chip->options & NAND_4PAGE_ARRAY)

              chip->erase_cmd = multi_erase_cmd;

       else

              chip->erase_cmd = single_erase_cmd;

 

       /* Do not replace user supplied command function ! */

       if (mtd->writesize > 512 && chip->cmdfunc == nand_command)

              chip->cmdfunc = nand_command_lp;

 

       printk(KERN_INFO "NAND device: Manufacturer ID:"

              " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,

              nand_manuf_ids[maf_idx].name, type->name);

 

       return type;

}

………………….

我们的erase_cmd是等于single_erase_cmd的;

好nand_get_flash_type就这样完了.

回到nand_scan_ident中来.

……………….

if (IS_ERR(type)) {

              printk(KERN_WARNING "No NAND device found!!!\n");

              chip->select_chip(mtd, -1);

              return PTR_ERR(type);

       }

 

       /* Check for a chip array */

       for (i = 1; i < maxchips; i++) {

              chip->select_chip(mtd, i);

              /* Send the command for reading device ID */

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

              /* Read manufacturer and device IDs */

              if (nand_maf_id != chip->read_byte(mtd) ||

                  type->id != chip->read_byte(mtd))

                     break;

       }

       if (i > 1)

              printk(KERN_INFO "%d NAND chips detected\n", i);

 

       /* Store the number of chips and calc total size for mtd */

       chip->numchips = i;

       mtd->size = i * chip->chipsize;

 

       return 0;

}

…………………..

这里maxchips是为1的.那个for不会执行的.不过多于一块的NAND也容易搞懂.

又回到了s3c24xx_nand_probe中了.

………………………………..

if (nmtd->scan_res == 0) {

                     s3c2410_nand_update_chip(info, nmtd);

                     nand_scan_tail(&nmtd->mtd);

                     s3c2410_nand_add_partition(info, nmtd, sets);

              }

下面还有几个函数,慢慢来,不要着急。

重要的学会知识,融会贯通,这才是学习的至真之境。

  评论这张
 
阅读(1210)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017