时间:2018.4.6 作者:Tom 工作:HWE 说明:如需转载,请注明出处。已注明转载
在前面的lowlevel_init文章中,分析了一部分的时钟代码,但是感觉稀里糊涂的。今天专门把时钟的代码拿出来分析一下。
/*
* system_clock_init: Initialize core clock and bus clock.
* void system_clock_init(void)
*/
system_clock_init:
ldr r0, =ELFIN_CLOCK_POWER_BASE @0xe0100000
#define ELFIN_CLOCK_POWER_BASE 0xE0100000
从上图中可以看出使用的外部时钟均是24MHz的。
/* Set Mux to FIN */1.时钟源使用外部晶振,
ldr r1, =0x0
str r1, [r0, #CLK_SRC0_OFFSET] 即所有时钟来源于外部时钟。
#define CLK_SRC0_OFFSET 0x200
ldr r1, =APLL_LOCKTIME_VAL
#define APLL_LOCKTIME_VAL 0xe10
str r1, [r0, #APLL_LOCK_OFFSET]
#define APLL_LOCK_OFFSET 0x00
将这个3600写入APLL_LOCK中。也就是分频系数设置成3600。
/********lxg added*********************/
ldr r0, =ELFIN_CLOCK_POWER_BASE @0xe0100000
#define ELFIN_CLOCK_POWER_BASE 0xE0100000
ldr r1, =MPLL_LOCKTIME_VAL
#define MPLL_LOCKTIME_VAL 0xe10
str r1, [r0, #MPLL_LOCK_OFFSET]
#define MPLL_LOCK_OFFSET 0x04
和上面一样设置MPLL的分频系数为3600。但是0xE0100004这个寄存器在数据手册中属于保留的寄存器。没有用。
估计是后面加上的,我们不管。
/********end*********************/
/* Disable PLL */禁用PLL
#if defined(CONFIG_CHECK_MPLL_LOCK)
这个宏我们在X210_sd中定义了。不过是个空函数,可能只是做个标记而已。
retryloop:
#endif
继续分析—》
ldr r1, =0x0
str r1, [r0, #APLL_CON0_OFFSET]
#define APLL_CON0_OFFSET 0x100
第31位设置为0,禁止APLL功能
ldr r1, =0x0
str r1, [r0, #MPLL_CON_OFFSET]
#define MPLL_CON_OFFSET 0x108
这个功能一样的: 第31位设置为0,禁止MPLL功能
ldr r1, [r0, #CLK_DIV0_OFFSET] 1.读
#define CLK_DIV0_OFFSET 0x300
ldr r2, =CLK_DIV0_MASK
#define CLK_DIV0_MASK 0x7fffffff
bic r1, r1, r2 2.清零
将r1中的31位保留,其他均清0。
ldr r2, =CLK_DIV0_VAL
#define CLK_DIV0_VAL ((0<<APLL_RATIO)|(4<<A2M_RATIO)|(4<<HCLK_MSYS_RATIO)|(1<<PCLK_MSYS_RATIO)\
|(3<<HCLK_DSYS_RATIO)|(1<<PCLK_DSYS_RATIO)|(4<<HCLK_PSYS_RATIO)|(1<<PCLK_PSYS_RATIO))
#define APLL_RATIO 0
#define A2M_RATIO 4
#define HCLK_MSYS_RATIO 8
#define PCLK_MSYS_RATIO 12
#define HCLK_DSYS_RATIO 16
#define PCLK_DSYS_RATIO 20
#define HCLK_PSYS_RATIO 24
#define PCLK_PSYS_RATIO 28
orr r1, r1, r2 3.改
对r1中的寄存器进行改。
str r1, [r0, #CLK_DIV0_OFFSET] 4.写
我们来看下结果:
ARMCLK = MOUT_MSYS
SCLKA2M = SCLKAPLL/5
HCLK_MSYS = ARMCLK/5
PCLK_MSYS = HCLK_MSYS/2
HCLK_DSYS = MOUT_DSYS/4
PCLK_DSYS = HCLK_DSYS/2
HCLK_PSYS = MOUT_PSYS/5
PCLK_PSYS = SCLK_PSYS/2
对照一下推荐的值:是一样的!!!
ldr r1, =APLL_VAL
#define APLL_VAL set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#elif defined(CONFIG_CLK_1000_200_166_133)
#define APLL_MDIV 0x7d
#define APLL_PDIV 0x3
#define APLL_SDIV 0x1
使用的是推荐值:1G。
str r1, [r0, #APLL_CON0_OFFSET]
#define APLL_CON0_OFFSET 0x100
设置ARMCLK为1G。
下面也就是设置MPLL和EPLL,VPLL
ldr r1, =MPLL_VAL
#define MPLL_VAL set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)
#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#define MPLL_MDIV 0x29b
#define MPLL_PDIV 0xc
#define MPLL_SDIV 0x1
str r1, [r0, #MPLL_CON_OFFSET]
ldr r1, =VPLL_VAL
str r1, [r0, #VPLL_CON_OFFSET]
/*******lxg added***********************/
ldr r1, =EPLL_VAL
str r1, [r0, #EPLL_CON_OFFSET]
这个查不到。
/*******lxg added***********************/
ldr r1, [r0, #CLK_DIV1_OFFSET]
#define CLK_DIV1_OFFSET 0x304
ldr r2, =CLK_DIV1_MASK
#define CLK_DIV1_MASK 0xffffffff
bic r1, r1, r2
清零。
ldr r2, =CLK_DIV1_VAL
#define CLK_DIV1_VAL ((1<<16)|(1<<12)|(1<<8)|(1<<4))
orr r1, r1, r2
str r1, [r0, #CLK_DIV1_OFFSET]
上述设置一样,但目前我们不给出结果,暂时用不到。下面一样的,都是设置一些分频系数。
ldr r1, [r0, #CLK_DIV2_OFFSET]
ldr r2, =CLK_DIV2_MASK
bic r1, r1, r2
ldr r2, =CLK_DIV2_VAL
orr r1, r1, r2
str r1, [r0, #CLK_DIV2_OFFSET]
ldr r1, [r0, #CLK_DIV4_OFFSET]
ldr r2, =CLK_DIV4_MASK
bic r1, r1, r2
ldr r2, =CLK_DIV4_VAL
#define CLK_DIV4_VAL 0x99990000
orr r1, r1, r2
str r1, [r0, #CLK_DIV4_OFFSET]
ldr r1, [r0, #CLK_DIV6_OFFSET]
ldr r2, =CLK_DIV6_MASK
bic r1, r1, r2
ldr r2, =CLK_DIV6_VAL
orr r1, r1, r2
str r1, [r0, #CLK_DIV6_OFFSET]
上述是设置各种分频因子。对于特殊功能的时钟,我们需要的时候再看。
/*******end*****************/
/*******end*****************/
#if defined(CONFIG_EVT1)
我们在x210_sd.h中定义了。
ldr r1, =AFC_ON
#define AFC_ON 0x00000000
str r1, [r0, #APLL_CON1_OFFSET]
#define APLL_CON1_OFFSET 0x104
时钟校准。
#endif
mov r1, #0x10000
1: subs r1, r1, #1
bne 1b
等待上述设置稳定,倒数65536个数。
#if defined(CONFIG_CHECK_MPLL_LOCK)
我们在x210_sd.h中定义了。
/* MPLL software workaround */
ldr r1, [r0, #MPLL_CON_OFFSET]
#define MPLL_CON_OFFSET 0x108
orr r1, r1, #(1<<28)
str r1, [r0, #MPLL_CON_OFFSET]
将28位置1,不知道啥作用,不用管。打开上锁检测功能。
mov r1, #0x100
1: subs r1, r1, #1
bne 1b
还是等待设置完成。
ldr r1, [r0, #MPLL_CON_OFFSET]
and r1, r1, #(1<<29)
cmp r1, #(1<<29)
bne retryloop
设置29位,将时钟锁定下来。
/* H/W lock detect disable */
ldr r1, [r0, #MPLL_CON_OFFSET]
bic r1, r1, #(1<<28)
str r1, [r0, #MPLL_CON_OFFSET]
将28位清0,不知道啥作用,不用管。禁用上锁检测功能。
#endif
ldr r1, [r0, #CLK_SRC0_OFFSET]
#define CLK_SRC0_OFFSET 0x200
//ldr r2, =0x10001111 //lxg changed.
ldr r2, =0x00000111
orr r1, r1, r2
str r1, [r0, #CLK_SRC0_OFFSET]
打开时钟输出。
// added by terry 2012.12.4 for camera
ldr r1, [r0, #CLK_SRC1_OFFSET]
bic r1, r1, #(0xf<<12)
orr r1, r1, #(0x1<<12) //0001 XusbXTI
str r1, [r0, #CLK_SRC1_OFFSET]
camera的时钟,我们暂时不分析。
#elif defined (CONFIG_MCP_SINGLE)
我们在x210_sd.h中定义了。
/* CLK_DIV6 */
/*ldr r1, [r0, #CLK_DIV6_OFFSET]
bic r1, r1, #(0x7<<12) @; ONENAND_RATIO: 0
str r1, [r0, #CLK_DIV6_OFFSET]*/ //lxg mask
没啥用,我们没有使用onenand。
#endif
mov pc, lr
总结:
1.设置时钟源为外部晶振。
2.设置APLL,MPLL的分频系数。
3.设置各级子分频系数。
4.根据APLL获取主时钟的时钟频率ARMCLK为1G。
5.设置其他功能的分频系数。
6.等待设置稳定,上锁。