u-boot第一階段start.s分析:lowlevel_init部分

  u-boot一般分爲兩個階段:

  第一階段:硬件相關初始化、初始化內存芯片爲bootloader做好準備、複製bootloader到RAM空間中、設置好棧方便調用C語言、跳轉到C代碼入口。這個部分是彙編語言部分,只是爲調用C語言做好準備。

  第二階段:初始化該階段需要使用到的硬件設備、檢測內存映射(MMU)、u-boot命令格式、爲內核設置啓動參數。這個部分就是C語言部分了。

以下是作者自己整理出的第一階段流程圖:u-boot分析第一階段流程圖:lowlevel_init,搭配着本文章閱讀更香哦~

  start.s文件位置:cpu\s3c64xx\start.s,怎麼知道這是開機運行的第一個程序呢?見u-boot頂層Makefile分析

.globl _start
_start: b	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

  第一句,跳轉到reset,設置CPU模式爲管理模式(svc),如下:

reset:
	/*
	 * set the cpu to SVC32 mode
	 */
	mrs	r0,cpsr
	bic	r0,r0,#0x1f
	orr	r0,r0,#0xd3
	msr	cpsr,r0

  然後關閉關閉數據和指令緩存,如下:

  爲什麼要關閉數據和指令緩存呢?

  因爲Caches是CPU內部的一個2級緩存,它的作用是將常用的數據和指令放在CPU內部。Caches是通過CP15管理的,剛上電的時候,CPU還不能管理Caches。上電的時候指令Cache可關閉,也可不關閉,但數據Cache一定要關閉,否則可能導致剛開始的代碼裏面,去取數據的時候,從Cache裏面取,而這時候RAM中數據還沒有Cache過來,導致數據預取異常 。

	/*
	 * flush v4 I/D caches
	 */
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */

  然後對端口進行設置:

	/* Peri port setup */
	ldr	r0, =0x70000000
	orr	r0, r0, #0x13
    	mcr	p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)

然後配置ONENAND控制器,若啓動定義了CONFIG_BOOT_ONENAND,對ONENAND flash 初始化,此類型ROM暫時不涉及,內容跳過:

#ifdef CONFIG_BOOT_ONENAND
	ldr	r0, =0x70000000		@ onenand controller setup
	orr	r0, r0, #0x100000
	ldr	r1, =0x4000
	orr	r1, r1, #0xe0
	str	r1, [r0]

#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430)
	orr	r0, r0, #300		@ disable watchdog
	mov	r1, #1
	str	r1, [r0]

	mov	r1, #0x23000000		@ start buffer register
	orr	r1, r1, #0x30000
	orr	r1, r1, #0xc800
#else
	mov	r1, =0x20000000		@ start buffer register
	orr	r1, r1, #0xc30000
	orr	r1, r1, #0xc800
