Chinaunix首页 | 论坛 | 博客
  • 博客访问: 82250
  • 博文数量: 26
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-06 17:25
文章分类

全部博文(26)

文章存档

2015年(18)

2013年(8)

我的朋友

分类: 嵌入式

2015-08-26 11:44:23

原文地址:AM335x SPL (三) 作者:skyajlm

由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中定义:

/* Since SPL did all of this for us, we don't need to do it twice. */
#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中,定义了所有时钟频率:

/* Put the pll config values over here */

#define OSC    24              /* 外部晶振为24MHz */

/* MAIN PLL Fdll = 1 GHZ, */
#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

/* Core PLL Fdll = 1 GHZ, */
#define COREPLL_M    1000    /* 125 * n */
#define COREPLL_N    23    /* (n -1 ) */

#define COREPLL_M4    10    /* CORE_CLKOUTM4 = 200 MHZ */
#define COREPLL_M5    8    /* CORE_CLKOUTM5 = 250 MHZ */
#define COREPLL_M6    4    /* CORE_CLKOUTM6 = 500 MHZ */

/*
* USB PHY clock is 960 MHZ. Since, this comes directly from Fdll, Fdll
* frequency needs to be set to 960 MHZ. Hence,
* For clkout = 192 MHZ, Fdll = 960 MHZ, divider values are given below
*/
#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 Subsystem PLL Structure_1

配置MPU PLL

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

    /* Set the PLL to bypass Mode */
    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 结构:

Core PLL

配置Core PLL

Core PLL Configuration

代码如下:

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

    /* Set the PLL to bypass Mode */
    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 结构

Peripheral PLL Structure

配置Peripheral PLL

Configuring the Peripheral 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);

    /* Set the PLL to bypass Mode */
    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信息如下:

image

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;

    /*
     * EVM SK 1.2A and later use gpio0_7 to enable DDR3.
     * This is safe enough to do on older revs.
     */
    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个部分需要设置,如下:

image

 

 

DDR PLL 结构:

image

配置DDR PLL:

image

image

代码如下:

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

    /* Set the PLL to bypass Mode */
    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();


阅读(1010) | 评论(0) | 转发(0) |
0

上一篇:AM335x SPL(二)

下一篇: AM335x SPL (四)

给主人留下些什么吧!~~