分类: LINUX
2011-02-24 12:00:52
Smdk2410可以编译通过之后,即可进入2440的移植了。2440和2410的资源差不多,主频和外设有点差别,所以我们就在board/samsung/下以smdk2410为模板建立自己目标板的项目,取名叫smdk2440。(代码中的修改用红色表示)
一、首先建立目标板文件
#cp -rf smdk2410/* smdk2440/ //将2410下所有的代码复制到2440下
#cd smdk2440 //进入smdk2440目录
#mv smdk2410.c smdk2440.c //将smdk2440下的smdk2410.c改名为smdk2440.c
#cd
../../../
//回到u-boot根目录
#cp include/configs/smdk2410.h include/configs/smdk2440.h //建立2440头文件
#gedit board/samsung/smdk2440/Makefile
修改smdk2440下Makefile的编译项,如下:
COBJS := smdk2440.o flash.o //因在smdk2440下我们将smdk2410.c改名为smdk2440.c
老版本的uboot是需要修改顶层makefile文件
在其中加入:
smdk2440_config : unconfig //2440编译选项格式
@$(MKCONFIG) $(@:_config=) arm
arm920t smdk2440 samsung s3c24x0
但是新版本的文件组织结构有很大变化,需要在boards.cfg文件中smdk2410的下面增加类似的一条:
smdk2440 arm arm920t - samsung s3c24x0
然后,测试下编译情况:
Make distclean
Make smdk2440_ config
Make all
不幸,出现如下错误:
board.c: In function 'board_init_f':
board.c:279: error: 'CONFIG_SYS_TEXT_BASE' undeclared (first use in this function)
board.c:279: error: (Each undeclared identifier is reported only once
board.c:279: error: for each function it appears in.)
make[1]: *** [board.o] 错误 1
make[1]: 离开目录“/home/bsc/samba/u-boot-2010.12/arch/arm/lib”
make: *** [arch/arm/lib/libarm.o] 错误 2
这说明我们前面为了编译通过而增加的宏定义可能是有问题的,事实上我们可以在网上查到一个patch,可以解决这些问题。但是这里,为了深入了解问题所在,我们手动一点点来修改而不是直接打上patch。
include/configs/smdk2410.h include/configs/smdk2440.h 文件中删除上面添加的宏定义:
#define
CONFIG_SYS_SDRAM_BASE
0x00000000
#define
CONFIG_SYS_INIT_SP_ADDR
(CONFIG_SYS_TEXT_BASE - GENERATED_GBL_DATA_SIZE)
添加如下宏定义(参考该patch)
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - GENERATED_GBL_DATA_SIZE)
然后再次编译,此次编译可以通过 至此我们建立起了目标板的框架,我们可以开始修改代码以适应我们的目标板。
二、目标板u-boot的硬件设备初始化。
(1)入口代码分析
一般在嵌入式系统软件开发中,在所有源码文件编译完成之后,链接器要读取一个链接分配文件,在该文件中定义了程序的入口 点,代码段、数据段等分配情况等。那么我们的2440开发板u-boot的这个链接文件就是cpu/arm920t/u-boot.lds,打开该文件部分代码如下:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm) //定义生成文件的目标平台是arm
ENTRY(_start) //定义程序的入口点是_start
SECTIONS
{
//其他一些代码段、数据段等分配
. = 0x00000000;
. = ALIGN(4);
.text
:
{
cpu/arm920t/start.o (.text)
*(.text)
}
..................
..................
}
知道了程序的入口点是_start,那么我们就打开2440开发板u-boot第一个要运行的程序cpu/arm920t/start.S,查找到_start的位置如下:
.globl
_start
_start: b
start_code //将程序的执行跳转到start_code处
从这个汇编代码可以看到程序又跳转到start_code处开始执行,那么再查找到start_code处的代码如下:
/*
* the actual start code
*/
start_code:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
bl coloured_LED_init //此处两行是对AT91RM9200DK开发板上的LED进行初始化的
bl red_LED_on
由此可以看到,start_code处才是u-boot启动代码的真正开始处。
(2)初始化代码修改
start.S中注释掉LED相关代码:
/*bl coloured_LED_init //这两行是AT91RM9200DK开发板的LED初始化,注释掉
bl red_LED_on*/
/*注释掉以下两行代码以便在内存中调试
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
*/
或者在在include/configs/smdk2440.h头文件中添加CONFIG_S3C2440宏
#define CONFIG_SKIP_LOWLEVEL_INIT
在include/configs/smdk2440.h头文件中添加CONFIG_S3C2440宏
#define
CONFIG_ARM920T 1 /* This is an ARM920T Core */
/*#define CONFIG_S3C2410 1 */ /* in a SAMSUNG S3C2410 SoC */需要注销此宏
/*#define
CONFIG_SMDK2410 1 */ /* on a SAMSUNG SMDK2410 Board */需要注销此宏
#define CONFIG_S3C2440 1 /* in a SAMSUNG S3C2440
SoC */添加此宏
#define CONFIG_SYS_CLK_FREQ 16934400/* the SMDK2440 has 16MHz input clock by bsc */
在u-boot中添加对S3C2440一些寄存器的支持、添加中断禁止部分和时钟设置部分。
由于2410和2440的寄存器及地址大部分是一致的,所以这里就直接在2410的基础上再加上对2440的支持即可,cpu/arm920t/start.S代码如下:
#ifdef CONFIG_S3C24X0
/* turn off the watchdog */
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-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
# if defined(CONFIG_S3C2440)
ldr r1, =0x7fff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
# if defined(CONFIG_S3C2440) //添加s3c2440的时钟部分
#define MPLLCON 0x4C000004 //系统主频配置寄存器基地址
#define UPLLCON 0x4C000008 //USB时钟频率配置寄存器基地址
#define CAMDIVN 0x4C000018
ldr r0, = CAMDIVN
mov r1, #0
str r1, [r0]
ldr r0, = CLKDIVN //设置分频系数FCLK:HCLK:PCLK = 1:3:6
ldr r1, = 0x7
str r1, [r0]
ldr r0, =MPLLCON //设置系统主频为405MHz
ldr r1, =0x6e031 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str r1, [r0]
ldr r0, =UPLLCON //设置USB时钟频率为48MHz
ldr r1, =0x3c042 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str r1, [r0]
# else //其他开发板的时钟部分,这里就不用管了,我们现在是做2440的
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C2440 */
#endif /* CONFIG_S3C24X0 */
S3C2440的时钟部分除了在start.S中添加外,还要在board/samsung/smdk2440/smdk2440.c修改或添加部分代码,如下:
#define FCLK_SPEED 2 //设置默认等于2,by bsc 2010-2-22 20:49
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
#define M_MDIV 0xA1
#define M_PDIV 0x3
#define M_SDIV 0x1
#elif FCLK_SPEED==2 /* Fout = 405MHz */
#define M_MDIV 0x6e //这三个值根据S3C2440芯片手册“PLL VALUE SELECTION TABLE”部分进行设置
#define M_PDIV 0x3
#define M_SDIV 0x1
#endif
#define USB_CLOCK 2 //设置默认等于2,即下面红色代码部分有效
#if USB_CLOCK==0
#define U_M_MDIV 0xA1
#define U_M_PDIV 0x3
#define U_M_SDIV 0x1
#elif USB_CLOCK==1
#define U_M_MDIV 0x48
#define U_M_PDIV 0x3
#define U_M_SDIV 0x2
#elif USB_CLOCK==2 /* Fout = 48MHz */
#define U_M_MDIV 0x3c //这三个值根据S3C2440芯片手册“PLL VALUE SELECTION TABLE”部分进行设置
#define U_M_PDIV 0x4
#define U_M_SDIV 0x2
#endif
修改/* arch number of SMDK2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2440;
在dram_init(void)函数中添加gd->ram_size初始化(此句比较重要):
gd->ram_size = PHYS_SDRAM_1_SIZE; /*add by bsc 2011/2/21 20:14:46*/
修改board/samsung/smdk2440/config.mk
CONFIG_SYS_TEXT_BASE = 0x33000000/*0x3f800000改为0x33000000 以便内存中调试*/
修改完毕后我们再重新编译u-boot,然后再下载到RAM中运行测试。tftp 0x33000000 u-boot.bin
go 0x33000000
结果终端有输出信息并且出现类似Shell的命令行,这说明这一部分移植完成。如果有其他问题可以在include/configs/smdk2440.h头文件中添加DEBUG宏用于调试。