天天看點

AM335x SPL(三)

由Makefile可知,SPL的入口在u-boot-2011.09-psp04.06.00.08\arch\arm\cpu\armv7\start.S中

SPL的功能無非是設定MPU的Clock、PLL,Power,DDR,Uart,Pin Mux,完成對U-Boot的引導的工作,是以SPL board port主要針對以上幾點。

在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中定義:

#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\Pll.c)

----> mpu_pll_config(MPUPLL_M_500);  (u-boot-2011.09-psp04.06.00.08\board\ti\am335x\Pll.c)  

      //設定MPU的頻率為500MHz,可以修改

----> core_pll_config();  (u-boot-2011.09-psp04.06.00.08\board\ti\am335x\Pll.c)

      //設定CORE頻率為1GHz

----> per_pll_config();  (u-boot-2011.09-psp04.06.00.08\board\ti\am335x\Pll.c)   

     //設定外設頻率為960MHz                     

----> interface_clocks_enable();  (u-boot-2011.09-psp04.06.00.08\board\ti\am335x\Pll.c) 

     //使能内部連接配接子產品的時鐘

----> power_domain_transition_enable();  (u-boot-2011.09-psp04.06.00.08\board\ti\am335x\Pll.c)  

     //使能子產品電源

----> per_clocks_enable();  (u-boot-2011.09-psp04.06.00.08\board\ti\am335x\Pll.c) 

     //使能外設子產品的時鐘

在u-boot-2011.09-psp04.06.00.08\arch\arm\include\asm\arch-ti81xx\Clocks_am335x.h中,定義了所有時鐘頻率:

#define OSC    24             

#define MPUPLL_M_500    500   

#define MPUPLL_M_550    550   

#define MPUPLL_M_600    600   

#define MPUPLL_M_720    720   

#define MPUPLL_N    23   

#define MPUPLL_M2    1

#define COREPLL_M    1000   

#define COREPLL_N    23   

#define COREPLL_M4    10   

#define COREPLL_M5    8   

#define COREPLL_M6    4   

#define PERPLL_M    960

#define PERPLL_N    23

#define PERPLL_M2    5

#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);

    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);

}

Core PLL 結構:

AM335x SPL(三)

配置Core 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);

    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);

}

Peripheral PLL 結構

AM335x SPL(三)

配置Peripheral 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);

    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)

設定所使用序列槽的基位址、複位序列槽、關閉 smart idle。

u32 uart_base = DEFAULT_UART_BASE;        // 預設使用的序列槽是UART0,基位址為 0x44E0_9000

enable_uart0_pin_mux();                   // 配置uart0相關引腳為 UART模式

同樣可以設定為其他序列槽,比如IA Motor Control Board就是使用的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轉序列槽晶片,序列槽驅動drivers\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的資料到 header 結構體,header 結構體原型為

struct am335x_baseboard_id {

    unsigned int  magic;

    char name[8];

    char version[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");

}     //讀eeprom到 header 結構體,會判斷magic是否為上表中提供的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;

    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\Pll.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);

    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();

to be continued……