当前位置:Linux教程 - Linux文化 - uboot移植到S3C44B0X开发板的经历

uboot移植到S3C44B0X开发板的经历


Sam Fei (email: [email protected])

(1) 事情来由 几个月前从朋友那里拿到了一块参考Micetek EV44b0-II开发板设计的板子,对其bootloader MBL感觉很不错. 朋友说可能是移植u-boot的.但Micetek并没有提供MBL的源代码, 因此当时没有仔细去研究. 最近公司准备想做基于S3C44B0X CPU的产品,因此购买了杭州立宇泰公司(www.hzlitai.com.cn)的armsys-c及armsys-b开发板和.armsys提供的bootloader是其公司自己开发的bootloader,觉得其USB这一块做的还可以,但利用USB下载调试uclinux是非常麻烦的,操作很不爽,其bootloader也不提供网络下载调试.因此自己计划移植u-boot.

(2) 开始 由于没有接触过u-boot,因此第一步要做的就是google一些资料. u-boot官方网站:http://sourceforge.net/projects/u-boot(比较慢) http://u-boot.sourceforge.net/这个快一些.

DENX U-Boot及Linux使用手册: http://coosign.blogchina.com/coosign/1318487.html, 这是一遍翻译的文档.主要介绍了u-boot编译及使用的命令.但没有涉及新板子的移植流程.

根据上面手册中的说明,下载了最新的u-boot代码,命令: #cvs -d:pserver:[email protected]:/cvsroot/u-boot login #cvs -z6 -d:pserver:[email protected]:/cvsroot/u-boot co -P u-boot

到board目录查了一下: #cd u-boot #cd board #find . -exec grep -l 44B0 {} \; 结果是: ./dave/B2/B2.c B2网站是: http://www.dave-tech.it,初初看了B2开发板的介绍,但不详细.包括使用的网络芯片等都没有介绍.

google "u-boot 移植"后查到一篇文章: "收集了一些关于U-BOOT的文章" http://www.bloghome.cn/index.php?op=ViewArticle&articleId=2111&blogId=390

里面搜集了不少关于u-boot移植的问题. 里面介绍了"U-Boot 在44B0X 开发板上的移植以及代码分析"的内容,仔细看了看.发现其移植的版本比较低,但对了解u-boot结构是满不错的,因为这个版本不支持44B0X,因此完全是支持新CPU的移植.了解到make XX_config是在Makefile中定义的. 另外"MPC8xx的U-Boot移植体会(ZT) "这一篇对u-boot介绍满详细的.但对移植工作只做了理论性和经验性介绍,没有具体的操作步骤.

"基于Atmel at91rm9200的armlinux的bootloader启动代码分析 " http://www.linuxfans.org/nuke/modules.php?name=News&file=print&sid=2765 里面介绍了u-boot移植到at91rm9200上的情况,可以参考一下.

另外就是仔细阅读u-boot下的README文件.

(3) 编译一把 看了相关的资料,心动不如行动.先编译一把看看情况.既然只有B2开发板是S3C44B0X CPU的,因此先编译一下B2开发板看看. 具体: #cd u-boot #make B2_config #make 结果顺利,成功编译.

(4) 开始动手移植 我以B2板子的程序做为模板来做. #cd board #cp -r dave wx (自己取个公司名wx) #cd wx #mv B2 wx20 (自己取个板子名wx20) #cd wx20 # mv B2.c wx20.c 修改Makefile及wx20.c, 主要是B2改成wx20.

增加配置文件: #cd include/configs #cp B2.h wx20.h 修改Makefile配置文件,增加wx20_config. 1432 wx20_config : unconfig 1433 @./mkconfig $(@:_config=) arm s3c44b0 wx20 wx [注:前面的数字是文件行号,以下一样]. 将board/wx目录下和wx20.h文件中的B2改成wx20或WX20.

这里其实是最重要的步骤,就是根据硬件的情况来修改相关的参数.由于对硬件板子的情况不是太了解,因此此时最需要的就是耐心地看看硬件资料.主要修改的地方有: include/configs/wx20.h ---- 配置文件,大部分参数是这里配置的. board/wx/wx20/lowlevel_init.S -- 内存参数配置 cpu/s3c44b0/serial.c -- 串口配置 cpu/s3c44b0/start.S -- 程序入口

