zz-am335x时钟clock寄存器配置141214d

来源:互联网 发布:rf仿真软件 编辑:程序博客网 时间:2024/05/27 20:16
//zz//####################################################################################


zz-am335x时钟clock寄存器配置141214d.txt


zz-write:
@2014-12-14 08:22:51
@2014-12-14 19:48:18
@2014-12-14 22:02:50
@2014-12-14 23:51:50
explicitly 显性时钟 PER/Functional Clock;打开则OCP被关断
@


REF:
AM335x_Technical_Reference_Manual(TRM).pdf
AM335x_TRM-zz141211a.pdf

ti-sdk-am335x-evm-06.00.00.00-Linux-x86-Install.bin
u-boot-2013.01-psp06ti-zz141214b.zip


KeyWord:
CLK_M_OSC => CLKINP
CLKOUT
CLKDCOLDO
CLKOUTx2

ADPLLS 为高速(Mpu,Core)
Mpu Core Display DDR 等时钟
ADPLLJ 为外设(低速 Peripheral)
Uart I2C MMC/SD 等时钟


PLL(不论ADPLLS ADPLLJ)设置,输入输出倍率关系
u-boot 的使用方式: M = 需要得到的输出时钟; N = 输入晶振频率-1; M2 = 1
主时钟
CLKOUT = (M / (N+1))*CLKINP*(1/M2)

CLKDCOLDO = (M / (N+1))*CLKINP

若有
CLKOUTX2 = 2 * [M / (N+1)] * CLKINP * [1/M2]

关于 Peripheral 时钟的设置(显性为 ADPLLJ/Per 时钟;使能了Functional就一定是,此时OCP被关断)
Functional Clock: explicitly
Inteface Clock(OCP): implicitly


//zz//####################################################################################
0.
u-boot 中的寄存器地址及结构体声明
s_init() => pll_init() 函数实现时钟 clock 的配置
后面 3. 4. 分析 pll_init() 函数内各函数针对寄存器的操作流程


const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER;
const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP;
const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL;
const struct cm_rtc *cmrtc = (struct cm_rtc *)CM_RTC;


struct cm_wkuppll {
unsigned int wkclkstctrl;/* offset 0x00 */
unsigned int wkctrlclkctrl;/* offset 0x04 */
unsigned int wkgpio0clkctrl;/* offset 0x08 */
unsigned int wkl4wkclkctrl;/* offset 0x0c */
...
}


...


void pll_init()
{
/* Start at 550MHz, will be tweaked up if possible. */
mpu_pll_config(MPUPLL_M_300);
core_pll_config(OPP_50);
per_pll_config();


/* Enable the required interconnect clocks */
enable_interface_clocks();


/* Power domain wake up transition */
power_domain_wkup_transition();


/* Enable the required peripherals */
enable_per_clocks();
}



//zz//####################################################################################
1.
am335x-TRM 手册章节中的配置说明


8 Power, Reset, and Clock Management (PRCM)
8.1.3 Clock Management
8.1.3.3 Clock Domain
时钟域选择与配置..


8.1.6 Clock Generation and Management
8.1.6.3 ADPLLS
8.1.6.4 ADPLLLJ (Low Jitter DPLL)


分别介绍各种时钟的配置方法..
8.1.6.6 Core PLL Description
8.1.6.7 Peripheral PLL Description
8.1.6.8 MPU PLL Description
...


8.1.12 Clock Module Registers
8.1.12.1 CM_PER Registers
8.1.12.1.22 CM_PER_UART1_CLKCTRL Register (offset = 6Ch)
开启 UART1/0 的 functional clock
8.1.12.1.27 CM_PER_TIMER2_CLKCTRL Register (offset = 80h)
开启 TIMER2 的 functional clock


