这一篇粗略讲一下lowlevel_init.S内部的模块。
1、_TEXT_BASE
1 #include
2 #include
3
4 #include
5
6 #ifdef CONFIG_SERIAL1
7 #define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
8 #elif defined(CONFIG_SERIAL2)
9 #define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART1_OFFSET)
10 #else
11 #define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART2_OFFSET)
12 #endif
13
14 _TEXT_BASE:
15 .word TEXT_BASE
16
来看一下最后两句的的反汇编
00000000 <_TEXT_BASE>:
0: 57e00000 .word 0x57e00000
看到这里的 0x57e00000 有种似曾相识的感觉,但是这段代码的特殊位置决定了这个地址是无效的。
回想一下上一篇的地址无关性,就能明白了。
2、点亮LED
17 .globl lowlevel_init
18 lowlevel_init:
19 mov r12, lr
20
21 /* LED on only #8 */
22 ldr r0, =ELFIN_GPIO_BASE
23 ldr r1, =0x55540000
24 str r1, [r0, #GPNCON_OFFSET]
25
26 ldr r1, =0x55555555
27 str r1, [r0, #GPNPUD_OFFSET]
28
29 ldr r1, =0xf000
30 str r1, [r0, #GPNDAT_OFFSET]
31
3、关闭看门狗
32 /* Disable Watchdog */
33 ldr r0, =0x7e000000 @0x7e004000
34 orr r0, r0, #0x4000
35 mov r1, #0
36 str r1, [r0]
37
从这里看到,在 start.S 中取出的关闭看门狗原来是移动到了这里执行。
这样做的好处是,让每个单独部分的代码信息显得更紧凑一些。
4、读一次外部中断,然后清除中断信号
38 /* External interrupt pending clear */
39 ldr r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET) /*EINTPEND*/
40 ldr r1, [r0]
41 str r1, [r0]
42
43 ldr r0, =ELFIN_VIC0_BASE_ADDR @0x71200000
44 ldr r1, =ELFIN_VIC1_BASE_ADDR @0x71300000
45
5、将所有中断设置为IRQ
51 /* Set all interrupts as IRQ */
52 mov r3, #0x0
53 str r3, [r0, #oINTMOD]
54 str r3, [r1, #oINTMOD]
55
6、等待中断清除
56 /* Pending Interrupt Clear */
57 mov r3, #0x0
58 str r3, [r0, #oVECTADDR]
59 str r3, [r1, #oVECTADDR]
60
这里的作用应该等效于禁用中断。
7、初始化系统时钟
61 /* init system clock */
62 bl system_clock_init
63 //具体实现代码在118行
8、初始化UART串口和NAND flash
64 #ifndef CONFIG_NAND_SPL
65 /* for UART */
66 bl uart_asm_init
67 #endif
68
69 #ifdef CONFIG_BOOT_NAND
70 /* simple init for NAND */
71 bl nand_asm_init
72 #endif
73
9、内存控制的初始化
74 /* Memory subsystem address 0x7e00f120 */
75 ldr r0, =ELFIN_MEM_SYS_CFG
76
77 /* Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1 */
78 mov r1, #S3C64XX_MEM_SYS_CFG_NAND
79 str r1, [r0]
80
81 bl mem_ctrl_asm_init
82
10、测试将要使用的功能
83 /* Wakeup support. Don't know if it's going to be used, untested. */
84 ldr r0, =(ELFIN_CLOCK_POWER_BASE + RST_STAT_OFFSET)
85 ldr r1, [r0]
86 bic r1, r1, #0xfffffff7
87 cmp r1, #0x8
88 beq wakeup_reset
89
90 1:
91 mov lr, r12
92 mov pc, lr
93
94 wakeup_reset:
95
96 /* Clear wakeup status register */
97 ldr r0, =(ELFIN_CLOCK_POWER_BASE + WAKEUP_STAT_OFFSET)
98 ldr r1, [r0]
99 str r1, [r0]
100
101 /* LED test */
102 ldr r0, =ELFIN_GPIO_BASE
103 ldr r1, =0x3000
104 str r1, [r0, #GPNDAT_OFFSET]
105
106 /* Load return address and jump to kernel */
107 ldr r0, =(ELFIN_CLOCK_POWER_BASE + INF_REG0_OFFSET)
108 /* r1 = physical address of s3c6400_cpu_resume function */
109 ldr r1, [r0]
110 /* Jump to kernel (sleep-s3c6400.S) */
111 mov pc, r1
112 nop
113 nop
11、时钟初始化的执行代码
114 /*
115 * system_clock_init: Initialize core clock and bus clock.
116 * void system_clock_init(void)
117 */
118 system_clock_init:
119 ldr r0, =ELFIN_CLOCK_POWER_BASE /* 0x7e00f000 */
120
121 #ifdef CONFIG_SYNC_MODE
122 ldr r1, [r0, #OTHERS_OFFSET]
123 mov r2, #0x40
124 orr r1, r1, r2
125 str r1, [r0, #OTHERS_OFFSET]
126
127 nop
128 nop
129 nop
130 nop
131 nop
132
133 ldr r2, =0x80
134 orr r1, r1, r2
135 str r1, [r0, #OTHERS_OFFSET]
136
137 check_syncack:
138 ldr r1, [r0, #OTHERS_OFFSET]
139 ldr r2, =0xf00
140 and r1, r1, r2
141 cmp r1, #0xf00
142 bne check_syncack
143 #else /* ASYNC Mode */
144 nop
145 nop
146 nop
147 nop
148 nop
149
150 /*
151 * This was unconditional in original Samsung sources, but it doesn't
152 * seem to make much sense on S3C6400.
153 */
154 #ifndef CONFIG_S3C6400
155 ldr r1, [r0, #OTHERS_OFFSET]
156 bic r1, r1, #0xC0
157 orr r1, r1, #0x40
158 str r1, [r0, #OTHERS_OFFSET]
159
160 wait_for_async:
161 ldr r1, [r0, #OTHERS_OFFSET]
162 and r1, r1, #0xf00
163 cmp r1, #0x0
164 bne wait_for_async
165 #endif
166
167 ldr r1, [r0, #OTHERS_OFFSET]
168 bic r1, r1, #0x40
169 str r1, [r0, #OTHERS_OFFSET]
170 #endif
171
172 mov r1, #0xff00
173 orr r1, r1, #0xff
174 str r1, [r0, #APLL_LOCK_OFFSET]
175 str r1, [r0, #MPLL_LOCK_OFFSET]
176
177 /* Set Clock Divider */
178 ldr r1, [r0, #CLK_DIV0_OFFSET]
179 bic r1, r1, #0x30000
180 bic r1, r1, #0xff00
181 bic r1, r1, #0xff
182 ldr r2, =CLK_DIV_VAL
183 orr r1, r1, r2
184 str r1, [r0, #CLK_DIV0_OFFSET]
185
186 ldr r1, =APLL_VAL
187 str r1, [r0, #APLL_CON_OFFSET]
188 ldr r1, =MPLL_VAL
189 str r1, [r0, #MPLL_CON_OFFSET]
190
191 /* FOUT of EPLL is 96MHz */
192 ldr r1, =0x200203
193 str r1, [r0, #EPLL_CON0_OFFSET]
194 ldr r1, =0x0
195 str r1, [r0, #EPLL_CON1_OFFSET]
196
197 /* APLL, MPLL, EPLL select to Fout */
198 ldr r1, [r0, #CLK_SRC_OFFSET]
199 orr r1, r1, #0x7
200 str r1, [r0, #CLK_SRC_OFFSET]
201
202 /* wait at least 200us to stablize all clock */
203 mov r1, #0x10000
204 1: subs r1, r1, #1
205 bne 1b
206
207 /* Synchronization for VIC port */
208 #if defined(CONFIG_SYNC_MODE)
209 ldr r1, [r0, #OTHERS_OFFSET]
210 orr r1, r1, #0x20
211 str r1, [r0, #OTHERS_OFFSET]
212 #elif !defined(CONFIG_S3C6400)
213 /* According to 661558um_S3C6400X_rev10.pdf 0x20 is reserved */
214 ldr r1, [r0, #OTHERS_OFFSET]
215 bic r1, r1, #0x20
216 str r1, [r0, #OTHERS_OFFSET]
217 #endif