第四章、TIny4412 U-BOOT移植四 配置时钟频率源码分析

上篇讲了配置时钟的原理,今天就结合源码具体分析一下。在U-Boot的源码中,系统时钟的初始化是放在板文件夹下的(board/Samsung/mytiny4412)的clock_init_zthtiny4412.S文件中的system_clock_init函数中。我们的Tiny4412是拷贝的smdk4212来的,所以,大家可以先参看smdk4212的clock_init_smdk4212.S文件中的system_clock_init函数来分析,完了再修改适合自己板子的程序。

对于芯片手册中每一个模块的学习,在了解前面的基本原理后,关键的寄存器的操作,可以先浏览一下这个模块的所有寄存器的简介,对各个寄存器的作用做到心中有数,这样,可以大体知道,需要配置哪些寄存器,不至于被下面一大堆的寄存器给弄懵了,系统时钟的寄存器介绍在第776开始的第7.9节REGISTERDESCRIPTION 。

我这里直接参照了FriendlyARM所提供的U-BOOT源码,基本上是复制了其tiny4412目录下的时钟设置代码,说明一下,我是学习为目录,所以很多代码都是从现有可以运行的程序那里复制来的,换句话说,我现在基本是在注释代码吧,下面顺着函数来分析:

一、输入源和分频比

设置时钟模块的时钟输入源和分频比,包括CPU,DMC,TOP,LEFTBUS,RIGHTBUS等。

1、CPU MUX /DIV的时钟源和分频比

由于要设置的模块寄存器比较多,这里我他仅仅分析一下如何设置 CPU MUX /DIV的时钟源和分频比,其设置过程是怎么样的。

开如之前,修改代码开头:

#ifdef CONFIG_EXYNOS4412

#include"smdk4412_val.h"à#include "zthtiny4412_val.h"

#else

#include"smdk4212_val.h"à#include "zthtiny4212_val.h"

#endif

再来看这个图3-1


图4-1、时钟源选择图

以及其设置寄存器如下表4-1截图所示:


表4-1、CLK_SRC_CPU寄存器设置

 

为了用24M的外部时钟进行分频,需设置MUX_APLL_SEL(MUXAPLL)为0,那么MUX_CORE_SEL也需设置成0,选择MOUTAPLL.其它的两位,按代码以前的设置为0,分别将MUX_MPLL_USER_SEL_C设置选择FINPLL.而MUX_HPM_SEL选择MOUTAPLL。所以此寄存器的设置值为0。设置完成后需要等待一定时间,让其设置成功,代码的实现方式是也可以与寄存器CLK_MUX_STAT_CPU的值相比较。如下表4-2所示为CLK_MUX_STAT_CPU状态值说明。


表4-2、CLK_MUX_STAT_CPU状态值说明

结合上表的设置值,设置完成后,MUX_MPLL_USER_SEL_C设置选择FINPLL那么26:24位的值应为001,而MUX_HPM_SEL选择MOUTAPLL,那么26:24位的值也应为001,同理,可分析出其他位的值,那么,此寄存器的值应为0x0111_0001下面来看看代码具体写法:

system_clock_init:

       push {lr}@将链接寄存器压栈    

       ldr   r0,=ELFIN_CLOCK_BASE @ELFIN_CLOCK_BASE=0x1003_0000 ,时钟寄存器的基地址

 

@CMU_CPU MUX / DIV

       ldr   r1,=0x0

       ldr   r2,=CLK_SRC_CPU_OFFSET@ CLK_SRC_CPU寄存器的偏移地址

       str    r1,[r0, r2]@ CLK_SRC_CPU寄存器的设置为0

 

       ldr r2, =CLK_MUX_STAT_CPU_OFFSET@CLK_MUX_STAT_CPU寄存器的偏移地址

       ldr r3, =0x01110001@需要比较的CLK_MUX_STAT_CPU设置值,即我们上面分析的值

       bl wait_mux_state  @跳转到wait_mux_state等待寄存器值设置成功

 

wait_mux_state:

       ldr r1, [r0, r2]@读取CLK_MUX_STAT_CPU寄存器的值

       cmp r1, r3CLK_MUX_STAT_CPU寄存器的值和0x01110001进行比较

       bne wait_mux_state@不等就再来一次

       mov pc, lr@等了就返回。

@也可以用以下的方法来等待一定的时间

@/* wait ?us */

@    mov r1, #0x10000

