嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解

2019-07-12 15:52发布

data/attach/1907/1qww3zewgvk83api8a59odg8znzragr6.jpgdata/attach/1907/nrbr8id2wuwxtbf2p4rqkjbluxuaup90.jpgdata/attach/1907/s00n3xmj9ec1081vfwwptb5csgbe3nlf.jpgdata/attach/1907/gpupgrsw972zxyl3v1dd564o24z44v0o.jpgdata/attach/1907/jxk7pg6ujqb81crutnl7bg4prxvxczf6.jpgdata/attach/1907/q05wcykkumgv6dysq6umabfeyfok2fpx.jpgdata/attach/1907/xtveomi480guzsam9r0is91a9dedyrbv.jpgdata/attach/1907/tthtm9e8n82ytmgbrxtankk9l3d4a8lc.jpgdata/attach/1907/4eokbwhn1djyf4oehfj8f628ab1zoxdb.jpg

嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。如有错误之处,谢请指正。


一、移植环境



二、移植步骤


本次移植的功能特点包括:



  • 支持Nand Flash读写

  • 支持从Nor/Nand Flash启动

  • 支持CS8900或者DM9000网卡

  • 支持Yaffs文件系统

  • 支持USB下载(还未实现)


1
.

了解u-boot主要的目录结构和启动流程,如下图。






u-boot
stage1代码通常放在cpu/xxxx/
start.S文件中,他用汇编语言写成;
u-boot
stage2代码通常放在lib_xxxx/board.c文件中,他用C语言写成。


各个部分的流程图如下:







2. 建立自己的开发板项目并测试编译。





目前u-boot对很多CPU直接支持,可以查看board目录的一些子目录,如:board/samsung/目录下就是对三星一些ARM处理器的支持,有smdk2400、smdk2410和smdk6400,但没有2440,所以我们就在这里建立自己的开发板项目。


1)因2440和2410的资源差不多,主频和外设有点差别,所以我们就在board/samsung/下建立自己开发板的项目,取名叫my2440



#tar -jxvf u-boot-2009.08.tar.bz2
//解压源码


#cd u-boot-2009.08/board/samsung/
//进入目录

#mkdir my2440
//创建my2440文件夹






2)因2440和2410的资源差不多,所以就以2410项目的代码作为模板,以后再修改





#cp -rf smdk2410/* my2440/
//将2410下所有的代码复制到2440下



#cd my2440
//进入my2440目录




#mv smdk2410.c my2440.c //将my2440下的smdk2410.c改名为my2440.c




#cd ../../../
//回到u-boot根目录





#cp include/configs/smdk2410.h include/configs/my2440.h

//建立2440头文件

#gedit board/samsung/my2440/Makefile
//修改my2440下Makefile的编译项,如下:









COBJS:=
my2440.o flash.o //因在my2440下我们将smdk2410.c改名为my2440.c






3)修改u-boot跟目录下的Makefile文件。查找到smdk2410_config的地方,在他下面按照smdk2410_config的格式建立my2440_config的编译选项,另外还要指定交叉编译器





#gedit Makefile







CROSS_COMPILE ?= arm-linux- //指定交叉编译器为arm-linux-gcc









smdk2410_config:unconfig //2410编译选项格式



@$(MKCONFIG) $(@:_config=


)

arm arm920t smdk2410 samsung s3c24x0






my2440_config:unconfig //2440编译选项格式



@$(MKCONFIG) $(@:_config=


)

arm arm920tmy2440 samsung s3c24x0





*说明:arm :CPU的架构(ARCH)



arm920t:CPU的类型



my2440 :对应在board目录下建立新的开发板项目的目录



samsung:新开发板项目目录的上级目录,如直接在board下建立新的开发板项目的目录,则这里就为NULL



s3c24x0:CPU型号



*注意:编译选项格式的第二行要用Tab键开始,否则编译会出错






4)测试编译新建的my2440开发板项目





#make my2440_config
//如果出现Configuring for my2440 board...则表示设置正确



#make //编译后在根目录下会出现u-boot.bin文件,则u-boot移植的第一步就算完成了







到此为止,u-boot对自己的my2440开发板还没有任何用处,以上的移植只是搭建了一个my2440开发板u-boot的框架,要使其功能实现,还要根据my2440开发板的具体资源情况来对u-boot源码进行修改。




3. 根据u-boot启动流程图的步骤来分析或者修改添加u-boot源码,使之适合my2440开发板(注:修改或添加的地方都用红 {MOD}表示
)。



1)my2440开发板u-boot的stage1入口点分析。

一般
在嵌入式系统软件开发中,在所有源码文件编译完成之后,链接器要读取一个链接分配文件,在该文件中定义了程序的入口点,代码段、数据段等分配情况等。那么
我们的my2440开发板u-boot的这个链接文件就是cpu/arm920t/u-boot.lds,打开该文件部分代码如下:




#gedit
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,那么我们就打开my2440开发板u-boot第一个要运行的程序cpu/arm920t/start.S(即u-boot的stage1部分)
,查找到_start的位置如下:




#gedit
cpu/arm920t/start.S







.
globl _start

_start:
b start_code//将程序的执行跳转到start_code处






从这个汇编代码可以看到程序又跳转到start_code处开始执行,那么再查找到start_code处的代码如下:





/*

* the actual start code

*/




start_code:


/*

* set the cpu to SVC32 mode

*/



mrsr0,
cpsr

bicr0,
r0,
#
0x1f

orrr0,
r0,
#
0xd3

msrcpsr,
r0


bl coloured_LED_init //此处两行是对AT91RM9200DK开发板上的LED进行初始化的


bl red_LED_on





由此可以看到,start_code处才是u-boot启动代码的真正开始处。以上就是u-boot的stage1入口的过程。

2)my2440开发板u-boot的stage1阶段的硬件设备初始化。



于在u-boot启动代码处有两行是AT91RM9200DK的LED初始代码,但我们my2440上的LED资源与该开发板的不一致,所以我们要删除或
屏蔽该处代码,再加上my2440的LED驱动代码(注:添加my2440
LED功能只是用于表示u-boot运行的状态,给调试带来方便,可将该段代码放到任何你想调试的地方),代码如下:





/*bl coloured_LED_init

//这两行是AT91RM9200DK开发板的LED初始化,注释掉



bl red_LED_on*/









#ifdefined(CONFIG_S3C2440)
//区别与其他开发板





//根据mini2440原理图可知LED分别由S3C2440的PB5、6、7、8口来控制,以下是PB端口寄存器基地址(查2440的DataSheet得知)


#

define
GPBCON 0x56000010





#

define
GPBDAT 0x56000014
#

define
GPBUP 0x56000018





//以下对寄存器的操作参照S3C2440的DataSheet进行操作


ldr r0,


=

GPBUP

ldr r1,


=


0x7FF //即:二进制11111111111,关闭PB口上拉


str r1,


[


r0]




ldr r0,


=


GPBCON//配置PB5、6、7、8为输出口,对应PBCON寄存器的第10-17位


ldr r1,


=


0x154FD //即:二进制010101010011111101


str r1,


[


r0]





ldr r0,


=


GPBDAT

ldr r1,


=


0x1C0 //即:二进制111000000,PB5设为低电平,6、7、8为高电平


str r1,


[

r0]








#endif




//此段代码使u-boot启动后,点亮开发板上的LED1,LED2、LED3、LED4不亮






include/configs/my2440.h头文件中添加CONFIG_S3C2440宏




#gedit
include/configs/my2440.h







#
define

CONFIG_ARM920T1/* This is an ARM920T Core*/

#
define

CONFIG_S3C24101/* in a SAMSUNG S3C2410 SoC */

#
define

CONFIG_SMDK24101/* on a SAMSUNG SMDK2410 Board */

#

define
CONFIG_S3C24401

/* in a SAMSUNG S3C2440 SoC*/








现在编译u-boot,在根目录下会生成一个u-boot.bin文件。然后我们利用mini2440原有的supervivi把u-
boot.bin下载到RAM中运行测试(注意:我们使用supervivi进行下载时已经对CPU、RAM进行了初始化,所以我们在u-boot中要屏
蔽掉对CPU、RAM的初始化),如下:






/
*#ifndef CONFIG_SKIP_LOWLEVEL_INIT //在start.S文件中屏蔽u-boot对CPU、RAM的初始化


blcpu_init_crit

#endif*/









#make my2440_config



#make




下载运行后可以看到开发板上的LED灯第一了亮了,其他三个熄灭,测试结果符合上面的要求。终端运行结果如下:



3)在u-boot中添加对
S3C2440一些寄存器的支持、添加中断禁止部分和时钟设置部分