8.1.12.2 CM_WKUP Registers
8.1.12.2.12 CM_CLKSEL_DPLL_MPU Register (offset = 2Ch)
8.1.12.2.27 CM_CLKSEL_DPLL_CORE Register (offset = 68h) 
8.1.12.2.35 CM_CLKMODE_DPLL_MPU Register (offset = 88h)
8.1.12.2.37 CM_CLKMODE_DPLL_CORE Register (offset = 90h)
8.1.12.2.43 CM_DIV_M2_DPLL_MPU Register (offset = A8h)
8.1.12.2.46 CM_WKUP_UART0_CLKCTRL Register (offset = B4h)
8.1.12.3.2 CLKSEL_TIMER2_CLK Register (offset = 8h)
可配置TIMER2 时钟为输入晶振CLKINP频率
8.1.12.2.52 CM_L4_WKUP_AON_CLKSTCTRL Register (offset = CCh) 
开启 interface clock (L4_WKUP), u-boot 中 TIMER2,UART1/0 都没用,用的是 functional clock ?

8.1.12.3 CM_DPLL Registers
8.1.12.4 CM_MPU Registers




//zz//####################################################################################
2.
时钟寄存器配置心得总结


1)
各时钟之间相关性不大(类比三星s5pv210的多次再分频)
Mpu Core Display DDR 及 Peripheral 时钟都是从 CLKINP(24M-25M-26M) 经过各自的 PLL 得到


2)
以上所说时钟,在各自的时钟图上都是 CLKOUT,计算公式都如下
CLKOUT = (M / (N+1))*CLKINP*(1/M2)
u-boot代码中用法,可以理解为: M2取1; 则 M 是想得到的CLKOUT的频率值(单位MHz), N 是 CLKINP 晶振的频率值(MHz)减一


3)
在得到以上各时钟后,才开始进行分频
例如 OCP(interface clock)中,给各 M3 M4 M5 设置分频系数,得到针对具体设备/接口的时钟; 例如: Uart Timer SPI I2C ...


像 Uart Timer 这些外设,有多种时钟可以选择: functional clock, interface clock(OCP)
interface clock 使用的是 Core clock (APLLS)中的 M3 M4 等分频作为时钟源的,需要在寄存器中打开 WKUP_L4_WKUP 等


functional clock 使用的是 Peripheral 时钟(APLLJ)设定的外设用的时钟,需要寄存器中打开 wkup_uart0ctrl, timer2clkctrl 或其他


TRM手册 8.1.6.2 Clock Structure 有如下一段话
The ADPLLS module is used for the Core, Display, ARM Subsystem and DDR PLLs
The ADPLLLJ module is used for the peripheral functional clocks


//zz//####################################################################################
3.
以u-boot代码为例,说明时钟输入输出频率的配置流程;
Core Mpu Per 的时钟流程是一样的.
TRM手册 8.1.6.6.1 Core PLL Configuration


1)
将 PLL 切换到 bypass mode; 通过设置 CM_CLKMODE_DPLL_CORE.DPLL_EN = 0x04


2)
while() 等待 CM_IDLEST_DPLL_CORE.ST_MN_BYPASS 为 1;
确保已经进入 bypass mode


3)
配置 CM_CLKSEL_DPLL_CORE.DPLL_MULT 和 DPLL_DIV 
即前面说的 M/(N+1) 和 M2


4)
配置 M4 M5 M6 各设备/接口的分频系数


5)
将 PLL 切换到 lock mode(也即退出了 bypass mode);
通过设置 CM_CLKMODE_DPLL_CORE.DPLL_EN = 0x7


6)
while() 等待 CM_IDLEST_DPLL_CORE.ST_DPLL_CLK 为 1;
确保 PLL 已经 locked


