⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hw_pll.c

📁 瑞星微公司RK27XX系列芯片的SDK开发包
💻 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 + -