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

📄 dvs.c

📁 SAMSUNG S3C6410 CPU BSP for winmobile6
💻 C
📖 第 1 页 / 共 2 页
字号:
//------------------------------------------------------------------------------
//
//  Module: dvs.c
//
//  Dynamic Voltage and Frequency Scaling Implementation
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <oal.h>
#include <s3c6410.h>
#include <bsp_cfg.h>
#include <pmplatform.h>

//#define ENABLE_VOLTAGE_CONTROL
//#define DVS_LEVEL_PROFILE

#define DVS_UPDATE_PERIOD_FINE	(100)
#define DVS_UPDATE_PERIOD_COARSE	(1000)

#define DVS_DEFAULT_DELAY (100)

typedef struct
{
	DWORD dwTickCount;
	DWORD dwIdleCount;
	DWORD dwIdleRate;
} IDLE_LOG;

//-----------------------------------------------------------------------------------
// Following System Clock configuration Level Transition Table has definition of 6 state
// and system can be changed adjacent state.
// for example,
//	{	SYS_L2,		means that current definition is from System Level 2.
//		50, SYS_L3,	means that if system idle rate reaches over 50%(idle), system level will be changed to level 3
//		10, SYS_L1,	means that if system idle rate is downto 10%(hardworking), system level will be changed to level 1
//		3, 1, 8	}	means current system level's(Lv 2) system clock configuration
//-----------------------------------------------------------------------------------
// Current System Level,
//				Shift Down Idle Rate,
//					Shift Down Level,
//							Shift Up Idle Rate,
//								Shift Up Level,
//										ARMCLK Divider,
//											HCLKx2 Divider,
//												PCLK Divider
//													MFCCLK Divider (MFCCLK = HCLKx2/Div)
//															VddARM
//																VddInternal
//-----------------------------------------------------------------------------------
DWORD g_aTransitionTable[SYS_LEVEL_MAX][11] =
{
#if	(S3C6410_ACLK == CLK_400MHz)

	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	1,	8,	2,	1000, 1000},	// 400, 100, 25, 100
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	1,	8,	2,	900, 975},	// 200, 100, 25, 100
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	3,	1,	8,	2,	900, 975},	// 133, 100, 25, 100
	{SYS_L3,		50, SYS_L4,		20, SYS_L1,	4,	1,	8,	2,	900, 975},	// 100, 100, 25, 100
	{SYS_L4,		60, SYS_L5,		20, SYS_L1,	4,	2,	4,	1,	900,	900},	// 100, 50, 25, 100
	{SYS_L5,		100, SYS_L5,		20, SYS_L1,	8,	2,	4,	1,	900, 900},	// 50, 50, 25, 100

#elif	(S3C6410_ACLK == CLK_532MHz)
	#if		(CPU_NAME == S3C6400)
	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	1,	8,	2,	1100, 1000},	// 532, 133, 33, 133
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	1,	8,	2,	900, 975},	// 266, 133, 33, 133
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	3,	1,	8,	2,	900, 975},	// 177, 133, 33, 133
	{SYS_L3,		50, SYS_L4,		20, SYS_L2,	4,	1,	8,	2,	900, 975},	// 133, 133, 33, 133
	{SYS_L4,		60, SYS_L5,		20, SYS_L2,	4,	2,	4,	1,	900, 900},	// 133, 66, 33, 133
	{SYS_L5,		100, SYS_L5,		20, SYS_L2,	8,	2,	4,	1,	900, 900},	// 66, 66, 33, 133
	#endif
	#if		(CPU_NAME == S3C6410)
		#if		(SYNCMODE)
	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	2,	8,	2,	1200, 1200},	// 532, 133, 33, 133
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	2,	8,	2,	1100, 1200},	// 266, 133, 33, 133
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	4,	2,	8,	2,	1100, 1200},	// 177, 133, 33, 133
	{SYS_L3,		50, SYS_L4,		20, SYS_L2,	4,	2,	8,	2,	1100, 1200},	// 133, 133, 33, 133
	{SYS_L4,		60, SYS_L5,		20, SYS_L2,	4,	4,	4,	1,	1100, 1000},	// 133, 66, 33, 133
	{SYS_L5,		100, SYS_L5,		20, SYS_L2,	8,	4,	4,	1,	1000, 1000},	// 66, 66, 33, 133

		#elif
	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	1,	8,	2,	1100, 1000},	// 532, 133, 33, 133
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	1,	8,	2,	900, 975},	// 266, 133, 33, 133
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	3,	1,	8,	2,	900, 975},	// 177, 133, 33, 133
	{SYS_L3,		50, SYS_L4,		20, SYS_L2,	4,	1,	8,	2,	900, 975},	// 133, 133, 33, 133
	{SYS_L4,		60, SYS_L5,		20, SYS_L2,	4,	2,	4,	1,	900, 900},	// 133, 66, 33, 133
	{SYS_L5,		100, SYS_L5,		20, SYS_L2,	8,	2,	4,	1,	900, 900},	// 66, 66, 33, 133
		#endif
	#endif
