Chinaunix首页 | 论坛 | 博客
  • 博客访问: 332693
  • 博文数量: 125
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 160
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-06 15:18
文章分类

全部博文(125)

文章存档

2014年(29)

2013年(93)

2012年(3)

分类: LINUX

2013-03-21 23:58:11

Arm-linux东东之5: 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就是这些:

struct nand_flash_dev nand_flash_ids[] = {

…………………

 

       {"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},

/*

        * 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;

       }

 

…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位有效地址所以高于17mask.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);

              }

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

只余三个函数了.不过千万不要小看这三个函数.个个都他妈的难.

 

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