由于2410和2440的寄存器及地址大部分是一致的,所以这里就直接在2410的基础上再加上对2440的支持即可,代码如下:




#gedit
cpu/arm920t/start.S







#if
defined(
CONFIG_S3C2400)
|
|
defined(
CONFIG_S3C2410) || defined(CONFIG_S3C2440)



/*
turn off the watchdog *
/



# if
defined(
CONFIG_S3C2400)


# define pWTCON0x15300000

# define INTMSK0x14400008/*
Interupt-
Controller base addresses *
/


# define CLKDIVN0x14800014/*
clock divisor register *
/


#else //下面2410和2440的寄存器地址是一致的



# define pWTCON0x53000000

# define INTMSK0x4A000008/*
Interupt-
Controller base addresses *
/


# define INTSUBMSK0x4A00001C

# define CLKDIVN0x4C000014/*
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)
//添加s3c2440的中断禁止部分



ldr r1,

=

0x7fff //
根据2440芯片手册,INTSUBMSK寄存器有15位可用





ldr r0,


=


INTSUBMSK
str

r1,


[

r0]



#

endif








# if

defined(

CONFIG_S3C2440

)
//添加s3c2440的时钟部分







#

define
MPLLCON0x4C000004
//系统主频配置寄存器基地址



#define UPLLCON0x4C000008//USB时钟频率配置寄存器基地址



ldr r0
,




=



CLKDIVN //设置分频系数FCLK:HCLK:PCLK = 1:4:8


mov r1

,




#


5

str r1

,




[


r0
]














ldr r0, =MPLLCON//设置系统主频为405MHz


ldr r1, =0x7F021//这个值参考
芯片手册“PLL VALUE SELECTION TABLE”部分


str r1, [r0]



ldr r0, =UPLLCON //设置USB时钟频率为48MHz


ldr r1, =0x38022 //这个值参考
芯片手册“PLL VALUE SELECTION TABLE”部分




str r1, [r0]



#

else
//其他开发板的时钟部分,这里就不用管了,我们现在是做2440的


/
*
FCLK
:
HCLK
:
PCLK
=
1
:
2
:
4
*
/

/
*
default FCLK is 120 MHz
!

*
/



ldrr0,
=
CLKDIVN
mov
r1,
#3
str
r1,
[
r0]




# endif



#endif
/*
CONFIG_S3C2400 |
|
CONFIG_S3C2410 |
|
CONFIG_S3C2440 *
/








S3C2440的时钟部分除了在start.S中添加外,还要分别在board/samsung/my2440/my2440.c和cpu/arm920t/s3c24x0/speed.c中修改或添加部分代码,如下:




#gedit
board/samsung/my2440/my2440.c
//设置主频和USB时钟频率参数与start.S中的一致









#
define

FCLK_SPEED 2 //设置默认等于2,即下面红 {MOD}代码部分有效



#
if
FCLK_SPEED=
=
0 /* Fout = 203MHz, Fin = 12MHz for Audio */

#
define

M_MDIV0xC3
#
define

M_PDIV0x4
#
define

M_SDIV0x1
#
elif

FCLK_SPEED=
=
1/* Fout = 202.8MHz */

#
define

M_MDIV0xA1
#
define

M_PDIV0x3
#
define

M_SDIV0x1
#

elif
FCLK_SPEED=

=


2

/* Fout = 405MHz */

#


define
M_MDIV0x7F //这三个值根据S3C2440
芯片手册“PLL VALUE SELECTION TABLE”部分进行设置

#


define
M_PDIV0x2
#


define
M_SDIV0x1


#
endif




#
define

USB_CLOCK 2 //设置默认等于2,即下面红 {MOD}代码部分有效



#
if
USB_CLOCK=
=
0
#
define

U_M_MDIV0xA1
#
define

U_M_PDIV0x3
#
define

U_M_SDIV0x1
#
elif



USB_CLOCK=
=
1
#
define

U_M_MDIV0x48
#
define

U_M_PDIV0x3
#
define

U_M_SDIV0x2
#


elif
USB_CLOCK
=

=



2
/* Fout = 48MHz */

#


define
U_M_MDIV0x38 //这三个值根据S3C2440
芯片手册“PLL VALUE SELECTION TABLE”部分进行设置

#




define
U_M_PDIV0x2
#




define
U_M_SDIV0x2


#
endif