#elif	(S3C6410_ACLK == CLK_634MHz)

	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	1,	8,	2,	1300, 975},	// 634, 133, 33, 133
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	1,	8,	2,	975, 975},	// 317, 133, 33, 133
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	3,	1,	8,	2,	900, 975},	// 211, 133, 33, 133
	{SYS_L3,		50, SYS_L4,		20, SYS_L2,	4,	1,	8,	2,	900, 975},	// 158, 133, 33, 133
	{SYS_L4,		60, SYS_L5,		20, SYS_L2,	4,	2,	4,	1,	900, 900},	// 158, 66, 33, 133
	{SYS_L5,		100, SYS_L5,		20, SYS_L2,	8,	2,	4,	1,	900, 900},	// 79, 66, 33, 133

#elif	(S3C6410_ACLK == CLK_800MHz)
#if		(CPU_NAME == S3C6410)
	// to be modified
	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	1,	8,	2,	1300, 975},	// 634, 133, 33, 133
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	1,	8,	2,	975, 975},	// 317, 133, 33, 133
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	3,	1,	8,	2,	900, 975},	// 211, 133, 33, 133
	{SYS_L3,		50, SYS_L4,		20, SYS_L2,	4,	1,	8,	2,	900, 975},	// 158, 133, 33, 133
	{SYS_L4,		60, SYS_L5,		20, SYS_L2,	4,	2,	4,	1,	900, 900},	// 158, 66, 33, 133
	{SYS_L5,		100, SYS_L5,		20, SYS_L2,	8,	2,	4,	1,	900, 900},	// 79, 66, 33, 133
#elif	(CPU_NAME == S3C6400)
#error ARMCLK_UNDEFINED_ERROR
#endif

#elif	(S3C6410_ACLK == CLK_667MHz)
#if		(CPU_NAME == S3C6410)
	// to be modified
	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	1,	8,	2,	1300, 975},	// 634, 133, 33, 133
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	1,	8,	2,	975, 975},	// 317, 133, 33, 133
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	3,	1,	8,	2,	900, 975},	// 211, 133, 33, 133
	{SYS_L3,		50, SYS_L4,		20, SYS_L2,	4,	1,	8,	2,	900, 975},	// 158, 133, 33, 133
	{SYS_L4,		60, SYS_L5,		20, SYS_L2,	4,	2,	4,	1,	900, 900},	// 158, 66, 33, 133
	{SYS_L5,		100, SYS_L5,		20, SYS_L2,	8,	2,	4,	1,	900, 900},	// 79, 66, 33, 133
#elif	(CPU_NAME == S3C6400)
#error ARMCLK_UNDEFINED_ERROR
#endif

#elif	(S3C6410_ACLK == CLK_1066MHz)
#if		(CPU_NAME == S3C6410)
	// to be modified
	{SYS_L0,		50, SYS_L1,		0, SYS_L0,	1,	1,	8,	2,	1300, 975},	// 634, 133, 33, 133
	{SYS_L1,		40, SYS_L2,		10, SYS_L0,	2,	1,	8,	2,	975, 975},	// 317, 133, 33, 133
	{SYS_L2,		40, SYS_L3,		10, SYS_L1,	3,	1,	8,	2,	900, 975},	// 211, 133, 33, 133
	{SYS_L3,		50, SYS_L4,		20, SYS_L2,	4,	1,	8,	2,	900, 975},	// 158, 133, 33, 133
	{SYS_L4,		60, SYS_L5,		20, SYS_L2,	4,	2,	4,	1,	900, 900},	// 158, 66, 33, 133
	{SYS_L5,		100, SYS_L5,		20, SYS_L2,	8,	2,	4,	1,	900, 900},	// 79, 66, 33, 133
#elif	(CPU_NAME == S3C6400)
#error ARMCLK_UNDEFINED_ERROR
#endif

#else
#error ARMCLK_UNDEFINED_ERROR
#endif
};

