/* SPDX-License-Identifier: BSD-3-Clause */
|
/*
|
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
|
*/
|
#include "Include/Library/CruLib.h"
|
#include <Library/DebugLib.h>
|
/** @addtogroup RK_HAL_Driver
|
* @{
|
*/
|
|
/** @addtogroup CRU
|
* @{
|
*/
|
|
/** @defgroup CRU_Private_Definition Private Definition
|
* @{
|
*/
|
/********************* Private MACRO Definition ******************************/
|
/********************* Private Structure Definition **************************/
|
|
static struct PLL_CONFIG PLL_TABLE[] = {
|
/* _mhz, _refDiv, _fbDiv, _postdDv1, _postDiv2, _dsmpd, _frac */
|
RK3588_PLL_RATE(1680000000, 2, 280, 1, 0),
|
RK3588_PLL_RATE(1512000000, 2, 252, 1, 0),
|
RK3588_PLL_RATE(1416000000, 2, 236, 1, 0),
|
RK3588_PLL_RATE(1188000000, 2, 198, 1, 0),
|
RK3588_PLL_RATE(1008000000, 2, 336, 2, 0),
|
RK3588_PLL_RATE(1000000000, 3, 500, 2, 0),
|
RK3588_PLL_RATE(983040000, 4, 655, 2, 23592),
|
RK3588_PLL_RATE(816000000, 2, 272, 2, 0),
|
RK3588_PLL_RATE(100000000, 3, 400, 5, 0),
|
{ /* sentinel */ },
|
};
|
|
static struct PLL_SETUP LPLL = {
|
.conOffset0 = &(DSUCRU->LPLL_CON[0]),
|
.conOffset1 = &(DSUCRU->LPLL_CON[1]),
|
.conOffset2 = &(DSUCRU->LPLL_CON[2]),
|
.conOffset3 = &(DSUCRU->LPLL_CON[3]),
|
.conOffset6 = &(DSUCRU->LPLL_CON[6]),
|
.modeOffset = &(DSUCRU->MODE_CON00),
|
.modeShift = 0,
|
.lockShift = 15,
|
.modeMask = 0x3,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP B0PLL = {
|
.conOffset0 = &(BIGCORE0CRU->B0PLL_CON[0]),
|
.conOffset1 = &(BIGCORE0CRU->B0PLL_CON[1]),
|
.conOffset2 = &(BIGCORE0CRU->B0PLL_CON[2]),
|
.conOffset3 = &(BIGCORE0CRU->B0PLL_CON[3]),
|
.conOffset6 = &(BIGCORE0CRU->B0PLL_CON[6]),
|
.modeOffset = &(BIGCORE0CRU->MODE_CON00),
|
.modeShift = 0,
|
.lockShift = 15,
|
.modeMask = 0x3,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP B1PLL = {
|
.conOffset0 = &(BIGCORE1CRU->B1PLL_CON[0]),
|
.conOffset1 = &(BIGCORE1CRU->B1PLL_CON[1]),
|
.conOffset2 = &(BIGCORE1CRU->B1PLL_CON[2]),
|
.conOffset3 = &(BIGCORE1CRU->B1PLL_CON[3]),
|
.conOffset6 = &(BIGCORE1CRU->B1PLL_CON[6]),
|
.modeOffset = &(BIGCORE1CRU->MODE_CON00),
|
.modeShift = 0,
|
.lockShift = 15,
|
.modeMask = 0x3,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP CPLL = {
|
.conOffset0 = &(CRU->CPLL_CON[0]),
|
.conOffset1 = &(CRU->CPLL_CON[1]),
|
.conOffset2 = &(CRU->CPLL_CON[2]),
|
.conOffset3 = &(CRU->CPLL_CON[3]),
|
.conOffset6 = &(CRU->CPLL_CON[6]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 8,
|
.lockShift = 15,
|
.modeMask = 0x3 << 8,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP GPLL = {
|
.conOffset0 = &(CRU->GPLL_CON[0]),
|
.conOffset1 = &(CRU->GPLL_CON[1]),
|
.conOffset2 = &(CRU->GPLL_CON[2]),
|
.conOffset3 = &(CRU->GPLL_CON[3]),
|
.conOffset6 = &(CRU->GPLL_CON[6]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 2,
|
.lockShift = 15,
|
.modeMask = 0x3 << 2,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP NPLL = {
|
.conOffset0 = &(CRU->NPLL_CON[0]),
|
.conOffset1 = &(CRU->NPLL_CON[1]),
|
.conOffset2 = &(CRU->NPLL_CON[2]),
|
.conOffset3 = &(CRU->NPLL_CON[3]),
|
.conOffset6 = &(CRU->NPLL_CON[6]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 0,
|
.lockShift = 15,
|
.modeMask = 0x3 << 0,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP V0PLL = {
|
.conOffset0 = &(CRU->V0PLL_CON[0]),
|
.conOffset1 = &(CRU->V0PLL_CON[1]),
|
.conOffset2 = &(CRU->V0PLL_CON[2]),
|
.conOffset3 = &(CRU->V0PLL_CON[3]),
|
.conOffset6 = &(CRU->V0PLL_CON[6]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 4,
|
.lockShift = 15,
|
.modeMask = 0x3 << 4,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP AUPLL = {
|
.conOffset0 = &(CRU->AUPLL_CON[0]),
|
.conOffset1 = &(CRU->AUPLL_CON[1]),
|
.conOffset2 = &(CRU->AUPLL_CON[2]),
|
.conOffset3 = &(CRU->AUPLL_CON[3]),
|
.conOffset6 = &(CRU->AUPLL_CON[6]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 6,
|
.lockShift = 15,
|
.modeMask = 0x3 << 6,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP PPLL = {
|
.conOffset0 = &(PHPTOPCRU->PPLL_CON[0]),
|
.conOffset1 = &(PHPTOPCRU->PPLL_CON[1]),
|
.conOffset2 = &(PHPTOPCRU->PPLL_CON[2]),
|
.conOffset3 = &(PHPTOPCRU->PPLL_CON[3]),
|
.conOffset6 = &(PHPTOPCRU->PPLL_CON[6]),
|
.lockShift = 15,
|
.rateTable = PLL_TABLE,
|
};
|
|
/********************* Private Variable Definition ***************************/
|
|
static uint32_t s_lpllFreq;
|
static uint32_t s_cpllFreq = 1500 * 1000 * 1000;;
|
static uint32_t s_gpllFreq = 1188 * 1000 * 1000;
|
static uint32_t s_npllFreq;
|
static uint32_t s_v0pllFreq;
|
static uint32_t s_ppllFreq;
|
static uint32_t s_aupllFreq;
|
|
/********************* Private Function Definition ***************************/
|
|
/** @} */
|
/********************* Public Function Definition ****************************/
|
|
/**
|
* @brief Get clk freq.
|
* @param clockName: CLOCK_Name id.
|
* @return rate.
|
* @attention these APIs allow direct use in the HAL layer.
|
*/
|
uint32_t
|
EFIAPI
|
HAL_CRU_ClkGetFreq(eCLOCK_Name clockName)
|
{
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
uint32_t pRate = 0, freq;
|
|
if (!s_cpllFreq) {
|
s_cpllFreq = HAL_CRU_GetPllV1Freq(&CPLL);
|
}
|
|
switch (clockName) {
|
case PLL_LPLL:
|
freq = HAL_CRU_GetPllV1Freq(&LPLL);
|
s_lpllFreq = freq;
|
|
return freq;
|
case PLL_B0PLL:
|
freq = HAL_CRU_GetPllV1Freq(&B0PLL);
|
|
return freq;
|
case PLL_B1PLL:
|
freq = HAL_CRU_GetPllV1Freq(&B1PLL);
|
|
return freq;
|
case PLL_CPLL:
|
freq = HAL_CRU_GetPllV1Freq(&CPLL);
|
s_cpllFreq = freq;
|
|
return freq;
|
case PLL_NPLL:
|
freq = HAL_CRU_GetPllV1Freq(&NPLL);
|
s_npllFreq = freq;
|
|
return freq;
|
case PLL_V0PLL:
|
freq = HAL_CRU_GetPllV1Freq(&V0PLL);
|
s_v0pllFreq = freq;
|
|
return freq;
|
case PLL_AUPLL:
|
freq = HAL_CRU_GetPllV1Freq(&AUPLL);
|
s_aupllFreq = freq;
|
|
return freq;
|
case PLL_PPLL:
|
freq = HAL_CRU_GetPllV1Freq(&PPLL);
|
s_ppllFreq = freq;
|
|
return freq;
|
case PLL_GPLL:
|
freq = HAL_CRU_GetPllV1Freq(&GPLL);
|
s_gpllFreq = freq;
|
|
return s_gpllFreq;
|
case CCLK_EMMC:
|
case SCLK_SFC:
|
case CCLK_SRC_SDIO:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
pRate = s_gpllFreq;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
pRate = s_cpllFreq;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
pRate = PLL_INPUT_OSC_RATE;
|
}
|
|
return pRate / HAL_CRU_ClkGetDiv(clkDiv) ;
|
case BCLK_EMMC:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
pRate = s_gpllFreq;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
pRate = s_cpllFreq;
|
}
|
|
return pRate / HAL_CRU_ClkGetDiv(clkDiv) ;
|
case CLK_REF_PIPE_PHY0:
|
case CLK_REF_PIPE_PHY1:
|
case CLK_REF_PIPE_PHY2:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
return PLL_INPUT_OSC_RATE;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
return s_ppllFreq / HAL_CRU_ClkGetDiv(clkDiv) ;
|
}
|
default:
|
break;
|
}
|
|
if ((clkMux == 0) && (clkDiv == 0)) {
|
return 0;
|
}
|
|
if (clkDiv) {
|
freq = pRate / (HAL_CRU_ClkGetDiv(clkDiv));
|
} else {
|
freq = pRate;
|
}
|
|
return freq;
|
}
|
|
/**
|
* @brief Set clk freq.
|
* @param clockName: CLOCK_Name id.
|
* @param rate: clk rate.
|
* @return HAL_Status.
|
* @attention these APIs allow direct use in the HAL layer.
|
*/
|
HAL_Status
|
EFIAPI
|
HAL_CRU_ClkSetFreq(eCLOCK_Name clockName, uint32_t rate)
|
{
|
HAL_Status error = HAL_OK;
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
uint32_t mux = 0, div = 0, pRate = 0;
|
|
if (!s_cpllFreq) {
|
s_cpllFreq = HAL_CRU_GetPllV1Freq(&CPLL);
|
}
|
|
switch (clockName) {
|
case PLL_LPLL:
|
error = HAL_CRU_SetPllV1Freq(&LPLL, rate);
|
s_lpllFreq = HAL_CRU_GetPllV1Freq(&LPLL);
|
|
return error;
|
case PLL_B0PLL:
|
error = HAL_CRU_SetPllV1Freq(&B0PLL, rate);
|
|
return error;
|
case PLL_B1PLL:
|
error = HAL_CRU_SetPllV1Freq(&B1PLL, rate);
|
|
return error;
|
case PLL_CPLL:
|
error = HAL_CRU_SetPllV1Freq(&CPLL, rate);
|
s_cpllFreq = HAL_CRU_GetPllV1Freq(&CPLL);
|
|
return error;
|
case PLL_PPLL:
|
error = HAL_CRU_SetPllV1Freq(&PPLL, rate);
|
s_ppllFreq = HAL_CRU_GetPllV1Freq(&PPLL);
|
|
return error;
|
case PLL_GPLL:
|
error = HAL_CRU_SetPllV1Freq(&GPLL, rate);
|
DEBUG ((DEBUG_INIT, "GPLL set rate: %d %x\n", rate, error));
|
s_gpllFreq = HAL_CRU_GetPllV1Freq(&GPLL);
|
return error;
|
case PLL_NPLL:
|
error = HAL_CRU_SetPllV1Freq(&NPLL, rate);
|
s_npllFreq = HAL_CRU_GetPllV1Freq(&NPLL);
|
|
return error;
|
case PLL_AUPLL:
|
error = HAL_CRU_SetPllV1Freq(&AUPLL, rate);
|
s_aupllFreq = HAL_CRU_GetPllV1Freq(&AUPLL);
|
|
return error;
|
case PLL_V0PLL:
|
error = HAL_CRU_SetPllV1Freq(&V0PLL, rate);
|
s_v0pllFreq = HAL_CRU_GetPllV1Freq(&V0PLL);
|
|
return error;
|
|
case CCLK_EMMC:
|
case SCLK_SFC:
|
case CCLK_SRC_SDIO:
|
if (PLL_INPUT_OSC_RATE % rate == 0) {
|
pRate = PLL_INPUT_OSC_RATE;
|
mux = 2;
|
} else if (s_cpllFreq % rate == 0){
|
pRate = s_cpllFreq;
|
mux = 1;
|
} else {
|
pRate = s_gpllFreq;
|
mux = 0;
|
}
|
break;
|
case BCLK_EMMC:
|
if (s_cpllFreq % rate == 0){
|
pRate = s_cpllFreq;
|
mux = 1;
|
} else {
|
pRate = s_gpllFreq;
|
mux = 0;
|
}
|
break;
|
|
case CLK_REF_PIPE_PHY0:
|
case CLK_REF_PIPE_PHY1:
|
case CLK_REF_PIPE_PHY2:
|
if (rate == PLL_INPUT_OSC_RATE) {
|
HAL_CRU_ClkSetMux(clkMux, 0);
|
HAL_CRU_ClkSetDiv(clkDiv, 0);
|
} else {
|
div = HAL_DIV_ROUND_UP(s_ppllFreq, rate);
|
HAL_CRU_ClkSetDiv(clkDiv, div);
|
HAL_CRU_ClkSetMux(clkMux, 1);
|
}
|
return HAL_OK;
|
|
default:
|
break;
|
}
|
|
if ((clkMux == 0) && (clkDiv == 0)) {
|
return HAL_INVAL;
|
}
|
|
div = HAL_DIV_ROUND_UP(pRate, rate);
|
if (clkMux) {
|
HAL_CRU_ClkSetMux(clkMux, mux);
|
}
|
if (clkDiv) {
|
HAL_CRU_ClkSetDiv(clkDiv, div);
|
}
|
|
return HAL_OK;
|
}
|
/** @} */
|
|
/** @} */
|
|
/** @} */
|