文件路径board/freescale/mx6q_sabresd/low_init.S
.globl lowlevel_init
lowlevel_init:
inv_dcache
init_l2cc
init_aips
init_clock
mov pc, lr
1.寄存器相关说明
r0-r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。
r4-r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。
r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。
13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
r15 是程序计数器 PC。它不能用于任何其它用途。
注意:在中断程序中,所有的寄存器都必须保护,编译器会自动保护R4~R11
2.代码段
2.1 inv_dcache
/* invalidate the D-CACHE */ /* CP15寄存器是系统控制协处理器,用于连接在内存中的页表描述符,此外还用于决定对MMU的操作。设置CP15寄存器的目的是失效Icache(指令cache)和Dcache(数据cache),然后禁止MMU和cache。 */
.macro inv_dcache
mov r0,#0 /* r0=0x0 */
mcr p15,2,r0,c0,c0,0 /* cache size selection register, select dcache */
/* CP15 中寄存器 C0 对应两个标识符寄存器,由访问 CP15 中的寄存器指令中的 <opcode2> 指定要访问哪个具体物理寄存器 */
/* 该指令将 ARM 处理器寄存器 R0 中的数据传送到协处理器 P15 的寄存器 c0 和 c0 中 */
/* MCR 指令将ARM 处理器的寄存器中的数据传送到协处理器的寄存器中。若协处理器不能成功地执行该操作,将产生未定义指令异常中断。 */
/* p15为指令操作的协处理器名。 标准名为:Pn (n的范围:0~15) */
/* 2 为协处理器的特定操作码 */
/* r0 为目标寄存器 */
/* c0 存放第1个操作数的协处理器寄存器 ID Code (1) */
/* c0 存放第2个操作数的协处理器寄存器 Catch type(1) */
/* 0 可选的协处理器特定操作码 */
mrc p15,1,r0,c0,c0,0 /* cache size ID register */ /* 清除cache ID */
/* 读取CP15的主标识寄存器的指令,该指令将主标识符寄存器的内容读取到ARM寄存器R0中 */
/* MRC 协处理器寄存器到ARM 处理器寄存器的数据传送指令 */
mov r0,r0,ASR #13 /* asr----逻辑右移并且符号位不参与运算 r0中的值右移13位,前面补1 */
ldr r3,=0xfff /* ldr常用于加载芯片外围功能部件的寄存器地址(32 位立即数),以实现各种控制操作加载32位立即数 装载32位立即数 */
and r0,r0,r3 /*获取r0的低12位*/
cmp r0,#0x7f /* r0与 7f 比较,设置相关标志位 */
moveq r6,#0x1000 /* 如果 r0 与 7f 相等, 则 r6 = 0x1000 */
beq size_done /* 如果相等就跳转,不相等就不跳转,这里的eq就是条件 */
cmp r0,#0xff /* r0与 ff 比较, */
moveq r6,#0x2000 /* 如果 r0 与 ff 相等, 则 r6 = 0x2000 */
movne r6,#0x4000 /* 如果 r0 与 ff 不相等, 则 r6 = 0x4000 */
size_done:
mov r2,#0
mov r3,#0x40000000
mov r4,#0x80000000
mov r5,#0xc0000000
d_inv_loop:
mcr p15,0,r2,c7,c6,2 /* invalidate dcache by set / way */
/* C6 MMU中的作用:内存失效地址 PU中:保护区域控制 */
/* C7 MMU:高速缓存和写缓存控制 */
mcr p15,0,r3,c7,c6,2 /* invalidate dcache by set / way */
mcr p15,0,r4,c7,c6,2 /* invalidate dcache by set / way */
mcr p15,0,r5,c7,c6,2 /* invalidate dcache by set / way */
add r2,r2,#0x20 /* r2 = r2 + 0x20 */
add r3,r3,#0x20
add r4,r4,#0x20
add r5,r5,#0x20
cmp r2,r6
bne d_inv_loop /* r6与r2不相等,则跳转到d_inv_loop继续 */
.endm
补充:协处理器部分说明
MCR{cond} coproc,opcode1,Rd(源寄存器),CRn(目标寄存器),CRm(目标寄存 器),opcode2
MCR 指令用于将ARM处理器寄存器中的数据传送到协处理器寄存器中。
CP15 的寄存器 C0
CP15 中寄存器 C0 对应两个标识符寄存器,由访问 CP15 中的寄存器指令中的 <opcode2> 指定要访问哪个具体物理寄存器, <opcode2> 与两个标识符寄存器的对应关系如下所示:
opcode2 编码 | 对应的标识符号寄存器 |
0b000 | 主标识符寄存器 |
0b001 | cache类型标识符寄存器 |
其 他 | 保留 |
2.2 init_l2cc
.macro init_l2cc
ldr r1, =0xa02000 /* LDR r0,=label
如果label是立即数,就把数值赋给r0, 如果lable是标识符,就把label地址的值赋给r0 */
/* r1= 0xa02000 */
ldr r0, =0x0
str r0, [r1, #0x100] /* 将R0中的值放到以R1中的值为地址 在偏移 0x100 的存储单元去 */
.endm /* init_l2cc */
补充:LDR,STR指令
LDR,STR 的第一操作数是目标寄存器,第二操作数是内存地址, LDR 内存 --> 寄存器; STR 寄存器 --> 内存
内存的表示方式有:立即数,寄存器,或寄存器加偏移,立即数:内存的物理位置,前面加个#,如0x56000050
寄存器,加个[],如[r1],偏移的话[r1,r2],或者[r1,#4],[r1,LSL #4]等,都差不多,就是把寄存器里的数当成地址。
STR R0,[R1] 是一个典型的存储指令,将R0中的值放到以R1中的值为地址的存储单元去。
2.3 init_aips
.macro init_aips
/*
* Set all MPROTx to be non-bufferable, trusted for R/W,
* not forced to user-mode.
*/
ldr r0, =AIPS1_ON_BASE_ADDR /* r0 = 0x0207 c000 */
ldr r1, =0x77777777 /* r1 = 0x77777777 */
str r1, [r0, #0x0] /* 将R1中的值放到以R0中的值为地址 在偏移 0x0 的存储单元去(0x0207 c000) */ /* AIPS-1 配置 */
str r1, [r0, #0x4] /* 将R1中的值放到(0x0207 c004这个地址)存储单元去 */
ldr r1, =0x0 /* 把0x0这个地址写到r1中 */
str r1, [r0, #0x40] /* 将R1中的值放到(0x0207 c040)存储单元去 *//* */
str r1, [r0, #0x44] /* 将R1中的值放到(0x0207 c044)存储单元去 */
str r1, [r0, #0x48] /* 将R1中的值放到(0x0207 c048)存储单元去 */
str r1, [r0, #0x4C] /* 将R1中的值放到(0x0207 c04c)存储单元去 */
str r1, [r0, #0x50] /* 将R1中的值放到(0x0207 c050)存储单元去 */
ldr r0, =AIPS2_ON_BASE_ADDR /* r0 = 0x02100000 */
ldr r1, =0x77777777
str r1, [r0, #0x0]
str r1, [r0, #0x4]
ldr r1, =0x0
str r1, [r0, #0x40]
str r1, [r0, #0x44]
str r1, [r0, #0x48]
str r1, [r0, #0x4C]
str r1, [r0, #0x50]
.endm /* init_aips */
补充:AIPSTZ Memory Map/Register Definition(AIPSTZx_OPACR)
3 BW Buffer Writes - 这个位决定是否允许对这个外设的写访问被缓冲。
2 SP Supervisor Protect - 这一点决定了外围设备是否需要主管特权来访问。
1 WP Write Protect - 这个位决定了外设是否允许写访问。
0 TP Trusted Protect - 这一点决定了外围设备是否允许来自anuntrusted master的访问。
对于AIPSTZ来说,缓冲写是不可用的。这个位应该设为'0'。
Address: Base address + 40h offset
OPAC0
非平台外围访问控制0
xxx0 TP — 允许来自不可信的主机的访问。
xxx1 TP — 不允许从不受信任的主人那里访问。如果一个存取是由一个不可信的主人尝试的,那么访问就会被一个错误响应终止,并且在IPS总线上没有启动外围访问。
xx0x WP — 这个外设允许写访问
xx1x WP — 这个外设是受保护的。如果尝试了写访问,则通过错误响应终止访问,并且在IPS总线上不启动外围访问。
x0xx SP — 这个外设不需要管理员权限级别的访问权限。.
x1xx SP — 这个外设需要管理员权限级别的访问权限。主权限级别必须通过hprot 1访问属性指示主管,并且必须设置主控权的MPROTx MPL控制位。如果没有,则使用错误响应终止访问,并且在IPS总线上不启动外围访问。
0xxx BW — 对这个外围设备的写访问不能被AIPSTZ所利用。
1xxx BW — 对这个外设的写访问权限被AIPSTZ进行缓冲。
2.4 init_clock
.macro init_clock
/* PLL1, PLL2, and PLL3 are enabled by ROM */
#ifdef CONFIG_PLL3
/* enable PLL3 for UART */
ldr r0, ANATOP_BASE_ADDR_W /* 0x020c 8000 */
/* power up PLL */
ldr r1, [r0, #ANATOP_USB1] /* ANATOP_USB1 = 0x10 将r0+ANATOP_USB1 地址的数据计读出,保存到r1中(r0的值不变) */
orr r1, r1, #0x1000 /* r1 = r1 | 0x1000 */ /* 将r1的第13位置1 */
str r1, [r0, #ANATOP_USB1] /* 将r1的值写入 r0+ANATOP_USB1 地址 */
/* enable PLL */
ldr r1, [r0, #ANATOP_USB1]
orr r1, r1, #0x2000 /* 将r1的第14位置1 */
str r1, [r0, #ANATOP_USB1]
/* wait PLL lock */
100:
ldr r1, [r0, #ANATOP_USB1]
mov r1, r1, lsr #31 /* r1左移31位 */
cmp r1, #0x1
bne 100b
/* clear bypass bit */
ldr r1, [r0, #ANATOP_USB1]
and r1, r1, #0xfffeffff /* 将r1的第17位置0 */
str r1, [r0, #ANATOP_USB1]
#endif
/* Restore the default values in the Gate registers */
ldr r0, CCM_BASE_ADDR_W /* 0x020c 4000 */
ldr r1, =0xC0003F
str r1, [r0, #CLKCTL_CCGR0] /* CLKCTL_CCGR0 = 0x68 */ /* 在0x020c 4068 这个地址中写值0xc0003f */ /* 时钟门控 CG0、1、2、11 */
ldr r1, =0x30FC00 /* r1 = 0x30FC00 */
str r1, [r0, #CLKCTL_CCGR1] /* CLKCTL_CCGR1 = 0x6c */ /* CG5、6、7、10 */
ldr r1, =0xFFFC000
str r1, [r0, #CLKCTL_CCGR2] /* CLKCTL_CCGR2 = 0x70 */ /* CG7、8、9、10、13 */
ldr r1, =0x3FF00000
str r1, [r0, #CLKCTL_CCGR3] /* CLKCTL_CCGR3 = 0x74 */ /* CG10、11、12、13、14 */
ldr r1, =0xFFF300
str r1, [r0, #CLKCTL_CCGR4] /* CLKCTL_CCGR4 = 0x78 */ /* CG4、6~11 *//* pl301_mx6qfast1_s133、pl301_mx6qper1_bch、pl301_mx6qper2_mainclk_enable、pwm1~4 */
ldr r1, =0xF0000C3
str r1, [r0, #CLKCTL_CCGR5] /* CLKCTL_CCGR5 = 0x7c */ /* CG0、3、12、13 *//* rom/sdma/uart/uart_serial */
ldr r1, =0x3FC
str r1, [r0, #CLKCTL_CCGR6] /* CLKCTL_CCGR6 = 0x80 */ /* CG1~4 *//* 使能 usdhc1~4 */
.endm
补充:
CCM Clock Gating Register 0 (CCM_CCGR0)
地址:0x020c 4068
这些比特位都被用来独立地打开或者关闭时钟,下表详细说明了每个模块可能的时钟活动条件。
在将其位设置为“0”之前,模块应该停止;该模块的时钟将立即停止。
上面的表格显示了不同CGRs的寄存器映射。时钟连接表应该用于匹配实际的进入相应模块的“CCM输出”时钟。
下图显示了CCM时钟门控寄存器0(ccmccgr0)。时钟门控寄存器为每个时钟的功率减少定义了时钟门控(CG(i)位)。有7个CGR寄存器。所需要的寄存器的数量是根据系统中外围设备的数量来决定的。
Address: 20C_4000h base + 68h offset = 20C_4068h
CCGR0 ~ CCGR6 原理都是一样的。