如果此时配置全部正确了,那么我们就简单的很了.(如果你用我的patch的话,就是如此了!)那么我也就不会仔细再去研究u-boot其他部分了. 困难就是你学习的最好机会!

(5) 开始编译 经过简单的参数修改,编译成功.然后下载u-boot.bin(二进制格式). 此时你可以用nm看一下u-boot(elf格式)的内容,会有所收获的.

然后用armsys的bootloader将u-boot.bin调入到内存0xc100000运行.结果可想而知,串口没有任何显示,而且死机.bootloader也必须断电重起.

(6) u-boot流程 原因是比较明显的,就是参数和硬件没有符合.因此接下来做的事情就是仔细阅读S3C44B0 CPU的硬件资料,包括内存配置,串口配置这些.我觉得要让串口出信息,最主要的就是CPU的初始化,内存配置和串口配置.另外就是了解u-boot程序运行流程,这个对了解需要设置的参数是非常有帮助的.我这里大致说一下u-boot运行流程.

入口: cpu/s3c44b0/start.S 主要是CPU初始化( cpu_init_crit ), 调内存配置函数( lowlevel_init ), 然后判断u-boot是否从flash运行,如果是就把u-boot代码拷贝到TEXT_BASE定义的地方.然后转到start_armboot.

start_armboot: lib_arm/board.c 进行各种初始化设置,主要有: cpu_init CPU相关的设置, 具体在./cpu/s3c44b0/cpu.c中. board_init 板子相关的设置, 具体在board/wx/wx20/wx20.c 中 interrupt_init中断设置,我们没有用,具体在./cpu/s3c44b0/interrupts.c中 env_init 初始化环境变量, 具体要看用什么介质来存储环境变量,如果用flash来存贮, 程序在common/env_flash.c中. init_baudrate 设置baud参数 serial_init 串口初始化, 具体在cpu/s3c44b0/serial.c. console_init_f 控制台设置, 具体在./common/console.c

display_banner 显示标题. dram_init 可用内存配置, 具体在./board/wx/wx20/wx20.c. flash_init flash初始化,具体./drivers/cfi_flash.c.

接下来就是环境变量初始化, 网络初始化,最后到main_loop,可以运行各种命令. (7) 主要参数修改 经过一段时间调试,终于串口出东西了,这段时间犯了一个小错误,走了一段冤枉路.其实配置参数可能早已正确,但串口老是乱码,原因是自己的u-boot.bin传下来时目录搞错了,结果老是运行错误的u-boot.bin.这段时间里主要改的参数有:

include/configs/wx20.h: #define CONFIG_S3C44B0_CLOCK_SPEED 64 CPU主频,armsys板的是64M #define PHYS_SDRAM_1 0x0c000000 /* SDRAM Bank #1 */ B2板子里的定义是错误的.还有RAM大小,flash大小需要修改,跟B2板不同.

#define CONFIG_DRIVER_RTL8019 #define RTL8019_BASE 0x08000000 配置rtl8019AS网络芯片.

#define CFG_LOAD_ADDR 0x0c008000 /* default load address */ uclinux运行入口地址

lowlevel_init.S: MEMORY_CONFIG: .long 0x11010102 .long 0x600 .long 0x7ffc .long 0x7ffc .long 0x7ffc .long 0x7ffc .long 0x2610 .long 0x18000 .long 0x18000 .long 0x960459 .long 0x10 .long 0x20 .long 0x20 由于对armsys硬件不是太了解,没有办法,只得看armsys bootloader程序,但每个版本又有差别.因此是用AXD调试看bootlaoder启动后0x1c80000中的值定的.

cpu/s3c44b0/serial.c: #elif CONFIG_S3C44B0_CLOCK_SPEED==64 divisor = 34; 串口设置,这个也是根据bootloader里的公式计算出来的.这里只定义了115200得值,其他没有去设置.

