uboot整个移植过程我们可以分为三个阶段: 一,移植可以从Nor flash启动的uboot 这个阶段是移植一个最简单的uboot,可以烧在Nor flash内运行. 二,移植支持Nand flash驱动的uboot 加入Nand flash驱动的支持,可以在uboot命令行下操作Nand flash.但还未能从Nand flash启动,只能在Nor flash内运行. 三,移植可以从Nor flash启动的uboot 可以烧录在Nand flash,并设置从Nand flash启动运行uboot.
分三个阶段进行移植,可以对整个uboot的移植过程及原理更加清晰明了,同时降低了发现问题时解决问题的困难度和解决范围.
首先介绍移植可以从Nor flash启动的uboot. 这个阶段相对简单一点,是移植一个最简单的uboot,可以烧在Nor flash内运行.不需要修改太多的东西。步骤如下:
测试一下默认的smdk2410_config配置能否在你的板子上正常运行 1.编译uboot1.1.4
#make smdk2410_config #make ARCH=arm |
注:编译针对arm的平台时,uboot默认使用arm-linux-gcc编译,若交叉编译器名字不一样,需要自行在Makefile里修改。
会出现两个错误.
错误信息一: cc1: Invalid option `abi=apcs-gnu' make[1]: *** [hello_world.o] Error 1 make[1]: Leaving directory `/root/u-boot-1.1.4/examples' make: *** [examples] Error 2 解决办法: 出错的文件是/cpu/arm920t/下的config.mk: 将 PLATform_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) 改成: PLATform_CPPFLAGS +=$(call cc-option,-mapcs-32,$(call cc-option,-mabi=apcs-gnu,))
错误信息二: make[1]: *** No rule to make target `hello_world.srec', needed by `all'. Stop. make[1]: Leaving directory `/work/src/u-boot-1.1.4/examples' 解决方法: 打开 examples/Makefile
把example文件夹下的Makefile中的 第126行 %.srec: % 改成 %.srec: %.o 第129行的
%.bin: % 改成 %.bin: %.o
2.若编译成功,则会在uboot源码下产生u-boot.bin文件。将这个文件烧录到nor flash。 注意: 默认u-boot的smdk2410_config是不支持nandflash的,只能在nor flash内运行,所以只能烧录到nor flash内运行。如果烧录到nandflash下是不能运行的。
3.参考开发板资料,设置好跳线,从nor flash启动。 启动信息如下:
U-Boot 1.1.4 (Dec 30 2007 - 23:25:02) U-Boot code: 33F80000 -> 33F9696C BSS: -> 33F9AC58 RAM Configuration: Bank #0: 30000000 64 MB *** Warning - bad CRC, using default environment Flash: 512 kB In: serial Out: serial Err: serial |
发现有3个问题: 1) 启动时开发板蜂鸣器一直在响。 怀疑是我的开发板蜂鸣器对应的GPIO口和smdk2410的GPIO口地址不对应,从而导致启动时误赋了值,一直在响。 2) Warning - bad CRC, using default environment 这个问题是因为第一次使用uboot时没有设置过变量,设置保存一下就不会在出现了。 3) Flash: 512 kB 我的板子Nor flash是1MB的,而这里显示512KB
4.下面进行uboot源码修改 这里主要根据开发板硬件的实际情况,基于smdk2410的源码进行修改(主要是配置文件include/configs/smdk2410.h),并解决如上碰到的问题1和3。
若对硬件板子的情况不是太了解,可以参考2410的datasheet以及开发板供应商提供的硬件资料。
从我开发板uboot第一次启动的情况来看,问题不是太大。 首先修改include/configs/smdk2410.h。里面包含了很多对目标板设置的宏。
smdk2410.h的内容和要修改的地方如下:
#define CONFIG_BOOTDELAY 3 /*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" */ #define CONFIG_ETHADDR 08:00:3e:26:0a:5b #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_IPADDR 192.168.1.103 #define CONFIG_SERVERIP 192.168.1.102 #define CONFIG_BOOTFILE "uImage" #define CONFIG_BOOTCOMMAND "tftp 30000000 uImage\; bootm 30000000" //这是bootdelay后运行的命令 //这些宏对应与uboot的变量,即在uboot命令行下执行printenv打印出的变量。可以在这里设置(定义为默认值),也可以在uboot启动后通过setenv命令设置。
#define CFG_PROMPT "ARMSYS2410 # " /* Monitor Command Prompt */ #define CFG_LOAD_ADDR 0x33000000 /* default load address */ #define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ #define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */ #define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */ |
解决问题3: 将 #define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ #if 0 #define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ #endif 改为: #define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ #if 0 #define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ #endif 注意如下两个地方: #ifdef CONFIG_AMD_LV800 #define PHYS_FLASH_SIZE 0x00100000 /* 1MB */ 这里解决了u-boot启动时的问题3即Nor Flash大小为512 kB ,是因为没有选择正确的Nor flash型号。 #define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */ #define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */ 宏CFG_ENV_ADDR定义了存放uboot变量的地址,换算一下为1MB-64KB=960KB地方,而实际uboot编译出来的大小仅为120KB左右,由此可以得出,即使从新烧录了新编译的uboot到Nor flash内,也不会影响先前设定使用的uboot变量。 #endif
注:可以在u-boot的README里查到这些部分宏的作用
5.解决蜂鸣器一直响问题 查看ARMSYS2410-B底板电路图,在Reset Singal模块里可以看到蜂鸣器(BUZZER)控制口连接到TOUT1引脚,并且低电平响。如下:
由s3c2410 Datasheet知道TOUT1复用了GPB1口。因此,只要在uboot启动时给GPBDAT寄存器适当赋值,关闭BUZZER就可以了。
修改smdk2410.c #vi board/smdk2410/smdk2410.c 找到board_init()函数 在gpio->GPBUP = 0x000007FF;下面 添加如下内容:
/*******stop beep******/ gpio->GPBDAT &= ~0x00000002; //Open BUZZER delay (5000000); //BUZZER Delay Time gpio->GPBDAT |= 0x00000002; |
6.重新编译 #make clean #make ARCH=arm
7.烧录u-boot.bin到nor flash 启动信息: U-Boot 1.1.4 (Jan 3 2008 - 23:11:07)
U-Boot code: 33F80000 -> 33F96DC4 BSS: -> 33F9B0E8 RAM Configuration: Bank #0: 30000000 64 MB Flash: 1 MB In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 ARMSYS2410 #
uboot移植记录之二 移植可以从Nor flash启动的uboot请参考uboot移植系列的《uboot移植记录之一》 http://blog.chinaunix.net/u2/60011/showart.php?id=1005057 下面介绍移植支持Nand flash驱动的uboot. 加入Nand flash驱动的支持,可以在uboot命令行下操作Nand flash.但还未能从Nand flash启动,只能在Nor flash内运行.支持从Nandflash启动会在下节介绍。 下面描述详细步骤: 1. 打开Nandflash驱动支持 要使uboot支持nand驱动,需要在smdk2410.h中将CFG_CMD_NAND部分注释取消,打开nandflash功能。 修改如下: /* include/configs/smdk2410.h */ #define CONFIG_COMMANDS \ (CONFIG_CMD_DFL | \ CFG_CMD_CACHE | \ CFG_CMD_NAND | \ /*CFG_CMD_EEPROM |*/ \ /*CFG_CMD_I2C |*/ \ /*CFG_CMD_USB |*/ \ CFG_CMD_REGINFO | \ CFG_CMD_DATE | \ CFG_CMD_ELF) 2. 添加nand_init()函数 Uboot对SMDK2410板的NAND Flash初始化部分没有写 即在lib_arm/board.c中的start_armboot函数中有这么一句: #if (CONFIG_COMMANDS & CFG_CMD_NAND) puts ("NAND:"); nand_init(); /* go init the NAND */ #endif 因为前面打开了CFG_CMD_NAND这个宏,uboot编译时会去查询nand_init()这个函数。而在board/smdk2410目录下任何源文件中都没有定义nand_init这个函数。所以需要我们补充这个函数以及这个函数涉及的底层操作。这里我们可以参考VCMA9板的nand_init函数,VCMA9板是一款用S3C2410的板子,因此这部分操作和SMDK2410 Demo Board很相似。大部分代码可以照搬。 分析VCM9板的nand_init()函数,发现需要拷贝如下内容: 首先将board/mpl/vcma9/vcma9.h中下面代码拷贝到common/cmd_nand.c中do_nand函数前面。 /* dongas - support nand driver */ #if (CONFIG_COMMANDS & CFG_CMD_NAND) typedef enum { NFCE_LOW, NFCE_HIGH } NFCE_STATE; static inline void NF_Conf(u16 conf) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); nand->NFCONF = conf; } static inline void NF_Cmd(u8 cmd) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); nand->NFCMD = cmd; } static inline void NF_CmdW(u8 cmd) { NF_Cmd(cmd); udelay(1); } static inline void NF_Addr(u8 addr) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); nand->NFADDR = addr; } static inline void NF_SetCE(NFCE_STATE s) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); switch (s) { case NFCE_LOW: nand->NFCONF &= ~(111); break; case NFCE_HIGH: nand->NFCONF |= (111); break; } } static inline void NF_WaitRB(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); while (!(nand->NFSTAT & (10))); } static inline void NF_Write(u8 data) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); nand->NFDATA = data; } static inline u8 NF_Read(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); return(nand->NFDATA); } static inline void NF_Init_ECC(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); nand->NFCONF |= (112); } static inline u32 NF_Read_ECC(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); return(nand->NFECC); } #endif /* dongas - support nand driver - end */ 再接着将board/mpl/vcma9/vcma9.c中下面代码拷贝到common/cmd_nand.c中来。 /* dongas - support nand driver */ /* * NAND flash initialization. */ #if (CONFIG_COMMANDS & CFG_CMD_NAND) extern ulong nand_probe(ulong physadr); static inline void NF_Reset(void) { int i; NF_SetCE(NFCE_LOW); NF_Cmd(0xFF); /* reset command */ for(i = 0; i 10; i++); /* tWB = 100ns. */ NF_WaitRB(); /* wait 200~500us; */ NF_SetCE(NFCE_HIGH); } static inline void NF_Init(void) { #if 0 /* a little bit too optimistic */ #define TACLS 0 #define TWRPH0 3 #define TWRPH1 0 #else #define TACLS 0 #define TWRPH0 4 #define TWRPH1 2 #endif NF_Conf((115)|(014)|(013)|(112)|(111)|(TACLS8)|(TWRPH04)|(TWRPH10)); /*nand->NFCONF = (1 /* 1 1 1 1, 1 xxx, r xxx, r xxx */ /* En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 */ NF_Reset(); } void nand_init(void) { S3C2410_NAND * const nand = S3C2410_GetBase_NAND(); NF_Init(); #ifdef DEBUG printf("NAND flash probing at 0x%.8lX\n", (ulong)nand); #endif printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20); } #endif /* dongas - support nand driver - end */ 另外还要在cmd_nand.c前面加上#include ,否则编译时会出现ERROR: "S3C2410_NAND" Undeclared错误! 最后将include/configs/VCMA.9中下面代码拷贝到include/configs/smdk2410.h中来。 /* dongas - support nand driver */ /*----------------------------------------------------------------------- * NAND flash settings */ #if (CONFIG_COMMANDS & CFG_CMD_NAND) #define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ #define SECTORSIZE 512 #define ADDR_COLUMN 1 #define ADDR_PAGE 2 #define ADDR_COLUMN_PAGE 3 #define NAND_ChipID_UNKNOWN 0x00 #define NAND_MAX_FLOORS 1 #define NAND_MAX_CHIPS 1 #define NAND_WAIT_READY(nand) NF_WaitRB() #define NAND_DISABLE_CE(nand) NF_SetCE(NFCE_HIGH) #define NAND_ENABLE_CE(nand) NF_SetCE(NFCE_LOW) #define WRITE_NAND_COMMAND(d, adr) NF_Cmd(d) #define WRITE_NAND_COMMANDW(d, adr) NF_CmdW(d) #define WRITE_NAND_ADDRESS(d, adr) NF_Addr(d) #define WRITE_NAND(d, adr) NF_Write(d) #define READ_NAND(adr) NF_Read() /* the following functions are NOP's because S3C24X0 handles this in hardware */ #define NAND_CTL_CLRALE(nandptr) #define NAND_CTL_SETALE(nandptr) #define NAND_CTL_CLRCLE(nandptr) #define NAND_CTL_SETCLE(nandptr) #define CONFIG_MTD_NAND_VERIFY_WRITE 1 #define CONFIG_MTD_NAND_ECC_JFFS2 1 #endif /* CONFIG_COMMANDS & CFG_CMD_NAND */ /* dongas - support nand driver - end */ 3. 重新编译uboot #make ARCH=arm 4. 测试加入Nand驱动支持的uboot 下面我们测试一下新编译的带Nand驱动支持的uboot是否有用。由于之前我们已经编译了NOR版本的uboot并烧录在nor flash中,这时我们无需重新烧录新编译的uboot到Nor Flash了。可以直接使用Nor里的uboot提供的串口传输功能,将新编译好的uboot(带nand驱动支持)通过串口传输到sdram中测试,相比重新烧录,这种方法高效率快捷得多。 传输的方法有两种: 1) 使用loadb指令加载uboot.bin loadb指令使用kermit协议从串口下载二进制文件到开发板的内存中,默认下载到0x33000000。当然你可以改在别的地址。 例如:loadb 30000000就是下载到0x30000000。 首先在uboot命令行模式下执行loadb指令 # loadb ## Ready for binary (kermit) download to 0x33000000 at 115200 bps... 然后选择超级终端菜单上:传送〉发送文件,文件名选择编译好的U-Boot.bin,协议选择Kermit发送,可以看到发送进度。 注:这里使用secure CRT好象不行,没发现其支持kermit协议,只能使用windows自带的超级终端或minicom 发送结束出现提示: ## Total Size = 0x00019a14 = 104980 Bytes ## Start Addr = 0x33000000 传输完后可以测试一下新编译的uboot是否有用: ARMSYS2410 # go 30000000 注:go指令可以直接执行指定内存地址上的程序,例如刚下载到0x30000000的支持NAND驱动的uboot。 2)其实这里也可以使用tftp协议将uboot下载到指定地址如0x30000000处,再用go指令执行。效果一样,相比上一种这种方法更快捷,前提是网络 功能可用。当然,因为我的板子使用的是CS8900网卡,默认smdk2410就是支持的,所以直接可以使用。(tftp的用法请参考相关资料) #tftpboot 30000000 u-boot.bin #go 30000000 执行go指令启动sdram中的uboot后,若出现了“NAND: 64MB”这一行,那么恭喜你,基本上可以确定你的Nand驱动移植已经成功了。 我的启动信息如下: ARMSYS2410 # go 30000000 ## Starting application at 0x30000000 ... U-Boot 1.1.4 (Jan 9 2008 - 00:08:10) U-Boot code: 33F80000 -> 33F9A04C BSS: -> 33F9E3E8 RAM Configuration: Bank #0: 30000000 64 MB Flash: 1 MB NAND: 64 MB ------------- 多了这一行! Happying! In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 ARMSYS2410 nand# 确认一下,输入help,发现比先前NOR版本的U-Boot多了一组nand命令! #help mw - memory write (fill) nand - NAND sub-system --------- 新增加的Nand命令 nboot - boot from NAND device …… help nand可以看到更详细的命令说明: ARMSYS2410 nand# help nand nand info - show available NAND devices nand device [dev] - show or set current device nand read[.jffs2[s]] addr off size nand write[.jffs2] addr off size - read/write `size' bytes starting at offset `off' to/from memory address `addr' nand erase [clean] [off size] - erase `size' bytes from offset `off 利用这些命令可以对Nandflash进行读写操作! 输入nand info可以查看NandFlash型片的信息: ARMSYS2410 # nand info Device 0: Samsung unknown 64Mb at 0x4e000000 (64 MB, 16 kB sector) 说明我们的Nand驱动移植成功了。(这里Nand型号显示为unknown没关系,默认的也可以使用) 是因为uboot的nand列表里没有K9S1208 64MB,可以自己添加, 加入NAND闪存芯片型号 在/include/linux/mtd/ nand_ids.h中对如下结构体赋值进行修改: static struct nand_flash_dev nand_flash_ids[] = { ...... {"Samsung K9F1208U0B", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0}, ....... } 这样对于该款NAND闪存芯片的操作才能正确执行。当然不添加也没关系,使用默认参数操作NAND也可以。 测试成功后我们将新编好的带Nand驱动支持的uboot烧录到Nor中。 这里也不需要使用工具烧录,用uboot提供的cp命令就可以将自身拷贝到Nor flash了。强大吧,呵呵~ 比sjflash烧快多了,uboot既然提供了这么多好的功能,如果不用就太可惜啦!:) 1) 先看看NOR Flash的情况: ARMSYS2410 nand# flinfo Bank # 1: AMD: 1x Amd29LV800BB (8Mbit) Size: 1 MB in 19 Sectors Sector Start Addresses: 00000000 (RO) 00004000 (RO) 00006000 (RO) 00008000 (RO) 00010000 (RO) 00020000 00030000 00040000 00050000 00060000 00070000 00080000 00090000 000A0000 000B0000 000C0000 000D0000 000E0000 000F0000 (RO) 一共有19个sector,其中前5个总计128kb的sector有U-Boot程序,是写保护的(RO)。要烧写首先要去掉写保护: 注:flinfo命令的作用是显示当前flash(nor)的信息 2) 去掉前5个sector的写保护,大小为128KB,足够容纳我们的uboot了。 ARMSYS2410 # protect off 0 1ffff Un-Protected 5 sectors 3) 再查看一下: ARMSYS2410 nand# flinfo Bank # 1: AMD: 1x Amd29LV800BB (8Mbit) Size%