#include<commmon.h>
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_TRAB)
#if defined(CONFIG_S3C2400)
#include<s3c2400.h>
#elif defined(CONFIG_S3C2410)
#include<s3c2410.h>
#endif
#define MPLL 0
#define UPLL 1
/*
typedef struct {
S3C24X0_REG32 LOCKTIME; //锁定时间计数寄存器
S3C24X0_REG32 MPLLCON; //MPLL配置寄存器
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
S3C24X0_REG32 CAMDIVN; // for s3c2440, by www.embedsky.net
} S3C24X0_CLOCK_POWER;
*/
//参数pllreg的值要么为0,要么为1,通过0或1来选择是MPLL还是UPLL
static ulong get_PLLCLK(int pllreg)
{
//定义数据机构S3C24X0_CLOCK_POWER的指针clk_power指向数据结构S3C24X0_CLOCK_POWER的起始地址
S3C24X0_CLOCK_POWER *const clk_power= S3C24X0_GetBase_CLOCK_POWER();
//通过p值来对输入频率(Fin)来进行分频的分频器P
//通过m值来对VCO的输出频率进行分频的分频器M
//通过s值来对VCO的输出频率进行分频的分频器S
// MPLL=(2*m*Fin)/(p*(2的s次方))
// m= M (分频器M的值) + 8
// p= P (分频器P的值) + 2
//UPLL和MPLL类似
ulong r,m,p,s;
if(pllreg==MPLL)(
{
r=clk_power->MPLLCON;
}
else if(pllreg==UPLL)
{
r=clk_power->UPLLCON
}
else
{
/*
void hang (void)
{
puts ("### ERROR ### Please RESET the board ###\n");
for (;;);
}
*/
hang();
}
m=((r&0xFF000)>>12)+8;
p=((r&0x003F0)>>4)+2;
s=r&0x3;
if(gd->bd->bi_arch_number==MACH_TYPE_SMDK2410)
{
return((CONFIG_SYS_CLK_FREQ *m)/(p<<s));
}
else
{
return((CONFIG_SYS_CLK_FREQ *m*2)/(p<<s));
}
}
ulong get_FCLK(void)
{
return(get_PLLCLK(MPLL));
}
#define S3C2440_CLKDIVN_PDIVN (1<<0)
#define S3C2440_CLKDIVN_HDIVN_MASK (3<<1)
#define S3C2440_CLKDIVN_HDIVN_1 (0<<1)
#define S3C2440_CLKDIVN_HDIVN_2 (1<<1)
#define S3C2440_CLKDIVN_HDIVN)4_8 (2<<1)
#define S3C2440_CLKDIVN_HDIVN_3_6 (3<<1)
#define S3C2440_CLKDIVN_UCLK (1<<3)
#define S3C2440_CAMDIVN_CAMCLK_MASK (0xf<<0)
#define S3C2440_CAMDIVN_CAMCLK_SEL (1<<4)
#define S3C2440_CAMDIVN_HCLK3_HALF (1<<8)
#define S3C2440_CAMDIVN_HCLK4_HALF (1<<9)
#define S3C2440_CAMDIVN_DVSEN (1<<12)
ulong get_HCLK(void)
{
S3C24X0_CLOCK_POWER *const clk_power = S3C24X0_GetBase_CLOCK_POWER();
unsigned long clkdiv;
unsigned long camdiv;
int hdiv = 1;
if(gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
{
//时钟分频控制寄存器CLKDIVN[2:1]可知HCLK与FCLK的关系
return((clk_power->CLKDIVN&0x2)?get_FCLK()/2:get_FCLK());
}
else
{
clkdiv=clk_power->CLKDIVN; //指向时钟分频控制器
camdiv=clk_power->CAMDIVN; //指向摄像头时钟分频控制器
switch(clkdiv & S3C2440_CLKDIVN_HDIVN_MASK)
{
case S3C2440_CLKDIVN_HDIVN_1:
hdiv=1;
break;
case S3C2440_CLKDIVN_HDIVN_2:
hdiv=2;
break;
case SeC2440_CLKDIVN_HDIVN_4_8:
hdiv=(camdiv & S3c2440_CAMDIVN_HCLK4_HALF)?8:4;
break;
case S3C2440_CLKDIVN_HDIVN_3_6:
hdiv=(camdiv * S3C2440_CAMDIVN_HCLK3_HALF)?6:3;
break;
}
return get_FCLK()/hdiv;
}
}
ulong get_PCLK(void)
{
S3C24X0_CLOCK_POWER *const clk_power=S3C24X0_GetBase_CLOCK_POWER();
unsigned long clkdiv;
unsigned long camdiv;
int hdiv=1;
if(gd->bd->bi_arch_number==MACH_TYPE_SMDK2410)
{
return((clk_power->CLKDIVN & 0x1)?get_HCLK()/2:get_HCLK());
}
else
{
clkdiv=clk_power->CLKDIVN;
camdiv=clk_power->CAMDIVN;
switch(clkdiv & S3C2440_CLKDIVN_HDIVN_MASK)
{
case S3C2440_CLKDIVN_HDIVN_1:
hdiv=1;
break;
case S3C2440_CLKDIVN_HDIVN_2:
hdiv=2;
break;
case S3C2440_CLKDIVN_HDIVN_4_8:
hdiv=(camdiv & S3C2440_CAMDIVN_HCLK4_HALF)?8:4;
break;
case S3C2440_CLKDIVN_HDIVN_3_6:
hdiv=(camdiv & S3C2440_CAMDIVN_HCLK4_HALF)?6:3;
break;
}
return get_FCLK()/hdiv/((clkdiv&S3C2440_CLKDIVN_PDIVN)?2:1);
}
}
ulong get_UCLK(void)
{
return(get_PLLCLK(UPLL));
}
#endif
/*
注:MPLL提供最终的CPU核使用度时钟FCLK
UPLL提供最终的USB使用的时钟UCLK=48MHz
锁定时间计数寄存器LOCKTIME的作用就是:CPU刚上电,MPLL不会立即工作(不稳定),所以要等待MPLL稳定后才能使用作为CPU时钟
FCLK:CPU内核使用的时钟
HCLK:CPU高速外设使用的时钟
FCLK:CPU低速外设使用的时钟
UCLK:USB,CAMERA使用的时钟
设定FCLK核UCLK完全是由MPLLCON和UPLLCON来决定的,具体牵扯到MDIV,PDIV,SDIV,计算公式如下:
FCLK/UCLK=(2*m*Fin)/(p*(2的s次方))
HCLK,PCLK与FLCK的关系是由时钟分频控制寄存器CLKDIVN[2:1],[0]的相应值和CAMDIVN[9],[8]联合作用的
UCLK,的值是由CLKDIVN[3]的值来决定的
*/