OK6410A 开发板 (三) 13 u-boot-2021.01 boot 解析 SPL 镜像运行部分 boot 详细解析

url 		: git@github.com:lisider/u-boot.git
branch 		: ok6410a
commit id 	: e63a4077ad3aea53107495b0b68b95e720fe6033
config 		: ok6410a_mini_defconfig
// 涉及的 .S .s .c 文件 有 67个
  • 从入口出口来看
// 运行在 0x0c00 0000
// 入口 为 arch/arm/lib/vectors.S 中的 _start 标号处的 b reset

reset 												arch/arm/cpu/arm1176/start.S 39	
	lowlevel_init(108) 								board/samsung/ok6410a/lowlevel_init.S 72
	_main(110)										arch/arm/lib/crt0.S 91
		board_init_f(117)							board/samsung/ok6410a/ok6410a.c 266
			debug_uart_init(271) 					include/debug_uart.h 193
				_debug_uart_init(196) 				drivers/serial/s3c64xx_serial.c 315	
		board_init_r(177) 							common/spl/spl.c 589
			spl_board_init(641) 					board/samsung/ok6410a/ok6410a.c 255
				spl_boot_mmc(258) 					board/samsung/ok6410a/bl2_mmc_copy.c 18
					mmc_bl2_copy(23) 				board/samsung/ok6410a/bl2_mmc_copy.c 7
						CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, bl2_base, MOVI_INIT_REQUIRED)(13) arch/arm/mach-s3c64xx/include/mach/movi.h 25
					bl2base(24) // 跳转到 u-boot 的u-boot镜像
			
  • 详细解析
// common/init/board_init.c
// register volatile gd_t *gd asm ("r9");
// arch/arm/include/asm/global_data.h:112:#define DECLARE_GLOBAL_DATA_PTR          register volatile gd_t *gd asm ("r9")

reset
	save_boot_params
		// null
	 mrs r0, cpsr
	 bic r0, r0, #0x3f
	 	// 清 bit[4:0] 为0 // 设置 mode 为 system 
	 	// 清 bit[5] 为 0 // 设置 T 为0 , 指令集 为 ARM
	 orr r0, r0, #0xd3
	 	// 与 0b11010011
	 	// 设置mode 为 Supervisor
	 	// 设置 I 为 1,disable IRQ
	 	// 设置 F 为 1,disable FIQ 
	 msr cpsr, r0
		// 设置 cpsr	 	
	 
	lowlevel_init
		spl_config_uart_baudrate
			ulong val = spl_uart_getclk(is_mpll) / 115200;
			_UBRDIV = val / 16 - 1;
			_UDIVSLOT = udivslot[val % 16];
		mem_ctrl_asm_init
	_main
		board_init_f_alloc_reserve
			// 申请 struct global_data 个字节 用来存储 gd_t *gd 指向的 gd_t 结构体
			// include/asm-generic/global_data.h 中 有 gd_t 的 定义
		board_init_f_init_reserve
			// 初始化 gd_t *gd 指向的 gd_t 结构体 空间 为 0
			// 初始化 gd_t *gd 指向的 gd_t 结构体 的 成员 malloc_base

			// 问题: spl 阶段初始化好的 gd结构体空间 , u-boot 阶段继承了吗?
			// u-boot 阶段没阶段,清空了.
			// 但是 u-boot 阶段不清空的话,就可以继承 spl 初始化好的数据
			// 在spl加载u-boot过程中,r9没变化,且r9指向的空间也没被破坏
		/*
		下面的这几行有两个目标
		// 此时开始布局ddr中的内存,而不是0x0c00 0000在的iram
		// i-ram 只用作 u-boot-spl.bin(最多8KB) 的存储,所以如果在这8KB使用堆栈,则有可能破坏 i-ram 中的 u-boot-spl.bin
		1. 设置sp
		2. 存储gd指针变量并clear gd指针变量指向的空间,并设置 gd->malloc_base = 0x5f9f ff20;
		
		ldr r0, =((0x5FB00000 - 0x0C)) 		=> r0 : 5FAF FFF4
		bic r0, r0, #7 						=> r0 : 5FAF FFF0
		mov sp, r0 							=> sp : 5FAF FFF0
		bl board_init_f_alloc_reserve 		=> r0 : 5f9f ff20 (5FAF FFF0 - 0x10 0000 - 0xD0)
		mov sp, r0 							=> sp : 5f9f ff20             ***** 设置了 栈指针
		mov r9, r0 							=> r9 : 5f9f ff20 			  ***** 存储了 gd指针变量的值
		bl board_init_f_init_reserve 		=> 初始化 (5f9fff20 - 5f9fff20+0xD0) 的空间
		*/


		/*
		// .code .rodata .data .bss .stack .heap
		此时i-ram的内存分布
		0C00 2000---------------------0C00 2000
					8KB(0x2000)大小,用于存储8KB的u-boot-spl.bin// 不管u-boot-spl.bin有没有8KB,都会从mmc上拷贝8KB过来
					内存中的u-boot.bin 中存在 .bss段 
					内存中的u-boot.bin 也存在 .code .rodata .data
		0C00 0000---------------------0C00 0000
		
		此时ddr的内存分布
		5FFF FFFF---------------------5FFF FFFF
					5120KB(0x500000)大小,空洞
		5FB0 0000---------------------
					16B(0x10)大小,空洞
		5FAF FFF0---------------------
					1024KB(0x100000)大小,用于sys_malloc
		5F9F FFF0---------------------
					208B(0xD0)大小,用于gd
		5F9F FF20---------------------
					255999KB(约250MB)大小,用于栈
		5000 0000---------------------5000 0000
		*/	

		board_init_f
			debug_uart_init  // 被调用时第一次使用栈(sp指针)
				board_debug_uart_init
					// null
				_debug_uart_init
					struct s3c64xx_uart *uart = (struct s3c64xx_uart *)0x7F005000;
					s3c64xx_serial_init(uart);
						uart->UFCON = 0;
						uart->UMCON = 0;
						uart->ULCON = 3;
						uart->UCON =0xa45;
					s3c64xx_serial_baud(uart, get_uart_clk(0), 115200);
						val = (uclk / baudrate) % 16;
						
						uart->UBRDIV = uclk / baudrate / 16 - 1;
						uart->UDIVSLOT = udivslot[val];
						
						for (val = 0; val < 100; val++)
						__asm__ __volatile__("": : :"memory");
						
						
		CLEAR_BSS
			ldr r0, =__bss_start
			
			
			ldr r3, =__bss_end
			mov r1, #0x00000000
			
			subs r2, r3, r0
			bl memset // lib/string.c
		spl_relocate_stack_gd
			// null
		board_init_r
			spl_set_bd
				// common/spl/spl.c static struct bd_info bdata __attribute__ ((section(".data")));
				// gd->bd = &bdata;
				// 填充bd , 为填充板子数据做准备
			spl_init
				// spl_common_init(1)
					// gd->malloc_limit = 0x100000;
					// gd->malloc_ptr = 0;
				// gd->flags |= GD_FLG_SPL_INIT; // include/asm-generic/global_data.h
				// 为 malloc 做准备
			timer_init
				// 设置 s3c6410的timer // 0x7F006000
				// 设置 gd->arch.timer_rate_hz
				// 设置 gd->arch.lastinc
				// 设置 gd->arch.timer_reset_value
				// 为 delay 做准备
			spl_board_init
				spl_boot_mmc
					ulong bl2base=0x5FB00000;
					mmc_bl2_copy
						writel(readl(HM_CONTROL4) | (0x3 << 16), HM_CONTROL4);
							// ({ u32 __v = ({ u32 __v = (*(volatile unsigned int *)((0x8c))); asm volatile ("mcr     p15, 0, %0, c7, c10, 5" : : "r" (0)); __v; }) | (0x3 << 16); asm volatile ("mcr     p15, 0, %0, c7, c10, 5" : : "r" (0)); (*(volatile unsigned int *)((0x8c)) = (__v)); __v; });
						ret = CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, bl2_base, MOVI_INIT_REQUIRED);
							// ret = (((int(*)(int, uint, ushort, uint *, int))(*((uint *)(0x0C004000 + 0x8))))(0,((*((volatile unsigned int*)(0x0C004000 - 0x4)) - ((1 * 1024) / 512)) - ((8 * 1024) / 512) - ((512 * 1024) / 512) - (0x4000 / 512)),((512 * 1024) / 512),bl2_base,0));
							
					bl2base
