📄 dvfc.c
字号:
{
// Request for transition to new voltage
PmicSwitchModeRegulatorSetVoltageLevel(pSP->sw, pSP->swVolt,
g_MC13783SwitcherVoltTable[pSP->voltIndex]);
// Update global tracking VSCNT
g_Vscnt = DVFC_VSCNT(g_MC13783SwitcherVoltTable[pSP->voltIndex], g_LowSpeedVolt, g_DvsSpeed);
RETAILMSG(g_bVerbose, (_T("DPTC volt update (swVolt = 0x%x, lowvolt = 0x%x, vscnt = %d)\r\n"),
g_MC13783SwitcherVoltTable[pSP->voltIndex], g_LowSpeedVolt, g_Vscnt));
}
// Update the DPTC threshold registers
OUTREG32(&g_pCCM->DCVR[0], g_DptcDcvrTable[pSP->freqIndex][pSP->voltIndex][0]);
OUTREG32(&g_pCCM->DCVR[1], g_DptcDcvrTable[pSP->freqIndex][pSP->voltIndex][1]);
OUTREG32(&g_pCCM->DCVR[2], g_DptcDcvrTable[pSP->freqIndex][pSP->voltIndex][2]);
OUTREG32(&g_pCCM->DCVR[3], g_DptcDcvrTable[pSP->freqIndex][pSP->voltIndex][3]);
// Enable the DPTC hardware
CSP_BITFINS(pmcr0, CCM_PMCR0_DPVCR, CCM_PMCR0_DPVCR_CHANGE_REQ);
OUTREG32(&g_pCCM->PMCR0, pmcr0);
// Avoid immediately overriding DPVV (voltage valid) when DVFS is
// transitioning to a higher voltage. The MC13783 PWRREADY signal
// can be used to set the DPVV after the new voltage setpoint
// has been reached, or we can just insert a fixed delay.
if (bFreqUpdate &&
(CSP_BITFEXT(pmcr0, CCM_PMCR0_UDSC) == CCM_PMCR0_UDSC_FREQ_UP))
{
Sleep(1);
}
CSP_BITFINS(pmcr0, CCM_PMCR0_DPVV, CCM_PMCR0_DPVV_VOLT_VALID);
OUTREG32(&g_pCCM->PMCR0, pmcr0);
}
cleanUp:
DVFC_UNLOCK();
}
//-----------------------------------------------------------------------------
//
// Function: BSPDvfcInit
//
// This function provides platform-specific initialization for supporting
// DVFS/DPTC.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL BSPDvfcInit(void)
{
BOOL rc = FALSE;
PHYSICAL_ADDRESS phyAddr;
UINT32 freq = 0;
HKEY hKey;
UINT32 keyVal, dnthr, upthr, dncnt, upcnt, emac;
UINT32 keySize = sizeof(keyVal);
BOOL bDvfsForceOff, bDptcForceOff;
// DDKClockSetCKO(TRUE, DDK_CLOCK_CKO_SRC_AHB, DDK_CLOCK_CKO_DIV_4);
// Map SDMA registers for access to ACR bit
if (g_pSDMA == NULL)
{
phyAddr.QuadPart = CSP_BASE_REG_PA_SDMA;
// Map peripheral physical address to virtual address
g_pSDMA = (PCSP_SDMA_REGS) MmMapIoSpace(phyAddr, sizeof(CSP_SDMA_REGS),
FALSE);
// Check if virtual mapping failed
if (g_pSDMA == NULL)
{
ERRORMSG(TRUE, (_T("MmMapIoSpace failed!\r\n")));
goto cleanUp;
}
}
// Mask DVFC interrupts
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_FSVAIM, CCM_PMCR0_FSVAIM_MASK);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_PTVAIM, CCM_PMCR0_PTVAIM_MASK);
// Claim the DVS pins
DDKIomuxSetPinMux(DDK_IOMUX_PIN_DVFS0, DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_NONE);
DDKIomuxSetPinMux(DDK_IOMUX_PIN_DVFS1, DDK_IOMUX_OUT_FUNC, DDK_IOMUX_IN_NONE);
// Determine current working point frequency
if (!DDKClockGetFreq(DDK_CLOCK_SIGNAL_ARM, &freq))
{
ERRORMSG(TRUE, (_T("DDKClockGetFreq failed for DDK_CLOCK_SIGNAL_ARM.\r\n")));
goto cleanUp;
}
// Configure DVFC setpoint parameters tied to CPU frequency
switch (freq)
{
case BSP_CLK_MCUPLL_FREQ:
case BSP_CLK_MCUPLL_FREQ_ALT:
// Start in high speed
g_CurSpeed = DVFC_SPEED_HIGH;
break;
default:
ERRORMSG(TRUE, (_T("Unsupported MCUPLL frequency.\r\n")));
goto cleanUp;
}
// Save off default bus configuration to restore from bus scaling
g_AhbPodf = EXTREG32BF(&g_pCCM->PDR0, CCM_PDR0_MAX_PODF);
g_IpgPodf = EXTREG32BF(&g_pCCM->PDR0, CCM_PDR0_IPG_PODF);
g_SdmaAcr = EXTREG32BF(&g_pSDMA->CONFIG, SDMA_CONFIG_ACR);
// Initialize the forced mode globals
g_DvfcForcedMode = DDK_CLOCK_DVFC_MODE_NORMAL;
// Supply default DVFC configuration
g_IstPriority = DVFC_IST_PRIORITY;
dnthr = DVFC_DNTHR;
upthr = DVFC_UPTHR;
dncnt = DVFC_DNCNT;
upcnt = DVFC_UPCNT;
emac = DVFC_EMAC;
bDvfsForceOff = FALSE;
bDptcForceOff = FALSE;
g_DvsSpeed = DVFC_DVSSPEED;
g_LowSpeedVolt = DVFC_LOWSPEED_VOLT;
g_LowBusVolt = DVFC_LOWBUS_VOLT;
g_bVerbose = FALSE;
// Attempt to read DVFS tuning parameters from registry
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, DVFC_REG_PATH, 0, 0, &hKey) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hKey, (_T("ThreadPriority")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
g_IstPriority = keyVal;
}
if (RegQueryValueEx(hKey, (_T("TrackingLoadDown")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
dnthr = DVFC_TRACKING_LOAD(keyVal) & ((1U << CCM_LTR0_DNTHR_WID) - 1);
}
if (RegQueryValueEx(hKey, (_T("TrackingLoadUp")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
upthr = DVFC_TRACKING_LOAD(keyVal) & ((1U << CCM_LTR0_UPTHR_WID) - 1);
}
if (RegQueryValueEx(hKey, (_T("TrackingWindowDown")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
dncnt = DVFC_TRACKING_WINDOW(keyVal, DVFC_FREQ_UP) & ((1U << CCM_LTR1_DNCNT_WID) - 1);
}
if (RegQueryValueEx(hKey, (_T("TrackingWindowUp")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
upcnt = DVFC_TRACKING_WINDOW(keyVal, DVFC_FREQ_DOWN) & ((1U << CCM_LTR1_UPCNT_WID) - 1);
}
if (RegQueryValueEx(hKey, (_T("TrackingEMAC")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
emac = keyVal & ((1U << CCM_LTR2_EMAC_WID) - 1);
}
if (RegQueryValueEx(hKey, (_T("DvfsForceOff")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
bDvfsForceOff = keyVal;
}
if (RegQueryValueEx(hKey, (_T("DptcForceOff")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
bDptcForceOff = keyVal;
}
if (RegQueryValueEx(hKey, (_T("DvsSpeed")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
g_DvsSpeed = keyVal & MC13783_SW_DVSSPEED_MAX;
}
if (RegQueryValueEx(hKey, (_T("LowSpeedVolt")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
g_LowSpeedVolt = keyVal;
}
if (RegQueryValueEx(hKey, (_T("LowBusVolt")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
g_LowBusVolt = keyVal;
}
if (RegQueryValueEx(hKey, (_T("Verbose")), NULL, NULL, (LPBYTE) &keyVal, &keySize) == ERROR_SUCCESS)
{
g_bVerbose = keyVal;
}
}
// Use global to track the VSCNT necessary for switching from the low-speed
// voltage setpoint to the high-speed voltage setpoint
g_Vscnt = DVFC_VSCNT(g_MC13783SwitcherVoltTable[g_SetPoint[DVFC_SPEED_HIGH].voltIndex],
g_LowSpeedVolt, g_DvsSpeed);
#if 0
// Configure MC13783 for dual-DVS mode
if (PmicRegisterWrite(MC13783_ARB_SW_ADDR, CSP_BITFVAL(MC13783_ARB_SW_SW1ABDVS, 1),
CSP_BITFMASK(MC13783_ARB_SW_SW1ABDVS)) != PMIC_SUCCESS)
{
ERRORMSG(TRUE, (_T("PmicRegisterWrite failed\r\n")));
goto cleanUp;
}
#endif
// Configure the default high-speed voltage
if (PmicSwitchModeRegulatorSetVoltageLevel(g_SetPoint[DVFC_SPEED_HIGH].sw,
g_SetPoint[DVFC_SPEED_HIGH].swVolt,
g_MC13783SwitcherVoltTable[g_SetPoint[DVFC_SPEED_HIGH].voltIndex])
!= PMIC_SUCCESS)
{
ERRORMSG(TRUE, (_T("PmicSwitchModeRegulatorSetVoltageLevel failed!\r\n")));
goto cleanUp;
}
// Configure the default high-speed DPTC thresholds
OUTREG32(&g_pCCM->DCVR[0], g_DptcDcvrTable[g_SetPoint[DVFC_SPEED_HIGH].freqIndex][g_SetPoint[DVFC_SPEED_HIGH].voltIndex][0]);
OUTREG32(&g_pCCM->DCVR[1], g_DptcDcvrTable[g_SetPoint[DVFC_SPEED_HIGH].freqIndex][g_SetPoint[DVFC_SPEED_HIGH].voltIndex][1]);
OUTREG32(&g_pCCM->DCVR[2], g_DptcDcvrTable[g_SetPoint[DVFC_SPEED_HIGH].freqIndex][g_SetPoint[DVFC_SPEED_HIGH].voltIndex][2]);
OUTREG32(&g_pCCM->DCVR[3], g_DptcDcvrTable[g_SetPoint[DVFC_SPEED_HIGH].freqIndex][g_SetPoint[DVFC_SPEED_HIGH].voltIndex][3]);
// Configure the default low-speed voltage
if (PmicSwitchModeRegulatorSetVoltageLevel(g_SetPoint[DVFC_SPEED_LOW].sw,
g_SetPoint[DVFC_SPEED_LOW].swVolt, g_LowSpeedVolt)
!= PMIC_SUCCESS)
{
ERRORMSG(TRUE, (_T("PmicSwitchModeRegulatorSetVoltageLevel failed!\r\n")));
goto cleanUp;
}
// Configure the DVS transition speed
if (PmicSwitchModeRegulatorSetDVSSpeed(g_SetPoint[DVFC_SPEED_HIGH].sw,
g_DvsSpeed) != PMIC_SUCCESS)
{
ERRORMSG(TRUE, (_T("PmicSwitchModeRegulatorSetDVSSpeed failed!\r\n")));
goto cleanUp;
}
// Configure counting range for 256 system clocks
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DCR, CCM_PMCR0_DCR_256_CLOCKS);
// Configure DVFS logic for integer frequency scaling of MCUPLL
// using MCU post-divider
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DFSUP1,
CCM_PMCR0_DFSUP1_MCUPLL_UPDATE);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DFSUP0,
CCM_PMCR0_DFSUP0_POSTDIV_UPDATE);
// Configure WFI sampling granularity
INSREG32BF(&g_pCCM->LTR0, CCM_LTR0_DIV3CK, DVFC_DIV3CK);
// Configure frequency transition thresholds compared against EMA
// for WFI signal
INSREG32BF(&g_pCCM->LTR0, CCM_LTR0_DNTHR, dnthr);
INSREG32BF(&g_pCCM->LTR0, CCM_LTR0_UPTHR, upthr);
INSREG32BF(&g_pCCM->LTR1, CCM_LTR1_PNCTHR, DVFC_PNCTHR);
// Configure number of consecutive times a threshold is exceeded
// before a frequency transition is requested
INSREG32BF(&g_pCCM->LTR1, CCM_LTR1_DNCNT, dncnt);
INSREG32BF(&g_pCCM->LTR1, CCM_LTR1_UPCNT, upcnt);
INSREG32BF(&g_pCCM->LTR1, CCM_LTR1_LTBRSR, 1);
// Disable weighted load tracking signals
OUTREG32(&g_pCCM->LTR2, 0);
OUTREG32(&g_pCCM->LTR3, 0);
// Configure EMA calculation
INSREG32BF(&g_pCCM->LTR2, CCM_LTR2_EMAC, emac);
RETAILMSG(g_bVerbose, (_T("LTR0 = 0x%x, LTR1 = 0x%x, LTR2 = 0x%x"), INREG32(&g_pCCM->LTR0), INREG32(&g_pCCM->LTR1), INREG32(&g_pCCM->LTR2)));
// Unmask selected DVFC interrupts
INSREG32(&g_pCCM->PMCR0, DVFC_INTR_MASK, DVFC_INTR_VAL);
// Initialize mutex for safe access to CCM registers
// used by the DVFC driver
g_hDvfcMutex = CreateMutex(NULL, FALSE, L"MUTEX_DVFC");
if (g_hDvfcMutex == NULL)
{
ERRORMSG(1, (_T("CreateMutex failed!\r\n")));
goto cleanUp;
}
// Initialize mutex for protecting bus scaling
g_hAcrMutex = CreateMutex(NULL, FALSE, L"MUTEX_ACR");
if (g_hAcrMutex == NULL)
{
ERRORMSG(1, (_T("CreateMutex failed!\r\n")));
goto cleanUp;
}
// Enable/disable DVFS features
if (bDvfsForceOff)
{
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEN, CCM_PMCR0_DVFEN_DVFS_DISABLE);
RETAILMSG(g_bVerbose, (_T("DVFS disabled\r\n")));
}
else
{
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEN, CCM_PMCR0_DVFEN_DVFS_ENABLE);
RETAILMSG(g_bVerbose, (_T("DVFS enabled (DVSSPEED = %d, VSCNT = %d)\r\n"),
g_DvsSpeed, g_Vscnt));
}
if (g_SetPoint[g_CurSpeed].dpten)
{
if (bDptcForceOff)
{
g_SetPoint[g_CurSpeed].dpten = FALSE;
// Disable the DPTC hardware
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DPTEN, CCM_PMCR0_DPTEN_DPTC_DISABLE);
RETAILMSG(g_bVerbose, (_T("DPTC disabled\r\n")));
}
else
{
// Enable the DPTC hardware
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DPTEN, CCM_PMCR0_DPTEN_DPTC_ENABLE);
// Enable DPTC reference circuits
SETREG32(&g_pCCM->PMCR0, DPTC_REF_CIRCUIT_MASK);
RETAILMSG(g_bVerbose, (_T("DPTC enabled\r\n")));
}
}
else
{
// Disable the DPTC hardware
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DPTEN, CCM_PMCR0_DPTEN_DPTC_DISABLE);
RETAILMSG(g_bVerbose, (_T("DPTC disabled")));
}
rc = TRUE;
cleanUp:
return rc;
}
//-----------------------------------------------------------------------------
//
// Function: BSPDvfcDeinit
//
// This function deinitializes the platform-specific DVFS/DPTC support
// established by BSPDvfcInit.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL BSPDvfcDeinit(void)
{
// Disable DPTC & DVFS
CLRREG32(&g_pCCM->PMCR0, DPTC_REF_CIRCUIT_MASK);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DPTEN, CCM_PMCR0_DPTEN_DPTC_DISABLE);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEN, CCM_PMCR0_DVFEN_DVFS_DISABLE);
// Unmap SDMA registers
if (g_pSDMA)
{
MmUnmapIoSpace(g_pSDMA, sizeof(CSP_SDMA_REGS));
g_pSDMA = NULL;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -