📄 hw_pll.c
字号:
/*********************************************************************************
* Copyright (C),2004-2005, Fuzhou Rockchip Co.,Ltd.
* All Rights Reserved
* V1.00
* FileName : Hw_pll.c
* Author : lzy
* Description:
* History :
* <author> <time> <version> <desc>
* lzy 07/6/29 1.0 ORG
*
$Log: Hw_pll.c,v $
Revision 1.3 2008/07/15 02:09:25 Administrator
HSL PLL BUG 更新!
Revision 1.2 2008/06/19 04:43:29 Administrator
代码整理!
Revision 1.1.1.1 2008/05/07 04:15:08 Administrator
no message
Revision 1.1.1.1 2008/03/06 13:29:04 Lingzhaojun
no message
Revision 1.1.1.1 2007/12/21 02:34:33 Lingzhaojun
12.21
Revision 1.1.1.1 2007/12/11 14:19:28 cvsadmin
no message
Revision 1.1.1.1 2007/12/01 01:30:06 Lingzhaojun
no message
Revision 1.9 2007/11/26 14:48:22 Huangxinyu
提交lzy的修改
Revision 1.8 2007/11/24 01:24:38 Hanjiang
pmu提交
Revision 1.7 2007/11/23 07:32:10 Huangshilin
no message
Revision 1.6 2007/11/10 04:21:32 Huangxinyu
调试修改
Revision 1.5 2007/10/23 08:22:10 Huangxinyu
调试后修改bug
Revision 1.4 2007/10/15 09:03:25 Huangxinyu
根据RK27提交修改driver
Revision 1.3 2007/10/08 02:38:39 Lingzhaojun
添加版本自动注释脚本
*********************************************************************************/
#include "include.h"
#include "Hw_include.h"
#include "Hw_scu.h"
#include "hw_pll.h"
#define pSCUReg ((pSCUReg_t)APB0_SCU_BASE)
#define ASM_LOOP_INSTRUCTION_NUM 4
#define ASM_LOOP_PER_US (Pll_get_arm_freq()/ASM_LOOP_INSTRUCTION_NUM)
chip_freq_t chip_freq = {200, 0, 0, HCLK_DIV2, PCLK_DIV2};
/**************************************************************************
* 函数名称: Pll_PowerDown
* 函数描述: Pll_PowerDown
* 入口参数: PLL_Select_t PLL 通道号
* 出口参数: 无
* 返回值: 无
* 注释:
***************************************************************************/
void Pll_PowerDown(PLL_Select_t pll_select)
{
addr_t plladdr;
plladdr = (addr_t)(&pSCUReg->SCU_PLLARM + pll_select);
if (PLL_DSP == pll_select)
{
chip_freq.dsp_freq = 0x00;
}
else if (PLL_AUX == pll_select)
{
chip_freq.aux_freq = 0x00;
}
SetRegBits32(plladdr, PLL_PD);
}
/**************************************************************************
* 函数名称: Pll_SetFrequence
* 函数描述: 设置PLL 的频率
* 入口参数: PLL_Select_t PLL 通道号
nMHz : PLL 的频率
* 出口参数: 无
* 返回值: 无
* 注释:
***************************************************************************/
void Pll_SetFrequence(PLL_Select_t pll_select, UINT32 nMHz)
{
addr_t plladdr;
UINT32 tmp, pll_lock;
plladdr = (addr_t)(&pSCUReg->SCU_PLLARM + pll_select);
pll_lock = 0x01 << pll_select;
if (ReadReg32(plladdr) & PLL_PD)
{
ClrRegBits32(plladdr, PLL_PD);
USDELAY(100);
}
#if 0
if (nMHz == 24)
{
WriteReg32(plladdr, PLL_SBE | PLL_EN | PLL_BYPASS);
}
else if ((nMHz <= 24) && (24 % nMHz == 0))
{
tmp = 24 / nMHz;
WriteReg32(plladdr, PLL_SBE | PLL_EN | PLL_BYPASS | (tmp - 1) << CLKOD_SHIFT);
}
else if (nMHz > 24)
{
if (nMHz < 33) // 25M ~ 33M vco= 100 ~ 132
{
WriteReg32(plladdr, PLL_SBE | PLL_EN | ((6 - 1) << CLKR_SHIFT) | ((nMHz - 1) << CLKF_SHIFT) | ((4 - 1) << CLKOD_SHIFT));
}
if (nMHz < 50) // 33 ~ 49, vco = 99 ~ 147
{
WriteReg32(plladdr, PLL_SBE | PLL_EN | ((8 - 1) << CLKR_SHIFT) | ((nMHz - 1) << CLKF_SHIFT) | ((3 - 1) << CLKOD_SHIFT));
}
else if (nMHz < 100) // 50M ~ 99M, vco = 100 ~ 198
{
WriteReg32(plladdr, PLL_SBE | PLL_EN | ((12 - 1) << CLKR_SHIFT) | ((nMHz - 1) << CLKF_SHIFT) | ((2 - 1) << CLKOD_SHIFT));
}
else // 100M ~ 200M
{
WriteReg32(plladdr, PLL_SBE | PLL_EN | ((24 - 1) << CLKR_SHIFT) | ((nMHz - 1) << CLKF_SHIFT) | ((1 - 1) << CLKOD_SHIFT));
}
delay_nops(5000); // delay 500 cycles @24M
while ((ReadReg32(&pSCUReg->SCU_STATUS) & pll_lock) == 0)
delay_nops(100);
}
else
{
WriteReg32(plladdr, PLL_SBE | PLL_PD);
}
#else
//FIRST ,ENTER BYPASS
//WriteReg32(plladdr, PLL_SBE|PLL_EN|PLL_BYPASS);
//080711,huangsl,目前来说,小于 24M的情况可以直接按 24M处理,BYPASS.
//另外根据DATA SHEET和实际应用,最好保证 vco=Rfef/Nr*Nf在 120M--240M之间.
//此范围之外,会发生未知结果.
if(nMHz <= 24)
{
WriteReg32(plladdr, PLL_SBE|PLL_EN|PLL_BYPASS);
}
else
{
INT32U nfClk = nMHz*2;
if(nMHz < 30 ) // 25M ~ 29 vco= 200 ~ 240
{
WriteReg32(plladdr, PLL_SBE|PLL_EN|((6-1)<<CLKR_SHIFT)|((nfClk-1)<<CLKF_SHIFT)|((8-1)<<CLKOD_SHIFT));
}
else if(nMHz < 40) // 30 ~ 39, vco = 180 ~ 240
{
WriteReg32(plladdr, PLL_SBE|PLL_EN|((8-1)<<CLKR_SHIFT)|((nfClk-1)<<CLKF_SHIFT)|((6-1)<<CLKOD_SHIFT));
}
else if(nMHz < 60) // 40M ~ 59M, vco = 160 ~ 240
{
WriteReg32(plladdr, PLL_SBE|PLL_EN|((12-1)<<CLKR_SHIFT)|((nfClk-1)<<CLKF_SHIFT)|((4-1)<<CLKOD_SHIFT));
}
else if (nMHz < 120) // 60M ~ 120M , VCO = 120 ~ 240
{
WriteReg32(plladdr, PLL_SBE|PLL_EN|((24-1)<<CLKR_SHIFT)|((nfClk-1)<<CLKF_SHIFT)|((2-1)<<CLKOD_SHIFT));
}
else // 120 ~ 240 , VCO = 120 ~ 240
{
WriteReg32(plladdr, PLL_SBE|PLL_EN|((24-1)<<CLKR_SHIFT)|((nMHz-1)<<CLKF_SHIFT)|((1-1)<<CLKOD_SHIFT));
}
//大概 0.3MS后处于稳定状态.
delay_nops(5000); // delay 500 cycles @24M
nfClk = 200000;
while( nfClk-->0 )
{
if( (ReadReg32(&pSCUReg->SCU_STATUS) & pll_lock) )
break;
delay_nops(100);
}
//while((ReadReg32(&pSCUReg->SCU_STATUS) & pll_lock) == 0)
// delay_nops(100);
//LAST CHANGE TO NORMAL PLL.
//ClrRegBits32(plladdr, PLL_BYPASS);
}
#endif
}
/**************************************************************************
* 函数名称: Pll_SetARMFreq
* 函数描述: 设置ARM PLL 和AHB APB的频率
* 入口参数: nMHz PLL 的频率
HCLK_div : AHB 分频值
PCLK_div : APB 分频值
* 出口参数: 无
* 返回值: 无
* 注释:
***************************************************************************/
void Pll_SetARMFreq(UINT32 nMHz, HCLK_Divider_t HCLK_div, PCLK_Divider_t PCLK_div)
{
UINT32 hclk_div, pclk_div;
UINT32 hclk, pclk;
INT32U byPass = 0;
if (nMHz > Max_ARM_Freq)
nMHz = Max_ARM_Freq;
if (nMHz < Min_ARM_Freq)
nMHz = Min_ARM_Freq;
hclk = nMHz >> HCLK_div;
pclk = hclk >> PCLK_div;
if (hclk <= Min_HCLK_Freq)
{
HCLK_div = HCLK_DIV1;
hclk = nMHz >> HCLK_div;
}
if (hclk > Max_HCLK_Freq)
{
HCLK_div = HCLK_DIV2;
}
if (pclk <= Min_PCLK_Freq)
{
PCLK_div = PCLK_DIV1;
pclk = hclk >> PCLK_div;
}
if (pclk > Max_PCLK_Freq)
{
PCLK_div = PCLK_DIV2;
}
if ((chip_freq.arm_freq == nMHz)
&& (chip_freq.ahb_div == HCLK_div)
&& (chip_freq.apb_div == PCLK_div))
return;
chip_freq.ahb_div = HCLK_div;
// because display will discontinues when switch to slow mode in RGB Panel, so remove following
//080711,huangsl,增加在 关闭背光的情况下进入 BYPASS模式(主要因为RGB会抖动).另外,由于 全局变量
// gSysState 可能在过程中背修改,所以增加 局部变量 byPass 来标记.
#ifdef RGB_PANEL //MCU 屏下,可以进入 SLOW 模式,大概时间为 0.3MS.
if(gSysState&SYS_LCD_OFF)
#endif
{
byPass = 1;
MaskRegBits32(&pSCUReg->SCU_DIVCON, ARM_SLOW_MASK, ARM_SLOW);
delay_nops(100);
MaskRegBits32(&pSCUReg->SCU_DIVCON, HCLK_MASK | PCLK_MASK | ARM_SLOW_MASK, PCLK_DIV1 | HCLK_DIV1 | ARM_SLOW);
delay_nops(100);
}
if (HCLK_DIV1 == HCLK_div)
Pll_SetFrequence(PLL_ARM, nMHz << 1);
else
Pll_SetFrequence(PLL_ARM, nMHz);
// while((ReadReg32(&pSCUReg->SCU_STATUS) & 0x08) != 0x08)
// delay_nops(100);
HCLK_div = (HCLK_DIV1 == HCLK_div) ? 0x01 : 0x00;
MaskRegBits32(&pSCUReg->SCU_DIVCON, PCLK_MASK | HCLK_MASK,
(HCLK_div << HCLK_SHIHL) | (PCLK_div << PCLK_SHIHL));
if( byPass )
{
MaskRegBits32(&pSCUReg->SCU_DIVCON, ARM_SLOW_MASK, ARM_NORMAL);
delay_nops(50);
}
chip_freq.arm_freq = nMHz;
chip_freq.apb_div = PCLK_div;
}
/**************************************************************************
* 函数名称: Pll_SetDSPFreq
* 函数描述: 设置DSP PLL 的频率
* 入口参数: nMHz PLL 的频率
* 出口参数: 无
* 返回值: 无
* 注释:
***************************************************************************/
void Pll_SetDSPFreq(UINT32 nMHz)
{
if (chip_freq.dsp_freq == nMHz)
return;
if (nMHz >= Max_DSP_Freq)
nMHz = Max_DSP_Freq;
if (nMHz <= Min_DSP_Freq)
nMHz = Min_DSP_Freq;
MaskRegBits32(&pSCUReg->SCU_DIVCON, DSP_SLOW_MASK, DSP_SLOW);
delay_nops(100);
Pll_SetFrequence(PLL_DSP, nMHz);
DelayMs_nops(1);
// while((ReadReg32(&pSCUReg->SCU_STATUS) & 0x10) != 0x10)
// delay_nops(100);
MaskRegBits32(&pSCUReg->SCU_DIVCON, DSP_SLOW_MASK, DSP_NORMAL);
delay_nops(100);
chip_freq.dsp_freq = nMHz;
}
/**************************************************************************
* 函数名称: Pll_SetAUXFreq
* 函数描述: 设置AUX PLL 的频率
* 入口参数: nKHz PLL 的频率
* 出口参数: 无
* 返回值: 无
* 注释:
***************************************************************************/
void Pll_SetAUXFreq(UINT32 nKHz)
{
}
/**************************************************************************
* 函数名称: Pll_get_dsp_freq
* 函数描述: 得到dsp 的主频值
* 入口参数: 无
* 出口参数: DSP 的频, MHz 为单位
* 返回值: 无
* 注释:
***************************************************************************/
UINT32 Pll_get_dsp_freq(void)
{
return (UINT32)chip_freq.dsp_freq;
}
/**************************************************************************
* 函数名称: Pll_get_arm_freq
* 函数描述: 得到arm 的主频值
* 入口参数: 无
* 出口参数: arm 的频率, MHz 为单位
* 返回值: 无
* 注释:
***************************************************************************/
UINT32 Pll_get_arm_freq(void)
{
return (UINT32)chip_freq.arm_freq;
}
/**************************************************************************
* 函数名称: Pll_get_ahb_freq
* 函数描述: 得到AHB 的主频值
* 入口参数: 无
* 出口参数: AHB 的频率, MHz 为单位
* 返回值: 无
* 注释:
***************************************************************************/
UINT32 Pll_get_ahb_freq(void)
{
UINT32 tmp;
tmp = Pll_get_arm_freq() >> chip_freq.ahb_div;
return tmp;
}
/**************************************************************************
* 函数名称: Pll_get_apb_freq
* 函数描述: 得到APB 的主频值
* 入口参数: 无
* 出口参数: APB 的频率, KHz 为单位
* 返回值: 无
* 注释:
***************************************************************************/
UINT32 Pll_get_apb_freq(void)
{
UINT32 tmp;
tmp = Pll_get_arm_freq() * 1000 >> chip_freq.ahb_div >> chip_freq.apb_div;
return tmp;
}
/**************************************************************************
* 函数名称: DelayMs_nops
* 函数描述: 软件延时
* 入口参数: msec
* 出口参数: 无
* 返回值: 无
* 注释:
***************************************************************************/
void DelayMs_nops(UINT32 msec)
{
unsigned int us;
us = msec * 1000 * ASM_LOOP_PER_US;
while (--us) {}
}
/**************************************************************************
* 函数名称: USDELAY
* 函数描述: 软件延时
* 入口参数: usec
* 出口参数: 无
* 返回值: 无
* 注释:
***************************************************************************/
void USDELAY(UINT32 usec)
{
unsigned int tmp;
tmp = usec * ASM_LOOP_PER_US;
while (--tmp) {}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -