#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
bl cpu_init_crit
#endif
执行完cpu_init_cp15后,跳转到cpu_init_crit执行。
ENTRY(cpu_init_crit)
/*
* 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.
*/
b lowlevel_init @ go setup pll,mux,memory
ENDPROC(cpu_init_crit)
#endif
最终跳转到lowlevel_init函数执行。此函数在**\u-boot-2012.10\board\samsung\goni\lowlevel_init.S**文件中。
25行到72行代码如下:
#include <config.h>
#include <version.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clock.h>
#include <asm/arch/power.h>
/*
* Register usages:
*
* r5 has zero always
* r7 has S5PC100 GPIO base, 0xE0300000
* r8 has real GPIO base, 0xE0300000, 0xE0200000 at S5PC100, S5PC110 repectively
* r9 has Mobile DDR size, 1 means 1GiB, 2 means 2GiB and so on
*/
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE
.globl lowlevel_init
lowlevel_init:
mov r11, lr
/* r5 has always zero */
mov r5, #0
ldr r7, =S5PC100_GPIO_BASE
ldr r8, =S5PC100_GPIO_BASE
/* Read CPU ID */
ldr r2, =S5PC110_PRO_ID
ldr r0, [r2]
mov r1, #0x00010000
and r0, r0, r1
cmp r0, r5
beq 100f
ldr r8, =S5PC110_GPIO_BASE
100:
/* Turn on KEY_LED_ON [GPJ4(1)] XMSMWEN */
cmp r7, r8
beq skip_check_didle @ Support C110 only
ldr r0, =S5PC110_RST_STAT
ldr r1, [r0]
and r1, r1, #0x000D0000
cmp r1, #(0x1 << 19) @ DEEPIDLE_WAKEUP
beq didle_wakeup
cmp r7, r8
一、
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE
在标号_TEXT_BASE处定义了一个数CONFIG_SYS_TEXT_BASE,它具体的数值在\u-boot-2012.10\board\samsung\goni\lowlevel_init.S同级目录下的config.mk文件中。
CONFIG_SYS_TEXT_BASE = 0x34800000
如上图所示,即最后内核text段会被加载到CONFIG_SYS_TEXT_BASE = 0x34800000地址处。
二、
1、
.globl lowlevel_init
lowlevel_init:
.globl表示lowlevel_init是全局函数,在别的文件中可以调用。
2、
mov r11, lr
将链接寄存器lr中的值存入r11。等函数返回的时候再把r11恢复到lr中。
3、
/* r5 has always zero */
mov r5, #0
r5中的值设置为0。
4、配置r7和r8寄存器
ldr r7, =S5PC100_GPIO_BASE
ldr r8, =S5PC100_GPIO_BASE
将r7,r8寄存器中的值都设为S5PC100_GPIO_BASE。它的值定义在#include <asm/arch/cpu.h>中。
#define S5PC100_GPIO_BASE 0xE0300000
表示的是GPIO的基地址。
#include <asm/arch/cpu.h>
#include <asm/arch/clock.h>
#include <asm/arch/power.h>
这三个文件在\u-boot-2012.10\arch\arm\include\asm\arch-s5pc1xx路径下,它是绝对路径。而在#include <asm/arch/cpu.h>中是相对路径,这是因为在编译的时候,在Makefile中将\u-boot-2012.10\arch\arm\include\asm软链接到asm,此时#include <asm/arch/cpu.h>就能找到绝对路径下的cpu.h文件。
5、设置芯片号
/* Read CPU ID */
ldr r2, =S5PC110_PRO_ID
cpu.h文件:
#define S5PC100_PRO_ID 0xE0000000
表示将芯片的芯片号,放入r2寄存器,芯片是S5PV210或者S5PC110,它的芯片号是0x43110xxx。如果芯片是S5PC100,芯片号是0x43100xxx。这样可以判断目前运行的是哪个型号的芯片。
6、设置S5PC110 GPIO的基地址
ldr r0, [r2]
mov r1, #0x00010000
and r0, r0, r1
cmp r0, r5
beq 100f
ldr r8, =S5PC110_GPIO_BASE
将0x43110xxx写入r0寄存器;
将0x00010000写入r1寄存器;
将r0和r1再与一下得到0x00010000,存入r0寄存器;
比较r5(#0)和r0(0x00010000),不等于;
将S5PC110_GPIO_BASE写入到r8寄存器,此时是110的GPIO基地址。
#define S5PC110_GPIO_BASE 0xE0200000
7、
100:
/* Turn on KEY_LED_ON [GPJ4(1)] XMSMWEN */
cmp r7, r8
beq skip_check_didle @ Support C110 only
r7不等于r8,所以跳过beq skip_check_didle @ Support C110 only
。
8、Reset Control Register
ldr r0, =S5PC110_RST_STAT
ldr r1, [r0]
and r1, r1, #0x000D0000
cmp r1, #(0x1 << 19) @ DEEPIDLE_WAKEUP
beq didle_wakeup
cmp r7, r8
S5PC110_RST_STAT在power.h中定义:
#define S5PC110_RST_STAT 0xE010A000
此寄存器功能为从什么状态唤醒,如果第19位是1,则表示从DEEPIDLE_WAKEUP状态唤醒。
ldr r1, [r0]
and r1, r1, #0x000D0000
cmp r1, #(0x1 << 19) @ DEEPIDLE_WAKEUP
三句判断第19位是否为1。
beq didle_wakeup
此句不运行。
cmp r7, r8
比较r7和r8。
9、GPJ4
skip_check_didle:
addeq r0, r8, #0x280 @ S5PC100_GPIO_J4
addne r0, r8, #0x2C0 @ S5PC110_GPIO_J4
执行addne r0, r8, #0x2C0 @ S5PC110_GPIO_J4
。此时r0=0xE020002C0。此地址为GPJ4的CON寄存器。
ldr r1, [r0, #0x0] @ GPIO_CON_OFFSET
bic r1, r1, #(0xf << 4) @ 1 * 4-bit
orr r1, r1, #(0x1 << 4)
str r1, [r0, #0x0] @ GPIO_CON_OFFSET
ldr r1, [r0, #0x4] @ GPIO_DAT_OFFSET
bic r1, r1, #(1 << 1)
str r1, [r0, #0x4] @ GPIO_DAT_OFFSET
此段代码为对GPJ4的配置。将GPJ4_1配置为output。并将GPJ4_1_DAT配置为0,低电平。
10、beq 100f
跳过。
11、同步寄存器
ldr r0, =0xe0f00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xe1f00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1800000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1900000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1a00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1b00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1c00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1d00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1e00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xf1f00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
ldr r0, =0xfaf00000
ldr r1, [r0]
bic r1, r1, #0x1
str r1, [r0]
此段代码设置同步寄存器。每个寄存器只有第0位有效,置0时为full状态,表示同步速率慢,但是平均出错率低。置1时为half状态,表示同步速率快,但是平均出错率高。此处全部设置为0.
注释中EVT0和EVT1表示次版本号。表示同型号不同批次的芯片。[7:0]可能会有差异。
12、ABB block
/*
* Diable ABB block to reduce sleep current at low temperature
* Note that it's hidden register setup don't modify it
*/
ldr r0, =0xE010C300
ldr r1, =0x00800000
str r1, [r0]
0xE010C300,此寄存器是”hidden register“,所以在手册里查不到,照写就行。
13、S5PC110_OTHERS
100:
/* IO retension release */
ldreq r0, =S5PC100_OTHERS @ 0xE0108200
ldrne r0, =S5PC110_OTHERS @ 0xE010E000
ldr r1, [r0]
ldreq r2, =(1 << 31) @ IO_RET_REL
ldrne r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))
orr r1, r1, r2
/* Do not release retention here for S5PC110 */
streq r1, [r0]
S5PC110_OTHERS 在power.h中定义。
#define S5PC110_OTHERS 0xE010E000
此句不执行。
ldreq r2, =(1 << 31) @ IO_RET_REL
ldrne r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))
将r2最高4位都设置成1。
orr r1, r1, r2
将r1和r2取或之后放入r1。
streq r1, [r0]
此句也不执行。所以14这一大段代码没有实际用途。
S5PC110_OTHERS此寄存器的作用是休眠时候的保持状态。
14、Watchdog
/* Disable Watchdog */
ldreq r0, =S5PC100_WATCHDOG_BASE @ 0xEA200000
ldrne r0, =S5PC110_WATCHDOG_BASE @ 0xE2700000
str r5, [r0]
配置看门狗寄存器。将r5(#0)写入寄存器。
第0位:禁止看门狗复位功能;
第2位:禁止看门狗中断;
第[4:3]:时钟分频为16;
第5位:禁止看门狗定时器运行;
第[15:8]:预分频器的值。
15、SROM
/* setting SRAM */
ldreq r0, =S5PC100_SROMC_BASE
ldrne r0, =S5PC110_SROMC_BASE
ldr r1, =0x9
str r1, [r0]
此处应该是SROM,配置SROM寄存器的值为9。(1001)
第0位:数据总线的宽度为16位;
第1位:地址总线为半字宽度即16位。
第2位:禁止等待;
第3位:使用高半字还是低半字。
16、IRQ
/* S5PC100 has 3 groups of interrupt sources */
ldreq r0, =S5PC100_VIC0_BASE @ 0xE4000000
ldrne r0, =S5PC110_VIC0_BASE @ 0xF2000000
add r1, r0, #0x00100000
add r2, r0, #0x00200000
/* S5PC100 has 3 groups of interrupt sources */ ,S5PC110 有4个中断群组,注释中未标注。
将S5PC110_VIC0_BASE+#0x00100000放入r1寄存器;
将S5PC110_VIC0_BASE+#0x00200000放入2寄存器;
/* Disable all interrupts (VIC0, VIC1 and VIC2) */
mvn r3, #0x0
str r3, [r0, #0x14] @ INTENCLEAR
str r3, [r1, #0x14] @ INTENCLEAR
str r3, [r2, #0x14] @ INTENCLEAR
将VIC0,VIC1,VIC2三个中断群组禁止。
mvn r3, #0x0
将#0赋给r3寄存器,并取反,即r3=0xffff;
再将0xfffff依次赋值给r0+14,r1+14,r2+14。
/* Set all interrupts as IRQ */
str r5, [r0, #0xc] @ INTSELECT
str r5, [r1, #0xc] @ INTSELECT
str r5, [r2, #0xc] @ INTSELECT
将三个寄存器群组设为IRQ 模式。
/* Pending Interrupt Clear */
str r5, [r0, #0xf00] @ INTADDRESS
str r5, [r1, #0xf00] @ INTADDRESS
str r5, [r2, #0xf00] @ INTADDRESS
将现在有中断信号的源全部清0;
17、跳转到uart_asm_init
开始配置串口。
/* for UART */
bl uart_asm_init
bl internal_ram_init