可以看出来 spl 的流程
	1. 上电
	2. 设置 cpsr
	3. 调用 lowlevel_init 初始化clock和uart和ddr和中断和gpio
	4. 调用_main
		4.1 整理ddr的内存布局
			.code .bss .data .rodata 在iram
			.heap .stack 在 ddr
		4.2 重新初始化uart
		4.3 清BSS (4.1为一体)
		4.4 填充gd
			为填充板子数据做准备
			为malloc做准备
			初始化timer,为delay做准备
		4.5 直接 调用 i-tcm 的函数拷贝 u-boot 到 ddr , 并跳转到 u-boot

	A. 初始化但是没有用到的东西
		uart 与 timer 与 中断 与 gpio
		.heap
		gd与已经初始化的gd成员


  • 详细解析 lowlevel_init
 mov r12, lr

 // GPKCON0
 ldr r0, =0x7f008000
 ldr r1, =0x55555555
 str r1, [r0, #0x800]
 // GPKCON1
 ldr r1, =0x55555555
 str r1, [r0, #0x804]
 // GPLCON0
 ldr r1, =0x22222666
 str r1, [r0, #0x810]


 mov r0, #0
 bl lcd_backlight_switch

 // GPMCON
 ldr r0, =0x7f008000
 ldr r1, =0x00111111
 str r1, [r0, #0x820]
 // GPMPUD
 ldr r1, =0x00000555
 str r1, [r0, #0x828]
 // GPMDAT
 ldr r1, =0x002a
 str r1, [r0, #0x824]
 // MEM1DRVCON
 ldr r1, =0
 str r1, [r0, #0x1D4]

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

 // EINTPEND
 ldr r0, =(0x7f008000 +0x924)
 ldr r1, [r0]
 str r1, [r0]

 // VIC0
 ldr r0, =(0x71200000) @0x71200000
 // VIC1
 ldr r1, =(0x71300000) @0x71300000

 // Disable all interrupts
 mvn r3, #0x0
 str r3, [r0, #(0x14)]
 str r3, [r1, #(0x14)]

 // Set all interrupts as IRQ
 mov r3, #0x0
 str r3, [r0, #(0x0C)]
 str r3, [r1, #(0x0C)]

 // Pending Interrupt Clear
 mov r3, #0x0
 str r3, [r0, #(0xF00)]
 str r3, [r1, #(0xF00)]
# 141 "../board/samsung/ok6410a/lowlevel_init.S"
 // ELFIN_CLOCK_POWER_BASE
 ldr r0, =0x7e00f000
 ldr r1, [r0, #0x1C]

 orr r1, r1, #0x2000



 str r1, [r0, #0x1C]



 mov r0, # 1

 bl spl_config_uart_baudrate




 bl uart_asm_init


 mov r0, #0x4F @'O'
 bl asm_putc
 mov r0, #0x4B @'K'
 bl asm_putc
# 184 "../board/samsung/ok6410a/lowlevel_init.S"
 mov r0, #0x2B @'+'
 bl asm_putc

 // Memory subsystem
 ldr r0, =0x7e00f120
 mov r1, #0x0D
 str r1, [r0]

 mov r0, #0x2B @'+'
 bl asm_putc
 
 // ddr
 bl mem_ctrl_asm_init

 mov r0, #0x2D @'-'
 bl asm_putc
 mov r0, #0x2D @'-'
 bl asm_putc

 // Wakeup support
 ldr r0, =(0x7e00f000 + 0x904)
 ldr r1, [r0]
 bic r1, r1, #0xfffffff7
 cmp r1, #0x8
 beq wakeup_reset

1:
 mov lr, r12
 mov pc, lr

  • 详细解析mem_ctrl_asm_init
 .globl mem_ctrl_asm_init
mem_ctrl_asm_init:

 ldr r0, =0x7e001000

 ldr r1, =0x4
 str r1, [r0, #(0x04)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 7800) - 1) / 1000000)
 str r1, [r0, #(0x10)]

 ldr r1, =(3<<1)
 str r1, [r0, #(0x14)]

 ldr r1, =1
 str r1, [r0, #(0x18)]

 ldr r1, =2
 str r1, [r0, #(0x1C)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 45) - 1) / 1000000 + 1)
 str r1, [r0, #(0x20)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 68) - 1) / 1000000 + 1)
 str r1, [r0, #(0x24)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1)
 ldr r2, =(((((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1) - 3) << 3)
 orr r1, r1, r2
 str r1, [r0, #(0x28)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 80) - 1) / 1000000 + 1)
 ldr r2, =(((((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 80) - 1) / 1000000 + 1) - 3) << 5)
 orr r1, r1, r2
 str r1, [r0, #(0x2C)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1)
 ldr r2, =(((((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 23) - 1) / 1000000 + 1) - 3) << 3)
 orr r1, r1, r2
 str r1, [r0, #(0x30)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 15) - 1) / 1000000 + 1)
 str r1, [r0, #(0x34)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 15) - 1) / 1000000 + 1)
 str r1, [r0, #(0x38)]

 ldr r1, =2
 str r1, [r0, #(0x3C)]

 ldr r1, =2
 str r1, [r0, #(0x40)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 120) - 1) / 1000000 + 1)
 str r1, [r0, #(0x44)]

 ldr r1, =(((((12000000/(3<<1)*266)/(1 +1)/(1 +1)) / 1000 * 120) - 1) / 1000000 + 1)
 str r1, [r0, #(0x48)]

 ldr r1, =0x0001001a
 str r1, [r0, #(0x0C)]

 ldr r1, =0xB45
 str r1, [r0, #(0x4C)]

 ldr r1, =0x150F0
 str r1, [r0, #(0x200)]

 ldr r1, =0x0
 str r1, [r0, #(0x304)]


 ldr r1, =0x0c0000
 str r1, [r0, #(0x08)]


 ldr r1, =0x000000
 str r1, [r0, #(0x08)]


 ldr r1, =0x040000
 str r1, [r0, #(0x08)]
 str r1, [r0, #(0x08)]


 ldr r1, =0x0a0000
 str r1, [r0, #(0x08)]


 ldr r1, =0x080032
 str r1, [r0, #(0x08)]


 mov r1, #0x0
 str r1, [r0, #(0x04)]

check_dmc1_ready:
 ldr r1, [r0, #(0x00)]
 mov r2, #0x3
 and r1, r1, r2
 cmp r1, #0x1
 bne check_dmc1_ready
 nop

 mov pc, lr
  • 详细解析之 gd_t

gd_t 	 // include/asm-generic/global_data.h
	arch // arch/arm/include/asm/global_data.h
		lastinc
		timer_reset_value
		timer_rate_hz
	struct bd_info *bd;
	unsigned long flags;
	unsigned int baudrate;
	unsigned long cpu_clk;
	unsigned long bus_clk;
	unsigned long pci_clk;
	unsigned long mem_clk;
	unsigned long fb_base;
	unsigned long malloc_limit;
	unsigned long malloc_ptr;

  • 详细解析之 timer
// 硬件部分

// base : 0x7F006000

// 相对地址
typedef struct {
    
                                                                     
 S3C64XX_REG32 TCFG0;                                                            
 S3C64XX_REG32 TCFG1;                                                            
 S3C64XX_REG32 TCON;                                                             
 S3C64XX_TIMER ch[4];                                                            
 S3C64XX_REG32 TCNTB4;                                                           
 S3C64XX_REG32 TCNTO4;                                                               
} S3C64XX_TIMERS; 
lib/time.c 中 有 __weak 声明的 
	函数(get_ticks get_timer timer_init)
arm/mach-s3c64xx/timer.c 
	实现(get_ticks get_timer timer_init 和 get_tbclk)
	提供给lib/time.c  如下函数 : get_tbclk  get_ticks  
	提供给common/spl/spl.c 如下函数 : timer_init


目的是在 spl/lib/time.c 中 提供 delay/udelay 函数

使用者
	命令中的 reset
	drivers/serial/serial.c 中的 U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); // 当前版本中 在 spl 中  无 实际作用
	用于 assert fail 和 panic
	
	

猜你喜欢

转载自blog.csdn.net/u011011827/article/details/115180741