static DWORD g_dwCurrentIdleTime;
static BOOL g_bDVSDisabledByUSB = FALSE;
static IDLE_LOG tLastLogFine;
static IDLE_LOG tLastLogCoarse;
static SYSTEM_ACTIVE_LEVEL g_CurrentLevel = SYS_L0;
static volatile S3C6410_SYSCON_REG *g_pSysConReg = NULL;
static volatile S3C6410_GPIO_REG *g_pGPIOReg = NULL;
static volatile unsigned int *g_pOTGLinkReg = NULL;
#ifdef DVS_LEVEL_PROFILE
static DWORD g_aDVFSProfileTable[SYS_LEVEL_MAX][2];
static BOOL g_bProfileDSV = FALSE;
static DWORD g_dwLastTickCount_NonDVS = 0;	// for Profile Non-DVS Idle rate
static DWORD g_dwLastIdleCount_NonDVS = 0;	// for Profile Non-DVS Idle rate
#endif

// Transition Table Data field macro
#define ShiftDownRate		(g_aTransitionTable[g_CurrentLevel][1])
#define ShiftDownLevel		((SYSTEM_ACTIVE_LEVEL)(g_aTransitionTable[g_CurrentLevel][2]))
#define ShiftUpRate			(g_aTransitionTable[g_CurrentLevel][3])
#define ShiftUpLevel			((SYSTEM_ACTIVE_LEVEL)(g_aTransitionTable[g_CurrentLevel][4]))
#define SysARMCLKDiv(x)		(g_aTransitionTable[x][5])
#define SysHCLKx2Div(x)		(g_aTransitionTable[x][6])
#define SysPCLKDiv(x)		(g_aTransitionTable[x][7])
#define SysMFCLKDiv(x)		(g_aTransitionTable[x][8])
#define VoltageARM(x)		(g_aTransitionTable[x][9])
#define VoltageInternal(x)	(g_aTransitionTable[x][10])

#define SETVOLTAGE_ARM			(1)
#define SETVOLTAGE_INTERNAL	(2)
#define SETVOLTAGE_BOTH		(SETVOLTAGE_ARM|SETVOLTAGE_INTERNAL)

void LTC3714_Init();
void LTC3714_VoltageSet(UINT32 uPwr, UINT32 uVoltage, UINT32 uDelay);
void ChangeDVSLevel(SYSTEM_ACTIVE_LEVEL eLevel);

void InitializeDVS(void)
{
	g_pSysConReg = (S3C6410_SYSCON_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_SYSCON, FALSE);
	g_pOTGLinkReg = (unsigned int *)OALPAtoVA(S3C6410_BASE_REG_PA_USBOTG_LINK, FALSE);
	g_CurrentLevel = SYS_L0;	// Initial System Level

#ifdef	ENABLE_VOLTAGE_CONTROL
	LTC3714_Init();

	// This is caused by SMDK board bug. You can erase this line if you use the other board.
	LTC3714_VoltageSet(SETVOLTAGE_BOTH, VoltageARM(g_CurrentLevel), DVS_DEFAULT_DELAY);
#endif
}

void SetCurrentIdleTime(DWORD dwIdleTime)
{
	g_dwCurrentIdleTime = dwIdleTime;
}

