uboot nand flash 启动 流程
1、initr_nand
首先在board_r.c中,initr_nand函数正式进入nand flash的初始化等操作。
static int initr_nand(void)
{
puts("NAND: ");
nand_init();
return 0;
}
2、nand_init
之后进入nand_init函数,该函数位于drivers\mtd\nand文件中的nand.c文件中,由于CONFIG_SYS_NAND_SELF_INIT未定义,所以后续调用nand_init_chip函数。
void nand_init(void)
{
#ifdef CONFIG_SYS_NAND_SELF_INIT//未定义
board_nand_init();
#else
int i;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)//初始化板上nand flash
nand_init_chip(i);
#endif
printf("%lu MiB\n", total_nand_size / 1024);
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
/*
* Select the chip in the board/cpu specific driver
*/
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}
3、nand_init_chip
而nand_init_chip同样位于drivers\mtd\nand文件中的nand.c文件中,该函数调用初始化函数,给mtd和nand两个结构体赋值,首先调用board_nand_init函数
#ifndef CONFIG_SYS_NAND_SELF_INIT
static void nand_init_chip(int i)
{
struct mtd_info *mtd = &nand_info[i];//该结构体位于\include\linux\mtd文件中的mtd.h文件中
struct nand_chip *nand = &nand_chip[i];//该结构体位于\include\linux\mtd文件中的nand.h文件中
ulong base_addr = base_address[i];
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
if (maxchips < 1)
maxchips = 1;
mtd->priv = nand;
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
if (board_nand_init(nand))
return;
if (nand_scan(mtd, maxchips))
return;
nand_register(i);
}
#endif
4.1、board_nand_init
函数主要初始化开发板相关与nand_flash的寄存器,和绑定nand_chip结构体中的调用函数,由于不同开发板调用函数不同,所以该函数内部赋值会不一样,本次使用的是NXP MX6ULL开发板,调用的是mxs_nand.c中的函数,其中关于带有ECC的读写函数和ECC的模式,**这里使用的是硬件自带ECC,每512字节需要9字节的ECC数据,最大可纠正8bit数据。**而不同的flash,会规定不同的nand flash ECC,这里规定每最少需要纠正4bit数据,需要用512Byte数据+4Byte备用数据和8字节奇偶校验数据。所以uboot中的ECC符合nand flash 最低ECC 标准。
int board_nand_init(struct nand_chip *nand)
{
struct mxs_nand_info *nand_info;
int err;
nand_info = malloc(sizeof(struct mxs_nand_info));
if (!nand_info) {
printf("MXS NAND: Failed to allocate private data\n");
return -ENOMEM;
}
memset(nand_info, 0, sizeof(struct mxs_nand_info));
err = mxs_nand_alloc_buffers(nand_info);
if (err)
goto err1;
err = mxs_nand_init(nand_info);
if (err)
goto err2;
memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout));
nand->priv = nand_info;
nand->options |= NAND_NO_SUBPAGE_WRITE;
nand->cmd_ctrl = mxs_nand_cmd_ctrl;
nand->dev_ready = mxs_nand_device_ready;
nand->select_chip = mxs_nand_select_chip;
nand->block_bad = mxs_nand_block_bad;
nand->scan_bbt = mxs_nand_scan_bbt;
nand->read_byte = mxs_nand_read_byte;
nand->read_buf = mxs_nand_read_buf;
nand->write_buf = mxs_nand_write_buf;
nand->ecc.read_page = mxs_nand_ecc_read_page;
nand->ecc.write_page = mxs_nand_ecc_write_page;
nand->ecc.read_oob = mxs_nand_ecc_read_oob;
nand->ecc.write_oob = mxs_nand_ecc_write_oob;
nand->ecc.layout = &fake_ecc_layout;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.bytes = 9;
nand->ecc.size = 512;
nand->ecc.strength = 8;
return 0;
err2:
free(nand_info->data_buf);
free(nand_info->cmd_buf);
err1:
free(nand_info);
return err;
}
4.1.1 mxs_nand_init
其中mxs_nand_init主要配置nand flash相关的硬件寄存器,GMPI和BCH寄存器。