4412 uboot启动过程分析之一

时间:2020-12-15 04:55:46
.globl _start
_start: b reset //uboot启动从_start开始,跳转到reset
ldr pc, _undefined_instruction //初始化中断向量表
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

系统启动后直接跳转到reset

reset:
mrs r0, cpsr //程序状态寄存器cpsr
bic r0, r0, #0x1f //cpsr的低五位被清零
orr r0, r0, #0xd3 //关中断,并进入SVC32模式
msr cpsr,r0
bl cpu_init_crit //跳转到cpu_init_crit,初始化内存,时钟等关键寄存器
reset设置为管理模式后进入cpu_init_crit

cpu_init_crit:

bl cache_init //初始化cache

/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs //ARM最多可支持16个协处理器p0-p15
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache

/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00001000 @ set bit 12 (---I) Icache
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0

/*
* Jump to board specific initialization...
* The Mask ROM will have already initialized
* basic memory. Go here to bump up clock rate and handle
* wake up conditions.
*/
mov ip, lr //cpu_init_crit被reset调用,lr保存用于返回reset函数的地址,
bl lowlevel_init //此处子函数cpu_init_crit发生二次调用,故将用于返回reset的lr保存,
mov lr, ip //调用lowlevel_init后lr更新为返回cpu_init_crit的地址
mov pc, lr

关闭cache和MMU,在arm中cache是cpu的内部缓存,MMU实现虚拟地址与物理地址的转换。

cache在cpu中用来存放常用的数据和指令,cache开启的情况下,cpu首先在cache中寻找需要的指令或数据,cache中没有再从RAM获取,uboot启动的时候不管cache是否初始化都不会有cpu需要的数据,uboot用来实现简单的初始化和引导操作,关闭cache优化uboot性能。

C语言不能控制cache的开关,但关键字volatile能够避免优化,所谓避免优化实际上就是编译器告诉cpu在获取这个变量时不要从cache中读取,因为这个变量是随时可变的,cache不能实时的反应这些变量的值,cpu每次读取都直接从变量实际地址读取。同样关闭MMU,在uboot刚启动的时候避免虚拟地址无物理地址的转换。

lowlevel_init是lowlevel_init.S下定义的全局函数,配置启动必须的硬件

	.globl lowlevel_init
lowlevel_init:

/* use iROM stack in bl2 */
ldr sp, =0x02060000 //上面提到关于函数调用返回地址的保存,cpu_init_crit将lr保存在ip,
push {lr} //lowlevel_init肯定会调用更多函数,所以将回调地址保存到iROM的堆栈中


#ifdef CONFIG_EXYNOS4412
bl set_ema_value //如果4412版本号大于2.0,设置apll,我们是1.1版本,不需要
#endif


/* initialization for CMU_SYSCLK_ISP function */
mov r1, #0
ldr r0, =0x10021174 /* CMU_RESET_ISP_SYS_PWR_REG */
str r1, [r0]
ldr r0, =0x100213B8 /* CMU_SYSCLK_ISP_SYS_PWR_REG */
str r1, [r0]


/* check reset status */
ldr r0, =(INF_REG_BASE + INF_REG1_OFFSET)
ldr r1, [r0]
//查看cpu是怎么复位的,如果从睡眠唤醒进入复位则发生跳转,否则继续执行
/* Sleep wakeup reset */
ldr r2, =S5P_CHECK_SLEEP
cmp r1, r2
beq wakeup_reset

/* PS-Hold high */
//拉高PSHOLD管脚,唤醒电源管理芯片
ldr r0, =0x1002330c
ldr r1, [r0]
orr r1, r1, #0x300
str r1, [r0]

/* set CP reset to low */
ldr r0, =0x11000C60
ldr r1, [r0]
ldr r2, =0xFFFFFF0F
and r1, r1, r2
orr r1, r1, #0x10
str r1, [r0]
ldr r0, =0x11000C68
ldr r1, [r0]
ldr r2, =0xFFFFFFF3
and r1, r1, r2
orr r1, r1, #0x4
str r1, [r0]
ldr r0, =0x11000C64
ldr r1, [r0]
ldr r2, =0xFFFFFFFD
and r1, r1, r2
str r1, [r0]

/* During sleep/wakeup or AFTR mode, pmic_init function is not available
* and it causes delays. So except for sleep/wakeup and AFTR mode,
* the below function is needed
*/
bl pmic_init //上电启动,需要初始化电源,如果是从睡眠状态恢复,则没到这一步

bl read_om //确定启动设备

/* when we already run in ram, we don't need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.
*/
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq after_copy /* r0 == r1 then skip sdram init and u-boot.bin loading */

ldr r0, =CHIP_ID_BASE
ldr r1, [r0]
lsr r1, r1, #8
and r1, r1, #3
cmp r1, #2
bne v310_1

/* Memory initialize */
bl mem_ctrl_asm_init

/* init system clock */
bl system_clock_init

b 1f
/*********/
1:
b load_uboot //加载uboot镜像
系统复位或上电重启后进入reset,在reset中将cpu设为管理模式后进入cpu_init_crit,在这里初始化cache并且关闭cache和MMU,跳转到lowlevel_init,在lowlevel_init中,根据不同的外部条件进行不同操作,首先判断系统是否从睡眠状态中复位,如果是则跳转到wakeup_reset,我们分析启动过程,显然不是不发生跳转,接下来就启动开发板上的电源,并且确定启动设备,同时通过pc判断执行环境的位置,如果已经在RAM中则证明RMA初始化uboot的拷贝都已经完成了,可以跳过,否则继续执行,初始化内存和时钟,跳转到load_uboot加载uboot镜像