分类: 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}