传统的SoC比如S3C2440,6410或者s5pv210,它们的Uboot在lowlevel_init.S文件中做了很多片上外设的初始化工作,比如配置部分GPIO口的电气属性,配置串口,配置DDR控制器等,配置的过程很简单,简单来说就是这样:
ldr r0,=外设寄存器地址
ldr r1,=寄存器的值
str r1,[r0] @r0和r1只是常用,也可以使用别的寄存器来进行这个过程
但是NXP的IMX6ULL这款SoC的Uboot,在lowlevel_init.S这个文件中仅仅只是在片内RAM中设置了堆栈,然后划分出一部分区域用于存储struct global_data的值:
ENTRY(lowlevel_init)
ldr sp, =CONFIG_SYS_INIT_SP_ADDR @设置sp指针到片内RAM的一块
bic sp, sp, #7 @8字节对齐
sub sp, sp, #GD_SIZE @留出struct global_data变量的区域
bic sp, sp, #7
mov r9, sp @把struct global_data变量的起始地方放到r9中
push {ip, lr}
bl s_init @对IMX6ULL来说,这个函数是个空函数
pop {ip, pc}
ENDPROC(lowlevel_init)
之后进入到_main函数,这个函数在arch/arm/lib/crt0.S中,对IMX6ULL来说这个函数几乎干了Uboot在启动Linux系统之前的所有事情。
1、上来重新设置以下堆栈指针,因为上述的lowlevel_init函数把sp指针指向struct global变量的起始地址去了。
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
2、连续三个函数调用。
mov r0, sp @进行函数调用的参数传递,把参数放到r0中
bl board_init_f_alloc_reserve @在片内SRAM留出malloc区域和新的global_data区域
mov sp, r0 @获取函数返回值
mov r9, r0
bl board_init_f_init_reserve @把上述留出的两个区域给清零
mov r0, #0
bl board_init_f @调用board_init_f函数,这个函数非常重要
boadr_init_f函数非常重要!它的作用有两个:一是初始化部分片上外设,比如串口,LCD接口,定时器等。二是初始化global_data中的所有成员变量,global_data的成员变量中有一大部分是地址信息,描述了外部DDR该如何划分,哪里是malloc区,哪里是重定位的起始地址,哪里是Uboot的终止地址等等。有了这些信息才能进行后续的Uboot代码重定位过程。
下面来看看board_inif_f函数,该函数位于/u