开发环境:Ubuntu 12.04
开发板:JZ2440 256M NandFlash 64M SDRAM
交叉编译器:arm-linux-gcc-4.3.2
u-boot:u-boot-2012.04.01
分析uboot中 make xxx_config过程 http://www.linuxidc.com/Linux/2017-06/145292.htm
U-Boot源代码下载地址 http://www.linuxidc.com/Linux/2011-07/38897.htm
最近在学习BootLoader,移植u-boot-2012.04.01到JZ2440开发板,现在把移植过程记录下来,一来梳理思路,二来方便以后更进一步学习。
一、 u-boot分析过程
a、 初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
b、如果bootloader比较大,要把它重定位到SDRAM
c、把内核从NAND FLASH读到SDRAM
d、设置"要传给内核的参数"
e、跳转执行内核
具体代码分析
1、set the cpu to SVC32 mode
2、turn off the watchdog
3、mask all IRQs by setting all bits in the INTMR
4、设置时钟比例
5、设置内存控制器
6、设置栈,调用C函数board_init_f
7、调用函数数组init_sequence里的各个函数
7.1 board_early_init_f : 设置系统时钟、设置GPIO
......................................
8、重定位代码
8.1 从NOR FLASH把代码复制到SDRAM
8.2 程序的链接地址是0,访问全局变量、静态变量、调用函数时是使"基于0地址编译得到的地址",现在把程序复制到了SDRAM,需要修改代码,把"基于0地址编译得到的地址"改为新地址。
8.3 程序里有些地址在链接时不能确定,要到运行前才能确定:fixabs
9、clear_bss
10、调用C函数board_init_r:第2阶段的代码
二、初始编译
1、 解压 u-boot-2012.04.01.tar.bz2
tar xjf u-boot-2012.04.01.tar.bz2
进入解压后文件目录
cd u-boot-2012.04.01
2、在解压后文件目录下根据靠近的单板,配置
make smdk2410_config
make
这个时候编译完成后是不能在JZ2440上正常运行
三、建立自己的单板,定制适合自己单板的bootloader
1、新建一个单板
cd board/samsung/
cp smdk2410 smdk2440 -rf
cd ../../include/configs/
cp smdk2410.h smdk2440.h
修改boards.cfg
仿照2410,添加2440
smdk2410 arm arm920t - samsung s3c24x0
添加
smdk2440 arm arm920t - samsung s3c24x0
make , 烧写调试
2、根据需求进一步配置
make menuconfig
3、修改Makefile ,开头指定架构和编译器
ARCH=arm
CROSS_COMPILE=arm-linux-
4、修改uboot代码,适合单板
uboot里先以60MHZ的时钟计算参数来设置内存控制器,但是MPLL还未设置
处理措施: 把MPLL的设置放到start.S里,取消board_early_init_f里对MPLL的设置
a、设置PLL的时钟的函数在_main中的board_init_f中初始化函数列表中的 boad_early_init_f 中,设置MPLL倍频值。它应该要在设置分频系数和初始化内存控制器之前来设置。
做如下修改: 在smdk2410.c文件中找到设置MPLL部分的代码,注释掉。
/* to reduce PLL lock time, adjust the LOCKTIME register */
//writel(0xFFFFFF, &clk_power->locktime);
/* configure MPLL */
//writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,
// &clk_power->mpllcon);
然后在start.S中再设置MPLL
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#if 0
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#else
/* 2. 设置时钟 400MHz */
ldr r0, =0x4c000014
// mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8
str r1, [r0]
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */
orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
/* MPLLCON = S3C2440_MPLL_200MHZ */
ldr r0, =0x4c000004
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
/* 启动ICACHE */
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
#endif
关闭看门狗、关中断
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#if 0
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#else
/* 2. 设置时钟 400MHz */
ldr r0, =0x4c000014
// mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8
str r1, [r0]
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */
orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
/* MPLLCON = S3C2440_MPLL_200MHZ */
ldr r0, =0x4c000004
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
/* 启动ICACHE */
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
#endif
关闭看门狗、关中断
#ifdef CONFIG_S3C24X0
/* turn off the watchdog */
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interrupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
# endif
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
#endif
b、内存控制器的设置值改为如下
在/board/samsung/smdk2410/lowlevel_init.S文件中做一下修改
SMRDATA:
#if 0
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x32
.word 0x30
.word 0x30
#else
.long 0x22011110 //BWSCON
.long 0x00000700 //BANKCON0
.long 0x00000700 //BANKCON1
.long 0x00000700 //BANKCON2
.long 0x00000700 //BANKCON3
.long 0x00000700 //BANKCON4
.long 0x00000700 //BANKCON5
.long 0x00018005 //BANKCON6
.long 0x00018005 //BANKCON7
.long 0x008C04F4 //REFRESH
.long 0x000000B1 //BANKSIZE
.long 0x00000030 //MRSRB6
.long 0x00000030 //MRSRB7
#endif
c、设置串口波特率(get_HCLK函数),乱码,查看串口波特率的设置,发现在get_HCLK里没有定义CONFIG_S3C2440宏
处理措施:在include/configs/smdk2440.h中
//#define CONFIG_S3C2410 /* specifically a SAMSUNG S3C2410 SoC */
//#define CONFIG_SMDK2410 /* on a SAMSUNG SMDK2410 Board */
#define CONFIG_S3C2440 /* specifically a SAMSUNG S3C2440 SoC */
#define CONFIG_SMDK2440 /* on a SAMSUNG SMDK2440 Board */
d、修改UBOOT支持NAND启动,原来的代码在链接时加了"-pie"选项, 使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)"
使得程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K)
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie 去掉这行
把init.c放入board/samsung/smdk2440目录,修改Makefile,使init.c编译进去
修改smdk2440.h ,修改CONFIG_SYS_TEXT_BASE为0x33f80000
#define CONFIG_SYS_TEXT_BASE 0x33f00000
init.c
/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))