void UpdateDVS(void)
{
	IDLE_LOG tCurLog;
	DWORD dwCurrentMSec;
	DWORD dwCurrentIdleMSec;
#ifdef DVS_LEVEL_PROFILE
	DWORD dwIdleTick, dwActiveTick;
#endif

	// Check USB Device in Use
	if (*g_pOTGLinkReg & (0x3<<18))
	{
		if (g_bDVSDisabledByUSB == FALSE)
		{
			g_bDVSDisabledByUSB = TRUE;
			ChangeDVSLevel(SYS_L0);
			OALMSG(TRUE, (L"[DVS] DVS disabled by USB\r\n"));
		}

		return;	// Do not apply DVS, when USB is in Use
	}

	if (g_bDVSDisabledByUSB == TRUE)
	{
		// Enable DVS after USB operation finished
		g_bDVSDisabledByUSB = FALSE;
		OALMSG(TRUE, (L"[DVS] DVS enabled\r\n"));
	}

	dwCurrentMSec = CurMSec;
	dwCurrentIdleMSec = g_dwCurrentIdleTime;

	if ( (dwCurrentMSec - tLastLogFine.dwTickCount) >=  DVS_UPDATE_PERIOD_FINE )
	{
		tCurLog.dwTickCount = dwCurrentMSec;
		tCurLog.dwIdleCount = g_dwCurrentIdleTime;
		tCurLog.dwIdleRate = (100*(dwCurrentIdleMSec-tLastLogFine.dwIdleCount))/(dwCurrentMSec-tLastLogFine.dwTickCount);

#ifdef DVS_LEVEL_PROFILE
		dwIdleTick = dwCurrentIdleMSec-tLastLogFine.dwIdleCount;
		dwActiveTick = (dwCurrentMSec-tLastLogFine.dwTickCount)-dwIdleTick;
#endif
		tLastLogFine.dwTickCount = tCurLog.dwTickCount;
		tLastLogFine.dwIdleCount = tCurLog.dwIdleCount;
		tLastLogFine.dwIdleRate = tCurLog.dwIdleRate;

		if (tCurLog.dwIdleRate < ShiftUpRate)	// Pump Up the Clock
		{
#ifdef DVS_LEVEL_PROFILE
			if (g_bProfileDSV)
			{
				g_aDVFSProfileTable[g_CurrentLevel][0] += dwIdleTick;		// Idle
				g_aDVFSProfileTable[g_CurrentLevel][1] += dwActiveTick;	// Active
			}
#endif
			//OALMSG(TRUE, (L"[%d:%d]\r\n", g_CurrentLevel, tCurLog.dwIdleRate));
			ChangeDVSLevel(ShiftUpLevel);
		}
		else
		{
			if ( (dwCurrentMSec - tLastLogCoarse.dwTickCount) >=  DVS_UPDATE_PERIOD_COARSE )
			{
				tCurLog.dwIdleRate = (100*(dwCurrentIdleMSec-tLastLogCoarse.dwIdleCount))/(dwCurrentMSec-tLastLogCoarse.dwTickCount);

#ifdef DVS_LEVEL_PROFILE
				dwIdleTick = dwCurrentIdleMSec-tLastLogCoarse.dwIdleCount;
				dwActiveTick = (dwCurrentMSec-tLastLogCoarse.dwTickCount)-dwIdleTick;

				if (g_bProfileDSV)
				{
					g_aDVFSProfileTable[g_CurrentLevel][0] += dwIdleTick;		// Idle
					g_aDVFSProfileTable[g_CurrentLevel][1] += dwActiveTick;	// Active
				}
#endif

				tLastLogCoarse.dwTickCount = tCurLog.dwTickCount;
				tLastLogCoarse.dwIdleCount = tCurLog.dwIdleCount;
				tLastLogCoarse.dwIdleRate = tCurLog.dwIdleRate;

				//OALMSG(TRUE, (L"[%d:%d]\r\n", g_CurrentLevel, tCurLog.dwIdleRate));

				if (tCurLog.dwIdleRate > ShiftDownRate)	// Pump Down the Clock
				{
					ChangeDVSLevel(ShiftDownLevel);
				}

			}
		}
	}
}

void ChangeDVSLevel(SYSTEM_ACTIVE_LEVEL NewLevel)
{
	if (g_CurrentLevel == NewLevel)
	{
		// There is no need to change
		return;
	}
	else
	{
#ifdef	ENABLE_VOLTAGE_CONTROL
		if(g_CurrentLevel > NewLevel)	// Clock Speed of New Level is Slower, Voltage of New Level is Lower
		{
			LTC3714_VoltageSet(SETVOLTAGE_ARM, VoltageARM(NewLevel), DVS_DEFAULT_DELAY/SysARMCLKDiv(NewLevel));
			LTC3714_VoltageSet(SETVOLTAGE_INTERNAL, VoltageInternal(NewLevel), DVS_DEFAULT_DELAY/SysARMCLKDiv(NewLevel));
		}
#endif

#if		(CPU_NAME == S3C6410)
	#if		(SYNCMODE)
	// In order to change clock divider values, clock source should be changed as FIN_APLL
	g_pSysConReg->CLK_SRC &= ~(0x7);
	g_pSysConReg->CLK_DIV0 = (g_pSysConReg->CLK_DIV0 & ~((0xf<<12)|(0xf<<8)|(0xf<<4)|(0xf)))
								| ((0x1<<12)|(0x3<<8)|(0x0<<4)|(0x0));	// ARM:HCLKx2:HCLK:PCLK = 1:2:2:2
	#endif
#endif

		// Change System Clock Divider
		g_pSysConReg->CLK_DIV0 = (g_pSysConReg->CLK_DIV0 & ~((0xf<<28)|(0xf<<12)|(0x7<<9)|(0x7)))
									| ((SysMFCLKDiv(NewLevel)-1)<<28)
									| ((SysPCLKDiv(NewLevel)-1)<<12)
									| ((SysHCLKx2Div(NewLevel)-1)<<9)
									| (SysARMCLKDiv(NewLevel)-1);
#if		(CPU_NAME == S3C6410)
	#if		(SYNCMODE)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -