一、编写目的
在《NAND_FLASH(K9F1208U0C)驱动分析》一文中,通过分析AT91SAM9260EK开发板Bootstrap中的NAND驱动时,发现该代码为了优化代码体积(4KB限制),没有实现nand的擦写驱动,因此现重新对U-BOOT的代码的NAND驱动进行分析。以加强对NAND的理解。
本文档用于记录NAND FLASH驱动分析的过程。所使用的代码为以前开发过的一个U-BOOT(64MB版本)。
二、驱动分析
1. 驱动入口
U-BOOT的C语言入口位于./lib_arm/board.c的start_armboot()中。在该函数中有调用NAND的初始化函数nand_init()。
start_armboot()中的代码片段(./lib_arm/board.c) |
#if defined(CONFIG_CMD_NAND) puts ("NAND: "); nand_init(); /* go init the NAND */ #endif
#if defined(CONFIG_CMD_ONENAND) onenand_init(); #endif |
2. NAND相关的结构体
a) NAND设备参数描述表
./include/linux/mtd/nand_ids.h中的结构定义 |
static struct nand_flash_dev nand_flash_ids[] = { {"Toshiba TC5816BDC", NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000, 0}, {"Toshiba TC5832DC", NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000, 0}, {"Toshiba TH58V128DC", NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000, 0}, {"Toshiba TC58256FT/DC", NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000, 0}, {"Toshiba TH58512FT", NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000, 0}, {"Toshiba TC58V32DC", NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000, 0}, {"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000, 0}, {"Toshiba TC58V16BDC", NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000, 0}, {"Toshiba TH58100FT", NAND_MFR_TOSHIBA, 0x79, 27, 0, 3, 0x4000, 0}, {"Samsung KM29N16000", NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000, 0}, {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000, 0}, {"Samsung KM29U128T", NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000, 0}, {"Samsung KM29U256T", NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000, 0}, {"Samsung unknown 64Mb", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0}, // 本核心板使用的NAND {"Samsung KM29W32000", NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000, 0}, // NAND_MFR_SAMSUNG = 0xEC {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000, 0}, {"Samsung KM29U64000", NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000, 0}, {"Samsung KM29W16000", NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000, 0}, {"Samsung K9F5616Q0C", NAND_MFR_SAMSUNG, 0x45, 25, 0, 2, 0x4000, 1}, {"Samsung K9K1216Q0C", NAND_MFR_SAMSUNG, 0x46, 26, 0, 3, 0x4000, 1}, {"Samsung K9F1G08U0M", NAND_MFR_SAMSUNG, 0xf1, 27, 0, 2, 0, 0}, {NULL,} }; |
该表记录着UBOOT所支持的NAND型号列表,软件读取NAND的ID值后,与该表中的ID值(K9F1208U0C的ID等于0xEC76)进行比较,如ID相等,则说明UBOOT目前支持该NAND芯片,则从该表中获取NAND的信息(BLOCK SIZE、PAGE SIZE等)。
b) MTD设备信息结构体typedef struct mtd_info nand_info_t
./include/linux/mtd/mtd.h中的结构定义 |
struct mtd_info { u_char type; u_int32_t flags; u_int32_t size; /* Total size of the MTD */
/* "Major" erase size for the device. Na飗e users may take this * to be the only erase size available, or may use the more detailed * information below if they desire */ u_int32_t erasesize;
u_int32_t oobblock; /* Size of OOB blocks (e.g. 512) */ u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */ u_int32_t oobavail; /* Number of bytes in OOB area available for fs */ u_int32_t ecctype; u_int32_t eccsize;
/* Kernel-only stuff starts here. */ char *name; int index;
/* oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) */ struct nand_oobinfo oobinfo;
/* Data for variable erase regions. If numeraseregions is zero, * it means that the whole device has erasesize as given above. */ int numeraseregions; struct mtd_erase_region_info *eraseregions;
/* This really shouldn't be here. It can go away in 2.5 */ u_int32_t bank_size;
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */ int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */ void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_oob) (struct mtd_info *mtd, loff_t to, si |