📄 dvfc.c
字号:
g_MC13783SwitcherVoltTable[0]);
pSP->voltIndex = 0;
// 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]);
// Complete the DPTC threshold update
CSP_BITFINS(pmcr0, CCM_PMCR0_DPVCR, CCM_PMCR0_DPVCR_CHANGE_REQ);
OUTREG32(&g_pCCM->PMCR0, pmcr0);
CSP_BITFINS(pmcr0, CCM_PMCR0_DPVV, CCM_PMCR0_DPVV_VOLT_VALID);
OUTREG32(&g_pCCM->PMCR0, pmcr0);
// Flag the DVFC IST that we are entering suspend mode
SETREG32(&g_pCCM->PMCR1, DDK_CLOCK_DVFC_MODE_SUSPEND);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEV, CCM_PMCR0_DVFEV_REQ_ALWAYS);
}
// We are powering on
else
{
// Restore state of DVFC module enables
if (dvfen == CCM_PMCR0_DVFEN_DVFS_ENABLE)
{
CSP_BITFINS(pmcr0, CCM_PMCR0_DVFEN, CCM_PMCR0_DVFEN_DVFS_ENABLE);
}
if (dpten == CCM_PMCR0_DPTEN_DPTC_ENABLE)
{
CSP_BITFINS(pmcr0, CCM_PMCR0_DPTEN, CCM_PMCR0_DPTEN_DPTC_ENABLE);
}
// Update the power management control register
OUTREG32(&g_pCCM->PMCR0, pmcr0);
// Flag the DVFC IST that we are leaving suspend mode
CLRREG32(&g_pCCM->PMCR1, DDK_CLOCK_DVFC_MODE_SUSPEND);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEV, CCM_PMCR0_DVFEV_REQ_ALWAYS);
}
DVFC_UNLOCK();
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: BSPDvfcIntrServ
//
// This function is invoked from the DVFC interrupt service thread to
// perform the frequency/voltage switch.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
void BSPDvfcIntrServ(void)
{
UINT32 pmcr0, pmcr1, pdr0, ptvai, fsvai, dvsup, acr;
PDVFC_SETPOINT pSP = &g_SetPoint[g_CurSpeed];
BOOL bFreqUpdate = FALSE, bVoltUpdate = FALSE, bBusUpdate = FALSE;
UINT32 stop_stat;
UINT32 ahbPodf = g_AhbPodf;
DVFC_LOCK();
// Grab the CCM registers for DVFC control
pmcr0 = INREG32(&g_pCCM->PMCR0);
pdr0 = INREG32(&g_pCCM->PDR0);
// Make sure previous DVFS request is complete
if (CSP_BITFEXT(pmcr0, CCM_PMCR0_UPDTEN) == CCM_PMCR0_UPDTEN_DISABLE_UPDATE)
{
goto cleanUp;
}
if (CSP_BITFEXT(pmcr0, CCM_PMCR0_PTVAIM) == CCM_PMCR0_PTVAIM_UNMASK)
{
ptvai = CSP_BITFEXT(pmcr0, CCM_PMCR0_PTVAI);
}
else
{
ptvai = CCM_PMCR0_PTVAI_VOLT_NO_CHANGE;
}
if (CSP_BITFEXT(pmcr0, CCM_PMCR0_FSVAIM) == CCM_PMCR0_FSVAIM_UNMASK)
{
fsvai = CSP_BITFEXT(pmcr0, CCM_PMCR0_FSVAI);
}
else
{
fsvai = CCM_PMCR0_FSVAI_FREQ_NO_CHANGE;
}
// If this is a forced DVFC mode request
if (CSP_BITFEXT(pmcr0, CCM_PMCR0_DVFEV) == CCM_PMCR0_DVFEV_REQ_ALWAYS)
{
// Clear the request
CSP_BITFINS(pmcr0, CCM_PMCR0_DVFEV, CCM_PMCR0_DVFEV_REQ_NOT_ALWAYS);
// DVFC mode flags are stored in PMCR1 DVGP bits
pmcr1 = INREG32(&g_pCCM->PMCR1);
// If panic mode is being forced
if (pmcr1 & DDK_CLOCK_DVFC_MODE_PANIC)
{
// If we are not already in forced panic mode
if (g_DvfcForcedMode != DDK_CLOCK_DVFC_MODE_PANIC)
{
// Create DVFS panic request and mask DVFS interrupts
CSP_BITFINS(pmcr0, CCM_PMCR0_FSVAIM, CCM_PMCR0_FSVAIM_MASK);
fsvai = CCM_PMCR0_FSVAI_FREQ_UP_PANIC;
g_DvfcForcedMode = DDK_CLOCK_DVFC_MODE_PANIC;
}
}
else
{
// If we are trying to suspend
if (pmcr1 & DDK_CLOCK_DVFC_MODE_SUSPEND)
{
// If we are not already in forced suspend mode
if (g_DvfcForcedMode != DDK_CLOCK_DVFC_MODE_SUSPEND)
{
// Create DVFS request to lower speed and mask DVFS interrupts
fsvai = CCM_PMCR0_FSVAI_FREQ_DOWN;
CSP_BITFINS(pmcr0, CCM_PMCR0_FSVAIM, CCM_PMCR0_FSVAIM_MASK);
g_DvfcForcedMode = DDK_CLOCK_DVFC_MODE_SUSPEND;
}
}
// Else if we are tring to lower the bus speed
else if (pmcr1 & DDK_CLOCK_DVFC_MODE_BUS_LOW)
{
// If we are not already in forced low-speed bus mode
if (g_DvfcForcedMode != DDK_CLOCK_DVFC_MODE_BUS_LOW)
{
// Create DVFS request to lower speed, mask DVFS interrupts,
// and scale the AHB
fsvai = CCM_PMCR0_FSVAI_FREQ_DOWN;
ahbPodf = DVFC_SCALED_AHB_PODF;
CSP_BITFINS(pmcr0, CCM_PMCR0_FSVAIM, CCM_PMCR0_FSVAIM_MASK);
g_DvfcForcedMode = DDK_CLOCK_DVFC_MODE_BUS_LOW;
}
}
// No panic, no suspend, no lower bus, return to normal DVFS
// operation
else
{
CSP_BITFINS(pmcr0, CCM_PMCR0_FSVAIM, CCM_PMCR0_FSVAIM_UNMASK);
g_DvfcForcedMode = DDK_CLOCK_DVFC_MODE_NORMAL;
}
}
}
dvsup = CSP_BITFEXT(pmcr0, CCM_PMCR0_DVSUP);
// Handle adjustment cases and give priority to
// rising voltage/frequency requests
// DPTC voltage increase request. Make sure DPTC is
// enabled for this speed and we are not already at the
// highest voltage.
if (((ptvai == CCM_PMCR0_PTVAI_VOLT_UP) ||
(ptvai == CCM_PMCR0_PTVAI_VOLT_UP_PANIC)) &&
(pSP->dpten) && (pSP->voltIndex != 0))
{
--pSP->voltIndex;
bVoltUpdate = TRUE;
RETAILMSG(g_bVerbose, (_T("DPTC UP\r\n")));
}
// DVFS frequency panic increase request.
else if (fsvai == CCM_PMCR0_FSVAI_FREQ_UP_PANIC)
{
g_CurSpeed = DVFC_SPEED_HIGH;
pSP = &g_SetPoint[DVFC_SPEED_HIGH];
CSP_BITFINS(pmcr0, CCM_PMCR0_UDSC, CCM_PMCR0_UDSC_FREQ_UP);
CSP_BITFINS(pmcr0, CCM_PMCR0_VSCNT, g_Vscnt);
bFreqUpdate = TRUE;
RETAILMSG(g_bVerbose, (_T("DVFS PANIC UP\r\n")));
}
// DVFS frequency increase request. Make sure we are
// not already at the highest DVS configuration or speed.
else if ((fsvai == CCM_PMCR0_FSVAI_FREQ_UP) && (dvsup != 0)
&& (g_CurSpeed != 0))
{
--g_CurSpeed;
pSP = &g_SetPoint[g_CurSpeed];
CSP_BITFINS(pmcr0, CCM_PMCR0_UDSC, CCM_PMCR0_UDSC_FREQ_UP);
CSP_BITFINS(pmcr0, CCM_PMCR0_VSCNT, g_Vscnt);
bFreqUpdate = TRUE;
RETAILMSG(g_bVerbose, (_T("DVFS UP\r\n")));
}
// DVFS frequency decrease request. Make sure we are
// not already at the lowest DVS configuration or speed.
else if ((fsvai == CCM_PMCR0_FSVAI_FREQ_DOWN) &&
(dvsup != 0x3) && (g_CurSpeed < (DVFC_NUM_SPEEDS-1)))
{
++g_CurSpeed;
pSP = &g_SetPoint[g_CurSpeed];
CSP_BITFINS(pmcr0, CCM_PMCR0_UDSC, CCM_PMCR0_UDSC_FREQ_DOWN);
bFreqUpdate = TRUE;
RETAILMSG(g_bVerbose, (_T("DVFS DOWN\r\n")));
}
// DPTC voltage decrease request. Make sure DPTC is
// enabled for this speed and we are not already at the
// lowest voltage.
else if ((ptvai == CCM_PMCR0_PTVAI_VOLT_DOWN) &&
(pSP->dpten) && (pSP->voltIndex < (DVFC_VOLT_LEVELS-1)))
{
++pSP->voltIndex;
bVoltUpdate = TRUE;
RETAILMSG(g_bVerbose, (_T("DPTC DOWN\r\n")));
}
// Check for scaling bus to high-speed
if (CSP_BITFEXT(pdr0, CCM_PDR0_MAX_PODF) > ahbPodf)
{
// Use unscaled AHB/IPG dividers
CSP_BITFINS(pdr0, CCM_PDR0_MAX_PODF, g_AhbPodf);
CSP_BITFINS(pdr0, CCM_PDR0_IPG_PODF, g_IpgPodf);
// Use unscaled SDMA ACR bit
acr = g_SdmaAcr;
// Set flags for bus/frequency scaling
bBusUpdate = TRUE;
bFreqUpdate = TRUE;
// If we are transitioning to high-speed and high-speed bus
if (g_CurSpeed == DVFC_SPEED_HIGH)
{
// Set VSCNT to minumum, voltage will by scaled by
// software to prevent peripheral overrun/underrun
// due to SDMA being disabled during DVS
CSP_BITFINS(pmcr0, CCM_PMCR0_VSCNT, 0);
// Scale the DVS voltage to the high-speed setpoint
// voltage.
DvfcScaleVoltage(g_SetPoint[DVFC_SPEED_LOW].sw,
g_SetPoint[DVFC_SPEED_LOW].swVolt,
g_LowBusVolt,
g_MC13783SwitcherVoltTable[0]);
RETAILMSG(g_bVerbose, (_T("DVFS BUS SCALE CPU/BUS = HIGH/HIGH\r\n")));
}
// Else we are staying at low CPU speed, but
// transitioning to high-speed bus
else
{
// Scale the DVS voltage higher before increasing
// the bus speed.
DvfcScaleVoltage(g_SetPoint[DVFC_SPEED_LOW].sw,
g_SetPoint[DVFC_SPEED_LOW].swVolt,
g_LowBusVolt,
g_LowSpeedVolt);
RETAILMSG(g_bVerbose, (_T("DVFS BUS SCALE CPU/BUS = LOW/HIGH\r\n")));
}
// Force DPTC logic to return to highest setpoint when we
// switch to high speed. This will provide a safe setpoint
// since we may have been in the scaled bus mode for a while.
g_SetPoint[DVFC_SPEED_HIGH].voltIndex = 0;
PmicSwitchModeRegulatorSetVoltageLevel(
g_SetPoint[DVFC_SPEED_HIGH].voltIndex,
g_SetPoint[DVFC_SPEED_HIGH].swVolt,
g_MC13783SwitcherVoltTable[0]);
}
// Check for scaling bus to low-speed
if (CSP_BITFEXT(pdr0, CCM_PDR0_MAX_PODF) < ahbPodf)
{
// Scale the AHB/IPG dividers
CSP_BITFINS(pdr0, CCM_PDR0_MAX_PODF, DVFC_SCALED_AHB_PODF);
CSP_BITFINS(pdr0, CCM_PDR0_IPG_PODF, DVFC_SCALED_IPG_PODF);
// Configure SDMA ACR setting for 1:1 ratio
acr = SDMA_CONFIG_ACR_AHB1X;
// Set flags for bus/frequency scaling
bBusUpdate = TRUE;
bFreqUpdate = TRUE;
RETAILMSG(g_bVerbose, (_T("DVFS BUS SCALE CPU/BUS = LOW/LOW\r\n")));
}
// If bus will be scaled
if (bBusUpdate)
{
// Acquire bus scaling lock
DVFC_ACRLOCK();
// Save active DMA channels
stop_stat = INREG32(&g_pSDMA->STOP_STAT);
// Halt active DMA channels
OUTREG32(&g_pSDMA->STOP_STAT, stop_stat);
// Wait for SDMA to go idle
while ((INREG32(&g_pSDMA->ONCE_STAT) & 0xF000) != 0x6000)
{
// RETAILMSG(TRUE, (_T("Waiting for DMA idle\r\n")));
}
}
// Disable DPTC voltage change requests
CSP_BITFINS(pmcr0, CCM_PMCR0_DPVCR, CCM_PMCR0_DPVCR_NO_CHANGE_REQ);
// Configure DVS signals
CSP_BITFINS(pmcr0, CCM_PMCR0_DVSUP, pSP->dvs);
// Update the power management control register
OUTREG32(&g_pCCM->PMCR0, pmcr0);
// If we are scaling the frequency
if (bFreqUpdate)
{
// Update the MCU dividers
CSP_BITFINS(pdr0, CCM_PDR0_MCU_PODF, pSP->mcuPodf);
// Initiate scaling by writing to PDR0
OUTREG32(&g_pCCM->PDR0, pdr0);
}
// If bus was scaled
if (bBusUpdate)
{
// Need to synchronize bus scaling by polling UPDTEN
while (EXTREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_UPDTEN) ==
CCM_PMCR0_UPDTEN_DISABLE_UPDATE);
// Configure SDMA ACR setting
INSREG32BF(&g_pSDMA->CONFIG, SDMA_CONFIG_ACR, acr);
// Restore SDMA channels active before scaling AHB/IPG
OUTREG32(&g_pSDMA->HSTART, stop_stat);
// Release bus scaling lock
DVFC_ACRUNLOCK();
// If we are scaling bus down, use software scaling
// to drop the voltage for the slower bus
if (acr == SDMA_CONFIG_ACR_AHB1X)
{
DvfcScaleVoltage(g_SetPoint[DVFC_SPEED_LOW].sw,
g_SetPoint[DVFC_SPEED_LOW].swVolt,
g_LowSpeedVolt,
g_LowBusVolt);
}
// Else bus was scaled up. If we switched to high speed,
// we need to reconfigure the low-speed voltage since we
// used software voltage scaling on this voltage setting.
else if (pSP->dvs == 0x0)
{
// Configure DVS voltage
PmicSwitchModeRegulatorSetVoltageLevel(
g_SetPoint[DVFC_SPEED_LOW].sw,
g_SetPoint[DVFC_SPEED_LOW].swVolt,
g_LowSpeedVolt);
}
RETAILMSG(g_bVerbose, (_T("ACR = %d\r\n"), acr));
}
// If DPTC is enabled for the current setpoint
if (pSP->dpten)
{
// If DPTC wants us to update the voltage
if (bVoltUpdate)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -