u-boot nand flash驱动架构分析一
2012-06-03 00:34
477 查看
在移植nand flash驱动之前,我们要先熟悉u-boot中nand flash驱动架构以及nand flash操作原理。
在u-boot启动过程中调用了nand_init函数,这就是nand flash驱动初始化的入口点。
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
我们看,这个函数被调用的前提条件是CONFIG_CMD_NAND宏被定义,所以如果你要操作nand flash,这个宏一定要在配置文件中被定义,我们先记在这里。进入nand_init函数中。
void nand_init(void)
{
int i;
unsigned int size = 0;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
size += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = i;
}
printf("%u MiB\n", 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
}
一个for循环,这里又有一个宏CONFIG_SYS_MAX_NAND_DEVICE,表示有几个nand flash设备,mini2440中只有一片nand flash,所以你需要在配置文件中定义这个宏为1。在进入nand_init_chip函数之前我们先将nand_init函数看完,首先计算出nand flash设备总大小,nand_curr_device表示当前nand flash设备编号,初始值为-1,由于我们这里只有一个nand flash设备,所以这个值应该用于为0才对。for循环结束之后打印出nand
flash设备总的大小。你如果没有定义CONFIG_SYS_NAND_SELECT_DEVICE这个宏,那么这个函数也就结束了,nand flash也就初始化完成了。
进入nand_init_chip函数中。
在看这个函数之前,我们要看传递给这个函数的三个参数,nand_info、nand_chip和base_address。这三个参数它们都是定义在nand.c中的三个全局变量,用于保存nand flash的相关信息,这就是初始化要的关键。nand_info主要和芯片本身相关,比如记录nand flash的大小等等。nand_chip这个结构主要记录nand flash它的操作相关,比如read、wirte等等。而base_address是记录的nand
flash主控制器的寄存器基地址。它是这样定义的。
#ifndef CONFIG_SYS_NAND_BASE_LIST
#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
#endif
static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
你如果没有定义CONFIG_SYS_NAND_BASE_LIST,那么寄存器基地址就是CONFIG_SYS_NAND_BASE,对于S3C2440呢这个值就为0x4E000000,所以你又需要在配置文件中定义这个宏。
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
ulong base_addr)
{
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
int __attribute__((unused)) i = 0;
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) == 0) {
if (nand_scan(mtd, maxchips) == 0) {
if (!mtd->name)
mtd->name = (char *)default_nand_name;
else
mtd->name += gd->reloc_off;
#ifdef CONFIG_MTD_DEVICE
/*
* Add MTD device so that we can reference it later
* via the mtdcore infrastructure (e.g. ubi).
*/
sprintf(dev_name[i], "nand%d", i);
mtd->name = dev_name[i++];
add_mtd_device(mtd);
#endif
} else
mtd->name = NULL;
} else {
mtd->name = NULL;
mtd->size = 0;
}
}
首先将nand flash操作相关指针nand_chip赋值给nand_info中的一个私有数据指针。
修改nand_chip的读写基地址为base_address,也就是0x4E000000。
然后是if语句中的board_nand_init函数,board_nand_init一看就和具体板子相关了。因为我们的处理器是S3C2440和S3C2410接近,而u-boot中又没有对S3C2440做移植,所以我们只有分析2410的。
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
DEBUGN("board_nand_init()\n");
clk_power->CLKCON |= (1 << 4);
/* initialize hardware */
twrph0 = 3; twrph1 = 0; tacls = 0;
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
NFCONF = cfg;
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2410_hwcontrol;
nand->dev_ready = s3c2410_dev_ready;
#ifdef CONFIG_S3C2410_NAND_HWECC
nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
nand->ecc.calculate = s3c2410_nand_calculate_ecc;
nand->ecc.correct = s3c2410_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW3_512;
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;
#endif
DEBUGN("end of nand_init\n");
return 0;
}
这个board_nand_init函数首先获取时钟电源管理的寄存器基地址,然后打开nand flash控制器的时钟使能。
然后设置nand flash控制器的配置寄存器。
又设置nand flash读写基地址为0x4e00000c。最后是对nand_chip结构的一些赋值,board_nand_init初始化完成。
在u-boot启动过程中调用了nand_init函数,这就是nand flash驱动初始化的入口点。
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
我们看,这个函数被调用的前提条件是CONFIG_CMD_NAND宏被定义,所以如果你要操作nand flash,这个宏一定要在配置文件中被定义,我们先记在这里。进入nand_init函数中。
void nand_init(void)
{
int i;
unsigned int size = 0;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
size += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = i;
}
printf("%u MiB\n", 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
}
一个for循环,这里又有一个宏CONFIG_SYS_MAX_NAND_DEVICE,表示有几个nand flash设备,mini2440中只有一片nand flash,所以你需要在配置文件中定义这个宏为1。在进入nand_init_chip函数之前我们先将nand_init函数看完,首先计算出nand flash设备总大小,nand_curr_device表示当前nand flash设备编号,初始值为-1,由于我们这里只有一个nand flash设备,所以这个值应该用于为0才对。for循环结束之后打印出nand
flash设备总的大小。你如果没有定义CONFIG_SYS_NAND_SELECT_DEVICE这个宏,那么这个函数也就结束了,nand flash也就初始化完成了。
进入nand_init_chip函数中。
在看这个函数之前,我们要看传递给这个函数的三个参数,nand_info、nand_chip和base_address。这三个参数它们都是定义在nand.c中的三个全局变量,用于保存nand flash的相关信息,这就是初始化要的关键。nand_info主要和芯片本身相关,比如记录nand flash的大小等等。nand_chip这个结构主要记录nand flash它的操作相关,比如read、wirte等等。而base_address是记录的nand
flash主控制器的寄存器基地址。它是这样定义的。
#ifndef CONFIG_SYS_NAND_BASE_LIST
#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
#endif
static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
你如果没有定义CONFIG_SYS_NAND_BASE_LIST,那么寄存器基地址就是CONFIG_SYS_NAND_BASE,对于S3C2440呢这个值就为0x4E000000,所以你又需要在配置文件中定义这个宏。
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
ulong base_addr)
{
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
int __attribute__((unused)) i = 0;
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) == 0) {
if (nand_scan(mtd, maxchips) == 0) {
if (!mtd->name)
mtd->name = (char *)default_nand_name;
else
mtd->name += gd->reloc_off;
#ifdef CONFIG_MTD_DEVICE
/*
* Add MTD device so that we can reference it later
* via the mtdcore infrastructure (e.g. ubi).
*/
sprintf(dev_name[i], "nand%d", i);
mtd->name = dev_name[i++];
add_mtd_device(mtd);
#endif
} else
mtd->name = NULL;
} else {
mtd->name = NULL;
mtd->size = 0;
}
}
首先将nand flash操作相关指针nand_chip赋值给nand_info中的一个私有数据指针。
修改nand_chip的读写基地址为base_address,也就是0x4E000000。
然后是if语句中的board_nand_init函数,board_nand_init一看就和具体板子相关了。因为我们的处理器是S3C2440和S3C2410接近,而u-boot中又没有对S3C2440做移植,所以我们只有分析2410的。
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
DEBUGN("board_nand_init()\n");
clk_power->CLKCON |= (1 << 4);
/* initialize hardware */
twrph0 = 3; twrph1 = 0; tacls = 0;
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
NFCONF = cfg;
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2410_hwcontrol;
nand->dev_ready = s3c2410_dev_ready;
#ifdef CONFIG_S3C2410_NAND_HWECC
nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
nand->ecc.calculate = s3c2410_nand_calculate_ecc;
nand->ecc.correct = s3c2410_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW3_512;
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;
#endif
DEBUGN("end of nand_init\n");
return 0;
}
这个board_nand_init函数首先获取时钟电源管理的寄存器基地址,然后打开nand flash控制器的时钟使能。
然后设置nand flash控制器的配置寄存器。
又设置nand flash读写基地址为0x4e00000c。最后是对nand_chip结构的一些赋值,board_nand_init初始化完成。
相关文章推荐
- u-boot nand flash驱动架构分析一
- FL2440的U-boot-2009.08移植(五)uboot架构中NAND Flash驱动修改
- U-Boot NAND FLASH驱动分析
- U-boot-2009.08移植(五)uboot架构中NAND Flash驱动修改
- <2012 12 05> FL2440开发板的U-boot-2010.09版本移植(六)uboot架构中NAND Flash驱动修改
- U-Boot NAND FLASH驱动分析
- nand flash 驱动分析之Uboot下
- fl2440的U-boot-2010.09移植(五)uboot架构中NAND Flash驱动修改
- 千兆网口 Freescale ETSEC + Marvell 88E1111 uboot Linux 驱动分析 五
- linux下Pl353 NAND Flash驱动分析
- 高通sensor架构实例分析之二(adsp驱动代码结构)
- ATA Disk在Linux中的驱动架构对比分析
- linux下I2C驱动架构全面分析
- Linux设备驱动程序架构分析之一个I2C驱动实例
- Linux系统LCD驱动架构分析
- CS8900 U-boot 网卡驱动分析
- 内核读写nand flash驱动分析(含注释)
- uboot2012 LCD驱动流程及机制分析
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的SPI驱动架构分析
- Linux设备驱动之I2C架构分析