cpu/s3c44b0/start.S: ldr r1, =PLLCON

#if CONFIG_S3C44B0_CLOCK_SPEED==66 ldr r0, =0x34031 /* 66MHz (Quartz=11MHz) */ #elif CONFIG_S3C44B0_CLOCK_SPEED==75 ldr r0, =0x610c1 /*B2: Xtal=20mhz Fclk=75MHz */ #elif CONFIG_S3C44B0_CLOCK_SPEED==64 ldr r0, =((M_DIV saveenv Saving Environment to Flash... Un-Protected 1 sectors Erasing Flash... done Erased 1 sectors Writing to Flash... done Protected 1 sectors ð printenv

但重新启动机器后,参数没有起作用,还是缺省的.仔细看了环境变量的程序,发现是由于ENV_IS_EMBEDDED定义造成的,而此变量定义是在./tools/envcrc.c中: # if (CFG_ENV_ADDR >= CFG_MONITOR_BASE) && \ ((CFG_ENV_ADDR + CFG_ENV_SIZE) 0C117DA0 BSS: -> 0C11C0F0 RAM Configuration: Bank #0: 0c000000 8 MB env_init flash_addr=20000 flash_addr=20000 env_ptr=20000 env_ptr->data=bootargs=setenv bootargs root=/dev/ram ip=192.168.1.100:::::eth0:off ether=25,0,0,0,eth0 ethaddr=00:50:c2:1e:af:fb envptr->crc=1470de2 1470de2 buffer->crc=1470de2 [flash_get_size, 224] Entering ... [flash_get_size, 232] value=bf [flash_get_size, 255] value=234b Flash: 2 MB env_ptr=20000 gd->env_addr=20004 gd->env_valid=1 env_relocate[211] offset = 0x0 env_relocate[229] malloced ENV at 00000000 In: Out: Err:

死机!!!

然后改回arm-elf编译: U-Boot 1.1.3 (Jul 3 2005 - 07:04:48)

U-Boot code: 0C100000 -> 0C119B98 BSS: -> 0C11DCD8 RAM Configuration: Bank #0: 0c000000 8 MB env_init flash_addr=20000 flash_addr=20000 env_ptr=20000 env_ptr->data=bootargs=setenv bootargs root=/dev/ram ip=192.168.1.100:::::eth0:off ether=25,0,0,0,eth0 ethaddr=00:50:c2:1e:af:fb envptr->crc=1470de2 1470de2 buffer->crc=1470de2 [flash_get_size, 224] Entering ... [flash_get_size, 232] value=bf [flash_get_size, 255] value=234b Flash: 2 MB env_ptr=20000 gd->env_addr=20004 gd->env_valid=1 env_relocate[211] offset = 0x0 env_relocate[229] malloced ENV at 0c0dfc08 In: serial Out: serial Err: serial rtl8019 MAC: 2a:2a:2a:2a:2a:2a Hit any key to stop autoboot: 0 =>

正常!因此最好是用arm-elf编译. 我在看网上查资料时记得有人说过"用arm-linux编译时,malloc返回0,而改成arm-elf编译时就好了".有个印象,具体帖子不记得在哪里了.所以后来我就一直使用arm-elf编译,没有再去试arm-linux编译.

(12) 网卡调试 剩下来的事情就是调网络了.根据上面配置rtl8019as后,网络仍然不同,然后参考uclinux驱动中的寄存器定义修改,网络就可以了.具体修改是: drivers/rtl8019.h 36 #define ETH_ADDR_SFT (8) 37 #define EI_SHIFT(x) ((x) setenv bootcmd "tftpboot; go 0xc008000" ==》设置错误 ## Starting application at 0x0C008000 ... => setenv bootcmd "tftpboot\; go 0xc008000" ==》需要有个\ => saveenv

重新开机运行u-boot: Hit any key to stop autoboot: 0 Unknown command '"tftpboot' - try 'help' ## Starting application at 0x0C008000 ... 结果还是不能自动下载uclinux和运行.经过调试才发现在设置bootcmd时多加了引号造成的!正确的设法是: => setenv bootcmd tftpboot \; go 0xc008000 ==》正确的设置

此时可以成功自动下载uclinux和运行了.

(15) flash运行 刻录到flash后,运行uclinux出现问题,运行到:uclinux 开中断后就死机,提示: Linux version 2.4.24-uc0 (root@samfei) (gcc version 2.95.3 20010315 (release)(ColdFire patches - 20010318 from http://fiddes.net/coldfire/)(uClinux XIP and shared lib patches from http://www.snapgear.com/)) #46 Áù 7ÔÂ 2 15:52:55 CST 2005 Processor: Samsung S3C44B0X revision 0 Architecture: S3C44B0X On node 0 totalpages: 2048 zone(0): 0 pages. zone(1): 2048 pages. zone(2): 0 pages. Kernel command line: root=/dev/rom0 init=/linuxrc

前面一直用armsys的bootloader,将u-boot下载到0xc300000运行,然后再load linux到0xc0080000运行,正常.而将u-boot刻录到flash后运行不正常,经过调试uclinux,到init/main.c中sti()函数后出现死机.因此怀疑中断向量设置问题.

将cpu/s3c44b0/start.S中代码修改成; 40 .globl _start 41 _start: b reset 42 /* 43 add pc, pc, #0x0c000000 44 add pc, pc, #0x0c000000 45 add pc, pc, #0x0c000000 46 add pc, pc, #0x0c000000 47 add pc, pc, #0x0c000000 48 add pc, pc, #0x0c000000 49 add pc, pc, #0x0c000000 50 */ 51 LDR PC, Undefined_Addr 52 LDR PC, SWI_Addr 53 LDR PC, Prefetch_Addr 54 LDR PC, Abort_Addr 55 LDR PC,RESERVE_Addr 56 LDR PC, IRQ_Addr 57 /* subs pc,lr,#4*/ 58 LDR PC, IRQ_Addr 59 /* subs pc,lr,#4*/

114 Undefined_Addr: 115 .word 0x0c000004 116 SWI_Addr: 117 .word 0x0c000008 118 Prefetch_Addr: 119 .word 0x0c00000C 120 Abort_Addr: 121 .word 0x0c000010 122 RESERVE_Addr: 123 .word 0x0c000014 124 IRQ_Addr: 125 .word 0x0c000018 126 FIQ_Addr: 127 .word 0x0c00001C 128 129 /* 130 * the actual reset code 131 */ 132 133 reset: 后编译,刻录,然后运行.正常了!!!

(16) 补丁制作和测试 [root@samfei u-boot]# make distclean [root@samfei 44b0]# mv u-boot u-boot.wx [root@samfei 44b0]# cvs -d:pserver:[email protected]:/cvsroot/u-boot login Logging in to server:[email protected]:2401/cvsroot/u-boot CVS password: [root@samfei 44b0]# cvs -z3 -d:pserver:[email protected]:/cvsroot/u-boot co -P u-boot cvs checkout: Updating u-boot U u-boot/CHANGELOG U u-boot/COPYING U u-boot/CREDITS U u-boot/MAINTAINERS 。。。。。。

[root@samfei 44b0]# diff -Naur u-boot u-boot.wx > uboot-wx-20050703.patch [root@samfei 44b0]# vi uboot-wx-20050703.patch 去掉没有用的文件.做补丁的好处就是自己可以很清楚的知道哪些文件修改了!做完了,别忘了测试一下.

[root@samfei 44b0]# cd u-boot [root@samfei u-boot]# patch -p1 < ../uboot-wx-20050703.patch [root@samfei u-boot]# make wx20_config [root@samfei u-boot]# make

(17) 后记 写这份材料化了不少时间.由于在调试的时候记录了大部分的调试信息,因此不用费脑筋去回忆.写完了这个经历,非常开心..一则自己可以温故而知新,二则就是与人共享啊.在开源的世界里,与人共享应该是件很快乐的一件事情. 目前micetek的板子坏了,手上没有,等我拿到板子再将u-boot移植上去.那时就不用那么麻烦了.呵呵.


摘自:linuxforum.net