一、 uboot 1.2.0移植
移植环境:VMware5.5.2+redhat9 开发板:SKY_2440B_V5.0或者V3.0
编译器:cross3.2(下载地址ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross3.2.tar.gz) Uboot:u-boot-1.2.0(下载地址:ftp://ftp.denx.de/pub/u-boot/) 先说明一下,移植过程按照tekkaman的blog移植的。 博客地址http://blog.chinaunix.net/u1/34474/index.html。
其中uboot的移植参照http://blog.chinaunix.net/u1/34474/showart.php?id=397315做的。 所下面写的移植过程,很多都是从blog上copy过来的,有不同的地方,我会另外指出。
1.用dk登录linux主机,在dk下创建一个myboard文件夹 2.解压cross3.2:解压到/usr/local/arm/文件夹下
最好在/usr/local/arm/下创建一个3.2文件夹,把解压在arm文件夹下的文件(夹)全部移到3.2下,因为后面可能还会用到3.4.1的交叉编译器。 3.解压uboot:将uboot解压到myboard文件夹下
tar xzvf u-boot-1.2.0.tar.bz2 –C /home/dk/myboard/ 4.进入uboot目录,修改Makefile
cd u-boot-1.2.0 vi Makefile
(1) 新建我的编译项
在1923行,即smdk2410_config编译项之后增加我的编译项 tekkaman2440_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t tekkaman2440 tekkaman s3c24x0 各项的意思如下: arm: CPU的架构(ARCH)
arm920t: CPU的类型(CPU),其对应于cpu/arm920t子目录。
tekkaman2440: 开发板的型号(BOARD),对应于board/tekkaman/tekkaman2440目录。 tekkaman: 开发者/或经销商(vender)。 s3c24x0: 片上系统(SOC)。
(2) 修改交叉编译器路径,我用的cross3.2是在/usr/local/arm/ 修改128行
CROSS_COMPILE=/usr/local/arm/3.2/bin/arm-linux- 5.在/board子目录中建立自己的开发板tekkaman2440目录
由于我在上一步板子的开发者/或经销商(vender)中填了 tekkaman ,所以开发板tekkaman2440目录一定要建在/board子目录中的tekkaman目录下 ,否则编译会出错。
$cd board
$mkdir tekkaman tekkaman/tekkaman2440 $cp -arf sbc2410x/* tekkaman/tekkaman2440/ $cd tekkaman/tekkaman2440 $mv sbc2410x.c tekkaman2440.c
还要记得修改自己的开发板tekkaman2440目录下的Makefile文件,不然编译时会出错: $vi Makefile
1
COBJS := tekkaman2440.o flash.o 6.在include/configs/中建立配置头文件
$cp include/configs/sbc2410x.h include/configs/tekkaman2440.h 7.测试编译能否成功
$make tekkaman2440_config
Configuring for tekkaman2440 board... (如果出现:
$ make tekkaman2440_config
Makefile:1927: *** 遗漏分隔符 。 停止。 请在U-boot的根目录下的Makefile的
@$(MKCONFIG) $(@:_config=) arm arm920t tekkaman2440 tekkaman) 前加上“Tab”键) $make
到这一步应该能编译成功,但是我的并没有编译成功,提示/common/cmd_bootm.c文件的464行的U_BOOT_CMD有错误,我是把其中的从#ifdef CONFIG_OF_FLAT_TREE到#endif都屏蔽掉,这样就可以编译过去了。可能还会出现类似的问题,用同样的方法可以解决。
下面修改Uboot中的文件,以匹配开发板 8.修改/cpu/arm920t/start.S
这个函数是arm920t系列的共有启动的汇编代码,UBOOT执行的第一个程序 (0)修改寄存器地址定义
/* turn off the watchdog */ #if defined(CONFIG_S3C2400) # define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */ #elif defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440) # define pWTCON 0x53000000这个定义了看门狗的寄存器地址
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */中断掩码的寄存器地址
# define INTSUBMSK 0x4A00001C中断掩码的寄存器地址
# define CLKDIVN 0x4C000014 /* clock divisor register */完成时钟分份的寄存器 #endif
(1)修改中断禁止部分 #if
defined(CONFIG_S3C2400)
||
defined(CONFIG_S3C2410)
||
defined(CONFIG_S3C2440)
ldr r0, =pWTCON把看门狗寄存器地址给了r0 mov r1, #0x0 r1等于0
str r1, [r0] 看门狗寄存器等于0 因为在启动时要关闭看门狗,不能让他产生中断影响启动,此时也根本不需要任何中断 /*
* mask all IRQs by setting all bits in the INTMR - default */
2
mov r1, #0xffffffff 关闭所有中断 ldr r0, =INTMSK str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x7ff //根据2410芯片手册,INTSUBMSK有11位可用, //vivi也是0x7ff,不知为什么U-Boot一直没改过来。 ldr r0, =INTSUBMSK str r1, [r0] # endif
# if defined(CONFIG_S3C2440)
ldr r1, =0x7fff //根据2440芯片手册,INTSUBMSK有15位可用 ldr r0, =INTSUBMSK str r1, [r0] # endif
(2)修改时钟设置(2440的主频可达533MHz,但是我设到533MHz时系统很不稳定,不知是不是SDRAM和总线配置的影响,所以现在先设到405MHz,以后在改进。) ldr r0, =CLKDIVN
这个值决定了FCLK HCLK PCLK的频率 FCLK是供给CPU的 是主频
HCLK是供给AHB总线(主要用于高性能模块(如CPU、DMA和DSP等)之间的连接,作为SoC的片上系统总线)上的外围设备
PCLK是供给APB总线(APB主要用于低带宽的周边外设之间的连接,例如UART、1284等)上的外围设备
UCLK是两路PLL中一路供给USB的频率
ARM总线技术在这里我不多介绍了, 对硬件感兴趣的同学建议多多了解,我有一回面试人家就问我这个了,405MHZ已经很高了,基本都够了,2410的200MHZ就能播放Mplayer视频,据说很流畅。
mov r1, #5 /* FCLK:HCLK:PCLK = 1:4:8 */
str r1, [r0]
mrc p15, 0, r1, c1, c0, 0 /*read ctrl register tekkaman*/ orr r1, r1, #0xc0000000 /*Asynchronous tekkaman*/ mcr p15, 0, r1, c1, c0, 0 /*write ctrl register tekkaman*/
他是用到了协处理器P15,此处理器主要设置mmu,时钟模式,caches,保护模式的。先把C0 C1的值读出到r1,设置后再写回。 FCLK:HCLK:PCLK的比例由CLKDIVN决定的,CLKDIVN寄存器的HDIVN和PDIVN决定比例的大小。因为此时的HDIVH不为0,将快速总线模式改为异步总线模式,操作协处理器P15改变模式即可,如果HDIVH不为0,而且是快速总线模式的话,那么CPU的主频由hclk控制,这样可以实现不改变HCLK和PCLCK的同时就能使CPU的主频减半或更多。网上的大虾说没有以上几句主频会是12MHZ,我的观点不同。这是数据手册原文
If HDIVN is not 0 and the CPU bus mode is the fast bus mode, the CPU will operate by the HCLK.This feature can be used to change the CPU frequency as a half or more without affecting the HCLKand PCLK #if defined(CONFIG_S3C2440)
3
/*now, CPU clock is 405.00 Mhz tekkaman*/
mov r1, #CLK_CTL_BASE /* tekkaman*/这是时钟寄存器的基地址 mov r2, #MDIV_405 /* mpll_405mhz tekkaman*/ add r2, r2, #PSDIV_405 /* mpll_405mhz tekkaman*/ str r2, [r1, #0x04] /* MPLLCON tekkaman */设置 MPLLCON #endif
#if defined(CONFIG_S3C2410)
/*now, CPU clock is 202.8 Mhz tekkaman*/ mov r1, #CLK_CTL_BASE /* tekkaman*/
mov r2, #MDIV_200 /* mpll_200mhz tekkaman*/ add r2, r2, #PSDIV_200 /* mpll_200mhz tekkaman*/ str r2, [r1, #0x04] /* MPLLCON tekkaman */ #endif
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410|| CONFIG_S3C2440 */
红色部分是我添加的,利用vivi的代码,将其设为405.00MHz 并在前面加上: #elif defined(CONFIG_S3C2410) # define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */ #define CLK_CTL_BASE 0x4C000000 /* tekkaman */ #if defined(CONFIG_S3C2440)
#define MDIV_405 0x7f << 12 /* tekkaman */ #define PSDIV_405 0x21 /* tekkaman */ #endif
#if defined(CONFIG_S3C2410)
#define MDIV_200 0xa1 << 12 /* tekkaman */ #define PSDIV_200 0x31 /* tekkaman */ #endif #endif〕
(3)将从Flash启动改成从NAND Flash启动。(特别注意:这和2410的程序有不同,不可混用!!!是拷贝vivi的代码。)
将以下U-Boot的重定向语句段:
这段代码将uboot搬运到ram中,这个是没有存放在nand的情况,下面咱们来看一下不在nand启动和在nand启动时此处的区别。
#ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */nor中的起始地址给了r0
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ram中的uboot代码的起始地址(这里关于uboot搬运这块在内存地址的部分,分了很多段,每一段空间具有不同功能,这是你理解uboot必须掌握的,非常关键,解释后续会提到些)
cmp r0, r1 /* don't reloc during debug */比较两个地址是否相同,不同则进行下面的搬运工作
4
beq stack_setup
在这里你会发现搬运了全部uboot,有的uboot把uboot的c部分搬运到内存_TEXT_BASE里面所放的地址处。
ldr r2, _armboot_start ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */ _bss_start-_armboot_start= armboot 因为_armboot_end的结束位置就是bss区的开始位置所以能计算出uboot代码的大小 add r2, r0, r2 /* r2 <- source end address */
以下就是把整个代码搬运到_TEXT_BASE里面所放的地址处,记住是内存地址,哈哈!! copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */ stmia r1!, {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
替换成:因为nand和nor的启动是有区别的,NOR Flash储存器较贵,而NAND Flash则相对便宜,所以很多用户选择在NAND Flash中执行启动代码,在SDRAM中执行主程序。为支持NAND Flash的BootLader,S3C2440有一个内部SRAM缓冲,称为‘Steppingstone’,启动时,NAND Flash的最先4K字节将被装载到Steppingstone中,装载到Steppingstone中的启动代码将执行。这都是硬件自动完成的不需要咱们软件参与。一般来说,启动代码将把NAND Flash的内容拷贝到SDRAM中,ECC将检测NAND的合法性,当拷贝完成时,主程序将在SDRAM中执行电源开启后,或系统重启后,NAND Flash控制器将自动装载4KB的BootLoader代码,载入代码后将执行。注意在自启动时,ECC不检测,因此,NAND Flash的头4KB要保证无错,下面我来带你分析它的源代码喽,嘿嘿!!!!忽然想家了,对了nand的硬件连接简单有兴趣的看一下了(NCON-Adv Flash,GPG13-Page size,GPG14-Address cycle,GPG15-总线宽度)
#ifdef CONFIG_S3C2440_NAND_BOOT @tekkaman@ 在以后会定义它的,不要忘了 @ reset NAND
mov r1, #NAND_CTL_BASE nand的寄存器基地址
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) CLE & ALE期间设置值|TWRPH0 期间设置值|TWRPH0 期间设置值|8位总线
str r2, [r1, #oNFCONF] 设置NFCONF寄存器,初始化作用 ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control初始化ECC解码/编码器(只写)
|强制拉低nFCE(允许片选)|允许NAND控制器
str r2, [r1, #oNFCONT] 设置 NFCONT ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) @ RnB Clear和nand is busy str r2, [r1, #oNFSTAT] ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
5