一、 步骤三:U-boot支持NAND启动
经过前两步我们的开发板已经支持了u-boot的NOR启动,在嵌入式开发中,由于nor FLASH的速度及容量上的原因,经常被NAND所替代,下面我们研究一下怎么从NAND上启动我们的u-boot
因为我们改过的代码需要在拷贝之前调用一段C程序,所以需要把对栈空间的初始化放在拷贝之前。
/* Set up the stack*/ 从后面移到前面,因为我们在后面的程序中需要调用C语言程序,所以在这里需要提前初始化栈空间 stack_setup: 。。。。。。。 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
#ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */ adr r0, _start ldr r1, _TEXT_BASE cmp r0, r1 /*根据启动代码的实际地址与链接地址判断是从RAM启动或者FLASH启动*/ beq clear_bss /*从ram启动则继续执行下面的内容*/ ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 #if 1 bl CopyCode2Ram /*调用C语言函数,从FLASH中拷贝镜像,此函数会自动识别是NOR启动还是NAND启动,此函数的实现为boot_init.c,需放在board/Samsung/unsp_2440/目录下*/ #else /*原U-BOOT:从NOR启动*/ add r2, r0, r2 copy_loop: ldmia r0!, {r3-r10} stmia r1!, {r3-r10} cmp r0, r2 ble copy_loop #endif #endif /* CONFIG_SKIP_RELOCATE_UBOOT */
boot_init.c文件是我们后来增加的文件,在u-boot启动的第一个阶段调用,第一阶段代码通过4k的SRAM运行,因此本函数必须链接到前4k的地址中,否则会调用不到此函数。
为此我们需做以下修改:
修改board/Samsung/unsp_2440/Makefile,在第28行左右的位置修改成以下形式
COBJS := unsp2440.o flash.o boot_init.o
这样就可以把我们编写的boot_init.c文件编译进去。
为了将boot_init.c链接到前4k代码中,我们还需修改以下文件:
arch/arm/cpu/arm920t/u-boot.lds u-boot的链接文件
.text : { arch/arm/cpu/arm920t/start.o (.text) board/samsung/unsp2440/lowlevel_init.o(.text) board/samsung/unsp2440/boot_init.o(.text) *(.text) }
将lowlevel_init.S跟boot_init.c文件均链接到前4K SRAM中。
我们可以重新编译并下载到开发板中,将开发板调到NAND启动,观察能否启动起来。
二、 步骤四:U-boot支持NAND操作
在上一节中我们说过,通常在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动,但不管是从Nor启动或者从Nand启动,进入第二阶段以后,两者的执行流程是相同的。
当u-boot的start.S运行到“_start_armboot: .word start_armboot”时,就会调用lib_arm/board.c中的start_armboot函数,至此u-boot正式进入第二阶段。
此时注意:以前较早的u-boot版本进入第二阶段后,对Nand Flash的支持有新旧两套代码,新代码在drivers/nand目录下,旧代码在drivers/nand_legacy目录 下,CFG_NAND_LEGACY宏决定了使用哪套代码,如果定义了该宏就使用旧代码,否则使用新代码。
但是现在的u-boot-2010.6版本对 Nand的初始化、读写实现是基于最近的Linux内核的MTD架构,删除了以前传统的执行方法,使移植没有以前那样复杂了,实现Nand的操作和基本命令都直接在drivers/mtd/nand目录下。
下面我们结合代码来分析一下u-boot在第二阶段的执行流程。
1. lib_arm/board.c文件中的start_armboot函数调用了drivers/mtd/nand/nand.c文件中的nand_init函数,如下: #if defined(CONFIG_CMD_NAND) //可以看到CONFIG_CMD_NAND宏决定了Nand的初始化 puts ("NAND: " ) ; nand_init(); #endif 2.nand_init调用了同文件下的nand_init_chip函数; 3.nand_init_chip函数调用drivers/mtd/nand/s3c2410_nand.c文件下的board_nand_init函数,然后再调用drivers/mtd/nand/nand_base.c函数中的nand_scan函数; 4.nand_scan函数调用了同文件下的nand_scan_ident函数等
因为2440和2410对nand控制器的操作有很大的不同,所以s3c2410_nand.c下对nand操作的函数就是我们做移植需要实现的部分了,他与具体的Nand Flash硬件密切相关。
为了区别与2410,这里我们就重新建立一个s3c2440_nand.c文件,在这里面来实现对nand的操作,代码参见S3c2440_nand.c:
s3c2440_nand.c
其次,在开发板配置文件include/configs/my2440.h文件中定义支持Nand操作的相关宏,如下:
/* Command line configuration. */ #define CONFIG_CMD_NAND #define CONFIG_NAND_S3C2440 1 #define CONFIG_CMDLINE_EDITING #ifdef CONFIG_CMDLINE_EDITING # undef CONFIG_AUTO_COMPLETE #else #define CONFIG_AUTO_COMPLETE #endif /* NAND flash settings */ #if defined(CONFIG_CMD_NAND) #define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址 #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_MTD_NAND_VERIFY_WRITE 1 //#define NAND_SAMSUNG_LP_OPTIONS 1 //注意:我们这里是64M的Nand Flash,所以不用,如果是128M的大块Nand Flash,则需加上 #endif
然后,在drivers/mtd/nand/Makefile文件中添加s3c2440_nand.c的编译项,如下
# gedit drivers/mtd/nand/Makefile COBJS- y + = s3c2440_nand.o COBJS- $ ( CONFIG_NAND_S3C2440) + = s3c2440_nand. o
重新编译,将u-boot烧入NAND FLASH,并敲入help,可以看到有关NAND FLASH操作的命令已经可以使用。
在启动过程中,我们可以看到一个警告信息:“*** Warning - bad CRC or NAND, using default environment”,这是因为我们还没有将u-boot的环境变量保存nand中的缘故,那现在我们就用u-boot的saveenv命令将环境变量保存在NAND FLASH中,如下:
#ifdef CONFIG_CMD_NAND #define CONFIG_ENV_IS_IN_NAND 1 #define CONFIG_ENV_OFFSET 0x30000 //将环境变量保存到nand中的0x30000位置 //注意这个地址不要跟bootloader等其它分区冲突 #define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ #else #define CONFIG_ENV_IS_IN_FLASH 1 //将环境变量存入norflash中 #define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ #endif
重新编译下载上述警告���失,我们可以使用saveenv将环境变量的值存入NAND FLASH中。
为了测试NAND驱动移植是否成功,我们使用loady命令配合nand命令完成相关测试。
修改include/configs/unsp2440.h中
#define CONFIG_SYS_PROMPT "unsp2440 # " /* Monitor Command Prompt */
重新编译生成u-boot
#loady 0x33000000 //采用ymodem协议从串口下载u-boot镜像到0x33000000中 #nand erase 0x0 0x30000 //擦除0x0到0x30000的FLASH地址 #nand write 0x33000000 0x0 0x30000 //将0x33000000中数据烧进NAND的0x0到0x30000中
重启开发板,观察提示符由smdk2410变为 unsp2440#,说明我们对NAND FLASH驱动的修改成功了。