@1: subs r1, r1, #1

@    bne  1b

 

好了,至此我们分析了如何设置 CPUMUX /DIV的时钟源选择的代码,但其分频比且没有进行设置,其实设置分频比的代码在后面设置完成LOCKOUT时间后才进行的,至于为什么这么安排我也不清楚,我们顺着代码分析就行,那这段代码还是在后面进行说明。

下面的代码是接着设置DMC,TOP,LEFTBUS,RIGHTBUS等寄存器,这里不做过多分析,以后我会给出详细源码,寄存器的值,针对我们板子是要进行必要修改的,重要的地方我还是会说明,如何查看手册就不做过多说明,接着说。

2、CMU_DMC MUX / DIV设置

这一段代码仅仅设置了其分频值,而其MUX值且没有设置,利用芯片启动的时的默认设置值,大家可以查看手册细细分析。这里参照tiny4412的Uboot进行了其DIV值设置。为什么取用这个值,我一时也还没有弄清楚,这里先留个问号,稍后再做说明。

@ CMU_DMC MUX / DIV  add by zth

@CLK_DIV_DMC1_VAL --Tiny4412_val.h

@defined(CONFIG_CLK_BUS_DMC_100_200)->CLK_DIV_DMC1_VAL=0X00113113

@CLK_DIV_DMC1_VAL=0X00111113

       ldr   r1,=CLK_DIV_DMC0_VAL 

       ldr   r2,=CLK_DIV_DMC0_OFFSET

       str    r1,[r0, r2]

       ldr   r1,=CLK_DIV_DMC1_VAL @CLK_DIV_DMC1_VAL=0x07071713

       ldr   r2,=CLK_DIV_DMC1_OFFSET

       str    r1,[r0, r2]

3、CMU_TOP MUX / DIV设置

CMU_TOP的MUX寄存器是CLK_SRC_TOP0和CLK_SRC_TOP1,他们的设置值分别由原值0X0变为0X00000110和0x01111000,分别利用比较其相应的状态寄存器CLK_MUX_STAT_TOP和CLK_MUX_STAT_TOP1的方法来确定值是否设置成功,当然也可以用等待一段时间的方法。

最后设置CLK_DIV_TOP寄存器,其值为0x01215474

@CMU_TOP MUX / DIV

@CLK_SRC_TOP0_VAL= 0x00000110

       ldr   r1,=CLK_SRC_TOP0_VAL

       ldr   r2,=CLK_SRC_TOP0_OFFSET

       str    r1,[r0, r2]

 

       ldr r2, =CLK_MUX_STAT_TOP_OFFSET

       @ldr r3, =0x11111111   

       ldr r3, =CLK_MUX_STAT_TOP_VAL @0x11111221

       bl wait_mux_state

 

@CLK_SRC_TOP1_VAL= 0x01111000

       ldr   r1,=CLK_SRC_TOP1_VAL

       ldr   r2,=CLK_SRC_TOP1_OFFSET

       str    r1,[r0, r2]

      

       ldr r2, =CLK_MUX_STAT_TOP1_OFFSET 

       @ldr r3, =0x01111110

       ldr r3, =CLK_MUX_STAT_TOP1_VAL  @0x02222110

       bl wait_mux_state

      

       @/* wait ?us */

@    mov r1, #0x10000

@1: subs r1, r1, #1

@    bne  1b

 

       ldr   r1,=CLK_DIV_TOP_VAL @0x01215474

       ldr   r2, =CLK_DIV_TOP_OFFSET

       str    r1,[r0, r2]

4、CMU_LEFTBUS MUX / DIV设置

CMU_LEFTBUSCMU的寄器设置和上述过程一样,这里不做过多说明,这里仅给出代码

       ldr   r1,=CLK_SRC_LEFTBUS_VAL

       ldr   r2,=CLK_SRC_LEFTBUS_OFFSET

       str    r1,[r0, r2]

 

       ldr r2, =CLK_MUX_STAT_LEFTBUS_OFFSET

       @ldr r3, =0x00000021

       ldr r3, =CLK_MUX_STAT_LEFTBUS_VAL@0x00000021

       bl wait_mux_state

 

       ldr   r1,=CLK_DIV_LEFRBUS_VAL

       ldr   r2,=CLK_DIV_LEFTBUS_OFFSET

       str    r1,[r0, r2]

5、CMU_RIGHTBUS MUX / DIV设置

CMU_LEFTBUS CMU的寄器设置和上述过程一样,这里不做过多说明,这里仅给出代码.

@ CMU_RIGHTBUS MUX / DIV

ldr   r1,=CLK_SRC_RIGHTBUS_VAL

       ldr   r2,=CLK_SRC_RIGHTBUS_OFFSET

       str    r1,[r0, r2]

 

       ldr r2, =CLK_MUX_STAT_RIGHTBUS_OFFSET

       @ldr r3, =0x00000021

       ldr r3, =CLK_MUX_STAT_RIGHTBUS_VAL  @0x00000021

       bl wait_mux_state

 

       ldr   r1,=CLK_DIV_RIGHTBUS_VAL

       ldr   r2,=CLK_DIV_RIGHTBUS_OFFSET

       str    r1,[r0, r2]

二、设置APLL/MPLL/EPLL/EPLL锁相环锁频时间

翻看手册,P371页,找到PLLCONTROL REGISTERS。

• (APLL_LOCK, R/W, Address =0x1004_0000)

• (MPLL_LOCK, R/W, Address =0x1004_0000)

• (EPLL_LOCK, R/W, Address =0x1003_0000)

• (VPLL_LOCK, R/W, Address =0xE010_0020)


表4-3、PLL寄存器锁定时间

这里出现了一个问题,APLL/MPLL/EPLL/VPLL的锁相环的时间是不一样的,而像S5PC100,频率为667MHz,他的A/M/E/HPLL的锁相环时间均是300us,这个时间一定要查芯片手册,如下截图的表3-4所示每一个寄存器的设置值,里面有完整的说明:





表4-4、xPLL_LOCK寄存器说明


参看上述说明,用如下宏定义先说明设置值

#if defined(CONFIG_CLK_ARM_800_APLL_800)

#define APLL_PDIV            0x3

#if defined(CONFIG_CLK_BUS_DMC_165_330)

#define MPLL_PDIV     0x5

#elifdefined(CONFIG_CLK_BUS_DMC_200_400)

#define MPLL_PDIV     0x3

#elif defined(CONFIG_CLK_BUS_DMC_220_440)

#define MPLL_PDIV     0x3

#endif

#define EPLL_PDIV     0x2

#define VPLL_PDIV     0x3

/* APLL_LOCK     */

#define APLL_LOCK_VAL   (APLL_PDIV * 270)/*  810*/

/* MPLL_LOCK    */

#define MPLL_LOCK_VAL  (MPLL_PDIV * 270)

/* EPLL_LOCK     */

#define EPLL_LOCK_VAL   (EPLL_PDIV * 3000)

/* VPLL_LOCK     */

#define VPLL_LOCK_VAL   (VPLL_PDIV * 3000)

 

接着进行设置,设置方法代码如下,代码的书写方式很明了,这里就不做过多说明。

@ Set PLL locktime

       ldr   r1,=APLL_LOCK_VAL

       ldr   r2,=APLL_LOCK_OFFSET

       str    r1,[r0, r2]

 

       ldr   r1,=MPLL_LOCK_VAL

       ldr   r2,=MPLL_LOCK_OFFSET

       str    r1,[r0, r2]

 

       ldr   r1,=EPLL_LOCK_VAL

       ldr   r2,=EPLL_LOCK_OFFSET

       str    r1,[r0, r2]

 

       ldr   r1,=VPLL_LOCK_VAL

       ldr   r2,=VPLL_LOCK_OFFSET

       str    r1,[r0, r2]

 

在这段代码后才是设置MCU_CPU的分频比的代码。设置值可以查看

P585 页7.9.1.136CLK_DIV_CPU0和7.9.1.137 CLK_DIV_CPU1页的寄存器列表。

由于zthtiny4412_val.h中可以设置其值,这里修改设置的值如下所示,这两个值的设置得以照APLL后的频来决定。不能随便设置,APLL设置好后,即可以知道APLL频率,此后根据CLK_DIV_CPU0和CLK_DIV_CPU1的说明来计算出所需的值进行设置即可,zthtiny4412_val.h中有设置好几类时钟频率的值,如APLL为800MHZ,1000MHZ时的值不一样。

@Set MCU_CPU Ratio

       ldr   r1,=CLK_DIV_CPU0_VAL

       ldr   r2,=CLK_DIV_CPU0_OFFSET

       str    r1,[r0, r2]

       ldr   r1,=CLK_DIV_CPU1_VAL

       ldr   r2,=CLK_DIV_CPU1_OFFSET

       str    r1,[r0, r2]

