1 U-Boot移植
在U-Boot源码中,与某一个特定的开发板相关的文件或文件夹并不多,主要包括这些(其中有些是自己创建的):
l board/davinci/dm6467evm/
l cpu/arm926ejs/davinci/
l lib_arm/
l include/configs/davinci_dm6467evm.h
l include/asm-arm/arch-davinci
l drivers/mtd/nand
l 顶层Makefile及以上文件夹中的Makefile、config.mk
所以,在阅读U-Boot源码时,只需要专注于这些文件及文件夹,其他的一些U-Boot通用代码、硬件驱动程序等,一般来说是不用改,直接拿来使用就是。不过,如果所使用的一些外设与U-Boot不兼容或者有其他一些问题,那就需要自己去修改驱动程序。其实驱动程序的修改也是挺难的,能不修改就尽量别动,否则改错了后果更严重。
1.1 U-Boot移植的一般步骤
对于不同的开发板进行U-Boot移植时,其实都是按照一个通用的步骤来进行的,只是根据不同的开发板硬件参数和不同的U-boot版本,有些步骤要省去,有些任务要添加。一个通用的U-Boot移植过程如图 4‑1所示。图中的步骤有些其实也不是必须的,同时也可能缺少一些步骤。总之,需要根据实际情况修改。
在U-Boot源码包的顶层目录下有一个README文件,里面也有一段讲述U-Boot移植步骤的,不过那是别人用代码写出的步骤,很有意思,这里引用一下。
int main(int argc, char *argv[]) { sighandler_t no_more_time;
signal(SIGALRM, no_more_time); alarm(PROJECT_DEADLINE - toSec (3 * WEEK));
Download latest U-Boot source;
while (learning) { Read the README file in the top level directory; Read http://www.denx.de/twiki/bin/view/DULG/Manual; Read applicable doc/*.README; Read the source, Luke; /* find . -name "*.[chS]" | xargs grep -i <keyword> */ }
if (a similar board exists) { /* hopefully... */ cp -a board/<similar> board/<myboard> cp include/configs/<similar>.h include/configs/<myboard>.h } else { Create your own board support subdirectory; Create your own board include/configs/<myboard>.h file; } Edit new board/<myboard> files Edit new include/configs/<myboard>.h
while (!running) { do { Add / modify source code; } until (compiles); Debug; }
return 0; }
void no_more_time (int sig) { hire_a_guru(); } |
1.2 DM6467 U-Boot移植步骤
针对我们的DM6467开发板,在进行U-Boot移植时,步骤也是按照图 4‑1来进行的。由于我们使用的U-Boot版本是2009.08,它不支持DM6467开发板,所以在移植时我们需要创建对应的一些文件和文件夹,创建方法下面会有详细叙述。
1.2.1 修改Makefile
u-boot-2009.08不支持DM6467开发板,需要手动在顶层的Makefile文件中添加配置信息。
在2910行添加: davinci_dm6467evm_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm926ejs dm6467evm davinci davinci |
U-Boot是根据此配置信息来确定开发板的型号和CPU架构等信息。同样,由于u-boot-2009.08不支持DM6467开发板,所以需要在board\davinci\文件夹中添加对应的开发板的文件夹,并在include\configs\目录中添加对应的头文件。u-boot-2009.08中对davinci系列开发板提供了通用的支持,我们可以直接修改在dvevm基础上修改,也可以创建自己的开发板文件夹,这里我们使用后者。
#在终端中使用以下命令创建开发板文件夹和头文件 cd /<your_dir>/u-boot-209.08/board/davinci cp –f dvevm/* dm6467evm/ cd /<your_dir>/u-boot-2009.08/include/configs cp –f davinci_dvevm.h davinci_dm6467evm.h |
另外,如果使用的U-Boot版本比2009.08新的话,那么本节中的几个步骤就可以省去了。
1.2.2 修改lib_arm/config.mk
要生成ARM端可执行文件,需要使用交叉编译工具。这里使用的交叉编译器是Sourcery G++,安装在/opt/arm-2009q1/bin目录下。要使编译器生效,需要先在/root/.bashrc文件最后添加“export PATH=$PATH:/opt/arm-2009q1/bin:”,然后在终端中运行“source /root/.bashrc”才能使用该交叉编译器。
lib_arm/config.mk文件的修改如下所示:
24行修改为: CROSS_COMPILE ?= arm-none-linux-gnueabi- |
在修改完此处后,就可以编译生成u-boot.bin文件了。
cd /<your_dir>/u-boot-2009.08 make distclean make davinci_dm6467evm_config make |
如果编译通过,就可以在顶层目录看到u-boot.bin等文件,这表明前面几个步骤是正确的。
1.2.3 修改include/configs/davinci_dm6467evm.h
davinci_dm6467evm.h文件是移植U-Boot时最核心的文件,需要在此文件中根据开发板上的资源和实际的功能需求来设置或者修改对应的参数以及宏定义。
在此文件中,主要的可能需要修改的部分包括时钟、网口、NAND Flash、DDR2 和启动参数等。
/*=======*/ /* Board */ /*=======*/ #define DAVINCI_DM6467EVM /* 定义开发板型号 */ #define CONFIG_SYS_NAND_SMALLPAGE /* NAND的page大小为512字节 */ /* #define CONFIG_SYS_USE_NOR */ /*注释此行代码,表示使用NAND不用NOR*/ #define CONFIG_SYS_USE_NAND /* 我们使用的Flash是NAND */ /* #define CONFIG_SOC_DM644X */ /* 注释此行代码,使用下面的DM646x */ #define CONFIG_SOC_DM646x /* 定义SOC型号,注意大小写!!! */ #define CFG_REFCLK_FREQ 33000000 /* 系统输入时钟为33MHz */
/*=============*/ /* Memory Info */ /*=============*/ /* 我们开发板使用的DDR2是256M,8个BANK,起始地址为0x8000000,都是默认参数,不需要修改 */
/*=====================*/ /* Flash & Environment */ /*=====================*/ /* 我们开发板上没有使用mtd,故屏蔽以下几行代码,不屏蔽会编译出错 */ /* #define CONFIG_MTD_PARTITIONS #define CONFIG_CMD_MTDPARTS #define MTDIDS_DEFAULT \ "nand0=davinci_nand.0" #define MTDPARTS_DEFAULT \ "mtdparts=davinci_nand.0:384k(bootloader)ro,4m(kernel),-(filesystem)" */ /* 我们开发板上NAND的起始地址是0x42000000,大小128M,smallpage */ #define CONFIG_SYS_NAND_BASE 0x42000000
/*==============================*/ /* U-Boot general configuration */ /*==============================*/ /* 设置bootdelay参数,在u-boot启动时,有3秒延时,用户可以按下任意键后推出自启动,进行个性化参数设置 */ #define CONFIG_BOOTDELAY 3 /* 这个宏定义用于条件编译输出ARM和DDR2时钟频率的函数,U-Boot-2009.08里没有此函数,所以屏蔽此行代码,当然,也可以自己编写 */ /* #define CONFIG_MISC_INIT_R */
/*===================*/ /* Linux Information */ /*===================*/ #define CONFIG_BOOTARGS "mem=120M console=ttyS0,115200n8 root=/dev/hda1 rw noinitrd ip=dhcp" /* 根据开发板设置的启动参数,在调试开发板时使用此参数比较方便 */ /* linux的文件系统使用NFS协议共享主机上的文件 */ /* #define CONFIG_BOOTARGS "mem=76M console=ttyS0,115200n8 noinitrd rw " \ "ip=192.168.0.68:192.168.0.83:192.168.0.254:255.255.255.0::eth0:off eth=00:0c:29:89:09:82 " \ "root=/dev/nfs nfsroot=192.168.0.83:/home/tirvideo/lyb/armfs vpif_display.ch2_numbuffers=0" */
#define CONFIG_BOOTCOMMAND "setenv setboot setenv bootargs \\$(bootargs) video=dm64xxfb:output=\\$(videostd);run setboot; bootm 0x2050000" /* 根据开发板设置的启动命令 */ /* 使用TFTP协议从主机下载linux内核映像文件到0x80700000地址(SDRAM)处进行启动 */ /* #define CONFIG_BOOTCONMMAND "tftp 0x80700000 uImage;ping 192.168.0.83; bootm" */ |
1.2.4 修改board/davinci/dm6467evm/dm6467evm.c
此文件中主要包含了board_init()函数,用于开发板初始化。board_init()函数的功能是指定全局变量中的开发板ID、初始化一些必须使用的外设模块、设置某些寄存器等。
#define DAVINCI_DM646X_LPSC_EMAC 14 /* PSC模块中EMAC的ID */
int board_init(void) { gd->bd->bi_arch_number = MACH_TYPE_DAVINCI_DM6467_EVM; gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
lpsc_on(DAVINCI_DM646X_LPSC_EMAC); /* 使能EMAC */ REG(PSC_PTCMD) = 1; /* 设置PTCMD.GO = 1,使EMAC状态变成enable状态 */
return 0; } |
1.2.5 其他修改
以上几个步骤是进行U-Boot移植时所必需的。但是完成以上几个步骤后编译U-Boot时会提示有错误。这是因为u-boot-2009.08版本没有完全支持DM6467,在driver/mtd/davinci_emac.c和cpu/arm926ejs/davinci/Makefile中还有需要修改的地方。
4.2.5.1 修改drivers/mtd/davinci_emac.c
对于DM6467 EMAC特有的寄存器,在u-boot-2009.08中是没有足够的支持的,所以需要修改此处以兼容DM6467。
/* davinci_eth_open()函数中添加红色标识的代码: */ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) { dv_reg_p addr; u_int32_t clkdiv, cnt; volatile emac_desc *rx_desc; debug_emac("+ emac_open\n"); adap_emac->SOFTRESET = 1; while (adap_emac->SOFTRESET != 0) {;}
#if defined(CONFIG_SOC_DM646x) adap_ewrap->SOFTRST = 1; while (adap_ewrap->SOFTRST != 0) {;} #else adap_ewrap->EWCTL = 0; for (cnt = 0; cnt < 5; cnt++) { clkdiv = adap_ewrap->EWCTL; } #endif
rx_desc = emac_rx_desc; adap_emac->TXCONTROL = 0x01; adap_emac->RXCONTROL = 0x01; adap_emac->MACINDEX = 0; adap_emac->MACADDRHI = (davinci_eth_mac_addr[3] << 24) | (davinci_eth_mac_addr[2] << 16) | (davinci_eth_mac_addr[1] << 8) | (davinci_eth_mac_addr[0]);
#if defined(CONFIG_SOC_DM646x) /* Set VALID and MATCH bit along with MAC address bytes */ adap_emac->MACADDRLO = (davinci_eth_mac_addr[5] << 8) | (davinci_eth_mac_addr[4]) | (1 << 19) | (1 << 20); #else adap_emac->MACADDRLO = (davinci_eth_mac_addr[5] << 8) | (davinci_eth_mac_addr[4]); #endif
/* dvinci_eth_close()函数中添加红色标识的代码 */ static void davinci_eth_close(struct eth_device *dev) { debug_emac("+ emac_close\n"); davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ adap_emac->SOFTRESET = 1;
#if defined(CONFIG_SOC_DM646X) adap_ewrap->SOFTRST = 0; #else adap_ewrap->EWCTL = 0; #endif
debug_emac("- emac_close\n"); } |
4.2.5.2 修改cpu/arm926ejs/davinci/makefile
我们使用的cpu是属于DM646x系列,在u-boot-2009.08中只是有对于此系列芯片的定义,但是代码并不完全兼容。在cpu/arm926ejs/davinci/Makefile中没有指定要生成dm646x.o的目标文件,所以需要添加相关代码。
33行添加: COBJS-$(CONFIG_SOC_DM646x) += dm646x.o |
1.3 改变硬件结构时如何修改U-Boot
对于Spectrum公司设计的DM6467开发板,TI推出了对应的修改过后的U-Boot源码和bin文件,但是,我们自己的开发板肯定和Spectrum公司的有一些不同,这些不同主要集中在NAND Flash、DDR2 SDRAM和输入时钟频率等,这就需要自己去修改U-Boot。
1.3.1 改变NAND Flash
在U-Boot中,对于NAND的支持主要通过两条途径实现。
第一,U-Boot中有它所支持的所有NAND型号的一个结构数组nand_flash_ids[],它存在于drivers/mtd/nand/nand_ids.c文件中,每种支持的NANDFlash都有对应的ID。在进行NAND初始化时,程序向NAND发送0x90命令,NAND就会返回其ID及参数信息,U-Boot通过匹配ID而获取NAND的型号和参数。例如,我们开发板上的NAND ID是0x78。
第二,在include/configs/davinci_dm6467evm.h头文件中,需要对NAND进行一些参数设置,例如“#defineCONFIG_SYS_USE_NAND”表示系统使用NAND Flash,“#define CONFIG_SYS_NAND_SMALLPAGE”表示NAND的页大小为512字节。
在自己设计开发板时,如果使用的NANDFlash型号与U-Boot不兼容,那么需要手动在nand_flash_ids[]中按格式添加所使用NAND的ID及其他参数信息。
如果所使用的NAND与U-Boot兼容,但是参数与默认参数设置不匹配时,需要在davinci_dm6467evm.h中修改。一般来说要修改的只有一个参数,即页大小。例如我们自己设计的开发板上的NAND页大小为2048字节(2K),所以需要在头文件中注释掉“#define CONFIG_SYS_NAND_SMALLPAGE”。
另外需要注意的是NAND在系统内存空间中的起始地址,如果设置错误那U-Boot是无法启动的。在DM6467中NAND的起始地址是0x4200 0000。
1.3.2 改变DDR2
对于DDR2的初始化是在UBL中完成的,U-Boot只需要根据头文件中定义的几个参数就可以直接使用DDR2.所以,如果使用了不同的DDR2,那么主要的修改是在UBL中,在U-Boot中的修改很少,主要是包括两三个宏定义。第一,“#define PHYS_SDRAM_1_SIZE 0x10000000”,定义DDR2的大小,默认是256M。第二,“#defineDDR_8BANKS”定义DDR2的bank数,默认是8个bank。
1.3.3 改变时钟输入频率
对于系统PLL的设置是在UBL中完成的,在U-Boot中不需要再次设置PLL。不过,在U-Boot中要设置参考时钟输入频率,因为U-Boot要根据它来计算出正确的ARM和DDR2时钟频率然后输出。
当系统的输入时钟频率发生变化时,只需要在davinci_dm6467evm.h中修改宏定义的值,“#defineCONFIG_SYS_HZ_CLOCK 33000000”表示设置系统输入时钟为33MHz,默认参数是27MHz。