📄 sysc.c
字号:
/**************************************************************************************
*
* Project Name : S3C6410 Validation
*
* Copyright 2006 by Samsung Electronics, Inc.
* All rights reserved.
*
* Project Description :
* This software is only for validating functions of the S3C6410.
* Anybody can use this software without our permission.
*
*--------------------------------------------------------------------------------------
*
* File Name : sysc.c
*
* File Description : This file implements the API functons for system controller.
*
* Author : Haksoo,Kim
* Dept. : AP Development Team
* Created Date : 2006/11/08
* Version : 0.1
*
* History
* - Created(Haksoo,Kim 2006/11/08)
* - Added sfr (Wonjoon.Jang 2007/01/08)
*
**************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "option.h"
#include "library.h"
#include "sfr6410.h"
#include "system.h"
#include "gpio.h"
#include "sysc.h"
//
#define rAPLL_LOCK (SYSCON_BASE+0x000)
#define rMPLL_LOCK (SYSCON_BASE+0x004)
#define rEPLL_LOCK (SYSCON_BASE+0x008)
#define rAPLL_CON (SYSCON_BASE+0x00c)
#define rMPLL_CON (SYSCON_BASE+0x010)
#define rEPLL_CON0 (SYSCON_BASE+0x014)
#define rEPLL_CON1 (SYSCON_BASE+0x018)
#define rCLK_SRC (SYSCON_BASE+0x01c)
#define rCLK_DIV0 (SYSCON_BASE+0x020)
#define rCLK_DIV1 (SYSCON_BASE+0x024)
#define rCLK_DIV2 (SYSCON_BASE+0x028)
#define rCLK_OUT (SYSCON_BASE+0x02c)
#define rHCLK_GATE (SYSCON_BASE+0x030)
#define rPCLK_GATE (SYSCON_BASE+0x034)
#define rSCLK_GATE (SYSCON_BASE+0x038)
//
#define rAHB_CON0 (SYSCON_BASE+0x100)
#define rAHB_CON1 (SYSCON_BASE+0x104)
#define rAHB_CON2 (SYSCON_BASE+0x108)
#define rSDMA_SEL (SYSCON_BASE+0x110)
#define rSW_RST (SYSCON_BASE+0x114)
#define rSYS_ID (SYSCON_BASE+0x118)
#define rMEM_SYS_CFG (SYSCON_BASE+0x120)
#define rQOS_OVERRIDE0 (SYSCON_BASE+0x124)
#define rQOS_OVERRIDE1 (SYSCON_BASE+0x128)
#define rMEM_CFG_STAT (SYSCON_BASE+0x12c)
//
#define rPWR_CFG (SYSCON_BASE+0x804)
#define rEINT_MASK (SYSCON_BASE+0x808)
#define rNORMAL_CFG (SYSCON_BASE+0x810)
#define rSTOP_CFG (SYSCON_BASE+0x814)
#define rSLEEP_CFG (SYSCON_BASE+0x818)
#define rOSC_FREQ (SYSCON_BASE+0x820)
#define rOSC_STABLE (SYSCON_BASE+0x824)
#define rPWR_STABLE (SYSCON_BASE+0x828)
#define rFPC_STABLE (SYSCON_BASE+0x82c)
#define rMTC_STABLE (SYSCON_BASE+0x830)
//
#define rOTHERS (SYSCON_BASE+0x900)
#define rRST_STAT (SYSCON_BASE+0x904)
#define rWAKEUP_STAT (SYSCON_BASE+0x908)
#define rBLK_PWR_STAT (SYSCON_BASE+0x90c)
#define rINFORM0 (SYSCON_BASE+0xA00)
#define rINFORM1 (SYSCON_BASE+0xA04)
#define rINFORM2 (SYSCON_BASE+0xA08)
#define rINFORM3 (SYSCON_BASE+0xA0c)
#define rINFORM4 (SYSCON_BASE+0xA10)
#define rINFORM5 (SYSCON_BASE+0xA14)
#define rINFORM6 (SYSCON_BASE+0xA18)
#define rINFORM7 (SYSCON_BASE+0xA1c)
u32 g_System_ID;
u8 g_System_Revision, g_System_Pass, g_SYNCACK;
u32 g_APLL, g_MPLL, g_ARMCLK, g_HCLKx2, g_HCLK, g_PCLK;
//////////
// Function Name : SYSC_ReadSystemID
// Function Description : This function reads system ID register
// Input : NONE
// Output : NONE
// Version :
void SYSC_ReadSystemID(void)
{
u32 temp;
temp = Inp32(rSYS_ID);
g_System_ID = (temp>>8)&0xffffff;
g_System_Revision = (temp>>4)&0xf;
g_System_Pass = (temp)&0xf;
return;
}
//////////
// Function Name : SYSC_GetClkInform
// Function Description : This function gets common clock information
// Input : NONE
// Output : NONE
// Version :
void SYSC_GetClkInform( void)
{
u8 muxApll, muxMpll, muxSync;
u8 divApll, divHclkx2, divHclk, divPclk;
u16 pllM, pllP, pllS;
u32 temp;
////
// clock division ratio
temp = Inp32(rCLK_DIV0);
divApll = temp & 0xf;
divHclkx2 = (temp>>9) & 0x7;
divHclk = (temp>>8) & 0x1;
divPclk = (temp>>12) & 0xf;
////
// Operating Mode
temp = Inp32(rOTHERS);
temp = (temp>>8)&0xf;
if(temp)
{
g_SYNCACK = 1;
}
else
{
g_SYNCACK = 0;
}
////
// ARMCLK
muxApll = Inp32(rCLK_SRC) & 0x1;
if(muxApll) //FOUT
{
temp = Inp32(rAPLL_CON);
pllM = (temp>>16)&0x3ff;
pllP = (temp>>8)&0x3f;
pllS = (temp&0x7);
g_APLL = ((FIN>>pllS)/pllP)*pllM;
}
else //FIN
{
g_APLL = FIN;
}
g_ARMCLK = g_APLL/(divApll+1);
////
// HCLK
muxSync = (Inp32(rOTHERS)>>7) & 0x1;
if(muxSync) //synchronous mode
{
g_HCLKx2 = g_APLL/(divHclkx2+1);
temp = Inp32(rMPLL_CON);
pllM = (temp>>16)&0x3ff;
pllP = (temp>>8)&0x3f;
pllS = (temp&0x7);
g_MPLL = ((FIN>>pllS)/pllP)*pllM;
}
else
{
muxMpll = (Inp32(rCLK_SRC)>>1) & 0x1;
if(muxMpll) //FOUT
{
temp = Inp32(rMPLL_CON);
pllM = (temp>>16)&0x3ff;
pllP = (temp>>8)&0x3f;
pllS = (temp&0x7);
g_MPLL = ((FIN>>pllS)/pllP)*pllM;
}
else //FIN
{
g_MPLL = FIN;
}
g_HCLKx2 = g_MPLL/(divHclkx2+1);
}
g_HCLK = g_HCLKx2/(divHclk+1);
////
// PCLK
g_PCLK = g_HCLKx2/(divPclk+1);
return;
}
//////////
// Function Name : SYSC_SetPLL
// Function Description : This function control PLL Output Frequency (APLL, MPLL:PLL9025X, EPLL:PLL9024X)
// Fout = (mdiv * Fin) / (pdiv x 2^sdiv), Fout = ((mdiv+k/2^16) * Fin) / (pdiv x 2^sdiv)
// Input : ePLL : APLL, MPLL, EPLL
// uMdiv : Mdiv Value ( 56 ~ 1023), ( 13 ~ 255)
// uPdiv : Pdiv Value ( 1~63)
// uSdiv : Sdiv Value ( 0~5 )
// uKdiv : PLL9025X (Not Used, 0), PLL9024X(0~65535)
// Output : NONE
// Version :
void SYSC_SetPLL(PLL_eTYPE ePLL, u32 uMdiv, u32 uPdiv, u32 uSdiv, u32 uKdiv)
{
u32 temp, uRegValue;
switch(ePLL)
{
case eAPLL:
// Check the Divider Value.
if( uMdiv < 56 || uMdiv > 1023)
{
printf(" Wrong Mdiv Value, Correct Value Range = (56 ~ 1023) (%d)\n", uMdiv);
}
if( uPdiv < 1 || uPdiv > 63)
{
printf(" Wrong Pdiv Value, Correct Value Range = (1 ~ 63) (%d)\n", uPdiv);
}
if( uSdiv > 5)
{
printf(" Wrong Sdiv Value, Correct Value Range = (0 ~ 5) (%d)\n", uSdiv);
}
// Check the Fvco Range
temp = ((FIN/uPdiv)*uMdiv)/1000000;
if( temp <1000 || temp > 2000)
{
printf(" Please select the proper M,P,S divider value\n");
printf(" Fvco Range = (1000MHz ~ 2000MHz), Current Value is (%d)MHz\n", temp);
}
uRegValue = (u32)(((u32)(0x1<<31))|(uMdiv<<16)|(uPdiv<<8)|(uSdiv<<0));
Outp32(rAPLL_CON, uRegValue);
break;
case eMPLL:
// Check the Divider Value.
if( uMdiv < 56 || uMdiv > 1023)
{
printf(" Wrong Mdiv Value, Correct Value Range = (56 ~ 1023) (%d)\n", uMdiv);
}
if( uPdiv < 1 || uPdiv > 63)
{
printf(" Wrong Pdiv Value, Correct Value Range = (1 ~ 63) (%d)\n", uPdiv);
}
if( uSdiv > 5)
{
printf(" Wrong Sdiv Value, Correct Value Range = (0 ~ 5) (%d)\n", uSdiv);
}
// Check the Fvco Range
temp = ((FIN/uPdiv)*uMdiv)/1000000;
if( temp <1000 || temp > 2000)
{
printf(" Please select the proper M,P,S divider value\n");
printf(" Fvco Range = (1000MHz ~ 2000MHz), Current Value is (%d)MHz\n", temp);
}
uRegValue = (u32)(((u32)(0x1<<31))|(uMdiv<<16)|(uPdiv<<8)|(uSdiv<<0));
Outp32(rMPLL_CON, uRegValue);
break;
case eEPLL:
// Check the Divider Value.
if( uMdiv < 13 || uMdiv > 255)
{
printf(" Wrong Mdiv Value, Correct Value Range = (56 ~ 1023) (%d)\n", uMdiv);
}
if( uPdiv < 1 || uPdiv > 63)
{
printf(" Wrong Pdiv Value, Correct Value Range = (1 ~ 63) (%d)\n", uPdiv);
}
if( uSdiv > 5)
{
printf(" Wrong Sdiv Value, Correct Value Range = (0 ~ 5) (%d)\n", uSdiv);
}
if( uKdiv >65535)
{
printf(" Wrong Kdiv Value, Correct Value Range = (0 ~ 65535) (%d)\n", uKdiv);
}
// Check the Fvco Range
temp = ((FIN/uPdiv)*(uMdiv+uKdiv>>16))/1000000;
if( temp <60 || temp > 250)
{
printf(" Please select the proper M,P,S divider value\n");
printf(" Fvco Range = (60MHz ~ 250MHz), Current Value is (%d)MHz\n", temp);
}
Outp32(rEPLL_CON1, uKdiv);
uRegValue = (u32)(((u32)(0x1<<31))|(uMdiv<<16)|(uPdiv<<8)|(uSdiv<<0));
Outp32(rEPLL_CON0, uRegValue);
break;
}
// Get Information
SYSC_GetClkInform();
}
//////////
// Function Name : SYSC_StopPLL
// Function Description : This function stop PLL.
// Fout = (mdiv * Fin) / (pdiv x 2^sdiv), Fout = ((mdiv+k/2^16) * Fin) / (pdiv x 2^sdiv)
// Input : ePLL : eAPLL,eMPLL, eEPLL
//
//
// Output : NONE
// Version :
void SYSC_StopPLL(PLL_eTYPE ePLL)
{
u32 uRegValue;
switch(ePLL)
{
case eAPLL:
uRegValue = Inp32(rAPLL_CON);
uRegValue = (uRegValue & ~(0x1<<31));
Outp32(rAPLL_CON, uRegValue);
break;
case eMPLL:
uRegValue = Inp32(rMPLL_CON);
uRegValue = (uRegValue & ~(0x1<<31));
Outp32(rMPLL_CON, uRegValue);
break;
case eEPLL:
uRegValue = Inp32(rEPLL_CON0);
uRegValue = (uRegValue & ~(0x1<<31));
Outp32(rEPLL_CON0, uRegValue);
break;
}
}
/////////
// Function Name : SYSC_RdLockDetect
// Function Description : This function reads Lock Detect bit of the A/MPLL (Hidden)
// Input : ePLL : eAPLL, eMPLL
// Output : TRUE/FALSE
// Version :
bool SYSC_RdLockDetect(PLL_eTYPE ePLL)
{
u32 uRegValue, uLockDetect;
switch(ePLL)
{
case eAPLL:
uRegValue = Inp32(rAPLL_CON);
uLockDetect = (uRegValue >>30)&(0x1);
break;
case eMPLL:
uRegValue = Inp32(rMPLL_CON);
uLockDetect = (uRegValue >>30)&(0x1);
break;
}
if(uLockDetect == 1)
{
return TRUE;
}
else
{
return FALSE;
}
}
//////////
// Function Name : SYSC_ChangeSYSCLK
// Function Description : This function control System Clock
// Fout = (mdiv * Fin) / (pdiv x 2^sdiv), Fout = ((mdiv+k/2^16) * Fin) / (pdiv x 2^sdiv)
// Input : eAPLLMPS : APLL M,P,S Value
// eMPLLMPS : MPLL M,P,S Value ( using at Async Mode )
// uARM_Ratio : ARM Divider
// uHCLKx2_Ratio : HCLKx2 Divider
// uPCLK_Ratio : PCLK Divider
// Other values are retained
// Output : NONE
// Version :
void SYSC_ChangeSYSCLK(APLL_eOUT eAPLLMPS, APLL_eOUT eMPLLMPS, u32 uARM_Ratio, u32 uHCLKx2_Ratio, u32 uPCLK_Ratio)
{
u32 uRegValue, uRegValue_A;
u32 uRegValue_M, uRegValue_E;
u32 uMVAL, uPVAL, uSVAL;
u32 uMVAL_M, uPVAL_M, uSVAL_M;
u32 uTemp;
uMVAL = (eAPLLMPS&0x3FF0000)>>16;
uPVAL = (eAPLLMPS&0xFF00)>>8;
uSVAL = eAPLLMPS&0x00FF;
uRegValue_A = (u32)(((u32)(0x1<<31))|(uMVAL<<16)|(uPVAL<<8)|(uSVAL<<0));
uMVAL_M = (eMPLLMPS&0x3FF0000)>>16;
uPVAL_M = (eMPLLMPS&0xFF00)>>8;
uSVAL_M = eMPLLMPS&0x00FF;
uTemp = (Inp32(rOTHERS)>>8)&0xF;
if(uTemp==0xF ) // Sync Mode
{
uRegValue_M = Inp32(rMPLL_CON);
}
else // ASync Mode
{
uRegValue_M = (u32)(((u32)(0x1<<31))|(uMVAL_M<<16)|(uPVAL_M<<8)|(uSVAL_M<<0));
uRegValue_E = Inp32(rEPLL_CON0);
}
// Divider Change
uRegValue = Inp32(rCLK_DIV0);
uRegValue = (uRegValue & ~(0xFE07)) | ((uPCLK_Ratio<<12)|(uHCLKx2_Ratio<<9)|(uARM_Ratio<<0));
Outp32(rCLK_DIV0, uRegValue);
// EVT0 W.A
Outp32(rMPLL_CON, uRegValue_M);
if(uTemp == 0)
{
Outp32(rEPLL_CON0, uRegValue_E);
}
// APLL Set
Outp32(rAPLL_CON, uRegValue_A);
Delay(1000);
SYSC_GetClkInform();
UART_InitDebugCh(0, 115200);
Delay(1000);
printf("============================ \n");
printf("Current Clock Information \n");
printf("ARMCLK: %.2fMHz HCLKx2: %.2fMHz HCLK: %.2fMHz PCLK: %.2fMHz\n",(float)g_ARMCLK/1.0e6, (float)g_HCLKx2/1.0e6, (float)g_HCLK/1.0e6, (float)g_PCLK/1.0e6);
printf("============================ \n");
}
//////////
// Function Name : SYSC_ChangeSYSCLK_1
// Function Description : This function control System Clock
// Fout = (mdiv * Fin) / (pdiv x 2^sdiv), Fout = ((mdiv+k/2^16) * Fin) / (pdiv x 2^sdiv)
// Input : eAPLLMPS : APLL M,P,S Value
// eMPLLMPS : MPLL M,P,S Value ( using at Async Mode )
// uARM_Ratio : ARM Divider
// uHCLKx2_Ratio : HCLKx2 Divider
// uPCLK_Ratio : PCLK Divider
// Other values are retained
// Output : NONE
// Version :
void SYSC_ChangeSYSCLK_1(APLL_eOUT eAPLLMPS, APLL_eOUT eMPLLMPS, u32 uARM_Ratio, u32 uHCLKx2_Ratio, u32 uPCLK_Ratio)
{
u32 uRegValue_A;
u32 uRegValue_M;
u32 uMVAL, uPVAL, uSVAL;
u32 uMVAL_M, uPVAL_M, uSVAL_M;
u32 uSYNCMODE;
u32 uRegValue_DIV0, uRegValue_SRC, uTemp, uTemp1;
uMVAL = (eAPLLMPS&0x3FF0000)>>16;
uPVAL = (eAPLLMPS&0xFF00)>>8;
uSVAL = eAPLLMPS&0x00FF;
uRegValue_A = (u32)(((u32)(0x1<<31))|(uMVAL<<16)|(uPVAL<<8)|(uSVAL<<0));
uMVAL_M = (eMPLLMPS&0x3FF0000)>>16;
uPVAL_M = (eMPLLMPS&0xFF00)>>8;
uSVAL_M = eMPLLMPS&0x00FF;
uSYNCMODE = (Inp32(rOTHERS)>>8)&0xF;
if(uSYNCMODE==0xF ) // Sync Mode
{
uRegValue_M = Inp32(rMPLL_CON);
}
else // ASync Mode
{
uRegValue_M = (u32)(((u32)(0x1<<31))|(uMVAL_M<<16)|(uPVAL_M<<8)|(uSVAL_M<<0));
}
// Clock Divider Change 1:2:2
uRegValue_DIV0 = Inp32(rCLK_DIV0);
uTemp = (uRegValue_DIV0&~(0xFFFF))|(1<<12)|((0<<9)|(1<<8)|(1<<4)|(0<<0)); // ARM:HCLKx2:HCLK:PCLK = 1:1:2:2
// Set-up Divider Value
uRegValue_DIV0 = (uRegValue_DIV0 & ~(0xFE07)) | ((uPCLK_Ratio<<12)|(uHCLKx2_Ratio<<9)|(uARM_Ratio<<0));
uRegValue_SRC = Inp32(rCLK_SRC);
uTemp1 = (uRegValue_SRC&~(0x7))|0x0;
Outp32(rCLK_SRC, uTemp1); // Clock Source Change
Outp32(rCLK_DIV0, uTemp); // Change Clock Divider
// PLL Change
if(uSYNCMODE == 0)
{
Outp32(rMPLL_CON, uRegValue_M);
}
Outp32(rAPLL_CON, uRegValue_A);
while(((Inp32(rAPLL_CON)>>30)&0x1)==0);
// Change Divider Value
Outp32(rCLK_DIV0, uRegValue_DIV0);
// Change Clock SRC
Outp32(rCLK_SRC, uRegValue_SRC);
Delay(1000);
SYSC_GetClkInform();
UART_InitDebugCh(0, 115200);
printf("============================ \n");
printf("Current Clock Information \n");
printf("ARMCLK: %.2fMHz HCLKx2: %.2fMHz HCLK: %.2fMHz PCLK: %.2fMHz\n",(float)g_ARMCLK/1.0e6, (float)g_HCLKx2/1.0e6, (float)g_HCLK/1.0e6, (float)g_PCLK/1.0e6);
printf("============================ \n");
}
#define uTIME_OF_XTAL (1.0e6/(float)FIN)
//////////
// Function Name : SYSC_SetLockTime
// Function Description : This function control APLL Lock Time (PLL9025X), Max 100us
// Fout = (mdiv * Fin) / (pdiv x 2^sdiv)
// Input : uLockTime : Max 100us, us order
// ePLL : PLL Type
// Output : NONE
// Version :
void SYSC_SetLockTime( PLL_eTYPE ePLL, u32 uLockTime)
{
u32 uLockCount;
uLockCount = (unsigned int)((float)uLockTime/((float)uTIME_OF_XTAL));
printf("uLockCount : 0x%x\n", uLockCount);
switch(ePLL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -