AM335x SPL 代码分析
AM335x SPL
一,
AM335x引导加载程序:
第一阶段:RBL(ROM)
第2阶段:SPL(内部RAM:0x402f0400)
第三阶段:U-Boot(一般外部DDR)
SPL是bootloader的第二部分,由RBL引导运行,主要目的就是引导U-Boot运行。
SPL也叫MLO,一般存放在SD或者Nand中。其中,在Nand中要求存在在从一个块开始的4个块中,因为RBL会从第一个块开始查找SPL,如果第一个失败后,从从第二个块开始继续查找,直到第四个块查找完毕,因此,SPL必须放在从第一个块开始的4个块中,SPL在Nand中的偏移地址分别为0x0 ,0x20000,0x40000和0x60000.U-Boot从第五个块开始存放,即0x80000。假设Nand的块大小为128K,则分布图如下:
- + - - - - - - - - - - - - + - - > 00000000 - > SPL启动 ( SPL副本 上 1块)
- | |
- | | - - > 0x0001FFFF - > SPL 结束
- | | - - > 0x00020000 - > SPL 。backup1开始 ( 第2块上的 SPL复制 )
- | |
- | | - - > 0x0003FFFF - > SPL 。backup1 结束
- | | - - > 0x00040000 - > SPL 。backup2开始 ( 第3个块上的 SPL复制 )
- | |
- | | - - > 0x0005FFFF - > SPL 。backup2 结束
- | | - - > 0x00060000 - > SPL 。backup3 start ( 第4块上的 SPL复制 )
- | |
- | | - - > 0x0007FFFF - > SPL 。backup3 end
- | | - - > 0x00080000 - > U -引导启动
- | |
- | | - - > 0x002BFFFF - > U -引导 结束
- | | - - > 0x00260000 - > ENV start
- | |
- | |
- | | - - > 0x0027FFFF - > ENV 结束
- | | - - > 0x00280000 - > Linux内核启动
- | |
- | |
- | |
- | |
- | | - - > 0x0077FFFF - > Linux内核 结束
- | | - - > 0x00780000 - > 文件系统启动
- | |
- | |
- | |
- | |
- | |
- | |
- | |
- | |
- | |
- | |
- | |
- | |
- + - - - - - - - - - - - - + - - > 0x10000000处- > 的NAND 端 (自由 端)
二,
SPL代码分析:
分析SPL代码,首先要看一下SPL目录下的Makefile文件,在Makefile中:
CONFIG_SPL_BUILD:= y
export CONFIG_SPL_BUILD
这个宏定义用于打开U-boot代码里有关SPL部分的分支。
另外,Makefile还交代了SPL涉及到的相关代码文件:
主要有u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7
u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ lib
u-boot-2011.09-psp04.06.00.08 \ drivers
等。
除了通过Makefile分析SPL涉及到的相关代码文件外,还可以简单的通过在编译SPL时,在make后加上O = am335x来将所有的.o文件归类在一起,在am335x / spl目录下:
通过上面的图,可以很清楚的了解SPL在编译时涉及到U-Boot中的代码文件
#linker 脚本 ifdef CONFIG_SPL_LDSCRIPT
#需要去掉双引号
LDSCRIPT:= $(addprefix $(SRCTREE)/,$(subst“,, $(CONFIG_SPL_LDSCRIPT)))
endif
该处指定了SPL的链接脚本文件
CONFIG_SPL_LDSCRIPT在u-boot-2011.09-psp04.06.00.08 \ include \ configs \ Am335x_evm.h中定义:
#define CONFIG_SPL_LDSCRIPT“$(CPUDIR)/omap-common/u-boot-spl.lds”
所以SPL的链接脚本是u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ omap-common \ u-boot-spl.lds
在u-boot-spl.lds中,空间分配如下:
内存{.sram:ORIGIN = CONFIG_SPL_TEXT_BASE,\
LENGTH = CONFIG_SPL_MAX_SIZE}
内存{.sdram:ORIGIN = CONFIG_SPL_BSS_START_ADDR,\
LENGTH = CONFIG_SPL_BSS_MAX_SIZE}
其中,CONFIG_SPL_TEXT_BASE,CONFIG_SPL_MAX_SIZE,CONFIG_SPL_BSS_START_ADDR,CONFIG_SPL_BSS_MAX_SIZE都在Am335x_evm.h定义:
#define CONFIG_SPL_TEXT_BASE 0x402F0400
#define CONFIG_SPL_MAX_SIZE(101 * 1024)
#define CONFIG_SPL_BSS_START_ADDR 0x80000000
#define CONFIG_SPL_BSS_MAX_SIZE 0x80000 / * 512 KB * /
因此,实际的空间分配如下:
MEMORY {.sram:ORIGIN = 0x402F0400,LENGTH =(101 * 1024)}
MEMORY {.sdram:ORigIN = 0x80000000,LENGTH = 0x80000}
SRAM From 0x402F0400开始用于存放.TEXT段,.rodata段,.data段内容
SDRAM从0x80000000开始用于存放.bss段内容
三,
由Makefile可知,SPL的入口在u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ start.S中
SPL的功能无非是设置MPU的时钟,PLL,电源,DDR,Uart,Pin Mux,完成对U-Boot的引导的工作,所以SPL板端口主要针对以上几点。
在start.S中:
cpu_init_crit
board_init_f
board_init_r
cpu_init_crit
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
其中,CONFIG_SKIP_LOWLEVEL_INIT在am335x_evm.h中定义:
/ *由于SPL为我们做了所有这些,我们不需要做两次。* /
#ifndef CONFIG_SPL_BUILD
#define CONFIG_SKIP_LOWLEVEL_INIT
#endif
由此可知,cpu_init_crit只在SPL中才进行编译,U-Boot中不编译,避免了同样的内容重复设置,比如DDR等。
cpu_init_crit
----> lowlevel_init(u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ omap-common \ lowlevel_init.S)
----> s_init(u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c)
---->关看门狗
----> pll_init(); // PLL和时钟设置
----> rtc32k_enable(); //使能RTC
---->串口设置
----> init_timer();
----> preloader_console_init();
----> I2C0初始化,读EEPROM
----> DDR设置(DDR2 \ DDR3)
pll_init(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c)
----> mpu_pll_config(MPUPLL_M_500); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c)
// 设置MPU的频率为500MHz,可以修改
----> core_pll_config(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c)
//设置CORE频率为1GHz
----> per_pll_config(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c)
//设置外设频率为960MHz
----> interface_clocks_enable(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c)
//使能内部连接模块的时钟
----> power_domain_transition_enable(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c)
//使能模块电源
----> per_clocks_enable(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c)
//使能外设模块的时钟
在u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ include \ asm \ arch-ti81xx \ Clocks_am335x.h中,定义了所有时钟频率:
/ *把pll配置值放在这里* /
#define OSC 24 / *外部晶振为24MHz * /
/ * MAIN PLL Fdll = 1GHZ,* /
#define MPUPLL_M_500 500 / * 125 * n * /
#define MPUPLL_M_550 550 / * 125 * n * /
#define MPUPLL_M_600 600 / * 125 * n * /
#define MPUPLL_M_720 720 / 125 * n * /
#define MPUPLL_N 23 / *(n-1)* /
#define MPUPLL_M2 1
/ *核心PLL Fdll = 1GHZ,* /
#define COREPLL_M 1000 / * 125 * n * /
#define COREPLL_N 23 / *(n-1)* /
#define COREPLL_M4 10 / * CORE_CLKOUTM4 = 200MHZ * /
#define COREPLL_M5 8 / * CORE_CLKOUTM5 = 250MHZ * /
#define COREPLL_M6 4 / * CORE_CLKOUTM6 = 500MHZ *
/ *
* USB PHY时钟为960 MHZ。因为,这直接来自Fdll,Fdll
*频率需要设置为960MHz。因此,
*对于clkout = 192MHz,Fdll = 960MHz,分频器值在下面给出
* /
#define PERPLL_M 960
#define PERPLL_N 23
#define PERPLL_M2 5
/ * DDR Freq is 266 MHZ for now * /
/ * Set Fdll = 400 MHZ,Fdll = M * 2 * CLKINP / N + 1; clkout = Fdll /(2 * M2)* /
#define DDRPLL_M 266
#define DDRPLL_N 23
#define DDRPLL_M2 1
MPU PLL结构:
配置MPU PLL:
代码如下:
void mpu_pll_config(int mpupll_M)
{
u32 clkmode,clksel,div_m2;
clkmode = readl(CM_CLKMODE_DPLL_MPU);
clksel = readl(CM_CLKSEL_DPLL_MPU);
div_m2 = readl(CM_DIV_M2_DPLL_MPU);
/ *将PLL设置为旁路模式* /
writel(PLL_BYPASS_MODE,CM_CLKMODE_DPLL_MPU);
while(readl(CM_IDLEST_DPLL_MPU)!= 0x00000100);
clksel = clksel&(〜0x7ffff);
clksel = clksel | ((mpupll_M << 0x8)| MPUPLL_N);
writel(clksel,CM_CLKSEL_DPLL_MPU);
div_m2 = div_m2&〜0x1f;
div_m2 = div_m2 | MPUPLL_M2;
writel(div_m2,CM_DIV_M2_DPLL_MPU);
clkmode = clkmode | 0x7;
writel(clkmode,CM_CLKMODE_DPLL_MPU);
while(readl(CM_IDLEST_DPLL_MPU)!= 0x1);
}}
核心PLL 结构:
配置核心PLL:
代码如下:
static void core_pll_config(void)
{
u32 clkmode,clksel,div_m4,div_m5,div_m6;
clkmode = readl(CM_CLKMODE_DPLL_CORE);
clksel = readl(CM_CLKSEL_DPLL_CORE);
div_m4 = readl(CM_DIV_M4_DPLL_CORE);
div_m5 = readl(CM_DIV_M5_DPLL_CORE);
div_m6 = readl(CM_DIV_M6_DPLL_CORE);
/ *将PLL设置为旁路模式* /
writel(PLL_BYPASS_MODE,CM_CLKMODE_DPLL_CORE);
while(readl(CM_IDLEST_DPLL_CORE)!= 0x00000100);
clksel = clksel&(〜0x7ffff);
clksel = clksel | ((COREPLL_M << 0x8)| COREPLL_N);
writel(clksel,CM_CLKSEL_DPLL_CORE);
div_m4 = div_m4&〜0x1f;
div_m4 = div_m4 | COREPLL_M4;
writel(div_m4,CM_DIV_M4_DPLL_CORE);
div_m5 = div_m5&〜0x1f;
div_m5 = div_m5 | COREPLL_M5;
writel(div_m5,CM_DIV_M5_DPLL_CORE);
div_m6 = div_m6&〜0x1f;
div_m6 = div_m6 | COREPLL_M6;
writel(div_m6,CM_DIV_M6_DPLL_CORE);
clkmode = clkmode | 0x7;
writel(clkmode,CM_CLKMODE_DPLL_CORE);
while(readl(CM_IDLEST_DPLL_CORE)!= 0x1);
}}
外设PLL 结构
配置外设PLL:
代码如下:
static void per_pll_config(void)
{
u32 clkmode,clksel,div_m2;
clkmode = readl(CM_CLKMODE_DPLL_PER);
clksel = readl(CM_CLKSEL_DPLL_PER);
div_m2 = readl(CM_DIV_M2_DPLL_PER);
/ *将PLL设置为旁路模式* /
writel(PLL_BYPASS_MODE,CM_CLKMODE_DPLL_PER);
while(readl(CM_IDLEST_DPLL_PER)!= 0x00000100);
clksel = clksel&(〜0x7ffff);
clksel = clksel | ((PERPLL_M << 0x8)| PERPLL_N);
writel(clksel,CM_CLKSEL_DPLL_PER);
div_m2 = div_m2&〜0x7f;
div_m2 = div_m2 | PERPLL_M2;
writel(div_m2,CM_DIV_M2_DPLL_PER);
clkmode = clkmode | 0x7;
writel(clkmode,CM_CLKMODE_DPLL_PER);
while(readl(CM_IDLEST_DPLL_PER)!= 0x1);
}}
串口设置(u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c)
设置所用使用串口的基地址,复位串口,关闭智能闲置。
u32 uart_base = DEFAULT_UART_BASE; //默认使用的串口是UART0,基地址为0x44E0_9000
enable_uart0_pin_mux(); //配置uart0相关引脚为UART模式
同样可以设置为其他串口,比如IA电机控制板就是使用的UART3,只要修改上面两步就可以了
init_timer(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c)
这里初始化的是timer2,在之前pll_init(); ----> per_clocks_enable(); 中使能的也是timer2,使用24MHz的OSC
preloader_console_init(); (u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ omap-common \ Spl.c)
主要是对串口波特率的设置,以及串口终端打印信息.BeagleBone板上使用的是USB转串口芯片,串口驱动驱动程序\ serial \ serial.c ,drivers \ serial \ns16550.c
I2C0初始化,读EEPROM(u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c)
i2c0接一个eeprom(CAT24C256W 256K * 8),i2c读取eeprom的数据到头结构体,头结构体原型为
struct am335x_baseboard_id {
unsigned int magic;
char name [8];
char版本[4];
char serial [12];
char config [32];
char mac_addr [NO_OF_MAC_ADDR] [ETH_ALEN];
};
BeagleBone开发板提供的eeprom信息如下:
enable_i2c0_pin_mux(); //配置i2c0相关引脚为I2C模式
i2c_init(CONFIG_SYS_I2C_SPEED,CONFIG_SYS_I2C_SLAVE); // i2c初始化,速度为标准速度100000,从设备
if(read_eeprom()){
printf(“read_eeprom()failure。continuing with ddr3 \ n”);
} // read eeprom to header Structural body,会判断magic is否为上表中提供的0xEE3355AA
DDR设置(DDR2 \ DDR3)(u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c)
u32 is_ddr3 = 0;
if(!strncmp(“A335X_SK”,header.name,8)){
is_ddr3 = 1;
/ *
* EVM SK 1.2A和更高版本使用gpio0_7启用DDR3。
*这是足够安全,以老的转速。
* /
enable_gpio0_7_pin_mux();
gpio_request(GPIO_DDR_VTT_EN,“ddr_vtt_en”);
gpio_direction_output(GPIO_DDR_VTT_EN,1);
//通过gpio0_7输出高电平来触发VTT稳压器,从而产生VTT_DDR电压
}
if(is_ddr3 == 1){
ddr_pll_config(303);
config_am335x_ddr3();
}
else {
ddr_pll_config(266);
config_am335x_ddr2();
}}
在设置DDR之前,要先判断是DDR2(变量is_ddr3 = 0)还是DDR3(变量is_ddr3 = 1),TI推出的开发板目前只有A335X_StarterKit支持DDR3,其余的是DDR2,包括BeagleBone
一开始默认为DDR2(设置is_ddr3 = 0),但是通过比对header.name是否为A335X_SK,来确定DDR3(设置is_ddr3 = 1)
根据不同的DDR来进行相应的DDR配置,主要有4个部分需要设置,如下:
DDR PLL 结构:
配置DDR PLL:
代码如下:
ddr_pll_config(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ P11.c);
//配置ddr的时钟频率,DDR2为266MHz,DDR3为303MHz
void ddr_pll_config(unsigned int ddrpll_M)
{
u32 clkmode,clksel,div_m2;
clkmode = readl(CM_CLKMODE_DPLL_DDR);
clksel = readl(CM_CLKSEL_DPLL_DDR);
div_m2 = readl(CM_DIV_M2_DPLL_DDR);
/ *将PLL设置为绕过模式* /
clkmode =(clkmode&0xfffffff8)| 0x00000004;
writel(clkmode,CM_CLKMODE_DPLL_DDR);
while((readl(CM_IDLEST_DPLL_DDR)&0x00000100)!= 0x00000100);
clksel = clksel&(〜0x7ffff);
clksel = clksel ((ddrpll_M << 0x8)| DDRPLL_N);
writel(clksel,CM_CLKSEL_DPLL_DDR);
div_m2 = div_m2&0xFFFFFFE0;
div_m2 = div_m2 | DDRPLL_M2;
writel(div_m2,CM_DIV_M2_DPLL_DDR);
clkmode =(clkmode&0xfffffff8)| 0x7;
writel(clkmode,CM_CLKMODE_DPLL_DDR);
while((readl(CM_IDLEST_DPLL_DDR)&0x00000001)!= 0x1);
}}
config_am335x_ddr2();
四,
分类: 嵌入式
board_init_f
【入口函数】start.s (u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ start.S )
/ *设置内部RAM中的堆栈指针以调用board_init_f * /
call_board_init_f:ldr
sp,=(CONFIG_SYS_INIT_SP_ADDR)
bic sp,sp,#7 / * ABI兼容性的8字节对齐* / ldr
r0,= 0x00000000
bl board_init_f
设置栈指针,跳转到board_init_f
内部RAM 分配如下:
1KB 0x402F0000 à (保护) 0x402F03FF à |
0x402F0400 à SPL (109KB ) 0x4030B7FF à |
SP 0x4030B800 à (10KB ) 0x4030DFFF à |
RBL 0x4030E000 à (8KB ) 0x4030FFFF à |
board_init_f ( u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ omap-common \ Spl.c )
void board_init_f(ulong dummy)
{
/ *
*我们调用relocate_code()与重定位目标相同
* CONFIG_SYS_SPL_TEXT_BASE。这将导致重定位获取
*跳过。相反,只有.bss初始化会发生。那是
* 我们所需要的
* /
debug(“>> board_init_f()\ n”);
relocate_code(CONFIG_SPL_STACK,&gdata,CONFIG_SPL_TEXT_BASE);
}}
代码重定位 relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
其中 3 个变量分别对应 r0,r1,r2 :
r0:CONFIG_SPL_STACK = 0x4030B7FC
r1: &gdata
r2: CONFIG_SPL_TEXT_BASE = 0x402F0400
relocate_code ( u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ start.S )
/ * ------------------------------------------------ ------------------------------ * /
/ *
* void relocate_code(addr_sp,gd,addr_moni)
*:
*这个“函数”不返回,而是继续在RAM中
*重新定位监视器代码后。
*:
* /
.globl relocate_code
relocate_code:
mov r4, r0 / * save addr_sp * /
mov r5, r1 / * save addr of gd * /
mov r6, r2 / *保存目的地址addr *
/ *设置堆栈* /
stack_setup:
mov sp,r4
adr r0,_start
cmp r0,r6
moveq r9,#0 / *没有重定位。重定位偏移(r9)= 0 * /
beq clear_bss / * skip重定位* /
mov r1,r6 / * r1 < - scratch for copy_loop * /
ldr r3,_image_copy_end_ofs
add r2,r0,r3 / * r2 < - 源端地址* /
copy_loop:
ldmia r0 !, {r9-r10} / *从源地址[r0]复制* /
stmia r1 !, {r9-r10} / *复制到目标地址[r1] * /
cmp r0,r2 / *直到源端地址[r2] * /
blo copy_loop
#ifndef CONFIG_SPL_BUILD
/ *
*修复.rel.dyn重定位
* /
ldr r0,_TEXT_BASE / * r0 < - 文本基础* /
sub r9,r6,r0 / * r9 <重定位偏移* /
ldr r10,_dynsym_start_ofs / * r10 < - sym表ofs * /
在FLASH中添加r10,r10,r0 / * r10 < - sym表*
ldr r2,_rel_dyn_start_ofs / * r2 < - rel dyns ofs * /
在FLASH中添加r2,r2,r0 / * r2 < - rel dyn start *
ldr r3,_rel_dyn_end_ofs / * r3 < - rel dyn of ofs * /
在FLASH中添加r3,r3,r0 / * r3 < - rel dyn end *
fixloop:
ldr r0,[r2] / * r0 < - 要固定的位置,IN FLASH!* /
添加r0,r0,r9 / * r0 < - 位置以固定在RAM * /
ldr r1,[r2,#4]
和r7,r1,#0xff
cmp r7,#23 / *相对修正?* /
beq fixrel
cmp r7,#2 / *绝对修正?* /
beq fixabs
/ *忽略未知类型的fixup * /
b fixnext
fixabs:
/ *绝对修正:将位置设置为(偏移)符号值* /
mov r1,r1,LSR#4 / * r1 < - .dynsym *中的符号索引*
添加r1,r10,r1 / * r1 < - 表中符号的地址* /
ldr r1,[r1,#4] / * r1 < - 符号值* /
添加r1,r1,r9 / * r1 <重定位的sym addr * /
b fixnext
fixrel:
/ *相对修复:按偏移量增加位置* /
ldr r1,[r0]
添加r1,r1,r9
fixnext:
str r1,[r0]
添加r2,r2,#8 / *每个rel.dyn条目是8字节* /
cmp r2,r3
blo fixloop
b clear_bss
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
_dynsym_start_ofs:
.word __dynsym_start - _start
#endif / * #ifndef CONFIG_SPL_BUILD * /
board_init_r
【入口函数】start.s (u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ start.S )
/ *
* 我们完了。不要返回,而是分支到板的第二部分
*初始化,现在从RAM运行。
* /
jump_2_ram:
/ *
*如果启用了I-cache,则使其无效
* /
#ifndef CONFIG_SYS_ICACHE_OFF
mcr p15,0,r0,c7,c5,0 @无效icache
mcr p15,0,r0,c7,c10,4 @ DSB
mcr p15,0,r0,c7,c5,4 ISB
#万一
ldr r0,_board_init_r_ofs
adr r1,_start
添加lr,r0,r1
添加lr,lr,r9
/ * board_init_r的设置参数* /
mov r0,r5 / * gd_t * /
mov r1,r6 / * dest_addr * /
/ *跳转到它... * /
mov pc,lr
_board_init_r_ofs:
.word board_init_r - _start
跳转到内部 RAM 执行board_init_r
board_init_r (u-boot-2011.09-psp04.06.00.08 \ arch \ arm \ cpu \ armv7 \ omap-common \ Spl.c )
void board_init_r(gd_t * id,ulong dummy)
{
u32 boot_device;
debug(“>> spl:board_init_r()\ n”);
mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
CONFIG_SYS_SPL_MALLOC_SIZE);
timer_init();
i2c_init(CONFIG_SYS_I2C_SPEED,CONFIG_SYS_I2C_SLAVE);
#ifdef CONFIG_SPL_BOARD_INIT // 宏在Am335x_evm.h 中打开
spl_board_init();
#万一
boot_device = omap_boot_device();
debug(“boot device - %d \ n”,boot_device);
switch(boot_device) {
#ifdef CONFIG_SPL_MMC_SUPPORT
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
spl_mmc_load_image();
打破;
#万一
#ifdef CONFIG_SPL_NAND_SUPPORT
case BOOT_DEVICE_NAND:
spl_nand_load_image();
打破;
#万一
#ifdef CONFIG_SPL_YMODEM_SUPPORT
case BOOT_DEVICE_UART:
spl_ymodem_load_image();
打破;
#万一
#ifdef CONFIG_SPL_SPI_SUPPORT
case BOOT_DEVICE_SPI:
spi_boot();
打破;
#万一
#ifdef CONFIG_SPL_ETH_SUPPORT
case BOOT_DEVICE_CPGMAC:
spl_eth_load_image();
打破;
#万一
默认:
printf(“SPL:Un-supported Boot Device - %d !!! \ n”,boot_device);
挂();
打破;
}}
switch(spl_image.os){
case IH_OS_U_BOOT:
debug(“跳转到U-Boot \ n”);
jump_to_image_no_args();
打破;
默认:
puts(“Unsupported OS image .. Jumping yet Yet .. \ n”);
jump_to_image_no_args();
}}
}}
board_init_r 流程
à mem_malloc_init //初始化内存,设为0 ,0x80208000 开始,大小1MB
à timer_init(); //接通本节能器初始化,使用定时器2 ,外部时钟源的24MHz
à i2c_init // I2C 初始化,速度为标准速度100000 ,从设备
à spl_board_init(); // spl 板级初始化
à boot_device配置= omap_boot_device(); //获取启动模式
à 开关(boot_device配置)
à spl_mmc_load_image(); ? // mmc 载入镜像
à spl_nand_load_image(); // nand 载入镜像
à spl_ymodem_load_image(); // ymode 载入镜像
à spi_boot(); // spi 载入镜像
à spl_eth_load_image(); //以太网载入镜像
àhang (); //挂起
à jump_to_image_no_args(); //跳转到uboot 的入口地址entry_point 执行
spl_board_init(); (u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c )
void spl_board_init(void)
{
uchar pmic_status_reg;
/ * init board_id,configure muxes * /
board_init(); ( u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c)
if(!strncmp(“A335BONE”,header.name,8)){
/ * BeagleBone PMIC代码* /
if(i2c_probe(TPS65217_CHIP_PM))
返回;
if(tps65217_reg_read(STATUS,&pmic_status_reg))
返回;
/ *将USB电流限制增加到1300mA * /
if(tps65217_reg_write(PROT_LEVEL_NONE,POWER_PATH,
USB_INPUT_CUR_LIMIT_1300MA,
USB_INPUT_CUR_LIMIT_MASK))
printf(“tps65217_reg_write failure \ n”);
/ *只有在板rev> A1 * /
if(!strncmp(header.version,“00A1”,4))
返回;
/ *将DCDC2(MPU)电压设置为1.275V * /
if(tps65217_voltage_update(DEFDCDC2,
DCDC_VOLT_SEL_1275MV)){
printf(“tps65217_voltage_update failure \ n”);
返回;
}}
/ *设置LDO3,LDO4输出电压为3.3V * /
if(tps65217_reg_write(PROT_LEVEL_2,DEFLS1,
LDO_VOLTAGE_OUT_3_3,LDO_MASK))
printf(“tps65217_reg_write failure \ n”);
if(tps65217_reg_write(PROT_LEVEL_2,DEFLS2,
LDO_VOLTAGE_OUT_3_3,LDO_MASK))
printf(“tps65217_reg_write failure \ n”);
if(!(pmic_status_reg&PWR_SRC_AC_BITMASK)){
printf(“无交流电源,禁用频率开关\ n”);
返回;
}}
/ *将MPU频率设置为720MHz * /
mpu_pll_config(MPUPLL_M_720);
} else {
uchar buf [4];
/ *
* EVM PMIC代码。所有的板目前想要一个MPU电压
*为1.2625V,CORE电压为1.1375V
* 720MHz。
* /
if(i2c_probe(PMIC_CTRL_I2C_ADDR))
返回;
/ * VDD1 / 2控制电压选择寄存器访问i / f * /
if(i2c_read(PMIC_CTRL_I2C_ADDR,PMIC_DEVCTRL_REG,1,buf,1))
返回;
buf [0] | = PMIC_DEVCTRL_REG_SR_CTL_I2C_SEL_CTL_I2C;
if(i2c_write(PMIC_CTRL_I2C_ADDR,PMIC_DEVCTRL_REG,1,buf,1))
返回;
if(!voltage_update(MPU,PMIC_OP_REG_SEL_1_2_6)&&
!voltage_update(CORE,PMIC_OP_REG_SEL_1_1_3))
/ * OPP 120的频率切换* /
mpu_pll_config(MPUPLL_M_720);
}}
}}
#万一
spl_board_init();
à board_init(); // 板级初始化
à PMIC //电源管理
à AM335x BeagleBone TPS65217
à mpu_pll_config(MPUPLL_M_720); //设MPU 频率为720MHz
à 其他板卡 (TPS65910 )
à mpu_pll_config(MPUPLL_M_720);
board_init(); ( u-boot-2011.09-psp04.06.00.08 \ board \ ti \ am335x \ Evm.c)
int board_init(void)
{
/ *配置i2c0引脚mux * /
enable_i2c0_pin_mux();
i2c_init(CONFIG_SYS_I2C_SPEED,CONFIG_SYS_I2C_SLAVE);
if(read_eeprom())
goto err_out;
detect_daughter_board();
if(!strncmp(“SKU#01”,header.config,6)){
board_id = GP_BOARD;
detect_daughter_board_profile();
} else if(!strncmp(“SKU#02”,header.config,6)){
board_id = IA_BOARD;
detect_daughter_board_profile();
} else if(!strncmp(“SKU#03”,header.config,6)){
board_id = IPP_BOARD;
} else if(!strncmp(“A335BONE”,header.name,8)){
board_id = BONE_BOARD;
profile = 1; / * profile 0在内部被认为是1 * /
daughter_board_connected = 0;
} else if(!strncmp(“A335X_SK”,header.name,8)){
board_id = SK_BOARD;
profile = 1; / * profile 0在内部被认为是1 * /
daughter_board_connected = 0;
} else {
printf(“没有找到识别的配置,”
“假设在概况0中的通用EVM具有”
“女儿板\ n”);
board_id = GP_BOARD;
profile = 1; / * profile 0在内部被认为是1 * /
daughter_board_connected = 1;
}}
configure_evm_pin_mux(board_id,header.version,profile,daughter_board_connected);
#ifndef CONFIG_SPL_BUILD
board_evm_init();
#万一
gpmc_init();
return 0;
err_out:
/ *
*当我们不能使用EEPROM来确定什么板子我们
*我们假设BeagleBone目前为止,因为我们还没有
*编程EEPROM。
* /
board_id = BONE_BOARD;
profile = 1; / * profile 0在内部被认为是1 * /
daughter_board_connected = 1;
configure_evm_pin_mux(board_id,header.version,profile,daughter_board_connected);
#ifndef CONFIG_SPL_BUILD
board_evm_init();
#万一
gpmc_init();
return 0;
}}
board_init();
à 设置,初始化 I2C ,读 EEPROM
à 有EEPROM
à 根据读到的信息, 判断板卡型号 GP_BOARD , IA_BOARD , IPP_BOARD (板卡有两部分组成)
BONE_BOARD , SK_BOARD (板卡单独一个整体)
à 根据不同型号,配置相应的引脚
configure_evm_pin_mux(board_id,header.version,profile,daughter_board_connected);
à gpmc_init(); // GPMC 初始化,默认为 8bit nand ,起始地址和大小在 Am335x_evm.h 定义
à 无EEPROM
à 假设为有两部分组成的 BONE_BOARD ,并进行引脚配置
configure_evm_pin_mux(board_id,header.version,profile,daughter_board_connected);
à gpmc_init();
co nfigure_evm_pin_mux(board_id,header.version,profile,daughter_board_connected); //引脚配置
代码给出的引脚配置有以下几种,分别对应不同的评估板:
beaglebone_pin_mux,
general_purpose_evm_pin_mux,
ia_motor_control_evm_pin_mux,
ip_phone_evm_pin_mux,
low_cost_evm_pin_mux,
sk_evm_pin_mux,
以beaglebone ,starterkit为例:
static struct evm_pin_mux beaglebone_pin_mux [] = {
{ uart0_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
{ i2c1_pin_mux,PROFILE_ALL&〜PROFILE_2&〜PROFILE_4,DEV_ON_BASEBOARD},
#ifdef CONFIG_NAND
{ nand_pin_mux,PROFILE_ALL&〜PROFILE_2&〜PROFILE_3,DEV_ON_DGHTR_BRD},
#万一
#ifndef CONFIG_NO_ETH
{ mii1_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
#万一
#ifdef CONFIG_MMC
{ mmc0_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
{mmc1_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
#万一
#ifdef CONFIG_SPI
{ spi0_pin_mux,PROFILE_2,DEV_ON_DGHTR_BRD},
#万一
{0},
};
Startkit 没有nand ,只有mmc ,有两个千兆网
static struct evm_pin_mux sk_evm_pin_mux [] = {
{ uart0_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
#ifdef CONFIG_MMC
{ mmc0_sk_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
#万一
#ifndef CONFIG_NO_ETH
{ rgmii1_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
{ rgmii2_pin_mux,PROFILE_ALL,DEV_ON_BASEBOARD},
#万一
{0},
};
HTTP://blog.chinaunix .NET /uid-12077574-id-3527521.html
jump_to_image_no_args();
跳转到 uboot 的入口地址entry_point执行,这个entry_point哪里来?是有 u-boot.img 头部信息提供。
至此,整个 AM335x SPL 代码全部分析完毕,主要还是这 3 个函数:
? cpu_init_crit // cpu 级初始化
? board_init_f // 代码重定位
? board_init_r // 板级初始化,并执行最终 u-boot