am335x 内核频率 ddr3频率 电压调整

由Makefile可知,SPL的入口在u-boot-2011.09-psp04.06.00.08archarmcpuarmv7start.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.08archarmcpuarmv7omap-commonlowlevel_init.S)

        ----> s_init   (u-boot-2011.09-psp04.06.00.08oard iam335xEvm.c)

                  ----> 关看门狗

                  ----> pll_init();  //PLL和时钟设置

                  ----> rtc32k_enable();  //使能RTC

                  ----> 串口设置

                  ----> init_timer();

                  ----> preloader_console_init();

                  ----> I2C0初始化,读EEPROM

                  ----> DDR设置(DDR2DDR3)

 

pll_init();  (u-boot-2011.09-psp04.06.00.08oard iam335xPll.c)

----> mpu_pll_config(MPUPLL_M_500);  (u-boot-2011.09-psp04.06.00.08oard iam335xPll.c)  

      //设置MPU的频率为500MHz,可以修改

----> core_pll_config();  (u-boot-2011.09-psp04.06.00.08oard iam335xPll.c)

      //设置CORE频率为1GHz

----> per_pll_config();  (u-boot-2011.09-psp04.06.00.08oard iam335xPll.c)   

     //设置外设频率为960MHz                     

----> interface_clocks_enable();  (u-boot-2011.09-psp04.06.00.08oard iam335xPll.c) 

     //使能内部连接模块的时钟

----> power_domain_transition_enable();  (u-boot-2011.09-psp04.06.00.08oard iam335xPll.c)  

     //使能模块电源

----> per_clocks_enable();  (u-boot-2011.09-psp04.06.00.08oard iam335xPll.c) 

     //使能外设模块的时钟

 

在u-boot-2011.09-psp04.06.00.08archarmincludeasmarch-ti81xxClocks_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.08oard iam335xEvm.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.08oard iam335xEvm.c)

这里初始化的是timer2,在之前 pll_init();----> per_clocks_enable(); 中使能的也是timer2,使用24MHz OSC

 

preloader_console_init();  (u-boot-2011.09-psp04.06.00.08archarmcpuarmv7omap-commonSpl.c)

主要是对串口波特率的设置,以及串口终端打印信息。BeagleBone板上使用的是USB转串口芯片,串口驱动driversserialserial.c 、driversserialns16550.c

I2C0初始化,读EEPROM  (u-boot-2011.09-psp04.06.00.08oard iam335xEvm.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 ");

}     //读eeprom到 header 结构体,会判断magic是否为上表中提供的0xEE3355AA 

 

    

DDR设置(DDR2DDR3)  (u-boot-2011.09-psp04.06.00.08oard iam335xEvm.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.08oard iam335xPll.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();

原文地址:https://www.cnblogs.com/zym0805/p/4134466.html