#endif

	sub	r0, r1, #0x0400		@ start address1 register

	ldr	r2, [r1, #0x84]		@ ecc bypass
	orr	r2, r2, #0x100
	str	r2, [r1, #0x84]

	mov	r3, #0x0		@ DFS, FBA
	str	r3, [r0, #0x00]
	str	r3, [r0, #0x04]		@ select dataram for DDP as 0

	mov	r4, #0x104		@ interrupt register
	mov	r5, #0x0002		@ FPA, FSA
	mov	r6, #0x0800		@ BSA

onenand_bl1_load:
	str	r5, [r0, #0x1c]		@ save FPA, FSA
	orr	r6, r6, #0x02		@ BSC
	str	r6, [r1, #0x00]		@ save BSA, BSC
	str	r3, [r1, r4]		@ clear interrupt
	str	r3, [r1, #0x80]		@ write load command

	mov	r7, #0x100		@ need small delay

onenand_wait_loop1:
	subs	r7, r7, #0x1
	bne	onenand_wait_loop1

	add	r5, r5, #0x2		@ next FPA, FSA
	sub	r6, r6, #0x2
	add	r6, r6, #0x200		@ next BSA
	cmp	r5, #0x8
	bne	onenand_bl1_load
#endif

  然後調用lowlevel_init對底層的初始化:

	bl	lowlevel_init	/* go setup pll,mux,memory */

  而在start.s並未找到關鍵字lowlevel_init,這個關鍵字在board\samsung\mini6410\lowlevel_init.s中被定義:

  主要做的工作就是:配置GPNIO、GPEIO、GPPIO端口輸出、關閉看門狗、清除外部中斷標誌、關閉所有的中斷、設置所有中斷類型爲IRQ、清除中斷標誌、system_clock_init系統時鐘初始化:(關閉看門狗、屏蔽中斷、設置FCLK:HCLK:PCLK時* 鍾比例)、uart_asm_init串口初始化、nand_asm_init是NAND FLASH初始化。

#include <config.h>
#include <version.h>

#include <s3c6410.h>
#include "mini6410_val.h"

_TEXT_BASE:
	.word	TEXT_BASE

	.globl lowlevel_init
lowlevel_init:
	mov	r12, lr /*保存程序的返回地址,等待程序調用執行完成之後返回原地址*/

	/* LED on only #8 */
	ldr	r0, =ELFIN_GPIO_BASE
	ldr	r1, =0x55540000
	str	r1, [r0, #GPNCON_OFFSET]

	ldr	r1, =0x55555555
	str	r1, [r0, #GPNPUD_OFFSET]

	ldr	r1, =0xf000
	str	r1, [r0, #GPNDAT_OFFSET]

	ldr	r0, =ELFIN_GPIO_BASE
	ldr	r1, =0x1
	str	r1, [r0, #GPECON_OFFSET]
	ldr	r1, =0x0
	str	r1, [r0, #GPEDAT_OFFSET]

	ldr	r0, =ELFIN_GPIO_BASE
	ldr	r1, =0x2A5AAAAA
	str	r1, [r0, #GPPCON_OFFSET]
	ldr	r1, =0x0
	str	r1, [r0, #GPPDAT_OFFSET]
	

	ldr	r1, =0x55555555
	str	r1, [r0, #MEM1DRVCON_OFFSET]

	/* Disable Watchdog */
	ldr	r0, =0x7e000000		@0x7e004000
	orr	r0, r0, #0x4000
	mov	r1, #0
	str	r1, [r0]

	@ External interrupt pending clear
	ldr	r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET)	/*EINTPEND*/
	ldr	r1, [r0]
	str	r1, [r0]

	ldr	r0, =ELFIN_VIC0_BASE_ADDR 	@0x71200000
	ldr	r1, =ELFIN_VIC1_BASE_ADDR 	@0x71300000

	@ Disable all interrupts (VIC0 and VIC1)
	mvn	r3, #0x0
	str	r3, [r0, #oINTMSK]
	str	r3, [r1, #oINTMSK]

	@ Set all interrupts as IRQ
	mov	r3, #0x0
	str	r3, [r0, #oINTMOD]
	str	r3, [r1, #oINTMOD]

	@ Pending Interrupt Clear
	mov	r3, #0x0
	str	r3, [r0, #oVECTADDR]
	str	r3, [r1, #oVECTADDR]

	/* init system clock */
	bl system_clock_init

	/* for UART */
	bl uart_asm_init

#if defined(CONFIG_NAND)
	/* simple init for NAND */
	bl nand_asm_init
#endif

#if 0
	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	1f			/* r0 == r1 then skip sdram init   */
#endif

	bl	mem_ctrl_asm_init

#if 1
        ldr     r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
        ldr     r1, [r0]
        bic     r1, r1, #0xfffffff7
        cmp     r1, #0x8
        beq     wakeup_reset

#endif

1:
	ldr	r0, =ELFIN_UART_BASE
	ldr	r1, =0x4b4b4b4b
	str	r1, [r0, #UTXH_OFFSET]

	mov	lr, r12
	mov	pc, lr
#if 1
wakeup_reset:

	/*Clear wakeup status register*/
	ldr	r0, =(ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET)
	ldr	r1, [r0]
	str	r1, [r0]

        /*LED test*/
        ldr     r0, =ELFIN_GPIO_BASE
        ldr     r1, =0x3000
        str     r1, [r0, #GPNDAT_OFFSET]

	/*Load return address and jump to kernel*/
	ldr	r0, =(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET)
	ldr	r1, [r0]	/* r1 = physical address of s3c6400_cpu_resume function*/
	mov	pc, r1		/*Jump to kernel (sleep-s3c6400.S)*/
	nop
	nop
#endif
/*
 * system_clock_init: Initialize core clock and bus clock.
 * void system_clock_init(void)
 */
system_clock_init:
	ldr	r0, =ELFIN_CLOCK_POWER_BASE	@0x7e00f000

#ifdef	CONFIG_SYNC_MODE
	ldr	r1, [r0, #OTHERS_OFFSET]
	mov	r2, #0x40
	orr	r1, r1, r2
	str	r1, [r0, #OTHERS_OFFSET]

	nop
	nop
	nop
	nop
	nop

	ldr	r2, =0x80
	orr	r1, r1, r2
	str	r1, [r0, #OTHERS_OFFSET]

check_syncack:
	ldr	r1, [r0, #OTHERS_OFFSET]
	ldr	r2, =0xf00
	and	r1, r1, r2
	cmp	r1, #0xf00
	bne	check_syncack
#else	/* ASYNC Mode */
	nop
	nop
	nop
	nop
	nop

	ldr	r1, [r0, #OTHERS_OFFSET]
	bic	r1, r1, #0xC0
	orr	r1, r1, #0x40
	str	r1, [r0, #OTHERS_OFFSET]

wait_for_async:
	ldr	r1, [r0, #OTHERS_OFFSET]
	and	r1, r1, #0xf00
	cmp	r1, #0x0
	bne	wait_for_async

	ldr	r1, [r0, #OTHERS_OFFSET]
	bic	r1, r1, #0x40
	str	r1, [r0, #OTHERS_OFFSET]
#endif

	mov	r1, #0xff00
	orr	r1, r1, #0xff
	str	r1, [r0, #APLL_LOCK_OFFSET]
	str	r1, [r0, #MPLL_LOCK_OFFSET]
	str	r1, [r0, #EPLL_LOCK_OFFSET]
/* CLKUART(=66.5Mhz) = CLKUART_input(532/2=266Mhz) / (UART_RATIO(3)+1) */
/* CLKUART(=50Mhz) = CLKUART_input(400/2=200Mhz) / (UART_RATIO(3)+1) */
/* Now, When you use UART CLK SRC by EXT_UCLK1, We support 532MHz & 400MHz value */

#if defined(CONFIG_CLKSRC_CLKUART)
	ldr   	r1, [r0, #CLK_DIV2_OFFSET]
	bic	r1, r1, #0x70000
	orr	r1, r1, #0x30000
	str	r1, [r0, #CLK_DIV2_OFFSET]
#endif


	ldr   	r1, [r0, #CLK_DIV0_OFFSET]	/*Set Clock Divider*/
	bic	r1, r1, #0x30000
	bic	r1, r1, #0xff00
	bic	r1, r1, #0xff
	ldr	r2, =CLK_DIV_VAL
	orr	r1, r1, r2
	str	r1, [r0, #CLK_DIV0_OFFSET]

	ldr	r1, =APLL_VAL
	str	r1, [r0, #APLL_CON_OFFSET]
	ldr	r1, =MPLL_VAL
	str	r1, [r0, #MPLL_CON_OFFSET]

	ldr	r1, =0x80200203			/* FOUT of EPLL is 96MHz */
	str	r1, [r0, #EPLL_CON0_OFFSET]
	ldr	r1, =0x0
	str	r1, [r0, #EPLL_CON1_OFFSET]

	ldr	r1, [r0, #CLK_SRC_OFFSET]	/* APLL, MPLL, EPLL select to Fout */

#if defined(CONFIG_CLKSRC_CLKUART)
	ldr	r2, =0x2007
#else
	ldr	r2, =0x7
#endif
	orr	r1, r1, r2

	str	r1, [r0, #CLK_SRC_OFFSET]

	/* wait at least 200us to stablize all clock */
	mov	r1, #0x10000
1:	subs	r1, r1, #1
	bne	1b
#if 0
	mrc	p15, 0, r0, c1, c0, 0
	orr	r0, r0, #0xc0000000	/* clock setting in MMU */
	mcr	p15, 0, r0, c1, c0, 0
#endif

#ifdef CONFIG_SYNC_MODE				/* Synchronization for VIC port */
	ldr	r1, [r0, #OTHERS_OFFSET]
	orr	r1, r1, #0x20
	str	r1, [r0, #OTHERS_OFFSET]
#else
	ldr	r1, [r0, #OTHERS_OFFSET]
	bic	r1, r1, #0x20
	str	r1, [r0, #OTHERS_OFFSET]
#endif
	mov	pc, lr


/*
 * uart_asm_init: Initialize UART in asm mode, 115200bps fixed.
 * void uart_asm_init(void)
 */
uart_asm_init:
	/* set GPIO to enable UART */
	@ GPIO setting for UART
	ldr	r0, =ELFIN_GPIO_BASE
	ldr	r1, =0x22222222
	str   	r1, [r0, #GPACON_OFFSET]
	ldr	r1, =0x2222
	str   	r1, [r0, #GPBCON_OFFSET]

	ldr	r0, =ELFIN_UART_CONSOLE_BASE		@0x7F005000
	mov	r1, #0x0
	str	r1, [r0, #UFCON_OFFSET]
	str	r1, [r0, #UMCON_OFFSET]

	mov	r1, #0x3                	@was 0.
	str	r1, [r0, #ULCON_OFFSET]

#if defined(CONFIG_CLKSRC_CLKUART)
	ldr	r1, =0xe45			/* UARTCLK SRC = 11 => EXT_UCLK1*/
#else
	ldr	r1, =0x245			/* UARTCLK SRC = x0 => PCLK */
#endif

	str	r1, [r0, #UCON_OFFSET]

#if defined(CONFIG_UART_50)
	ldr	r1, =0x1A
#elif defined(CONFIG_UART_66)
	ldr	r1, =0x22
#else
	ldr	r1, =0x1A
#endif
	str	r1, [r0, #UBRDIV_OFFSET]

#if defined(CONFIG_UART_50)
	ldr	r1, =0x3
#elif defined(CONFIG_UART_66)
	ldr	r1, =0x1FFF
#else
	ldr	r1, =0x3
#endif
	str	r1, [r0, #UDIVSLOT_OFFSET]

	ldr	r1, =0x4f4f4f4f
	str	r1, [r0, #UTXH_OFFSET]		@'O'

	mov	pc, lr

/*
 * Nand Interface Init for SMDK6400 */
nand_asm_init:
	ldr	r0, =ELFIN_NAND_BASE
	ldr	r1, [r0, #NFCONF_OFFSET]
	orr	r1, r1, #0x70
	orr	r1, r1, #0x7700
	str     r1, [r0, #NFCONF_OFFSET]

	ldr	r1, [r0, #NFCONT_OFFSET]
	orr	r1, r1, #0x03
	str     r1, [r0, #NFCONT_OFFSET]

	mov	pc, lr

#ifdef CONFIG_ENABLE_MMU

/*
 * MMU Table for SMDK6400
 */

	/* form a first-level section entry */
.macro FL_SECTION_ENTRY base,ap,d,c,b
	.word (\base << 20) | (\ap << 10) | \
	      (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
.endm
.section .mmudata, "a"
	.align 14
	// the following alignment creates the mmu table at address 0x4000.
	.globl mmu_table
mmu_table:
	.set __base,0
	// 1:1 mapping for debugging
	.rept 0xA00
	FL_SECTION_ENTRY __base,3,0,0,0
	.set __base,__base+1
	.endr

	// access is not allowed.
	.rept 0xC00 - 0xA00
	.word 0x00000000
	.endr

	// 128MB for SDRAM 0xC0000000 -> 0x50000000
	.set __base, 0x500
	.rept 0xC80 - 0xC00
	FL_SECTION_ENTRY __base,3,0,1,1
	.set __base,__base+1
	.endr

	// access is not allowed.
	.rept 0x1000 - 0xc80
	.word 0x00000000
	.endr

#endif

  然後跳轉到mem_ctrl_asm_init初始化DDR

	bl	mem_ctrl_asm_init

  而這個mem_ctrl_asm_init初始化DDR在哪兒定義的呢?答案就是:cpu\s3c64xx\s3c6410\cpu_init.s文件裏面:

#include <config.h>
#include <s3c6410.h>

	.globl mem_ctrl_asm_init
mem_ctrl_asm_init:
	ldr	r0, =ELFIN_MEM_SYS_CFG			@Memory sussystem address 0x7e00f120
	mov	r1, #0xd				@ Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1
	str	r1, [r0]

	ldr	r0, =ELFIN_DMC1_BASE			@DMC1 base address 0x7e001000

	ldr	r1, =0x04
	str	r1, [r0, #INDEX_DMC_MEMC_CMD]

	ldr	r1, =DMC_DDR_REFRESH_PRD
	str	r1, [r0, #INDEX_DMC_REFRESH_PRD]

	ldr	r1, =DMC_DDR_CAS_LATENCY
	str	r1, [r0, #INDEX_DMC_CAS_LATENCY]

	ldr	r1, =DMC_DDR_t_DQSS
	str	r1, [r0, #INDEX_DMC_T_DQSS]

	ldr	r1, =DMC_DDR_t_MRD
	str	r1, [r0, #INDEX_DMC_T_MRD]

	ldr	r1, =DMC_DDR_t_RAS
	str	r1, [r0, #INDEX_DMC_T_RAS]

	ldr	r1, =DMC_DDR_t_RC
	str	r1, [r0, #INDEX_DMC_T_RC]

	ldr	r1, =DMC_DDR_t_RCD
	ldr	r2, =DMC_DDR_schedule_RCD
	orr	r1, r1, r2
	str	r1, [r0, #INDEX_DMC_T_RCD]

	ldr	r1, =DMC_DDR_t_RFC
	ldr	r2, =DMC_DDR_schedule_RFC
	orr	r1, r1, r2
	str	r1, [r0, #INDEX_DMC_T_RFC]

	ldr	r1, =DMC_DDR_t_RP
	ldr	r2, =DMC_DDR_schedule_RP
	orr	r1, r1, r2
	str	r1, [r0, #INDEX_DMC_T_RP]

	ldr	r1, =DMC_DDR_t_RRD
	str	r1, [r0, #INDEX_DMC_T_RRD]

	ldr	r1, =DMC_DDR_t_WR
	str	r1, [r0, #INDEX_DMC_T_WR]

	ldr	r1, =DMC_DDR_t_WTR
	str	r1, [r0, #INDEX_DMC_T_WTR]

	ldr	r1, =DMC_DDR_t_XP
	str	r1, [r0, #INDEX_DMC_T_XP]

	ldr	r1, =DMC_DDR_t_XSR
	str	r1, [r0, #INDEX_DMC_T_XSR]

	ldr	r1, =DMC_DDR_t_ESR
	str	r1, [r0, #INDEX_DMC_T_ESR]

	ldr	r1, =DMC1_MEM_CFG
	str	r1, [r0, #INDEX_DMC_MEMORY_CFG]

	ldr	r1, =DMC1_MEM_CFG2
	str	r1, [r0, #INDEX_DMC_MEMORY_CFG2]

	ldr	r1, =DMC1_CHIP0_CFG
	str	r1, [r0, #INDEX_DMC_CHIP_0_CFG]

	ldr	r1, =DMC_DDR_32_CFG
	str	r1, [r0, #INDEX_DMC_USER_CONFIG]

	@DMC0 DDR Chip 0 configuration direct command reg
	ldr	r1, =DMC_NOP0
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@Precharge All
	ldr	r1, =DMC_PA0
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@Auto Refresh	2 time
	ldr	r1, =DMC_AR0
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@MRS
	ldr	r1, =DMC_mDDR_EMR0
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@Mode Reg
	ldr	r1, =DMC_mDDR_MR0
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

#ifdef CONFIG_SMDK6410_X5A
	ldr	r1, =DMC1_CHIP1_CFG
	str	r1, [r0, #INDEX_DMC_CHIP_1_CFG]

	@DMC0 DDR Chip 0 configuration direct command reg
	ldr	r1, =DMC_NOP1
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@Precharge All
	ldr	r1, =DMC_PA1
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@Auto Refresh	2 time
	ldr	r1, =DMC_AR1
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@MRS
	ldr	r1, =DMC_mDDR_EMR1
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]

	@Mode Reg
	ldr	r1, =DMC_mDDR_MR1
	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
#endif

	@Enable DMC1
	mov	r1, #0x0
	str	r1, [r0, #INDEX_DMC_MEMC_CMD]

check_dmc1_ready:
	ldr	r1, [r0, #INDEX_DMC_MEMC_STATUS]
	mov	r2, #0x3
	and	r1, r1, r2
	cmp	r1, #0x1
	bne	check_dmc1_ready
	nop
	mov	pc, lr


/* Below code is for ARM926EJS and ARM1026EJS */
	.globl cleanDCache
cleanDCache:
	mrc	p15, 0, pc, c7, c10, 3	/* test/clean D-Cache */
	bne	cleanDCache
	mov	pc, lr

	.globl cleanFlushDCache
cleanFlushDCache:
	mrc	p15, 0, pc, c7, c14, 3	/* test/cleanflush D-Cache */
	bne	cleanFlushDCache
	mov	pc, lr

	.globl cleanFlushCache
cleanFlushCache:
	mrc	p15, 0, pc, c7, c14, 3	/* test/cleanflush D-Cache */
	bne	cleanFlushCache
	mcr	p15, 0, r0, c7, c5, 0	/* flush I-Cache */
	mov	pc, lr

	.ltorg

返回分析到lowlevel_init.s中:

wakeup_reset是清除喚醒狀態寄存器,然後返回到start.S中line240。

  下一步是判斷啓動地址並複製程序至RAM:

	/* when we already run in ram, we dont need to relocate U-Boot.
	 * and actually, memory controller must be configured before U-Boot
	 * is running in ram.
	 */
	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   */

  此處判斷程序運行地址是否在RAM中,如果沒有,複製啓動程序否則調用after_copy將程序複製到RAM中,也就是重定位,且根據定義的FLASH去拷貝這個程序,也就是針對NOR FLASH/NAND FLASH/MOVINAND FLASH/ONE NAND FLASH設備啓動的代碼複製進行區分設置:


#ifdef CONFIG_BOOT_NOR			/* relocate U-Boot to RAM */
	adr	r0, _start		/* r0 <- current position of code   */
	ldr	r1, _TEXT_PHY_BASE	/* r1 <- destination                */
	ldr	r2, _armboot_start
	ldr	r3, _bss_start
	sub	r2, r3, r2		/* r2 <- size of armboot            */
	add	r2, r0, r2		/* r2 <- source end address         */

nor_copy_loop:
	ldmia	r0!, {r3-r10}		/* copy from source address [r0]    */
	stmia	r1!, {r3-r10}		/* copy to   target address [r1]    */
	cmp	r0, r2			/* until source end addreee [r2]    */
	ble	nor_copy_loop
	b	after_copy
#endif

#ifdef CONFIG_BOOT_NAND
	mov	r0, #0x1000
	bl	copy_from_nand
#endif

#ifdef CONFIG_BOOT_MOVINAND
	ldr	sp, _TEXT_PHY_BASE
	bl	movi_bl2_copy
	b	after_copy
#endif

#ifdef CONFIG_BOOT_ONENAND
	ldr	sp, =0x50000000		@ temporary stack

#ifdef CONFIG_S3C6400
	mov	r1, =0x20000000		@ start buffer register
	orr	r1, r1, #0xc30000
	orr	r1, r1, #0xc800
#else
	mov	r1, #0x23000000		@ start buffer register
	orr	r1, r1, #0x30000
	orr	r1, r1, #0xc800
#endif

	ldr	r2, [r1, #0x84]		@ ecc bypass
	orr	r2, r2, #0x100
	str	r2, [r1, #0x84]

	sub	r0, r1, #0x0400		@ start address1 register

	str	r3, [r0, #0x00]
	str	r3, [r0, #0x04]		@ select dataram for DDP as 0

	mov	r4, #0x104		@ interrupt register

	mov	r6, #0x0c00		@ fixed dataram1 sector number
	str	r6, [r1, #0x00]

	mov	r3, #0x0		@ DFS, FBA
	mov	r5, #0x0000		@ FPA, FSA
	ldr	r9, =CFG_PHY_UBOOT_BASE	@ destination

onenand_bl2_load:
	str	r3, [r0, #0x00]		@ save DFS, FBA
	str	r5, [r0, #0x1c]		@ save FPA, FSA

	mov	r7, #0x0		@ clear interrupt
	str	r7, [r1, r4]
	str	r7, [r1, #0x80]		@ write load command

	mov	r8, #0x1000
onenand_wait_loop2:
	subs	r8, r8, #0x1
	bne	onenand_wait_loop2

onenand_wait_int:			@ wait INT and RI
	ldr	r7, [r1, r4]
	mov	r8, #0x8000
	orr	r8, r8, #0x80
	tst	r7, r8
	beq	onenand_wait_int

	mov	r7, #0x0		@ clear interrupt
	str	r7, [r1, r4]

	mov	r8, #0xc00		@ source address (dataram1)
	mov	r10, #0x40		@ copy loop count (64 = 2048 / 32)

	stmia	sp, {r0-r7}		@ backup

onenand_copy_to_ram:
	ldmia	r8!, {r0-r7}
	stmia	r9!, {r0-r7}
	subs	r10, r10, #0x1
	bne	onenand_copy_to_ram

	ldmia	sp, {r0-r7}		@ restore

	add	r5, r5, #0x4		@ next FPA
	cmp	r5, #0x100		@ last FPA?
	bne	onenand_bl2_load

	/* next block */
	mov	r5, #0x0		@ reset FPA
	add	r3, r3, #0x1		@ next FBA
	cmp	r3, #0x2		@ last FBA?
	bne	onenand_bl2_load
	b	after_copy
#endif

#ifdef CONFIG_BOOT_ONENAND_IROM
	ldr	sp, _TEXT_PHY_BASE
	bl	onenand_bl2_copy
	b	after_copy
#endif

  以下代碼是拷貝程序之前需要設置的寄存器:

after_copy:
	ldr	r0, =ELFIN_GPIO_BASE
	ldr	r1, =0xC00
	str	r1, [r0, #GPPDAT_OFFSET]
	ldr	r1, [r0, #GPFPUD_OFFSET]
	bic	r1, r1, #0xc0000000
	orr	r1, r1, #0x80000000
	str	r1, [r0, #GPFPUD_OFFSET]
	ldr	r1, [r0, #GPFDAT_OFFSET]
	orr	r1, r1, #0x8000
	str	r1, [r0, #GPFDAT_OFFSET]
	ldr	r1, [r0, #GPFCON_OFFSET]
	bic	r1, r1, #0xc0000000
	orr	r1, r1, #0x40000000
	str	r1, [r0, #GPFCON_OFFSET]

接下來啓用域訪問:

#ifdef CONFIG_ENABLE_MMU
enable_mmu:
	/* enable domain access */
	ldr	r5, =0x0000ffff
	mcr	p15, 0, r5, c3, c0, 0		@ load domain access register

	/* 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			/* Set CR_M to enable MMU */
	mcr	p15, 0, r0, c1, c0, 0
	nop
	nop
	nop
	nop
#endif

然後設置棧:

skip_hw_init:
	/* Set up the stack						    */
stack_setup:
#ifdef CONFIG_MEMORY_UPPER_CODE
	ldr	sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc)
#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                        */
#ifdef CONFIG_USE_IRQ
	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
	sub	sp, r0, #12		/* leave 3 words for abort-stack    */

#endif

然後設置_bss_start、_bss_end地址、清bss段:

clear_bss:
	ldr	r0, _bss_start		/* find start of bss segment        */
	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

然後程序跳轉到start_armboot執行。

這就進入了u-boot的第二個階段!下節更精彩!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章