/***************************************************************************
* *
* Copyright (c) 2008 Nuvoton Technolog. All rights reserved. *
* *
***************************************************************************/
/****************************************************************************
*
* FILENAME : wb_config.c
*
* VERSION : 1.1
*
* DESCRIPTION :
* PLL control functions of Nuvoton ARM9 MCU
*
* HISTORY
*
*
* IBR set clocks default value
* UPLL= 240MHz
* SYS = 120MHz
* CPU = 60MHz
* HCLK = 60MHz
*
*
*
*
****************************************************************************/
#include <string.h>
#include "wblib.h"
#if 0
WB_PLL_T _sysClock;
WB_CLKFREQ_T _sysFreq; //MHz, added on [2009/03/11]
#endif
//static _sysClockIniFlag = FALSE;
static UINT32 g_u32SysClkSrc;
static UINT32 g_u32UpllKHz = 240000, g_u32ApllKHz=240000, g_u32SysKHz = 120000, g_u32CpuKHz = 60000, g_u32HclkKHz = 60000;
static UINT32 g_u32Hclk1KHz, g_u32ApbKHz;
static UINT32 g_u32REG_APLL, g_u32REG_UPLL;
static UINT32 g_u32SysDiv, g_u32CpuDiv, g_u32ApbDiv;
BOOL bIsCpuOver2xHclk = FALSE;
static UINT32 g_u32ExtClk = 27000;
#define PD_RAM_BASE 0xFF000000
#define PD_RAM_SIZE 0x1000
extern UINT8 _tmp_buf[];
//#define DBG_PRINTF sysprintf
#define DBG_PRINTF(...)
void InitDelay(void)
{
}
void sysInitDDR(void)
{
UINT32 u32Delay;
outp32( 0xb0000224, 0x00000E6E);
outp32( 0xb0000220, 0x1008CE6E);
outp32( 0xb000020C, 0x00000019);
outp32( 0xb0003030, 0x00001010);
outp32( 0xb0003010, 0x00000005);
outp32( 0xb0003004, 0x00000021);
outp32( 0xb0003004, 0x00000023);
outp32( 0xb0003004, 0x00000027);
while(inp32(0xb0003004) & BIT2);
outp32( 0xb000301C, 0x00001002);
outp32( 0xb0003018, 0x00000122);
outp32( 0xb0003004, 0x00000027);
while(inp32(0xb0003004) & BIT2);
outp32( 0xb0003004, 0x0000002B);
while(inp32(0xb0003004) & BIT3);
outp32( 0xb0003004, 0x0000002B);
while(inp32(0xb0003004) & BIT3);
outp32( 0xb0003018, 0x00000022);
u32Delay=250;
while(u32Delay--);
outp32( 0xb0003004, 0x00000020);
outp32( 0xb0003034, 0x00AAAA00);
outp32( 0xb0003008, 0x000080C0);
outp32( 0xb00000A0, 0x00000000);
}
void sysInitDDRStart(void)
{
UINT32 vram_base, aic_status = 0;
VOID (*wb_func)(void);
aic_status = inpw(REG_AIC_IMR); //Disable interrupt
outpw(REG_AIC_MDCR, 0xFFFFFFFF);
/*
void sysInitDDR(void)
*/
vram_base = PD_RAM_BASE;
memcpy((char *)_tmp_buf, (char *)vram_base, PD_RAM_SIZE); //Backup RAM content
memcpy((VOID *)vram_base,(VOID *)sysInitDDR, PD_RAM_SIZE); //
// Entering clock switch function
wb_func = (void(*)(void)) vram_base;
DBG_PRINTF("Jump to SRAM\n");
wb_func();
//wb_func(eSrcClk, u32Hclk, bIsUp2Hclk3X, u32SysDiv);
//Restore VRAM
memcpy((VOID *)vram_base, (VOID *)_tmp_buf, PD_RAM_SIZE);
outpw(REG_AIC_MDCR, 0xFFFFFFFF); // Disable all interrupt
outpw(REG_AIC_MECR, aic_status); // Restore AIC setting
}
/*-----------------------------------------------------------------------------------------------------------
*
* Function : sysInitMemory
*
* DESCRIPTION :
* According to the external clock and expected PLL output clock to get the content of PLL controll register
*
* Parameters
* eSysPll : eSYS_APLL or eSYS_UPLL
* u32FinKHz: External clock. Unit: KHz
* Return
* PLL clock.
* HISTORY
* 2010-07-15
*
-----------------------------------------------------------------------------------------------------------*/
UINT32 sysInitMemory(void)
{
sysInitDDRStart();
return 0;
}
/*-----------------------------------------------------------------------------------------------------------
*
* Function : sysGetPLLOutputKhz
*
* DESCRIPTION :
* According to the external clock and expected PLL output clock to get the content of PLL controll register
*
* Parameters
* eSysPll : eSYS_APLL or eSYS_UPLL
* u32FinKHz: External clock. Unit: KHz
* Return
* PLL clock.
* HISTORY
* 2010-07-15
*
-----------------------------------------------------------------------------------------------------------*/
UINT32 sysGetPLLOutputKhz(
E_SYS_SRC_CLK eSysPll,
UINT32 u32FinKHz
)
{
UINT32 u32Freq, u32PllCntlReg;
UINT32 NF, NR, NO;
UINT8 au8Map[4] = {1, 2, 2, 4};
if(eSysPll==eSYS_APLL)
u32PllCntlReg = inp32(REG_APLLCON);
else if(eSysPll==eSYS_UPLL)
u32PllCntlReg = inp32(REG_UPLLCON);
if(u32PllCntlReg&0x10000) //PLL power down.
return 0;
NF = (u32PllCntlReg&FB_DV)+2;
NR = ((u32PllCntlReg & IN_DV)>>9)+2;
NO = au8Map[((u32PllCntlReg&OUT_DV)>>14)];
DBG_PRINTF("PLL regster = 0x%x\n", u32PllCntlReg);
DBG_PRINTF("NF = %d\n", NF);
DBG_PRINTF("NR = %d\n", NR);
DBG_PRINTF("NO = %d\n", NO);
u32Freq = u32FinKHz*NF/NR/NO;
DBG_PRINTF("PLL Freq = %d\n", u32Freq);
return u32Freq;
}
volatile BOOL bIsCheckPllConstraint = FALSE;
void sysCheckPllConstraint(BOOL bIsCheck)
{
bIsCheckPllConstraint = bIsCheck;
}
/*-----------------------------------------------------------------------------------------------------------
*
* Function : sysGetPLLControlRegister
*
* DESCRIPTION :
* According to the external clock and expected PLL output clock to get the content of PLL controll register
*
* Parameters
* u32FinKHz : External clock. Unit:KHz
* u32TargetKHz: PLL output clock. Unit:KHz
* Return
* 0 : No any fit value for the specified PLL output clock
* PLL control register.
* HISTORY
* 2010-07-15
*
-----------------------------------------------------------------------------------------------------------*/
UINT32 sysGetPLLControlRegister(UINT32 u32FinKHz, UINT32 u32TargetKHz)
{
unsigned int u32OUT_DV, u32IN_DV, u32FB_DV;
unsigned int u32NR, u32NF, u32NO;
unsigned int au32Array[4] = {1 , 2, 2, 4};
unsigned u32Target;
unsigned int u23Register=0;
do
{
for(u32OUT_DV =0 ; u32OUT_DV<4; u32OUT_DV=u32OUT_DV+1)
{
for(u32IN_DV =0 ; u32IN_DV<32; u32IN_DV=u32IN_DV+1)
{
for(u32FB_DV =0 ; u32FB_DV<512; u32FB_DV=u32FB_DV+1)
{
u32NR = (2 * (u32IN_DV + 2));
u32NF = (2 * (u32FB_DV + 2));
u32NO = au32Array[u32OUT_DV];
if( (u32FinKHz/u32NR)<1000 )
continue;
if( (u32FinKHz/u32NR)>15000)
continue;
if( ((u32FinKHz/u32NR)*u32NF) <100000)
continue;
if( ((u32FinKHz/u32NR)*u32NF) >500000)
continue;
u32Target = u32FinKHz*u32NF/u32NR/u32NO;
if(u32TargetKHz==u32Target)
{
u23Register = (u32OUT_DV<<14) | (u32IN_DV<<9) | (u32FB_DV);
return u23Register;
}
if(bIsCheckPllConstraint==TRUE)
{
unsigned int u32VerifyFout;
DBG_PRINTF("===================================================\n");
if((u32FinKHz*u32NF/u32NR)<250000)
DBG_PRINTF("Frequency is preferred");
DBG_PRINTF("Frequency out = %d\n", u32Fout);
u23Register = (u32OUT_DV<<14) | (u32IN_DV<<9) | (u32FB_DV);
DBG_PRINTF("Register = 0x%x\n", u23Register);
u32VerifyFout = sysGetPLLOutputKhz(u32FinKHz, u23Register);
DBG_PRINTF("Verify Fout = %d KHz\n", u32VerifyFout);
}
}
}
}
u32TargetKHz = u32TargetKHz -4000; //- 4MHz
}while((u23Register==0));
return 0;
}
/*-----------------------------------------------------------------------------------------------------------
* Function: sysSetPLLControlRegister
*