210的时钟域框图
由上图可知:
210的时钟系统由3个部分组成:分别是MSYS域,DSYD域,PSYS域。
由上图可知各个域的时钟名称:
MSYS域:
ARMCLK: 给cpu内核工作的时钟,也就是所谓的主频。
HCLK_MSYS: MSYS域的高频时钟,给DMC0和DMC1使用
PCLK_MSYS: MSYS域的低频时钟
HCLK_IMEM:给iROM和iRAM(合称iMEM)使用
DSYS域:
HCLK_DSYS:DSYS域的高频时钟
PCLK_DSYS:DSYS域的低频时钟
PSYS域:
HCLK_PSYS:PSYS域的高频时钟
PCLK_PSYS:PSYS域的低频时钟
SCLK_ONENAND:给ONENAND使用
时钟域时钟产生图如下:
各个器件模块的CLK引脚时钟形成之路:
几点说明:
MUX:指的是多选一开关,就是用来选择输入时钟源的。
PLL:学名为锁相环(Phase Locked Loop),在这里用来把输入频率进行倍频的,因为晶振输入的频率不高,必须把时钟频率提高到一定的值然后在给分给各个器件使用。
DIV:就是分频器,作用和PLL刚好相反,是用来把输入频率进行分频的,因为每个器件要求的时钟频率不同,所以进过倍频到一个高时钟后,必须进行分频到各个器件要求的时钟频率后才能被各个器件所使用。
思考一个问题:如果我不用一个器件的话,
DIV:就是分频器,作用和PLL刚好相反,是用来把输入频率进行分频的,因为每个器件要求的时钟频率不同,所以进过倍频到一个高时钟后,必须进行分频到各个器件要求的时钟频率后才能被各个器件所使用。
思考一个问题:如果我不用一个器件的话,如果本来要送给这个器件的这个时钟也送到了这个连接这个器件的引脚上会有什么不好?
结果是:因为这个时钟在器件的时钟引脚上可能会对这个器件造成一定影响,这个影响是多种多样的,但是肯定有不好的影响,所以我们要如何解决这个问题呢?
答案就是有一个的叫
结果是:因为这个时钟在器件的时钟引脚上可能会对这个器件造成一定影响,这个影响是多种多样的,但是肯定有不好的影响,所以我们要如何解决这个问题呢?
答案就是有一个的叫(Clock Gating Control Register)的寄存器,它是专门用来决定各个时钟传递的通断的,就好像一个阀门一样,可以打开,也可以关闭。
这样我们就可以精确控制每个时钟的通断了。
这样我们就可以精确控制每个时钟的通断了。
所以,由上图可知:
总的来说,210的时钟系统的设计思路是先把由MUX开关选择的晶振产生的固定时钟输入到Soc中,在Soc中先由各个PLL把时钟进行倍频到一定的频率,然后一部分直接成为了时钟域的时钟频率,另一部分再经过一系列的MUX选择后,然后再经过DIV进行分频后成为各个时钟域的时钟频率。
210的一些推荐时钟值:
? freq(ARMCLK) = 1000 MHz
? freq(HCLK_MSYS) = 200 MHz
? freq(HCLK_IMEM) = 100 MHz
? freq(PCLK_MSYS) = 100 MHz
? freq(HCLK_DSYS) = 166 MHz
? freq(PCLK_DSYS) = 83 MHz
? freq(HCLK_PSYS) = 133 MHz
? freq(PCLK_PSYS) = 66 MHz
? freq(SCLK_ONENAND) = 133 MHz, 166 MHz
下图是210手册中时钟域的最大频率表:
由上面的一些推荐值,我们就可以通过设置一些寄存器来产生这些推荐值。
下面来认识一些时钟系统的SFR:
倍频控制寄存器(PLL Control Registers):
APLL_LOCK / MPLL_LOCK / EPLL_LOCK / VPLL_LOCK:这是用来设置倍频的LOCKTIME(锁存时间)的,因为当上电复位后,系统在Fin(晶振时钟频率)下运行,当使用锁相环倍频时,倍频开始时会有一段时间系统的时钟是不稳定的,这段时间的时钟应该不能被使用,所以要把系统时钟锁存一段时间来度过这个危险期。等到锁存器能输出稳定时钟时就可以使用倍频后的时钟了。所以用这个来设置PLL的锁存时间。
同理倍频有锁存时间,那分频肯定也有锁存时间。
下图是手册上关于锁存时间的描述:
接下来就是最重要的倍频系数设置的寄存器了:
APLL_CON0, R/W, Address = 0xE010_0100
MPLL_CON, R/W, Address = 0xE010_0108
EPLL_CON0/ EPLL_CON1, R/W, Address = 0xE010_0110/0xE010_0114
460MHz ≤ FVCO ≤ 660MHz when VSEL=HIGH.
FOUT: 12MHz ≤ FOUT ≤ 660MHz
Don't set the value PDIV or MDIV to all zeros.
VPLL_CON, R/W, Address = 0xE010_0120
时钟源控制寄存器(CLOCK SOURCE CONTROL REGISTERS):用来选择时钟源的,就是MUX
CLK_SRC0, R/W, Address = 0xE010_0200
CLK_SRC1, R/W, Address = 0xE010_0204
CLK_SRC2, R/W, Address = 0xE010_0208
CLK_SRC3, R/W, Address = 0xE010_020C
CLK_SRC4, R/W, Address = 0xE010_0210
CLK_SRC5, R/W, Address = 0xE010_0214
CLK_SRC6, R/W, Address = 0xE010_0218
时钟源屏蔽寄存器:是用来屏蔽MUX的,也就是说如果该寄存器中各MUX开关对应的位如果是屏蔽的话,MUX是失效的,MUX后的时钟被切断了,也就是MUX后就没有时钟输出了。
CLK_SRC_MASK0, R/W, Address = 0xE010_0280
CLK_SRC_MASK1,R/W, Address = 0xE010_0284
时钟分频控制寄存器(CLOCK DIVIDER CONTROL REGISTER):
CLK_DIV0, R/W, Address = 0xE010_0300
CLK_DIV1, R/W, Address = 0xE010_0304
CLK_DIV2, R/W, Address = 0xE010_0308
CLK_DIV3, R/W, Address = 0xE010_030C
CLK_DIV3, R/W, Address = 0xE010_030C
CLK_DIV5, R/W, Address = 0xE010_0314
CLK_DIV6, R/W, Address = 0xE010_0318
CLK_DIV7, R/W, Address = 0xE010_031C
时钟门控寄存器(CLOCK GATING CONTROL REGISTER):和上面的CLK_SRC_MASKn寄存器的区别是:MASK是用来控制MUX的通断的,而GATE是用来通断各个器件时钟(也就是经过PLL,MUX,DIV后到达各个器件CLK引脚之前的时钟,就是上面的《各个器件模块的CLK引脚时钟形成之路》图的最后时钟输出到的那个器件就是这个门控寄存器)。
CLK_GATE_SCLK, R/W, Address = 0xE010_0444
CLK_GATE_IP0, R/W, Address = 0xE010_0460
CLK_GATE_IP0, R/W, Address = 0xE010_0460
CLK_GATE_IP2, R/W, Address = 0xE010_0468
CLK_GATE_IP3, R/W, Address = 0xE010_046C
CLK_GATE_IP4, R/W, Address = 0xE010_0470
CLK_GATE_BLOCK, R/W, Address = 0xE010_0480
CLK_GATE_IP5, R/W, Address = 0xE010_0484
时钟分频状态寄存器(CLOCK DIVIDER STATUS SFRS):这是用来检查分频器的输出是否已经稳定
CLK_DIV_STAT0, R, Address = 0xE010_1000
CLK_DIV_STAT1, R, Address = 0xE010_1004
时钟MUX状态寄存器(CLOCK MUX STATUS SFRS):当CLK_SRCx寄存器改变时,也就是把输入时钟从一个时钟换到另一个时钟时,会有一个时钟不稳定的时期,所以就要用这个状态位来检测MUX的输出时钟是否稳定了。
CLK_MUX_STAT0, R, Address = 0xE010_1100
CLK_MUX_STAT1, R, Address = 0xE010_1104
为什么没有倍频状态寄存器呢?
原来是因为在PLL设置时已经设置了一个锁存时间值,这个值要确保经过锁存时间后时钟就可以用了,所以我们的锁存时间正常使用默认值(最大值)。
其他的SFR:Other SFRs (SWRESET, R/W, Address = 0xE010_2000),该位是用来进行软件重启的
时钟输出控制寄存器(CLOCK OUTPUT CONFIGURATION REGISTER):
Internal clocks can be monitored through XCLKOUT PAD. CLK_OUT register selects an internal clock among PLL
outputs, USBPHY output, HDMIPHY output, RTC, TICK, system bus clocks, ARMCLK, HPM clock and external
OSCs. It also divides the selected clock. This is just for debugging. Do not supply this to other components as
clock.
这个是用来调试的
还记得这个嘛?
? freq(ARMCLK) = 1000 MHz
? freq(HCLK_MSYS) = 200 MHz
? freq(HCLK_IMEM) = 100 MHz
? freq(PCLK_MSYS) = 100 MHz
? freq(HCLK_DSYS) = 166 MHz
? freq(PCLK_DSYS) = 83 MHz
? freq(HCLK_PSYS) = 133 MHz
? freq(PCLK_PSYS) = 66 MHz
? freq(SCLK_ONENAND) = 133 MHz, 166 MHz
下面是配置出这些值的参考图解:
以上的寄存器的设置,可以参考数据手册上的参考值进行设置
汇编初始化时钟代码,仅供参考:
-
// 时钟控制器基地址
-
#define ELFIN_CLOCK_POWER_BASE 0xE0100000
-
-
// 时钟相关的寄存器相对时钟控制器基地址的偏移值
-
#define APLL_LOCK_OFFSET 0x00
-
#define MPLL_LOCK_OFFSET 0x08
-
-
#define APLL_CON0_OFFSET 0x100
-
#define APLL_CON1_OFFSET 0x104
-
#define MPLL_CON_OFFSET 0x108
-
-
#define CLK_SRC0_OFFSET 0x200
-
#define CLK_SRC1_OFFSET 0x204
-
#define CLK_SRC2_OFFSET 0x208
-
#define CLK_SRC3_OFFSET 0x20c
-
#define CLK_SRC4_OFFSET 0x210
-
#define CLK_SRC5_OFFSET 0x214
-
#define CLK_SRC6_OFFSET 0x218
-
#define CLK_SRC_MASK0_OFFSET 0x280
-
#define CLK_SRC_MASK1_OFFSET 0x284
-
-
#define CLK_DIV0_OFFSET 0x300
-
#define CLK_DIV1_OFFSET 0x304
-
#define CLK_DIV2_OFFSET 0x308
-
#define CLK_DIV3_OFFSET 0x30c
-
#define CLK_DIV4_OFFSET 0x310
-
#define CLK_DIV5_OFFSET 0x314
-
#define CLK_DIV6_OFFSET 0x318
-
#define CLK_DIV7_OFFSET 0x31c
-
-
#define CLK_DIV0_MASK 0x7fffffff
-
-
// 这些M、P、S的配置值都是查数据手册中典型时钟配置值的推荐配置得来的。
-
// 这些配置值是三星推荐的,因此工作最稳定。如果是自己随便瞎拼凑出来的那就要
-
// 经过严格测试,才能保证一定对。
-
#define APLL_MDIV 0x7d // 125
-
#define APLL_PDIV 0x3
-
#define APLL_SDIV 0x1
-
-
#define MPLL_MDIV 0x29b // 667
-
#define MPLL_PDIV 0xc
-
#define MPLL_SDIV 0x1
-
-
#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
-
#define APLL_VAL set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
-
#define MPLL_VAL set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)
-
-
-
.global clock_init
-
clock_init:
-
ldr r0, =ELFIN_CLOCK_POWER_BASE
-
-
// 1 设置各种时钟开关,暂时不使用PLL
-
ldr r1, =0x0
-
// 芯片手册P378 寄存器CLK_SRC:Select clock source 0 (Main)
-
str r1, [r0, #CLK_SRC0_OFFSET]
-
-
// 2 设置锁定时间,使用默认值即可
-
// 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间
-
ldr r1, =0x0000FFFF
-
str r1, [r0, #APLL_LOCK_OFFSET]
-
str r1, [r0, #MPLL_LOCK_OFFSET]
-
-
// 3 设置分频
-
// 清bit[0~31]
-
ldr r1, [r0, #CLK_DIV0_OFFSET]
-
ldr r2, =CLK_DIV0_MASK
-
bic r1, r1, r2
-
ldr r2, =0x14131440
-
orr r1, r1, r2
-
str r1, [r0, #CLK_DIV0_OFFSET]
-
-
// 4 设置PLL
-
// FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHz
-
ldr r1, =APLL_VAL
-
str r1, [r0, #APLL_CON0_OFFSET]
-
// FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
-
ldr r1, =MPLL_VAL
-
str r1, [r0, #MPLL_CON_OFFSET]
-
-
// 5 设置各种时钟开关,使用PLL
-
ldr r1, [r0, #CLK_SRC0_OFFSET]
-
ldr r2, =0x10001111
-
orr r1, r1, r2
-
str r1, [r0, #CLK_SRC0_OFFSET]
-
-
mov pc, lr
顺带提下:
下图是210的IROM里的初始化时钟值:
而我们u-boot里要把ARMCLK设置为1000MHz,使CPU运行的更快,所以在u-boot里有初始化时钟的代码。
阅读(2722) | 评论(0) | 转发(0) |