三、下面的代码就是开始倍频

1、倍频APLL

这个倍频值需根据需求参考手册来时行设置。这里有不同频进行设置,每一个设置值不做过多说明,仅仅说明一下参考位置,设置值P,M,S可以设置寄存器APLL_CON0,如下图所示,其中,其上电初始化后,如果外部的时钟晶振是24MHZ的话,那么其频率为800MHZ。但需要注意的是设置的输出频率范围在21.9MHZ到1400MHZ

且P,M,S的范围在以下的区间如下表4-5所示。


 


表4-5、APLL_CON0设置寄存器值

设置值的可取值,可以查看手册447页,表7-2所示。

查此表当设置值P为3,M为175,S为0时,即可让输出频率为1400MHz.

大家一定会注意到代码里对APLL_CON1也进行了设置,那么APLL_CON1主要设置什么呢,查看手册581页,说实话很多设置值是什么意思我也完全不明白,那么我们怎么设置呢,APLL_CON1说明后面一列给出了默认值,OK,那么我设置的就是这个值,其实如果我们设置成默认值,系列上电就是这个值,应可以根本不用这段代码,直接注释了也行吧?

 

2、倍频MPLL

在倍频MPLL之前,有一小段代码是读取MPLL_CON0的值,来断定其设置值是否已将MPLL设置成不是400MHZ,如果是就不在进行MPLL设置直接调过,进行EPLL设置。这一段代码如下:

/* check MPLL and if MPLL is not 400 Mhzskip MPLL resetting for C2C operation */

ldr   r2,=MPLL_CON0_OFFSET

ldr r1, [r0, r2]

ldr r3, =0xA0640301

cmp r1, r3

bne skip_mpll

上数代码中的魔数为什么是0xA0640301,大家可以对照寄存器设置值,以400MHZ为目标进行设置,即可明白为什么是这个值。即将P,M,S分别设置成100,3,1,然后使能PLL就是这个值。

下面接着倍频MPLL的代码、MPLL的设置寄存器为MPLL_CON0和MPLL_CON1,其中MPLL_CON1设置值保持上电初始化值即可。

@ Set MPLL

ldr   r1,=MPLL_CON1_VAL

ldr   r2,=MPLL_CON1_OFFSET

str    r1,[r0, r2]

ldr   r1,=MPLL_CON0_VAL

ldr   r2,=MPLL_CON0_OFFSET

str    r1,[r0, r2]

skip_mpll:

 

3、倍频EPLL和VPLL

EPLL和VPLL的P/M/S位配置查找方法同上面一样,但要注意的是EPLL和VPLL分别有三个寄存器需要设置,其中EPLL_CON1、EPLL_CON2、APLL_CON1、EPLL_CON2都保持其上电默认值即可。

他们两个寄存器的设置代码如下:

skip_mpll:

@ Set EPLL

       ldr     r1, =EPLL_CON2_VAL

       ldr     r2, =EPLL_CON2_OFFSET

       str     r1, [r0, r2]

       ldr     r1, =EPLL_CON1_VAL

       ldr     r2, =EPLL_CON1_OFFSET

       str     r1, [r0, r2]

       ldr     r1, =EPLL_CON0_VAL

       ldr     r2, =EPLL_CON0_OFFSET

       str     r1, [r0, r2]

 

@ Set VPLL

       ldr     r1, =VPLL_CON2_VAL

       ldr     r2, =VPLL_CON2_OFFSET

       str     r1, [r0, r2]

       ldr     r1, =VPLL_CON1_VAL

       ldr     r2, =VPLL_CON1_OFFSET

       str     r1, [r0, r2]

       ldr     r1, =VPLL_CON0_VAL

       ldr     r2, =VPLL_CON0_OFFSET

       str     r1, [r0, r2]

下面一代代码相当于等待设置,其实现的方法就是等待xPLL_CON0的第29位自动在LOCKOUT时间完后变为1。

wait_pll_lock:

       ldrr1, [r0, r2]

       tstr1, #(1<<29)

       beqwait_pll_lock

       movpc, lr

       ldrr2, =APLL_CON0_OFFSET

       blwait_pll_lock

       ldrr2, =MPLL_CON0_OFFSET

       blwait_pll_lock

       ldrr2, =EPLL_CON0_OFFSET

       blwait_pll_lock

       ldrr2, =VPLL_CON0_OFFSET

       blwait_pll_lock

