天天看點

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,則分布圖如下:

  1. + - - - - - - - - - - - - + - - > 00000000 - >  SPL啟動  ( SPL副本  上  1塊)
  2. |             |
  3. |             | - - > 0x0001FFFF - >  SPL  結束 
  4. |             | - - > 0x00020000 - >  SPL 。backup1開始  (  第2塊上的 SPL複制  )
  5. |             |
  6. |             | - - > 0x0003FFFF - >  SPL 。backup1  結束 
  7. |             | - - > 0x00040000 - >  SPL 。backup2開始  (  第3個塊上的 SPL複制  )
  8. |             |
  9. |             | - - > 0x0005FFFF - >  SPL 。backup2  結束 
  10. |             | - - > 0x00060000 - >  SPL 。backup3 start  (  第4塊上的 SPL複制  )
  11. |             |
  12. |             | - - > 0x0007FFFF - >  SPL 。backup3  end
  13. |             | - - > 0x00080000 - >  U -引導啟動
  14. |             | 
  15. |             | - - > 0x002BFFFF - >  U -引導  結束 
  16. |             | - - > 0x00260000 - >  ENV start
  17. |             |
  18. |             |
  19. |             | - - > 0x0027FFFF - >  ENV  結束
  20. |             | - - > 0x00280000 - >  Linux核心啟動
  21. |             |
  22. |             |
  23. |             |
  24. |             |
  25. |             | - - > 0x0077FFFF - >  Linux核心  結束
  26. |             | - - > 0x00780000 - >  檔案系統啟動
  27. |             |
  28. |             |
  29. |             |
  30. |             |
  31. |             |
  32. |             |
  33. |             |
  34. |             |
  35. |             |
  36. |             |
  37. |             |
  38. |             |
  39. + - - - - - - - - - - - - + - - > 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目錄下:

AM335x SPL 代碼分析
AM335x SPL 代碼分析
AM335x SPL 代碼分析
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結構:

AM335x SPL 代碼分析

配置MPU PLL:

AM335x SPL 代碼分析

代碼如下:

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  結構:

AM335x SPL 代碼分析

配置核心PLL:

AM335x SPL 代碼分析

代碼如下:

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  結構

AM335x SPL 代碼分析

配置外設PLL:

AM335x SPL 代碼分析

代碼如下:

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資訊如下:

AM335x SPL 代碼分析

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個部分需要設定,如下:

AM335x SPL 代碼分析

DDR PLL  結構:

AM335x SPL 代碼分析

配置DDR PLL:

AM335x SPL 代碼分析
AM335x SPL 代碼分析

代碼如下:

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