uboot的函数入口要查看链接脚本中ENTTRY的入口参数,我们这里的链接脚本在board/samsung/x210/u-boot.lds,这个文件里面的开头有一句ENTRY(_start),所以uboot的入口就是在_start这个标识的地方。
* Base codes by scsuh (sc.suh)
*/
//x210_sd.h对开发板的宏定义配置文件,这个文件会被用来生成一个autoconfig.mk文件,这个文件会被主Makefile引入,指导整个编译过程
#include
#include
这个头文件的内容是uboot的版本号。这个版本号在uboot启动时会被打印出来
#if defined(CONFIG_ENABLE_MMU)
#include
#endif
#include
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
/*
.word 汇编伪指令,定义四字节的变量,值就是 0x2000,地址就是当前的地址。相当于是一个数组 0x2000 0x0 0x0 0x0 共16字节为后面计算校验和填充占位,这16字节的占位是为了保证正式的p_w_picpath的头部确实有16字节,
*/
.word 0x2000
.word 0x0
.word 0x0 //但是这16字节的内容是不对的,需要后面去计算校验和,然后重新填充
.word 0x0
#endif
.globl _start
_start: b reset
/*
异常向量的构建,异常向量表中的每一种异常都需要处理,但是我们在uboot中并未非常细致的处理各种异常,原因是uboot执行的时间很短,异常比较少,如果发生异常,重启即可。b reset 跳转到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
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq
_pad:
.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef
/*
意思是,如果当前地址不对齐则自动向后走地址直到对齐,并且向后走的那些内存要用0xdeadbeef进行填充,使其对齐。对齐访问的原因是:有时候是效率要求,有时候是硬件特殊要求必须对齐
*/
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
_TEXT_BASE:
.word TEXT_BASE
/*
mkconfig中提到的那个链接时指定uboot的链接地址(值就是0xc3e00000这是一个虚拟地址)
这两行相当于是一个指针,指针名为TEXT_BASE,所以我们后面可以直接ld TEXT_BASE 来使用TEXT_BASE 这个值,源代码中和配置Makefile中很多变量是可以互相运送的,简单来说有些符号的值可以从Makefile中传递到源代码中。
_TEXT_BASE:
.word TEXT_BASE
_TEXT_BASE:一个标识符号,类似一个指针
.word :相当于一个四字节的变量
TEXT_BASE :一个值
这样将来我们使用lds去加载_TEXT_BASE这个标识的时候就可以直接加载TEXT_BASE 这个值。
*/
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE: //物理地址
.word CFG_PHY_UBOOT_BASE //33e00000 uboot在DDR中的物理地址
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
/*
* the actual reset code 真正的复位代码
*/
reset:
/*
* set the cpu to SVC32 mode and IRQ & FIQ disable
*/
msr cpsr_c, #0xd3
/*
I & F disable, Mode: 0x13 - SVC,C位也就是I F mode 这三位(0-7这个8位)
0xd3=11010011,对应到这8位分别 I=1 F=1 T=0 mode=0x13 对应为SVC模式。ARMCPU在复位时默认是工作在SVC模式下的,这里只是为了保险起见,在软件上再次将其设置为SVC模式。整个uboot启动过程中都是工作在SVC模式。
在我们的cpsr寄存器的C位写上0xd3
cpsr:程序状态寄存器,
*/
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
cpu_init_crit:
bl disable_l2cache //禁止L2 cache
bl set_l2cache_auxctrl_cycle //l2 cache相关的初始化
bl enable_l2cache //使能l2 cache
/*
* Invalidate L1 I/D //刷新l1 cache 的icache 和dchahce
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
/*
* disable MMU stuff and caches //关闭 MMU
*/
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, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
//总结:上面5步都是和CPU和MMU有关的,不用去细看,大概知道即可
/* Read booting information */
/*
启动介质的选择也就是芯片的OM5-OM0这6个引脚的电平高低来决定的,对应的寄存为0xE0000004,这个寄存器的值会根据OM引脚上的电平高低而自动设置,我们通过读这个寄存器的值就可以确定是从哪种介质启动(Nand,SD卡还是其他)。
*/
ldr r0, =PRO_ID_BASE //0xE0000000
ldr r1, [r0,#OMR_OFFSET] //0x04 r1 0xE0000004
bic r2, r1, #0xffffffc1
/*
r2 里面存放的就是这个值,如下所示,根据r2的值来确定启动方式。bic 位清除 将r1的和 #0xffffffc1的反码进行按位与,得到的值写入r1寄存器中。
*/
/* NAND BOOT */
cmp r2, #0x0 @ 512B 4-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x2 @ 2KB 5-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x4 @ 4KB 5-cycle 8-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x6 @ 4KB 5-cycle 16-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x8 @ OneNAND Mux
moveq r3, #BOOT_ONENAND
/* SD/MMC BOOT */
cmp r2, #0xc
moveq r3, #BOOT_MMCSD
/*
BOOT_MMCSD 实际是一个宏,值是0x03,也就是将0x03放到r3中以备后用(判断从哪个通道启动)
*/
/* NOR BOOT */
cmp r2, #0x14
moveq r3, #BOOT_NOR
/* Uart BOOTONG failed */
cmp r2, #(0x1<<4)
moveq r3, #BOOT_SEC_DEV
ldr r0, =INF_REG_BASE
str r3, [r0, #INF_REG3_OFFSET]
//将我们的r3,也就是BOOT_MMCSD 的值放到[r0, #INF_REG3_OFFSET]中保存,后用
/*
* Go setup Memory and board specific bits prior to relocation.
*/
ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */
//设置栈,记住SP5PV210是满减栈,也就是入栈时向下延伸
sub sp, sp, #12 /* set stack */
mov fp, #0
/*
第一次设置栈,因为当前整个代码还在SRAM(96KB)中运行,此时DDR还未被初始化,还不能使用,所以设置的栈也是在SRAM中的。栈地址0xd0036000 是自己指定的,指定的原则是这个空间只能给栈用,不会被别人占用。
*/
bl lowlevel_init /* go setup pll,mux,memory */
/*
底层初始化,也就是CPU里面的东西,这里需要调用函数,所以需要栈,故上面要把栈设置好。在调用函数之前初始化栈,主要原因是在被调用的函数内还有再次调用函数,而BL只会将返回地址存储到LR中,但是我们只有一个LR,所以在第二层调用函数前要先将LR入栈,否则函数返回时第一层的返回地址就丢了。
这个函数的位置:lowlevel_init.S (i:\windows_share\uboot\board\samsung\x210):lowlevel_init
总结:lowlevel_init.S这个文件主要做了以下事情
检查复位状态 IO恢复 关看门狗 开发板的供电锁存 时钟初始化 DDR初始化 串口初始化并打印'O' tzpc初始化 打印'K'
*/
/* To hold max8698 output before releasing power on switch,
* set PS_HOLD signal to high
/*
开发板供电锁存,(第二次),其实没意义,因为在lowlevel_init 已经做了,但是做两次也不会出错(可能是移植的人没注意)
*/
ldr r0, =0xE010E81C /* PS_HOLD_CONTROL register */
ldr r1, =0x00005301 /* PS_HOLD output high */
str r1, [r0]
/* get ready to call C functions
/*
设置DDR中的栈,之前设置的是SRAM中的栈,因为那个时候DDR还没有初始化,所以在SRAM中分配了一部分的内存供给栈使用,现在DDR已经被初始化,所以需要把栈挪移到DDR上。
*/
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */ //0x33E00000
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
/* 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.
*/
/*
再次判断运行位置是在SRAM还是DDR,本次判断的目的不同,之前在lowlevel_inti判断是为了判断是否执行时钟初始化和DDR初始化,这里再次判断是为了判断是否要进行重定位。
在我们冷启动的时候,uboot的第一部分(BL1)开机自动从SD卡加载到SRAM中正在运行,uboot的第二部分(BL2:整个uboot)还在SD卡中,运行到这里时uboot的第一阶段即将结束,但是在结束之前要将第二部分加载到DDR的链接地址处(也就是33e00000)。
*/
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 flash copy */
#if defined(CONFIG_EVT1)
/* If BL1 was copied from SD/MMC CH2 */
ldr r0, =0xD0037488
/*
这个内存地址的值是被硬件自动设置的,硬件根据SD//卡在哪个通道中,会将这个地址的内容设置为相应的值
*/
ldr r1, [r0]
//譬如我们从SD0通道启动时,这个值为EB000000;从SD2通道/启动时这个值为EB20000
ldr r2, =0xEB200000
cmp r1, r2
beq mmcsd_boot
/*
如果相等则直接执行mmcsd_boot
如果我们不是从外部的SD卡启动,而是从内部的iNand启动,则不会相等那么就会往下执行
*/
#endif
//这里其实也是在判断从哪里启动
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET]
//读取[r0, #INF_REG3_OFFSET]中的值(这个值我们在之前已经根据启动通道设置好了)
cmp r1, #BOOT_NAND /* 0x0 => boot device is nand */
beq nand_boot
cmp r1, #BOOT_ONENAND /* 0x1 => boot device is onenand */
beq onenand_boot
cmp r1, #BOOT_MMCSD
/*
通过前面的分析可知即使没有上面那部分,最终还是会进入到(如果是SD卡启动)mmcsd_boot这个函数中去
*/
beq mmcsd_boot //进行重定位,具体单参照mmcsd_boot
/*****************************************
mmcsd_boot:
#if DELETE
ldr sp, _TEXT_PHY_BASE
sub sp, sp, #12
mov fp, #0
#endif
bl movi_bl2_copy
// 跳转到这个函数,这个函数是一个语言函数,在uboot/cpu/s5pc11x/movi.c中, 在这个函数里面通过一定的宏定义和判断最终调用copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,CFG_PHY_UBOOT_BASE, 0);函数来完成重定位
参数分析:
2:通道号。2表示SD通道2也就是外部的SD卡,0表示通道0,也就是内部iNand
MOVI_BL2_POS:BL2在SD卡中的开始的扇区号,这个必须和在SD卡烧录uboot时的相同
MOVI_BL2_BLKCNT:uboot的长度占用的扇区数(这里我们定义的uboot是2K)
CFG_PHY_UBOOT_BASE:重定位时将uboot的BL2复制到DDR中的起始地址,其实就是33e00020。
b after_copy
************************************************/
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot
nand_boot:
mov r0, #0x1000
bl copy_from_nand
b after_copy
onenand_boot:
bl onenand_bl2_copy
b after_copy
mmcsd_boot:
#if DELETE
ldr sp, _TEXT_PHY_BASE
sub sp, sp, #12
mov fp, #0
#endif
bl movi_bl2_copy
b after_copy
nor_boot:
bl read_hword
b after_copy
after_copy: //重定位完成
//虚拟地址映射
#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
//mrc :读CP15协处理器里面的寄存器 mcr:写CP15协处理器里面的寄存器
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
nop
nop
nop
nop
#endif
skip_hw_init:
/* Set up the stack
/*
第三次设置栈 ,这次设置栈还是在DDR中,之前虽然已经在DDR中已经设置过一次栈了,但是本次设置栈的目的是将栈是将栈放在比较合适(安全,紧凑而不浪费内存的地方。
我们实际将栈设置在uboot起始地址(33e00000)上方2MB(341FFFFF)大小的地方,实际供栈使用的空间为2M-200K(uboot大小)-0x1000)
*/
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#else
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#if defined(CONFIG_USE_IRQ)
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
#endif
clear_bss: //清bss段,BSS段主要用来存放未初始化的全局变量和未初始化的局部静态变量
ldr r0, _bss_start /* find start of bss segment */注意这里表示bss段开头和结尾的符号的bss_start 和bss_start是从我们的链接脚本u-boot.lds中得来的
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot
/*
uboot第一阶段的最后一句话:指针指向_start_armboot这个C语言函数,这个函数就是我们uboot的第二阶段,所以这句代码的作用就是将uboot第二阶段执行的函数地址给PC,实际上就是用一个远跳转直接跳转到DDR中的第二节点开始地址处。
远跳转的含义就是这句话加载的地址和当前运行地址无关,而和链接地址有关,因此这个远跳可以实现从SRAM中的第一阶段跳转到DDR中的第二阶段
总结:uboot第一阶段做的事情
1 构建异常向量表 2 设置CPU为SVC模式
3 进入low_lever_init.S
(1)关看门狗 (2 )开icache (3)开发板供电自锁 (4)根据判断当前执行的位置在SRAM还是DDR来判断是否初始化时钟和DDR (5)串口初始化并打印'OK'
4 DDR重定位,将SD卡中的uboot搬移到DDR中
5 建立虚拟地址映射表并开启MMU
6 跳转到第二阶段
*/
_start_armboot:
.word start_armboot
#if defined(CONFIG_ENABLE_MMU)
_mmu_table_base:
.word mmu_table
#endif
/*
* copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)
* r0: size to be compared
* Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size
*/
.globl copy_from_nand
copy_from_nand:
push {lr} /* save return address */
mov r9, r0
mov r9, #0x100 /* Compare about 8KB */
bl copy_uboot_to_ram
tst r0, #0x0
bne copy_failed
#if defined(CONFIG_EVT1)
ldr r0, =0xd0020000
#else
ldr r0, =0xd0030000
#endif
ldr r1, _TEXT_PHY_BASE /* 0x23e00000 */
#if !defined(CONFIG_SECURE_BOOT)
1: ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne compare_failed /* not matched */
subs r9, r9, #4
bne 1b
#endif
pop {pc} /* all is OK */
copy_failed:
nop /* copy from nand failed */
b copy_failed
compare_failed:
nop /* compare failed */
b compare_failed
/*
* we assume that cache operation is done before. (eg. cleanup_before_linux())
* actually, we don't need to do anything about cache if not use d-cache in U-Boot
* So, in this function we clean only MMU. by scsuh
*
* void theLastJump(void *kernel, int arch_num, uint boot_params);
*/
#if defined(CONFIG_ENABLE_MMU)
.globl theLastJump
theLastJump:
mov r9, r0
ldr r3, =0xfff00000
ldr r4, _TEXT_PHY_BASE
adr r5, phy_last_jump
bic r5, r5, r3
orr r5, r5, r4
mov pc, r5
phy_last_jump:
/*
* disable MMU stuff
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */
bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
orr r0, r0, #0x00000002 /* set bit 2 (A) Align */
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
mov r0, #0
mov pc, r9
#endif
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#define MODE_SVC 0x13
#define I_BIT 0x80
/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/
.macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current user stack
stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CFG_MALLOC_LEN)
sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
ldmia r2, {r2 - r3} @ get values for "aborted" pc and cpsr (into parm regs)
add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack
add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp @ save current stack into r0 (param register)
.endm
.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
add r8, sp, #S_PC @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
stmdb r8, {sp, lr}^ @ Calling SP, LR
str lr, [r8, #0] @ Save calling PC
mrs r6, spsr
str r6, [r8, #4] @ Save CPSR
str r0, [r8, #8] @ Save OLD_R0
mov r0, sp
.endm
.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
.endm
.macro get_bad_stack
ldr r13, _armboot_start @ setup our mode stack (enter in banked mode)
sub r13, r13, #(CFG_MALLOC_LEN) @ move past malloc pool
sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ move to reserved a couple spots for abort stack
str lr, [r13] @ save caller lr in position 0 of saved stack
mrs lr, spsr @ get the spsr
str lr, [r13, #4] @ save spsr in position 1 of saved stack
mov r13, #MODE_SVC @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13 @ switch modes, make sure moves will execute
mov lr, pc @ capture return pc
movs pc, lr @ jump to next instruction & switch modes.
.endm
.macro get_bad_stack_swi
sub r13, r13, #4 @ space on current stack for scratch reg.
str r0, [r13] @ save R0's value.
ldr r0, _armboot_start @ get data regions start
sub r0, r0, #(CFG_MALLOC_LEN) @ move past malloc pool
sub r0, r0, #(CFG_GBL_DATA_SIZE+8) @ move past gbl and a couple spots for abort stack
str lr, [r0] @ save caller lr in position 0 of saved stack
mrs r0, spsr @ get the spsr
str lr, [r0, #4] @ save spsr in position 1 of saved stack
ldr r0, [r13] @ restore r0
add r13, r13, #4 @ pop stack entry
.endm
.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm
.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack_swi
bad_save_user_regs
bl do_software_interrupt
.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort
.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort
.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used
#if defined(CONFIG_USE_IRQ)
.align 5
irq:
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs
.align 5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bl do_fiq
irq_restore_user_regs
#else
.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq
.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif
.align 5
.global arm_cache_flush
arm_cache_flush:
mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache
mov pc, lr @ back to caller
/*
* v7_flush_dcache_all()
*
* Flush the whole D-cache.
*
* Corrupted registers: r0-r5, r7, r9-r11
*
* - mm - mm_struct describing address space
*/
.align 5
.global v7_flush_dcache_all
v7_flush_dcache_all:
ldr r0, =0xffffffff
mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR
ands r3, r0, #0x7000000
mov r3, r3, LSR #23 @ Cache level value (naturally aligned)
beq Finished
mov r10, #0
Loop1:
add r2, r10, r10, LSR #1 @ Work out 3xcachelevel
mov r1, r0, LSR r2 @ bottom 3 bits are the Ctype for this level
and r1, r1, #7 @ get those 3 bits alone
cmp r1, #2
blt Skip @ no cache or only instruction cache at this level
mcr p15, 2, r10, c0, c0, 0 @ write the Cache Size selection register
mov r1, #0
mcr p15, 0, r1, c7, c5, 4 @ PrefetchFlush to sync the change to the CacheSizeID reg
mrc p15, 1, r1, c0, c0, 0 @ reads current Cache Size ID register
and r2, r1, #0x7 @ extract the line length field
add r2, r2, #4 @ add 4 for the line length offset (log2 16 bytes)
ldr r4, =0x3FF
ands r4, r4, r1, LSR #3 @ R4 is the max number on the way size (right aligned)
clz r5, r4 @ R5 is the bit position of the way size increment
ldr r7, =0x00007FFF
ands r7, r7, r1, LSR #13 @ R7 is the max number of the index size (right aligned)
Loop2:
mov r9, r4 @ R9 working copy of the max way size (right aligned)
Loop3:
orr r11, r10, r9, LSL r5 @ factor in the way number and cache number into R11
orr r11, r11, r7, LSL r2 @ factor in the index number
mcr p15, 0, r11, c7, c6, 2 @ invalidate by set/way
subs r9, r9, #1 @ decrement the way number
bge Loop3
subs r7, r7, #1 @ decrement the index
bge Loop2
Skip:
add r10, r10, #2 @ increment the cache number
cmp r3, r10
bgt Loop1
Finished:
mov pc, lr
.align 5
.global disable_l2cache
disable_l2cache:
mrc p15, 0, r0, c1, c0, 1
bic r0, r0, #(1<<1)
mcr p15, 0, r0, c1, c0, 1
mov pc, lr
.align 5
.global enable_l2cache
enable_l2cache:
mrc p15, 0, r0, c1, c0, 1
orr r0, r0, #(1<<1)
mcr p15, 0, r0, c1, c0, 1
mov pc, lr
.align 5
.global set_l2cache_auxctrl
set_l2cache_auxctrl:
mov r0, #0x0
mcr p15, 1, r0, c9, c0, 2
mov pc, lr
.align 5
.global set_l2cache_auxctrl_cycle
set_l2cache_auxctrl_cycle:
mrc p15, 1, r0, c9, c0, 2
bic r0, r0, #(0x1<<29)
bic r0, r0, #(0x1<<21)
bic r0, r0, #(0x7<<6)
bic r0, r0, #(0x7<<0)
mcr p15, 1, r0, c9, c0, 2
mov pc,lr
.align 5
CoInvalidateDCacheIndex:
;/* r0 = index */
mcr p15, 0, r0, c7, c6, 2
mov pc,lr
#if defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_CINTEGRATOR)
/* Use the IntegratorCP function from board/integratorcp/platform.S */
#elif defined(CONFIG_S5PC11X)
/* For future usage of S3C64XX*/
#else
.align 5
.globl reset_cpu
reset_cpu:
ldr r1, rstctl /* get addr for global reset reg */
mov r3, #0x2 /* full reset pll+mpu */
str r3, [r1] /* force reset */
mov r0, r0
_loop_forever:
b _loop_forever
rstctl:
.word PM_RSTCTRL_WKUP
#endif