zoukankan      html  css  js  c++  java
  • 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();

  • 相关阅读:
    yii 引入文件
    CodeForces 621C Wet Shark and Flowers
    面试题题解
    POJ 2251 Dungeon Master
    HDU 5935 Car(模拟)
    HDU 5938 Four Operations(暴力枚举)
    CodeForces 722C Destroying Array(并查集)
    HDU 5547 Sudoku(dfs)
    HDU 5583 Kingdom of Black and White(模拟)
    HDU 5512 Pagodas(等差数列)
  • 原文地址:https://www.cnblogs.com/zym0805/p/4134466.html
Copyright © 2011-2022 走看看