第二章第六节 U-Boot-2013.04启动分析2
接下来是执行带返回跳转指令“bl lowlevel_init”。调用lowlevel_init函数(位于boardsamsungsmdk6410lowlevel_init.s)。lowlevel_init函数的工作是进行与单板相关的初始化工作,故名思议,这个初始化仅仅是最低限度(lowlevel)的,包括led灯配置(便于观察现象)、关闭看门狗、设置中断、配置系统时钟、初始化串口、初始化内存和初始化唤醒复位。 1) 配置led 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] 这里应该改成与s3c6410相适应的配置,单板使用GPM0-GPM3管脚驱动led。根据s3c6410用户手册中的端口M控制寄存器章节可以对程序作出如下修改。 /* LED on only #8 */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x00111111 str r1, [r0, #GPMCON_OFFSET] ldr r1, =0x00000555 str r1, [r0, #GPMPUD_OFFSET] /* all of LEDs are power on */ ldr r1, =0x000f str r1, [r0, #GPMDAT_OFFSET] 根据需要,LED测试自行修改: /* LED test */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x0003 str r1, [r0, #GPMDAT_OFFSET] 2) 关闭看门狗 ldr r0, =0x7e000000 @0x7e004000 orr r0, r0, #0x4000 mov r1, #0 str r1, [r0] 大多数微处理器都带有看门狗,当看门狗没有被定时清零(喂狗)时,将引起复位,这可防止程序跑飞,也可以防止程序运行时候出现死循环。设计者必须清楚看门狗的溢出时间以决定在合适的时候清除看门狗。在内核中通常用于防止出现死循环,U-Boot直接关闭看门狗。 3) 设置中断 /* 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] 4) 配置系统时钟 S3C6410有三个PLL(锁相环),分别为APLL、MPLL和EPLL。其中APLL产生ACLK,给CPU使用,MPLL产生HCLKX2、HCLK和PCLK,HCLKX2主要提供时钟给DDR使用,最大可以到266MHz。HCLK用作AXIAHB总线时钟,APB用作APB总线时钟。接AXI和AHB总线的外设最大时钟为133MHz,接APB总线的外设最大时钟为66MHz。UART的时钟可以由MPLL或者EPLL提供。 系统时钟初始化起始于: system_clock_init: ldr r0, =ELFIN_CLOCK_POWER_BASE /* 0x7e00f000 */ S3C6400的时钟系统与S3C6410有所差异,其中将 /* FOUT of EPLL is 96MHz */ ldr r1, =0x200203 修改成: ldr r1, =0x80200203 5) 串口初始化 uart_asm_init: /* set GPIO to enable UART */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x220022 str r1, [r0, #GPACON_OFFSET] mov pc, lr 6) NAND Flash控制器初始化 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, #0x07 str r1, [r0, #NFCONT_OFFSET] mov pc, lr 简单地对NAND Flash主机控制器的时间参数初始化。 7) 内存初始化 调用mem_ctrl_asm_init函数,跳入到arch/arm/cpu/arm1176/s3c64xx/ mem_ctrl_asm_init.s中。系统上电,在利用内存控制器访问外部内存之前,需要进行一系列初始化工作,如图2. 3。主要做两件事情:配置内存控制器和初始化外部内存设备。配置内存控制器包括时间参数、位宽、片选和ID配置等。初始化外部内存设备,通过操作P1DIRECTCMD寄存器,发出初始化系列:“nop”命令,Prechargeall命令,Autorefresh命令,Autorefresh命令,EMRS命令,MRS命令。 S3C6410的DRAM控制器是基于 ARM PrimeCell CP003 AXI DMC(PL340),S3C6410的存储器端口0并不支持DRAM,所以只能选用存储器端口1(DMC1)。S3C6410的DMC1基址ELFIN_DMC1_BASE的值为0x7e00_1000。当DMC1使用32位数据线DRAM时,需要配置MEM_SYS_CFG寄存器,将芯片管脚Xm1DATA[31:16]设置为DMC1的数据域。单板利用两块64M×16的DDR SDRAM芯片K4X1G163PC组合成一块大小为64M×32的芯片,此时,MEM_SYS_CFG[7]必须清零。 DDR时间参数根据K4X1G163PC手册得到,并定义在s3c6410.h头文件中,利用宏NS_TO_CLK(t)将时间参数转化成时钟周期,再写入相应的寄存器中。一块K4X1G163PC行地址为A0 - A13,列地址为A0 - A9,BANK地址为B0-B1。寻址范围为128Mb。特别注意的是,片选寄存器DMC1_CHIP0_CFG的值:P1_chip_0_cfg[16] = 1,选择Bank-Row-Column组织结构。地址匹配值为0x50,地址屏蔽位0xF0,屏蔽了总线的高八位。因此寻址范围0x5xxxx_xxxx(0x5000_0000~0x5ff_ffff 即256 MiB)。 8) 唤醒复位初始化 /* Wakeup support. Don't know if it's going to be used, untested. */ ldr r0, =(ELFIN_CLOCK_POWER_BASE + RST_STAT_OFFSET) ldr r1, [r0] bic r1, r1, #0xfffffff7 cmp r1, #0x8 beq wakeup_reset
|