/*
* armboot - Startup Code for OMAP3530/ARM Cortex CPU-core
*
* Copyright (c) 2004 Texas Instruments
*
* Copyright (c) 2001 Marius Gröger
* Copyright (c) 2002 Alex Züpke
* Copyright (c) 2002 Gary Jennejohn
* Copyright (c) 2003 Richard Woodruff
* Copyright (c) 2003 Kshitij
* Copyright (c) 2006-2008 Syed Mohammed Khasim
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include
#include
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start
_start: 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 */
__blank_zone_start:
.fill 1024*5,1,0
__blank_zone_end:
.globl _blank_zone_start
_blank_zone_start:
.word __blank_zone_start
.globl _blank_zone_end
_blank_zone_end:
.word __blank_zone_end
.balignl 16,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
.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
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
_clr_remap_fmc_entry:
.word FMC_TEXT_ADRS + do_clr_remap - TEXT_BASE
_clr_remap_ddr_entry:
.word MEM_BASE_DDR + do_clr_remap - TEXT_BASE
_clr_remap_ram_entry:
.word RAM_START_ADRS + do_clr_remap - TEXT_BASE
_copy_abort_code:
.word copy_abort_code
/*
* the actual reset code
*/
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr @获取cpsr值到r0
bic r0, r0, #0x1f @清空r0的0x1f部分的bit
orr r0, r0, #0xd3 @将r0的0xd3位置1
msr cpsr,r0 @保存r0到cpsr
/*
* Invalidate L1 I/D 禁用L1的icache/dcache
*/
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和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, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
/*
* read system register REG_SC_GEN2 读该寄存器,检查是否自举模式
* check if ziju flag
*/
ldr r0, =SYS_CTRL_REG_BASE
ldr r1, [r0, #REG_SC_GEN2]
ldr r2, =0x7a696a75 /* magic for "ziju" */
ldr r3, [r0, #REG_SC_GEN20] /* pcie slave start up flag*/
cmp r3, r2
beq after_ziju @GEN20等于幻数,即pcie启动直接跳到af_zi
cmp r1, r2
bne normal_start_flow @GEN2不等于幻数,即不用自举,跳到nor_
mov r1, sp /* save sp */
str r1, [r0, #REG_SC_GEN2] /* clear ziju flag */
after_ziju:
/* init PLL/DDRC/pin mux/... */
ldr r0, _blank_zone_start
ldr r1, _TEXT_BASE
sub r0, r0, r1
cmp r3, r2
beq pcie_slave_addr
ldr r1, =RAM_START_ADRS
ldr sp, =STACK_TRAINING
b ziju_ddr_init
pcie_slave_addr:
ldr r1, =0x0
ldr sp, =PCIE_SLV_STACK
ldr r4, =SYS_CTRL_REG_BASE
str r2, [r4, #HI3519V101_SYSBOOT10]
ziju_ddr_init:
add r0, r0, r1
mov r1, #0x0 /* flags: 0->normal 1->pm */
bl init_registers /* init PLL/DDRC/... */
/* after ziju, we need ddr traning */
/*#ifdef CONFIG_DDR_TRAINING_V2*/
ldr r0, =REG_BASE_SCTL
bl start_ddr_training /* DDR training */
/*#endif*/
ldr r0, =SYS_CTRL_REG_BASE
ldr r2, =PCIE_SLV_DDR_INIT_FLG
str r2, [r0, #HI3519V101_SYSBOOT9]
ldr r2, =0x7a696a75
ldr r1, [r0, #HI3519V101_SYSBOOT10]
cmp r1, r2
beq pcie_slave_hold
ldr r1, [r0, #REG_SC_GEN2]
mov sp, r1 /* restore sp */
ldr r1, [r0, #REG_SC_GEN3]
mov pc, r1 /* return to bootrom */
pcie_slave_hold:
ldr r2, [r0, #HI3519V101_SYSBOOT9]
ldr r1, =0x7964616f /* complete flag */
cmp r1, r2
bne pcie_slave_hold
ldr r1, =0x0
str r1, [r0, #HI3519V101_SYSBOOT9]
mov pc, #0x0
nop
nop
nop
nop
nop
nop
nop
nop
b . /* bug here */
normal_start_flow:
/* init serial and printf a string. */
ldr sp, =STACK_TRAINING @保存sp
bl uart_early_init @初始化串口
bl msg_main_cpu_startup @打印一行System startup
/*
* enable cci snoop for GSF and VDMA
*/
ldr r0, =CCI_PORT_CTRL_0
mov r3, #CCI_ENABLE_REQ
str r3, [r0]
4: ldr r0, =CCI_CTRL_STATUS
ldr r1, [r0]
tst r1, #1
bne 4b
/*
* enable cci snoop for core 0
*/
ldr r0, =CCI_PORT_CTRL_1
mov r3, #CCI_ENABLE_REQ
str r3, [r0]
5: ldr r0, =CCI_CTRL_STATUS
ldr r1, [r0]
tst r1, #1
bne 5b
@if running not boot from nand/spi/emmc,
@we skipping boot_type checking.
mov r0, pc, lsr#24 @pc左移24bit
cmp r0, #0x0 @检查pc高8bit是否为0
bne check_bootrom_type @不为0则在bootrom中,跳过boot_type检查
check_boot_type:
ldr r0, =SYS_CTRL_REG_BASE
ldr r0, [r0, #REG_SYSSTAT]
mov r6, r0, lsr#5
and r6, #0x1
cmp r6, #0 @ [5]=0 意味着从存储控制器启动 fmc /* SPI Nor/Nand and Nand */
ldreq pc, _clr_remap_fmc_entry @ 执行该地址指向的函数!拷贝存储器上内容到dram
@otherwise, [31]=1 means boot from bootrom, err
beq bug
check_bootrom_type:
cmp r0, #0x4
/*boot from bootrom,we copy the uboot.bin to ram (0x4010500)*/
ldreq pc, _clr_remap_ram_entry @ 清除重映射
do_clr_remap:
/* do clear remap */
ldr r4, =SYS_CTRL_REG_BASE
ldr r0, [r4, #REG_SC_CTRL]
@Set clear remap bit.
orr r0, #(1<<8)
str r0, [r4, #REG_SC_CTRL] @ 清除sc_ctrl寄存器的remap bit
/*
* Set ACTLR.SMP to 1
* This is a bug on Cortex-A7 MPCORE. see buglist of Cortex-A7
* The D-caches are disabled when ACTLR.SMP is set to 0 regardless
* of the value of the cache enable bit. so we must set SMP bit of
* ACTLR register before enable D-cache
*/
mrc p15, 0, r0, c1, c0, 1
orr r0, #(1 << 6)
mcr p15, 0, r0, c1, c0, 1
@enable I-Cache now
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
@Check wether I'm running in dynamic mem bank
mov r0, pc, lsr#28
cmp r0, #8
blo ddr_init @小于8执行ddr_init
no_ddr_init:
adrl r0, _start
b copy_to_ddr
ddr_init:
ldr r0, _blank_zone_start
ldr r1, _TEXT_BASE
sub r0, r0, r1 @r0存储了_blank_zone_start-_TEXT_BASE
adrl r1, _start @r1存储了_start
add r0, r0, r1 @r0存储了_start+_blank_zone_start-TEXT_BASE
mov r1, #0 /* flags: 0->normal 1->pm */
bl init_registers @ 根据reg.bin初始化全片寄存器
/*#ifdef CONFIG_DDR_TRAINING_V2*/
ldr sp, =STACK_TRAINING
ldr r0, =REG_BASE_SCTL
bl start_ddr_training /* DDR training */
/*#endif*/
check_boot_mode:
ldr r0, =SYS_CTRL_REG_BASE
ldr r0, [r0, #REG_SYSSTAT]
mov r6, r0, lsr#4
and r6, #0x3
cmp r6, #BOOT_FROM_EMMC
bne copy_flash_to_ddr @不相等,即为从flash启动,拷贝内容到ddr
#ifdef CONFIG_HIMCI_V200
emmc_boot:
ldr r0, _TEXT_BASE
ldr r1, _armboot_start
ldr r2, _bss_start
sub r1, r2, r1
bl emmc_boot_read
b jump_to_ddr
#endif
copy_flash_to_ddr:
/* relocate SPI nor/nand Boot to DDR */
cmp r6, #BOOT_FROM_DDR
beq copy_to_ddr
ldr r0, =FMC_TEXT_ADRS /* 0x1400_0000 */
copy_to_ddr:
/* now, r0 stores __reset offset from where we get started */
ldr r1, _TEXT_BASE /* r1 stores where we will copy uboot to */
/* compare source and target address, *
*if equal no copy to target address */
cmp r0, r1
beq copy_abort_code
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
/* memcpy(r1, r0, r2) */
bl memcpy
jump_to_ddr:
ldr r0, _TEXT_BASE
ldr pc, _copy_abort_code
copy_abort_code:
ldr r1, =0x00000000
mov r2, #0x4000
/* memcpy(r1, r0, r2) */
bl memcpy
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot
sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 @ leave 3 words for abort-stack
and sp, sp, #~7 @ 8 byte alinged for (ldr/str)d
/* Clear BSS (if any). Is below tx (watch load addr - need space) */
clear_bss:
ldr r0, _bss_start @ find start of bss segment
ldr r1, _bss_end @ stop here
mov r2, #0x0 @ clear value
clbss_l:
str r2, [r0] @ clear BSS location
cmp r0, r1 @ are we at the end yet
add r0, r0, #4 @ increment clear index pointer
bne clbss_l @ keep clearing till at end
ldr pc, _start_armboot @ jump to C code
_start_armboot: .word start_armboot
bug:
nop
nop
nop
nop
nop
nop
nop
nop
b . /* bug here */
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ void memcpy(r1, r0, r2);
@
.align 2
memcpy:
add r2, r0, r2
memcpy_loop:
ldmia r0!, {r3 - r10}
stmia r1!, {r3 - r10}
cmp r0, r2
ble memcpy_loop
mov pc, lr
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.align 2
msg_main_cpu_startup:
mov r5, lr
add r0, pc, #4
bl uart_early_puts
mov pc, r5
L10:
#ifndef CONFIG_SUPPORT_CA_RELEASE
.ascii "\r\n\r\nSystem startup\r\n\0"
#else
.ascii "\r\n\r\n\r\n\0"
#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, #(CONFIG_SYS_MALLOC_LEN)
@ set base 2 words into abort
sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE + 8)
@ 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)
@ move past malloc pool
sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)
@ move to reserved a couple
sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE + 8)
@ 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
@ move past malloc pool
sub r0, r0, #(CONFIG_SYS_MALLOC_LEN)
@ move past gbl and a couple
sub r0, r0, #(CONFIG_SYS_GBL_DATA_SIZE + 8)
@ 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
#ifdef 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 effective 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
/*
* 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:
stmfd r13!, {r0 - r5, r7, r9 - r12, r14}
mov r7, r0 @ take a backup of device type
cmp r0, #0x3 @ check if the device type is
@ GP
moveq r12, #0x1 @ set up to invalid L2
smi: .word 0x01600070 @ Call SMI monitor (smieq)
cmp r7, #0x3 @ compare again in case its
@ lost
beq finished_inval @ if GP device, inval done
@ above
mrc p15, 1, r0, c0, c0, 1 @ read clidr
ands r3, r0, #0x7000000 @ extract loc from clidr
mov r3, r3, lsr #23 @ left align loc bit field
beq finished_inval @ if loc is 0, then no need to
@ clean
mov r10, #0 @ start clean at cache level 0
inval_loop1:
add r2, r10, r10, lsr #1 @ work out 3x current cache
@ level
mov r1, r0, lsr r2 @ extract cache type bits from
@ clidr
and r1, r1, #7 @ mask of the bits for current
@ cache only
cmp r1, #2 @ see what cache we have at
@ this level
blt skip_inval @ skip if no cache, or just
@ i-cache
mcr p15, 2, r10, c0, c0, 0 @ select current cache level
@ in cssr
mov r2, #0 @ operand for mcr SBZ
mcr p15, 0, r2, c7, c5, 4 @ flush prefetch buffer to
@ sych the new cssr&csidr,
@ with armv7 this is 'isb',
@ but we compile with armv5
mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
and r2, r1, #7 @ extract the length of the
@ cache lines
add r2, r2, #4 @ add 4 (line length offset)
ldr r4, =0x3ff
ands r4, r4, r1, lsr #3 @ find maximum number on the
@ way size
clz r5, r4 @ find bit position of way
@ size increment
ldr r7, =0x7fff
ands r7, r7, r1, lsr #13 @ extract max number of the
@ index size
inval_loop2:
mov r9, r4 @ create working copy of max
@ way size
inval_loop3:
orr r11, r10, r9, lsl r5 @ factor way and cache number
@ into r11
orr r11, r11, r7, lsl r2 @ factor index number into r11
mcr p15, 0, r11, c7, c6, 2 @ invalidate by set/way
subs r9, r9, #1 @ decrement the way
bge inval_loop3
subs r7, r7, #1 @ decrement the index
bge inval_loop2
skip_inval:
add r10, r10, #2 @ increment cache number
cmp r3, r10
bgt inval_loop1
finished_inval:
mov r10, #0 @ swith back to cache level 0
mcr p15, 2, r10, c0, c0, 0 @ select current cache level
@ in cssr
mcr p15, 0, r10, c7, c5, 4 @ flush prefetch buffer,
@ with armv7 this is 'isb',
@ but we compile with armv5
ldmfd r13!, {r0 - r5, r7, r9 - r12, pc}
#include "lowlevel_init.S"