nand_init()函数其实现过程与内核nand驱动大致差不多,涉及到的结构体有pxa3xx_nand,此结构体包含mtd_info,mtd_info结构体在注册进mtd子系统时需要用到
比较重要的结构体还有nand_chip,这个结构体实现对nand操作的基本方法。应该提供:选中,发命令,发地址,发数据,读数据,判断状态的功能
void nand_init()
{
struct pxa3xx_nand_platform_data pxa_nandinfo;
struct pxa3xx_nand *nand; //具体哪类型芯片如下:
int chip;
pxa_nandinfo.mmio_base = CONFIG_SYS_NAND_BASE;
pxa_nandinfo.enable_arbiter = 1;
pxa_nandinfo.RD_CNT_DEL = 0;
nand = pxa3xx_nand_probe(&pxa_nandinfo);
if (!nand) {
printf("pxa3xx-nand probe failed!!\n");
return;
}
for (chip = 0; chip < CONFIG_SYS_MAX_NAND_DEVICE; chip ++) {
if (nand->mtd[chip]) {
memcpy(&(nand_info[chip]), nand->mtd[chip], sizeof(struct mtd_info));
if (nand_curr_device < 0)
nand_curr_device = chip;
}
}
if (nand_curr_device < 0)
printf("No NAND dev is found !!!\n\n");
}
此处的probe与内核层的probe功能差不多,即实现nand的初始化和基本操作函数。
struct pxa3xx_nand *pxa3xx_nand_probe(struct pxa3xx_nand_platform_data *pdata)
{
struct pxa3xx_nand *nand;
struct pxa3xx_bbm *bbm;
struct mtd_info *mtd;
int i;
nand = alloc_nand_resource(pdata); //分配一个nand资源
if (!nand)
return NULL;
//对分配的nand结构体资源进行初始化
nand->enable_arbiter = pdata->enable_arbiter;
nand->RD_CNT_DEL = pdata->RD_CNT_DEL;
//通过id号找到具体的nand设备
pxa3xx_nand_detect_flash(nand);
//
for (i = 0; i < NUM_CHIP_SELECT; i ++) {
mtd = nand->mtd[i];
if (mtd) {
bbm = mtd->bbm;
pxa3xx_nand_init_mtd(mtd); //重要:对nand_chip结构体进行赋值,包括对nand的基本操作如选中,发命令,发地址,发数据,读数据,判断状态的功能,
if (pxa3xx_nand_scan(mtd)) { //对mtd和chip最后进行初始化
printf("failed to scan nand\n");
}
mtd->name = mtd_names[i];
#ifdef CONFIG_CMD_UBI
add_mtd_device(mtd); //添加设备
#endif
}
}
下面函数中的f取值是具体支持的flash各参数指标。如
static struct pxa3xx_nand_flash esmt1G81A = {
.timing = &esmt_timing,
.cmdset = &largepage_cmdset,
.name = “ESMT F59L1G81A”,
.page_per_block = 64,
.page_size = 2048,
.flash_width = 8,
.dfc_width = 8,
.num_blocks = 1024,
.chip_id = 0xf192,
.chip_id_mask = 0xffff,
.ecc_type = ECC_BCH,
.ecc_strength = 1,
};
static int pxa3xx_nand_detect_flash(struct pxa3xx_nand *nand)
{
struct pxa3xx_nand_flash *f;
struct nand_chip *chip;
struct pxa3xx_nand_info *info;
struct mtd_info *mtd;
uint32_t id = -1;
int i, ret, chip_select;
f = builtin_flash_types[0]; //取出一个支持的具体设备并给f赋初值
chip_select = 0;
for (; chip_select < NUM_CHIP_SELECT; chip_select ++) {
mtd = nand->mtd[chip_select];
chip = mtd->priv;
info = mtd->priv;
ret = pxa3xx_nand_sensing(info, chip_select); //对nand控制器的寄存器进行赋值并复位
if (!ret) {
free (nand->mtd[chip_select]);
nand->mtd[chip_select] = NULL;
continue;
}
pxa3xx_nand_cmdfunc(mtd, NAND_CMD_READID, 0, 0); //读取ID操作
id = *((uint32_t *)(info->data_buff));
if (id == 0) {
kfree(mtd);
nand->mtd[chip_select] = NULL;
continue;
}
for (i = 1; i < ARRAY_SIZE(builtin_flash_types); i++) {
f = builtin_flash_types[i];
/* find the chip in default list */
if (f->chip_id == (id & f->chip_id_mask)) { //查找是否支持此id类型设备。若支持则对mtd进行赋值初始化。
// printf("detect chip id 0x%x on cs %d, %s\n",
// f->chip_id, chip_select, f->name);
pxa3xx_nand_config_flash(info, f, 1);
chip->cellinfo = info->data_buff[2];
mtd->writesize = f->page_size;
mtd->oobsize = mtd->writesize / 32;
mtd->erasesize = f->page_size * f->page_per_block;
if (is_power_of_2(mtd->erasesize))
mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
else
mtd->erasesize_shift = 0;
if (is_power_of_2(mtd->writesize))
mtd->writesize_shift = ffs(mtd->writesize) - 1;
else
mtd->writesize_shift = 0;
mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
break;
}
}
if (i == ARRAY_SIZE(builtin_flash_types)) {
kfree(mtd);
nand->mtd[chip_select] = NULL;
printf("ERROR!! flash on cs %d id %x not defined!!!\n",
chip_select, id);
continue;
}
}
return 0;
}
具体函数调用关系如下:
nand_init()–>pxa3xx_nand_probe(&pxa_nandinfo)
–>pxa3xx_nand_detect_flash(nand)
–>pxa3xx_nand_sensing(info, chip_select)
–>pxa3xx_nand_cmdfunc(mtd, NAND_CMD_READID, 0, 0)
–>pxa3xx_nand_init_mtd(mtd)
–>pxa3xx_nand_scan(mtd)
–>nand_scan_tail(mtd)
–>add_mtd_device(mtd)