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目录下:

clip_image002

clip_image002 [6]

clip_image002 [8]

clip_image002 [10]

通过上面的图,可以很清楚的了解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结构_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

配置核心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结构

配置外设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_codeCONFIG_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
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值