分类: LINUX
2016-06-28 09:58:38
目录
插图清单
2.1. 2.2. 2.3. 2.4.目录
摘要
下面是Linux MTD中,获取nand flash型号,各个参数,以及硬件特性的函数,其实也就是nand_get_flash_type,下面对其详细解析:
此处的编程,不是写软件,写代码,而是对于硬件来说的,可以理解为对硬件编程,只不过其工具是硬件内部的逻辑,而不是你用的软件。对Nand Flash的编程,本质上就是实现写操作,将数据写到Nand Flash里面去,所以对于nand flash,可以简单的理解为 program编程=write写(数据)。
1.2. Datasheet(数据手册)
这个词,本来没啥好说的,接触多了,自然就知道了。但是对于和我类似,最开始接触的时候,就是没搞懂这个词的具体含义。其中文翻译,一般称作,数据手册,意思就是,一个关于描述硬件各个硬件特性,参数以及/或者如何操作,如何使用的文档。
1.3. Erasesize / Writesize
这个是Linux MTD中,关于块大小和页大小的别名,第一次见到的时候,把我搞糊涂了,后来才慢慢明白的。因为,nand 操作的写基本单位页,所以,writesize,对应的就是pagesize,页大小。而擦除操作的基本单位是blocksize,块大小,所以也叫它erasesize。在此简单提一下这几个名词,方便和我遇到类似问题的朋友。
1.4. Spare Area / Redundant Area / OOB
nand flash中每一页对应一块区域,用于存放校验的ECC数据和其他一些信息,比如上层文件系统放的和自己文件系统相关的数据。这个区域,在Linux MTD相关系统中,被称作oob(out of band),可以翻译为带外,也就是nand flash的一个页,可以称作一个band,band之外,对应的就是指那个多出来的,特殊的区域了。而nand flash的datasheet中,一般成为spare area,可译为空闲区域,另外,在ID的含义解释中也叫做redundant area,可译为冗余区域,归根结底,都是一个含义。不要被搞糊涂了就好。
1.5. Page Register(页寄存器)
nand flash硬件中的一块地方,名字叫做register,实际就是一个数据缓存,一个buffer,用于存放那些从flash读出来或者将要写入到flash中的。其实叫做页缓存,更合适,更容易明白其含义。此页寄存器的大小=页大小+ oob 大小,即pagesize+oob,对于常见的页是2KB的,此页寄存器就是2KB+64=2112字节。
1.6. Chip和Plane
对于chip,其实任何某个型号的flash,都可以称其是一个chip,但是实际上,此处的chip,是针对内部来说的,也就是某型号的flash,内部有几个chip,比如下面会举例说到的,三星的2GB的K9WAG08U1A芯片(可以理解为外部芯片/型号)内部装了2个单片是1GB的K9K8G08U0A,此时就称 K9WAG08U1A内部有2个chip,而有些单个的chip,内部又包含多个plane,比如上面的K9K8G08U0A内部包含4个单片是2Gb的Plane。只有搞清楚了此处的chip和plane的关系,才能明白后面提到的多页(Multi Plane / Multi Page)编程和交互(interleave)编程的含义。
第 2 章 代码详细解析
目录
摘要
详细代码可以在这里找到:linux/drivers/mtd/nand/nand_base.c2407/*
2408 * Get the flash and manufacturer id and lookup if the type is supported
2409 */
2410static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2411 struct nand_chip *chip,
2412 int busw, int *maf_id)
2413{
2414 struct nand_flash_dev *type = NULL;
2415 int i, dev_id, maf_idx;
2416 int tmp_id, tmp_manf;
2417
2418 /* Select the device */
2419 chip->select_chip(mtd, 0);
2420
2421 /*
2422 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
2423 * after power-up
2424 */
2425 chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
2426
2427 /* Send the command for reading device ID */
2428 chip->cmdfunc(mtd, NAND_CMD_READID
, 0x00, -1);
2429
2430 /* Read manufacturer and device IDs */
2431 *maf_id = chip->read_byte(mtd);
2432 dev_id = chip->read_byte(mtd);
2433
2434 /* Try again to make sure, as some systems the bus-hold or other
2435 * interface concerns can cause random data which looks like a
2436 * possibly credible NAND flash to appear. If the two results do
2437 * not match, ignore the device completely.
2438 */
2439
2440 chip->cmdfunc(mtd, NAND_CMD_READID
, 0x00, -1);
2441
2442 /* Read manufacturer and device IDs */
2443
2444 tmp_manf = chip->read_byte(mtd);
2445 tmp_id = chip->read_byte(mtd);
2446
2447 if (tmp_manf != *maf_id || tmp_id != dev_id) {
2448 printk(KERN_INFO "%s: second ID read did not match "
2449 "%02x,%02x against %02x,%02x\n", __func__,
2450 *maf_id, dev_id, tmp_manf, tmp_id);
2451 return ERR_PTR(-ENODEV);
2452 }
2453
2454 /* Lookup the flash id */
2455 for (i = 0; nand_flash_ids
[i].name != NULL; i++) {
2456 if (dev_id == nand_flash_ids[i].id) {
2457 type = &nand_flash_ids[i];
2458 break;
2459 }
2460 }
2461
2462 if (!type)
2463 return ERR_PTR(-ENODEV);
2464
2465 if (!mtd->name)
2466 mtd->name = type->name;
2467
2468 chip->chipsize = (uint64_t)type->chipsize << 20
;
2469
2470 /* Newer devices have all the information in additional id bytes */
2471 if (!type->pagesize) {
2472 int extid;
2473 /* The 3rd id byte holds MLC / multichip data */
2474 chip->cellinfo
= chip->read_byte(mtd);
2475 /* The 4th id byte is the important one */
2476 extid = chip->read_byte(mtd);
2477 /* Calc pagesize */
2478 mtd->writesize = 1024 << (extid & 0x3);
2479 extid >>= 2;
2480 /* Calc oobsize */
2481 mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
2482 extid >>= 2;
2483 /* Calc blocksize. Blocksize is multiples of 64KiB */
2484 mtd->erasesize = (64 * 1024) << (extid & 0x03);
2485 extid >>= 2;
2486 /* Get buswidth information */
2487 busw = (extid & 0x01) ? NAND_BUSWIDTH_16
: 0;
2488
2489 } else {
2490 /*
2491 * Old devices have chip data hardcoded in the device id table
2492 */
2493 mtd->erasesize = type->erasesize;
2494 mtd->writesize = type->pagesize;
2495 mtd->oobsize = mtd->writesize / 32;
2496 busw = type->options & NAND_BUSWIDTH_16;
2497 }
2498
2499 /* Try to identify manufacturer */
2500 for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
2501 if (nand_manuf_ids[maf_idx].id == *maf_id)
2502 break;
2503 }
2504
2505 /*
2506 * Check, if buswidth is correct. Hardware drivers should set
2507 * chip correct !
2508 */
2509 if (busw != (chip->options & NAND_BUSWIDTH_16)) {
2510 printk(KERN_INFO "NAND device: Manufacturer ID:"
2511 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
2512 dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
2513 printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
2514 (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
2515 busw ? 16 : 8);
2516 return ERR_PTR(-EINVAL);
2517 }
2518
2519 /* Calculate the address shift from the page size */
2520 chip->page_shift
= ffs(mtd->writesize) - 1;
2521 /* Convert chipsize to number of pages per chip -1. */
2522 chip->pagemask
= (chip->chipsize >> chip->page_shift) - 1;
2523
2524 chip->bbt_erase_shift = chip->phys_erase_shift =
2525 ffs(mtd->erasesize) - 1;
2526 if (chip->chipsize & 0xffffffff)
2527 chip->chip_shift =
ffs((unsigned)chip->chipsize) - 1;
2528 else
2529 chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;
2530
2531 /* Set the bad block position */
2532 chip->badblockpos = mtd->writesize > 512 ?
2533 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
2534
2535 /* Get chip options, preserve non chip based options */
2536 chip->options &= ~NAND_CHIPOPTIONS_MSK;
2537 chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
2538
2539 /*
2540 * Set chip as a default. Board drivers can override it, if necessary
2541 */
2542 chip->options |= NAND_NO_AUTOINCR;
2543
2544 /* Check if chip is a not a samsung device. Do not clear the
2545 * options for chips which are not having an extended id.
2546 */
2547 if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
2548 chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
2549
2550 /* Check for AND chips with 4 page planes */
2551 if (chip->options & NAND_4PAGE_ARRAY)
2552 chip->erase_cmd = multi_erase_cmd;
2553 else
2554 chip->erase_cmd = single_erase_cmd;
2555
2556 /* Do not replace user supplied command function ! */
2557 if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
2558 chip->cmdfunc = nand_command_lp;
2559
2560 printk
(KERN_INFO "NAND device: Manufacturer ID:"
2561 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
2562 nand_manuf_ids[maf_idx].name, type->name);
2563
2564 return type;
2565}