void mpu_pll_config(int mpupll_M)
{
u32 clkmode, clksel, div_m2;


//zz// 8.1.12.2.35 CM_CLKMODE_DPLL_MPU Register (offset = 88h)
clkmode = readl(&cmwkup->clkmoddpllmpu);
//zz// 8.1.12.2.12 CM_CLKSEL_DPLL_MPU Register (offset = 2Ch)
clksel = readl(&cmwkup->clkseldpllmpu);
//zz// 8.1.12.2.43 CM_DIV_M2_DPLL_MPU Register (offset = A8h)
div_m2 = readl(&cmwkup->divm2dpllmpu);


/* Set the PLL to bypass Mode */
writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
;


clksel = clksel & (~CLK_SEL_MASK);
clksel = clksel | ((mpupll_M << CLK_SEL_SHIFT) | MPUPLL_N);
writel(clksel, &cmwkup->clkseldpllmpu);


div_m2 = div_m2 & ~CLK_DIV_MASK;
div_m2 = div_m2 | MPUPLL_M2;
writel(div_m2, &cmwkup->divm2dpllmpu);


//zz// Set the PLL to DPLL and wait for Complete
clkmode = clkmode | CLK_MODE_SEL;
writel(clkmode, &cmwkup->clkmoddpllmpu);


while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
;
}




void core_pll_config(int opp)
{
u32 clkmode, clksel, div_m4, div_m5, div_m6;


//zz// 8.1.12.2.37 CM_CLKMODE_DPLL_CORE Register (offset = 90h)
clkmode = readl(&cmwkup->clkmoddpllcore);
//zz// 8.1.12.2.27 CM_CLKSEL_DPLL_CORE Register (offset = 68h)
clksel = readl(&cmwkup->clkseldpllcore);
//zz// 8.1.12.2.33 CM_DIV_M4_DPLL_CORE Register (offset = 80h) 
// 80h 84h D8h
div_m4 = readl(&cmwkup->divm4dpllcore);
div_m5 = readl(&cmwkup->divm5dpllcore);
div_m6 = readl(&cmwkup->divm6dpllcore);

/* Set the PLL to bypass Mode */
writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
;

//zz// if opp == OPP_50) ... else OPP_100
//zz// OPP_100 packaging chip: 1GHz (the highest frequency)
clksel = clksel & (~CLK_SEL_MASK);
//zz// 1GHz: 1000<<8 | (OSC-1)
clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N);
writel(clksel, &cmwkup->clkseldpllcore);


div_m4 = div_m4 & ~CLK_DIV_MASK;
//zz// 200MHz: 10 
div_m4 = div_m4 | COREPLL_M4;
writel(div_m4, &cmwkup->divm4dpllcore);


//zz// 250MHz: 8
div_m5 = div_m5 & ~CLK_DIV_MASK;
div_m5 = div_m5 | COREPLL_M5;
writel(div_m5, &cmwkup->divm5dpllcore);


//zz// 500MHz: 4
div_m6 = div_m6 & ~CLK_DIV_MASK;
div_m6 = div_m6 | COREPLL_M6;
writel(div_m6, &cmwkup->divm6dpllcore);


//zz// 0x7: CLK_MODE(out of bypass mode)
clkmode = clkmode | CLK_MODE_SEL;
writel(clkmode, &cmwkup->clkmoddpllcore);


while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
;
}


void per_pll_config()
{
u32 clkmode, clksel, div_m2;


//zz// 8.1.12.2.35 CM_CLKMODE_DPLL_MPU Register (offset = 88h) 
clkmode = readl(&cmwkup->clkmoddpllper);
//zz// 8.1.12.2.40 CM_CLKSEL_DPLL_PERIPH Register (offset = 9Ch) 
clksel = readl(&cmwkup->clkseldpllper);
//zz// 8.1.12.2.44 CM_DIV_M2_DPLL_PER Register (offset = ACh)
div_m2 = readl(&cmwkup->divm2dpllper);


/* Set the PLL to bypass Mode */
writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);


while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
;


clksel = clksel & (~CLK_SEL_MASK);
//zz// 960MHz: 960<<8 | (OSC-1)
clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N);
writel(clksel, &cmwkup->clkseldpllper);


div_m2 = div_m2 & ~CLK_DIV2_MASK;
//zz// 192MHz: 5
div_m2 = div_m2 | PERPLL_M2;
writel(div_m2, &cmwkup->divm2dpllper);


//zz// 0x07: out of bypass mode, CLK_MODE
// and wait for CLK_MODE complete
clkmode = clkmode | CLK_MODE_SEL;
writel(clkmode, &cmwkup->clkmoddpllper);


while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
;


writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
}
//zz//####################################################################################
4.
外设functional clock 时钟的选择
以 UART0(1) TIMER2 为例做说明,u-boot代码中,用作console和精确的硬件定时器


//zz// 19.2.1 UART Connectivity Attributes
/* UART0 
//Power Domain: Wake-Up Domain
//Clock Domain: PD_WKUP_L4_WKUP_GCLK (OCP) <=> implicitly
PD_WKUP_UART0_GFCLK (Func) <=> explicitly
*/


//zz// 20.1.2.1 Timer Connectivity Attributes
/*  Timer[2–7] 
//Clock Domain: PD_PER_L4LS_GCLK (OCP) <=> implicitly
// Functional Clocks:<=> explicitly
// PD_PER_TIMER2_GCLK (Timer 2)
// ...
*/
void enable_per_clocks()
{
/* Enable the module clock */
writel(PRCM_MOD_EN, &cmper->timer2clkctrl);
while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN)
;


/* Select the Master osc 24 MHZ as Timer2 clock source */
writel(0x1, &cmdpll->clktimer2clk);


//zz// we don't enable WKUP_L4_WKUP(interface clock)
// so Uart0 Clock is WKUP_UART0 functional clock
// Table 19-4. UART0 => Uart0 clk is (PER_CLKOUTM2/4)
/* UART0 */
writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl);
while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN)
;


}


//zz// 8.1.12.2.52 CM_L4_WKUP_AON_CLKSTCTRL Register (offset = CCh)
// L4_WKUP(did not set,and implicitly) for OCP/interface clock
/* Enable the required interconnect clocks */
enable_interface_clocks();
/* Power domain wake up transition */
power_domain_wkup_transition();


//zz//####################################################################################
5.
寄存器 地址查找


1)
寄存器基址
手册 2 Memory Map (寄存器基址)
Table 2-2. L4_WKUP Peripheral Memory Map
CM_PER 0x44E0_0000 0x44E0_3FFF 1KB Clock Module Peripheral Registers
CM_WKUP 0x44E0_0400 0x44E0_04FF 256 Bytes Clock Module Wakeup Registers
CM_DPLL 0x44E0_0500 0x44E0_05FF 256 Bytes Clock Module PLL Registers
CM_MPU 0x44E0_0600 0x44E0_06FF 256 Bytes Clock Module MPU Registers


2)
寄存器位偏移,位值意义


手册 8.1.12.2.12 CM_CLKSEL_DPLL_MPU Register (offset = 2Ch) [reset = 0h]
[18:8] DPLL_MULT DPLL multiplier factor (2 to 2047)
倍频(M),通常设置为想得到的 CLKOUT 频率
[6:0] DPLL_DIVDPLL divider factor (0 to 127) 
分频(N),通常设置为输入晶振频率(CLKINP,单位MHz)减1


手册 8.1.12.2.43 CM_DIV_M2_DPLL_MPU Register (offset = A8h) [reset = 1h]
[4:0] 设置 M2 分频系数为 1-31
通常设置为1,不再分频


手册 8.1.12.2.35 CM_CLKMODE_DPLL_MPU Register (offset = 88h) [reset = 4h]
[2:0] 设置 DPLL 模式
0x4 = DPLL_MN_BYP_MODE
0x7 = DPLL_LOCK_MODE


//zz//####################################################################################
6.
关于 Peripheral 时钟的设置(显性为 ADPLLJ/Per 时钟;使能了Functional就一定是,此时OCP被关断)
Functional Clock: explicitly
Inteface Clock(OCP): implicitly


例如 UART0 的 Functional Clock 使能有如下这段说明 
8.1.12.2.46 CM_WKUP_UART0_CLKCTRL Register (offset = B4h) 
0x02: Module is explicitly enabled. Interface clock (if not
used for functions) may be gated according to the clock domain
state. Functional clocks are guarantied to stay present. As long as in
this configuration, power domain sleep transition cannot happen

//zz//####################################################################################



0 0