在分频之前,必须要先选择时钟源,否则怎么分频呢?接下的来代码再一次进行时钟源选择。

4、选择时钟源

选择时钟源的寄存器设置方法和前面介绍的一样,只是这里需根据新的时钟源选择对相应的寄存器值,进行设置,

这一次我们需要选择倍频后的时钟,不然还选择输入的24MHZ时钟能做什么呢?例如CLK_SRC_CPU寄存器,参考芯片手册时钟生成电路框图以APLL以例,查找FOUTAPLL和FINPLL,由图所知,FINPLL是没有倍频的频率,我们要选的是倍频后的,所以应该选择FOUTAPLL,所以寄存器CLK_SRC_CPU的第0位MUX_APLL_SEL应设置成1.同理我们将第24位MUX_MPLL_USER_SEL_C也设置成1,先择倍频后的MPLL,这样,这个寄存器的设置值为0x01000001


图4-2、APPL时钟源选择说明图

表4-6、CLK_SRC_CPU说明


设置完成后,同样读取相应的状态寄存器,和其对应的值进行比较,以确定是否完成设置。状态寄存器的值应是多少,怎么来的这里不再进行说明,大家可以参考前文所述。完成的代码如下:

@reset the clock's souce.

       ldr   r1, =0x01000001

       ldr   r2, =CLK_SRC_CPU_OFFSET

       str    r1, [r0, r2]

 

       ldrr2, =CLK_MUX_STAT_CPU_OFFSET

       ldrr3, =0x02110002

       blwait_mux_state

其他寄存器的设置方法类似,这真是一个很烦琐的工作,希望大家耐心一点,细心一点,一次设置通过,不要因为一位的差错,没有得到相应的输出,还得再来一次,这里这么写也劝勉一下我自己。关于后面设置过程中可能会碰到ONENAND的时钟选择问题,ONENAND用的是什么CLK,在Tiny4412中是没有接ONENADN的吧,我们用的是NANDFLASH,因此,这一位应该可以不配置也行,保持默认值吧。

 

这里说个插曲,这里有一小段代码如下所示,其功能是用来确定所设置的芯片是不是Exynos4412,是就接着设置,不是就直接跳到310_2处执行,这一位置也是此函数的返回位置。

       ldr   r0, =CHIP_ID_BASE @ 0x10000000

       ldr   r1, [r0]

       lsr    r1, r1, #8

       and  r1, r1, #3

       cmp r1, #2

       bne  v310_2

选择完成时钟源后,其实就可以开始进行分频了,但是由于前面的代码我们已将每个相关的寄存器进行了设置,这里就没有必要再进行一次分频设置了。如果大家想看一个系统的过程,可以参考网友“南山一梦”的博文。我是顺着代码分析说明的,过程可能和他的博文设置方式的不太一样,我也是初学,其中很多也不明白,这么写也是希望自己能记住这个过程。下面还是顺着代码说吧,下面的代码是进行C2C(chipto chip)的设置,C2C是什么呢,手册第40章有明确的说明,大家可以好好的看看。


5、Chip to chip /C2C设置

这里需要我们先定义一个宏变量,如果定义了

#ifdef CONFIG_C2C

宏变量,如果定义了这个宏变量再进行C2C设置。

进行C2C设置的第一步是检验第8章中C2C_CTRL的寄存器最后一位是不是为1,检验其是否已经使能了C2C功能,如果使能了就直接完成设置,因为第8章有说明,如果使能了这个值,那个动态内存管理就会利用其默认值来进行自动管理内存。所应就不用单独设置不同的模块了。


如果没有使能就继续进行设置。

其代码如下:

       /* check C2C_CTRL enable bit */

       ldr r3,=S5PV310_POWER_BASE@0x1002_0000   chapter8  page644

       ldr r1, [r3, #C2C_CTRL_OFFSET]@C2C_CTRL_OFFSET=24

       and r1, r1, #1

       cmp r1, #0

       bne v310_2

 

接下来的代码是设置几个相关动态内存管理寄存器。要明白这些代码是如何设置的,弄清楚APB总线等协议,我现在刚开如学,想早点走完一次UBOOT移植工作,这里对这段代码不做过多说明,留下个遗憾,改天再来补充完整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值