📄 ddk_clk.c
字号:
// Allow OEM to configure EMI clock gating
BSPClockSetEmiGatingMode(index, mode);
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: DDKClockGetGatingMode
//
// Retrieves the clock gating mode of the peripheral.
//
// Parameters:
// index
// [in] Index for referencing the peripheral clock gating control
// bits.
//
// pMode
// [out] Current clock gating mode for the peripheral.
//
// Returns:
// Returns TRUE if the clock gating mode was set successfully, otherwise
// returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKClockGetGatingMode(DDK_CLOCK_GATE_INDEX index, DDK_CLOCK_GATE_MODE *pMode)
{
UINT32 mcgrIndex, mcgrShift;
// Divide clock gating index by 16 to determine MCGR register index
mcgrIndex = index >> 4;
// Calculate shift for MCG bits by using the index within the
// MCGR register (0-15) and multiply by 2
mcgrShift = (index % 16) << 1;
*pMode = ((INREG32(&g_pCCM->CGR[mcgrIndex])) >> mcgrShift)
& CCM_CGR_CG_MASK;
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: DDKClockGetFreq
//
// Retrieves the clock frequency in Hz for the specified clock signal.
//
// Parameters:
// sig
// [in] Clock signal.
//
// freq
// [out] Current frequency in Hz.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKClockGetFreq(DDK_CLOCK_SIGNAL sig, UINT32 *freq)
{
return BSPClockGetFreq(sig, freq);
}
//-----------------------------------------------------------------------------
//
// Function: DDKClockConfigBaud
//
// Configures the input source clock and dividers for the specified
// CCM peripheral baud clock output.
//
// Parameters:
// sig
// [in] Clock signal to configure.
//
// src
// [in] Selects the input clock source.
//
// preDiv
// [in] Specifies the value programmed into the baud clock predivider.
//
// postDiv
// [in] Specifies the value programmed into the baud clock postdivider.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKClockConfigBaud(DDK_CLOCK_SIGNAL sig, DDK_CLOCK_BAUD_SOURCE src,
UINT32 preDiv, UINT32 postDiv)
{
BOOL rc = TRUE;
UINT32 oldReg, newReg, *pPDR;
UINT32 ccmrShift, ccmrMask;
UINT32 preDivShift, preDivMask, postDivShift, postDivMask;
switch (sig)
{
case DDK_CLOCK_SIGNAL_SSI1:
ccmrShift = CCM_CCMR_SSI1S_LSH;
ccmrMask = CSP_BITFMASK(CCM_CCMR_SSI1S);
preDivShift = CCM_PDR1_SSI1_PRE_PODF_LSH;
preDivMask = CSP_BITFMASK(CCM_PDR1_SSI1_PRE_PODF);
postDivShift = CCM_PDR1_SSI1_PODF_LSH;
postDivMask = CSP_BITFMASK(CCM_PDR1_SSI1_PODF);
pPDR = &g_pCCM->PDR1;
break;
case DDK_CLOCK_SIGNAL_SSI2:
ccmrShift = CCM_CCMR_SSI2S_LSH;
ccmrMask = CSP_BITFMASK(CCM_CCMR_SSI2S);
preDivShift = CCM_PDR1_SSI2_PRE_PODF_LSH;
preDivMask = CSP_BITFMASK(CCM_PDR1_SSI2_PRE_PODF);
postDivShift = CCM_PDR1_SSI2_PODF_LSH;
postDivMask = CSP_BITFMASK(CCM_PDR1_SSI2_PODF);
pPDR = &g_pCCM->PDR1;
break;
case DDK_CLOCK_SIGNAL_FIRI:
ccmrShift = CCM_CCMR_FIRS_LSH;
ccmrMask = CSP_BITFMASK(CCM_CCMR_FIRS);
preDivShift = CCM_PDR1_FIRI_PRE_PODF_LSH;
preDivMask = CSP_BITFMASK(CCM_PDR1_FIRI_PRE_PODF);
postDivShift = CCM_PDR1_FIRI_PODF_LSH;
postDivMask = CSP_BITFMASK(CCM_PDR1_FIRI_PODF);
pPDR = &g_pCCM->PDR1;
break;
case DDK_CLOCK_SIGNAL_CSI:
// CSI has different clock source selections
if (src == DDK_CLOCK_BAUD_SOURCE_SERPLL)
{
src = CCM_CCMR_CSCS_SERIAL_CLK;
}
else if (src == DDK_CLOCK_BAUD_SOURCE_USBPLL)
{
src = CCM_CCMR_CSCS_USB_CLK;
}
else
{
rc = FALSE;
break;
}
ccmrShift = CCM_CCMR_CSCS_LSH;
ccmrMask = CSP_BITFMASK(CCM_CCMR_CSCS);
preDivShift = 0;
preDivMask = 0;
preDiv = 0;
postDivShift = CCM_PDR0_CSI_PODF_LSH;
postDivMask = CSP_BITFMASK(CCM_PDR0_CSI_PODF);
pPDR = &g_pCCM->PDR0;
break;
case DDK_CLOCK_SIGNAL_USB:
// USBPLL is only USB clock source
if (src != DDK_CLOCK_BAUD_SOURCE_USBPLL)
{
rc = FALSE;
break;
}
ccmrMask = 0;
preDivShift = CCM_PDR1_USB_PRDF_LSH;
preDivMask = CSP_BITFMASK(CCM_PDR1_USB_PRDF);
postDivShift = CCM_PDR1_USB_PODF_LSH;
postDivMask = CSP_BITFMASK(CCM_PDR1_USB_PODF);
pPDR = &g_pCCM->PDR1;
break;
default:
rc = FALSE;
break;
}
// If baud configuration is available
if (rc)
{
// Update the global clock signal table
BSPClockUpdateFreq(sig, src, preDiv, postDiv);
// Update the source selection
if (ccmrMask)
{
// Grab mutex before updating CCMR
WaitForSingleObject(g_hDdkClkMutex, INFINITE);
INSREG32(&g_pCCM->CCMR, ccmrMask, (src << ccmrShift));
ReleaseMutex(g_hDdkClkMutex);
}
// Update the dividers
preDiv <<= preDivShift;
preDiv &= preDivMask;
postDiv <<= postDivShift;
postDiv &= postDivMask;
do
{
oldReg = INREG32(pPDR);
newReg = (oldReg & (~(preDivMask | postDivMask)))
| (preDiv) | (postDiv);
} while (InterlockedTestExchange(pPDR,
oldReg, newReg) != oldReg);
}
return rc;
}
//-----------------------------------------------------------------------------
//
// Function: DDKClockSetCKO
//
// Configures the clock output source (CKO) signal.
//
// Parameters:
// bEnable
// [in] Set to TRUE to enable CKO output. Set to FALSE to disable
// CKO output.
//
// src
// [in] Selects the CKO source signal.
//
// div
// [in] Specifies the CKO divide factor.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKClockSetCKO(BOOL bEnable, DDK_CLOCK_CKO_SRC src, DDK_CLOCK_CKO_DIV div)
{
// Configure the CKO signal using the CCM COSR
OUTREG32(&g_pCCM->COSR, CSP_BITFVAL(CCM_COSR_CLKOEN, bEnable) |
CSP_BITFVAL(CCM_COSR_CLKOSEL, src) |
CSP_BITFVAL(CCM_COSR_CLKODIV, div));
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: DDKClockEnablePanicMode
//
// Forces the DVFS logic to report a panic condition so that the system
// will immediately transition to the highest DVFS setpoint and prevent
// future requests to a lower setpoint.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKClockEnablePanicMode(void)
{
WaitForSingleObject(g_hDvfcMutex, INFINITE);
// If this is first panic request
if (BSPClockIncrPanicRequests() == 1)
{
// Issue request to enter panic mode
SETREG32(&g_pCCM->PMCR1, DDK_CLOCK_DVFC_MODE_PANIC);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEV, CCM_PMCR0_DVFEV_REQ_ALWAYS);
}
ReleaseMutex(g_hDvfcMutex);
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: DDKClockDisablePanicMode
//
// Restores normal DVFS operation from a prior request for panic mode
// and allows the DVFS logic to request higher/lower setpoints as needed.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKClockDisablePanicMode(void)
{
WaitForSingleObject(g_hDvfcMutex, INFINITE);
// If there are no active panic requests
if (BSPClockDecrPanicRequests() == 0)
{
// Issue request to return to normal mode
CLRREG32(&g_pCCM->PMCR1, DDK_CLOCK_DVFC_MODE_PANIC);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEV, CCM_PMCR0_DVFEV_REQ_ALWAYS);
}
ReleaseMutex(g_hDvfcMutex);
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: DDKClockBusScale
//
// Scales the AHB bus clock by an integer factor.
//
// Parameters:
// ratio
// [in] Specifies the integer ratio used to scale the
// AHB bus clock.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL DDKClockBusScale(UINT32 ratio)
{
BOOL rc = TRUE;
DDK_CLOCK_GATE_MODE cgm;
DDKClockGetGatingMode(DDK_CLOCK_GATE_INDEX_IPU, &cgm);
if (cgm != DDK_CLOCK_GATE_MODE_DISABLED)
{
DEBUGMSG(TRUE, (_T("DDKClockBusScale: IPU clock is enabled, ignoring request...\r\n")));
rc = FALSE;
goto cleanUp;
}
WaitForSingleObject(g_hDvfcMutex, INFINITE);
switch(ratio)
{
// No scaling
case 1:
CLRREG32(&g_pCCM->PMCR1, DDK_CLOCK_DVFC_MODE_BUS_LOW);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEV, CCM_PMCR0_DVFEV_REQ_ALWAYS);
break;
// Scale down 1:2
case 2:
SETREG32(&g_pCCM->PMCR1, DDK_CLOCK_DVFC_MODE_BUS_LOW);
INSREG32BF(&g_pCCM->PMCR0, CCM_PMCR0_DVFEV, CCM_PMCR0_DVFEV_REQ_ALWAYS);
break;
// Invalid ratio
default:
ERRORMSG(TRUE, (_T("Invalid bus scale ratio 0x%x"), ratio));
rc = FALSE;
break;
}
ReleaseMutex(g_hDvfcMutex);
cleanUp:
return rc;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -