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