6. 第 2 章 代码详细解析
详细代码可以在这里找到:linux/drivers/mtd/nand/nand_base.c
2.1. 解析函数nand_get_flash_type
2407/*
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,%02xn", __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) {
2
7. 代码详细解析
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
}
}
type = &nand_flash_ids[i];
break;
if (!type)
return ERR_PTR(-ENODEV);
if (!mtd->name)
mtd->name = type->name;
chip->chipsize = (uint64_t)type->chipsize << 20 ;
/* Newer devices have all the information in additional id bytes */
if (!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;
}
/* Try to identify manufacturer */
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct !
*/
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 bitn",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
3
8. 代码详细解析
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565}
}
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;
if (chip->chipsize & 0xffffffff)
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
else
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 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;
/*
* Set chip as a default. Board drivers can override it, if necessary
*/
chip->options |= NAND_NO_AUTOINCR;
/* Check if chip is a not a samsung device. Do not clear the
* options for chips which are not having an extended id.
*/
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;
选中芯片,才能对其操作。
发送ReadID的命令:0x90,去取得芯片的ID信息
根据datasheet中的定义,第一个字节,简称byte1,是生产厂商的信息,不同的厂商,对应不同
的数字。而byte2是芯片类型,不同的nand flash芯片,对应不同的设备ID,也就是一个字节的数
字。
4
10. 代码详细解析
* @pagesize: Pagesize in bytes. Either 256 or 512 or 0
* If the pagesize is 0, then the real pagesize
* and the eraseize are determined from the
* extended id bytes in the chip
* @erasesize: Size of an erase block in the flash device.
* @chipsize: Total chipsize in Mega Bytes
* @options: Bitfield to store chip relevant options
*/
struct nand_flash_dev {
char *name;
int id;
unsigned long pagesize;
unsigned long chipsize;
unsigned long erasesize;
unsigned long options;
};
在结构体数组nand_flash_ids[]中,预先定义了,目前所支持的很多类型Nand Flash的具体物理参
数,主要是上面结构体中的页大小pagesize,芯片大小chipsize,块大小erasesize,而id变量表
示此类型的芯片,用哪个数字来表示。
此处通过刚读取到的设备ID,去和预先定义好的那个结构体数组nand_flash_ids[]中的每一个ID去
比较,如果相等,那么说明支持此款nand falsh,而其他的信息,就可以直接从后面几项中直接获
得了。
当pagesize为0的时候
如果pagesize是0,那么说明关于pagesize和其他一些信息,要通过读取额外的ID来
获得,这也就是待会下面要详细解释的。
而对于旧的一些nand flash,在表项中其pagesize不是0,就可以直接可以从上面的预定义的表里
面获得了。
比如,对于常见的三星的型号为K9K8G08U0A的nand flash,其设备号是0xD3,找到匹配的表项
就是:
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
因此也就知道,其容量是1024MB,设备相关物理特性是1GiB 3,3V 8-bit了。
而关于pagesize和块大小erasesize此处都是0,就只能另外从后面读取的ID中获得了。
10
此处由于上面表中的chipsize是MB=2 Bytes为单位的,所以要左移20位,换算成byte单位
解释下面代码第三个字节之前,要先把图标帖出来,才更容易看得懂具体的解释:
6