/* SPDX-License-Identifier: BSD-3-Clause */
|
/*
|
* Copyright (c) 2021 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 */
|
RK_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
|
RK_PLL_RATE(1512000000, 1, 126, 2, 1, 1, 0),
|
RK_PLL_RATE(1416000000, 1, 118, 2, 1, 1, 0),
|
RK_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
|
RK_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
|
RK_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0),
|
RK_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
|
RK_PLL_RATE(200000000, 1, 100, 3, 4, 1, 0),
|
{ /* sentinel */ },
|
};
|
|
static struct PLL_SETUP APLL = {
|
.conOffset0 = &(CRU->APLL_CON[0]),
|
.conOffset1 = &(CRU->APLL_CON[1]),
|
.conOffset2 = &(CRU->APLL_CON[2]),
|
.conOffset3 = &(CRU->APLL_CON[3]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 0,
|
.lockShift = 10,
|
.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]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 4,
|
.lockShift = 10,
|
.modeMask = 0x3 << 4,
|
.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]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 6,
|
.lockShift = 10,
|
.modeMask = 0x3 << 6,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP NPLL = {
|
.conOffset0 = &(CRU->NPLL_CON[0]),
|
.conOffset1 = &(CRU->NPLL_CON[1]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 10,
|
.lockShift = 10,
|
.modeMask = 0x3 << 10,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP VPLL = {
|
.conOffset0 = &(CRU->VPLL_CON[0]),
|
.conOffset1 = &(CRU->VPLL_CON[1]),
|
.modeOffset = &(CRU->MODE_CON00),
|
.modeShift = 12,
|
.lockShift = 10,
|
.modeMask = 0x3 << 12,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP PPLL = {
|
.conOffset0 = &(PMUCRU->PPLL_CON[0]),
|
.conOffset1 = &(PMUCRU->PPLL_CON[1]),
|
.conOffset2 = &(PMUCRU->PPLL_CON[2]),
|
.conOffset3 = &(PMUCRU->PPLL_CON[3]),
|
.modeOffset = &(PMUCRU->MODE_CON00),
|
.modeShift = 0,
|
.lockShift = 10,
|
.modeMask = 0x3 << 0,
|
.rateTable = PLL_TABLE,
|
};
|
|
static struct PLL_SETUP HPLL = {
|
.conOffset0 = &(PMUCRU->HPLL_CON[0]),
|
.conOffset1 = &(PMUCRU->HPLL_CON[1]),
|
.conOffset2 = &(PMUCRU->HPLL_CON[2]),
|
.conOffset3 = &(PMUCRU->HPLL_CON[3]),
|
.modeOffset = &(PMUCRU->MODE_CON00),
|
.modeShift = 2,
|
.lockShift = 10,
|
.modeMask = 0x3 << 2,
|
.rateTable = PLL_TABLE,
|
};
|
|
/********************* Private Variable Definition ***************************/
|
|
static uint32_t s_apllFreq;
|
static uint32_t s_cpllFreq;
|
static uint32_t s_gpllFreq = 1188 * 1000 * 1000;
|
static uint32_t s_npllFreq;
|
static uint32_t s_vpllFreq;
|
static uint32_t s_ppllFreq;
|
static uint32_t s_hpllFreq;
|
static uint32_t s_clk_gmac_xpcs_mii;
|
static uint32_t s_clk_gmac_in;
|
|
/********************* Private Function Definition ***************************/
|
|
/** @} */
|
/********************* Public Function Definition ****************************/
|
|
/** @defgroup CRU_Exported_Functions_Group5 Other Functions
|
* @{
|
*/
|
|
/**
|
* @brief Get frac clk freq.
|
* @param clockName: CLOCK_Name id
|
* @return clk rate.
|
* How to calculate the Frac clk divider:
|
* numerator is frac register[31:16]
|
* denominator is frac register[15:0]
|
* clk rate = pRate * numerator / denominator
|
* for a better jitter, pRate > 20 * rate
|
*/
|
static uint32_t HAL_CRU_ClkFracGetFreq(eCLOCK_Name clockName)
|
{
|
uint32_t freq = 0;
|
uint32_t muxSrc = 0, mux = CLK_GET_MUX(clockName);
|
uint32_t divSrc = 0, divFrac = 0;
|
uint32_t n, m, pRate;
|
|
switch (clockName) {
|
case CLK_UART1:
|
muxSrc = CLK_GET_MUX(CLK_UART1_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART1_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART1_FRAC);
|
break;
|
case CLK_UART2:
|
muxSrc = CLK_GET_MUX(CLK_UART2_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART2_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART2_FRAC);
|
break;
|
case CLK_UART3:
|
muxSrc = CLK_GET_MUX(CLK_UART3_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART3_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART3_FRAC);
|
break;
|
case CLK_UART4:
|
muxSrc = CLK_GET_MUX(CLK_UART4_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART4_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART4_FRAC);
|
break;
|
case CLK_UART5:
|
muxSrc = CLK_GET_MUX(CLK_UART5_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART5_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART5_FRAC);
|
break;
|
case CLK_UART6:
|
muxSrc = CLK_GET_MUX(CLK_UART6_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART6_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART6_FRAC);
|
break;
|
case CLK_UART7:
|
muxSrc = CLK_GET_MUX(CLK_UART7_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART7_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART7_FRAC);
|
break;
|
case CLK_UART8:
|
muxSrc = CLK_GET_MUX(CLK_UART8_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART8_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART8_FRAC);
|
break;
|
case CLK_UART9:
|
muxSrc = CLK_GET_MUX(CLK_UART9_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART9_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART9_FRAC);
|
break;
|
default:
|
|
return 0;
|
}
|
|
n = (CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] & 0xffff0000) >> 16;
|
m = CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] & 0x0000ffff;
|
|
if (HAL_CRU_ClkGetMux(muxSrc)) {
|
pRate = s_cpllFreq / HAL_CRU_ClkGetDiv(divSrc);
|
} else {
|
pRate = s_gpllFreq / HAL_CRU_ClkGetDiv(divSrc);
|
}
|
|
if (HAL_CRU_ClkGetMux(mux) == 0) {
|
freq = pRate;
|
} else if (HAL_CRU_ClkGetMux(mux) == 1) {
|
freq = (pRate / m) * n;
|
} else if (HAL_CRU_ClkGetMux(mux) == 2) {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
}
|
|
/**
|
* @brief Set frac clk freq.
|
* @param clockName: CLOCK_Name id.
|
* @param rate: clk set rate
|
* @return HAL_Status.
|
* How to calculate the Frac clk divider:
|
* if pRate > 20 * rate, select frac divider
|
* else select normal divider, but the clk rate may be not accurate
|
*/
|
static HAL_Status HAL_CRU_ClkFracSetFreq(eCLOCK_Name clockName, uint32_t rate)
|
{
|
uint32_t muxSrc, mux = CLK_GET_MUX(clockName);
|
uint32_t divSrc, divFrac;
|
uint32_t n = 0, m = 0;
|
uint32_t gateId, fracGateId;
|
|
switch (clockName) {
|
case CLK_UART1:
|
muxSrc = CLK_GET_MUX(CLK_UART1_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART1_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART1_FRAC);
|
gateId = CLK_UART1_GATE;
|
fracGateId = CLK_UART1_FRAC_GATE;
|
break;
|
case CLK_UART2:
|
muxSrc = CLK_GET_MUX(CLK_UART2_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART2_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART2_FRAC);
|
gateId = CLK_UART2_GATE;
|
fracGateId = CLK_UART2_FRAC_GATE;
|
break;
|
case CLK_UART3:
|
muxSrc = CLK_GET_MUX(CLK_UART3_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART3_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART3_FRAC);
|
gateId = CLK_UART3_GATE;
|
fracGateId = CLK_UART3_FRAC_GATE;
|
break;
|
case CLK_UART4:
|
muxSrc = CLK_GET_MUX(CLK_UART4_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART4_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART4_FRAC);
|
gateId = CLK_UART4_GATE;
|
fracGateId = CLK_UART4_FRAC_GATE;
|
break;
|
case CLK_UART5:
|
muxSrc = CLK_GET_MUX(CLK_UART5_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART5_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART5_FRAC);
|
gateId = CLK_UART5_GATE;
|
fracGateId = CLK_UART5_FRAC_GATE;
|
break;
|
case CLK_UART6:
|
muxSrc = CLK_GET_MUX(CLK_UART6_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART6_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART6_FRAC);
|
gateId = CLK_UART6_GATE;
|
fracGateId = CLK_UART6_FRAC_GATE;
|
break;
|
case CLK_UART7:
|
muxSrc = CLK_GET_MUX(CLK_UART7_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART7_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART7_FRAC);
|
gateId = CLK_UART7_GATE;
|
fracGateId = CLK_UART7_FRAC_GATE;
|
break;
|
case CLK_UART8:
|
muxSrc = CLK_GET_MUX(CLK_UART8_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART8_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART8_FRAC);
|
gateId = CLK_UART8_GATE;
|
fracGateId = CLK_UART8_FRAC_GATE;
|
break;
|
case CLK_UART9:
|
muxSrc = CLK_GET_MUX(CLK_UART9_SRC);
|
divSrc = CLK_GET_DIV(CLK_UART9_SRC);
|
divFrac = CLK_GET_DIV(CLK_UART9_FRAC);
|
gateId = CLK_UART9_GATE;
|
fracGateId = CLK_UART9_FRAC_GATE;
|
break;
|
default:
|
|
return HAL_INVAL;
|
}
|
|
HAL_CRU_ClkEnable(gateId);
|
HAL_CRU_ClkEnable(fracGateId);
|
if (PLL_INPUT_OSC_RATE == rate) {
|
HAL_CRU_ClkSetMux(mux, 2);
|
HAL_CRU_ClkDisable(gateId);
|
} else if ((!(s_gpllFreq % rate)) && ((s_gpllFreq / rate) < 31)) {
|
HAL_CRU_ClkSetDiv(divSrc, s_gpllFreq / rate);
|
HAL_CRU_ClkSetMux(muxSrc, 0);
|
HAL_CRU_ClkSetMux(mux, 0);
|
HAL_CRU_ClkDisable(fracGateId);
|
} else if ((!(s_cpllFreq % rate)) && ((s_cpllFreq / rate) < 31)) {
|
HAL_CRU_ClkSetDiv(divSrc, s_cpllFreq / rate);
|
HAL_CRU_ClkSetMux(muxSrc, 1);
|
HAL_CRU_ClkSetMux(mux, 0);
|
HAL_CRU_ClkDisable(fracGateId);
|
} else {
|
HAL_CRU_FracdivGetConfig(rate, s_gpllFreq, &n, &m);
|
HAL_CRU_ClkSetDiv(divSrc, 1);
|
HAL_CRU_ClkSetMux(muxSrc, 0);
|
CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] = (n << 16) | m;
|
HAL_CRU_ClkSetMux(mux, 1);
|
}
|
|
return HAL_OK;
|
}
|
|
/**
|
* @brief Get gmac clk freq.
|
* @param clockName: CLOCK_Name id
|
* @return clk rate.
|
*/
|
static uint32_t HAL_CRU_ClkGmacGetFreq(eCLOCK_Name clockName)
|
{
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
uint32_t freq;
|
|
switch (clockName) {
|
case ACLK_PHP:
|
case ACLK_USB:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = 297000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 198000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 99000000;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
case HCLK_PHP:
|
case HCLK_USB:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = 148500000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 99000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 74250000;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
case PCLK_PHP:
|
freq = HAL_CRU_ClkGmacGetFreq(ACLK_PHP) / (HAL_CRU_ClkGetDiv(clkDiv));
|
|
return freq;
|
case PCLK_USB:
|
freq = HAL_CRU_ClkGmacGetFreq(ACLK_USB) / (HAL_CRU_ClkGetDiv(clkDiv));
|
|
return freq;
|
case CLK_MAC0_2TOP:
|
case CLK_MAC1_2TOP:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = 125000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 50000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 25000000;
|
} else {
|
freq = HAL_CRU_ClkGetFreq(PLL_PPLL);
|
}
|
|
return freq;
|
|
case CLK_MAC0_OUT:
|
case CLK_MAC1_OUT:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = 125000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 50000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 25000000;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
|
case CLK_GMAC0_PTP_REF:
|
case CLK_GMAC1_PTP_REF:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = 62500;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 100000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 50000000;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
|
case SCLK_GMAC0_RGMII_SPEED:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP);
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP);
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP) / 50;
|
} else {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP) / 5;
|
}
|
|
return freq;
|
|
case SCLK_GMAC1_RGMII_SPEED:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP);
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP);
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP) / 50;
|
} else {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP) / 5;
|
}
|
|
return freq;
|
|
case SCLK_GMAC0_RMII_SPEED:
|
if (HAL_CRU_ClkGetMux(clkMux)) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP) / 2;
|
} else {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP) / 20;
|
}
|
|
return freq;
|
|
case SCLK_GMAC1_RMII_SPEED:
|
if (HAL_CRU_ClkGetMux(clkMux)) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP) / 2;
|
} else {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP) / 20;
|
}
|
|
return freq;
|
case SCLK_GMAC0:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP);
|
} else {
|
freq = s_clk_gmac_in;
|
}
|
|
return freq;
|
|
case SCLK_GMAC1:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP);
|
} else {
|
freq = s_clk_gmac_in;
|
}
|
|
return freq;
|
|
case SCLK_GMAC0_RX_TX:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = HAL_CRU_ClkGetFreq(SCLK_GMAC0_RGMII_SPEED);
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = HAL_CRU_ClkGetFreq(SCLK_GMAC0_RMII_SPEED);
|
} else {
|
freq = s_clk_gmac_xpcs_mii;
|
}
|
|
return freq;
|
case SCLK_GMAC1_RX_TX:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = HAL_CRU_ClkGetFreq(SCLK_GMAC1_RGMII_SPEED);
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = HAL_CRU_ClkGetFreq(SCLK_GMAC1_RMII_SPEED);
|
} else {
|
freq = s_clk_gmac_xpcs_mii;
|
}
|
|
return freq;
|
default:
|
|
return 0;
|
}
|
}
|
|
/**
|
* @brief Set gmac clk freq.
|
* @param clockName: CLOCK_Name id.
|
* @param rate: clk set rate
|
* @return HAL_Status.
|
*/
|
static HAL_Status HAL_CRU_ClkGmacSetFreq(eCLOCK_Name clockName, uint32_t rate)
|
{
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
uint32_t clkDiv = CLK_GET_DIV(clockName);
|
uint32_t mux = 0, div = 0;
|
|
switch (clockName) {
|
case ACLK_PHP:
|
case ACLK_USB:
|
if (rate >= 297000000) {
|
mux = 0;
|
} else if (rate >= 198000000) {
|
mux = 1;
|
} else if (rate >= 99000000) {
|
mux = 2;
|
} else {
|
mux = 3;
|
}
|
break;
|
case HCLK_PHP:
|
case HCLK_USB:
|
if (rate >= 148500000) {
|
mux = 0;
|
} else if (rate >= 99000000) {
|
mux = 1;
|
} else if (rate >= 74250000) {
|
mux = 2;
|
} else {
|
mux = 3;
|
}
|
break;
|
case PCLK_PHP:
|
div = HAL_DIV_ROUND_UP(HAL_CRU_ClkGmacGetFreq(ACLK_PHP), rate);
|
|
break;
|
case PCLK_USB:
|
div = HAL_DIV_ROUND_UP(HAL_CRU_ClkGmacGetFreq(ACLK_USB), rate);
|
|
break;
|
|
case CLK_MAC0_2TOP:
|
case CLK_MAC1_2TOP:
|
case CLK_MAC0_OUT:
|
case CLK_MAC1_OUT:
|
if (rate == 125000000) {
|
mux = 0;
|
} else if (rate == 50000000) {
|
mux = 1;
|
} else if (rate == 25000000) {
|
mux = 2;
|
} else {
|
mux = 3;
|
}
|
|
break;
|
|
case CLK_GMAC0_PTP_REF:
|
case CLK_GMAC1_PTP_REF:
|
if (rate == 62500) {
|
mux = 0;
|
} else if (rate == 100000000) {
|
mux = 1;
|
} else if (rate == 50000000) {
|
mux = 2;
|
} else {
|
mux = 3;
|
}
|
|
break;
|
|
case SCLK_GMAC0_RGMII_SPEED:
|
if (rate == HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP) / 50) {
|
mux = 2;
|
} else if (rate == HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP) / 5) {
|
mux = 3;
|
} else {
|
mux = 0;
|
}
|
break;
|
|
case SCLK_GMAC1_RGMII_SPEED:
|
if (rate == HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP) / 50) {
|
mux = 2;
|
} else if (rate == HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP) / 5) {
|
mux = 3;
|
} else {
|
mux = 0;
|
}
|
break;
|
|
case SCLK_GMAC0_RMII_SPEED:
|
if (rate == HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP) / 2) {
|
mux = 1;
|
} else {
|
mux = 0;
|
}
|
break;
|
|
case SCLK_GMAC1_RMII_SPEED:
|
if (rate == HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP) / 2) {
|
mux = 1;
|
} else {
|
mux = 0;
|
}
|
break;
|
case SCLK_GMAC0:
|
if (rate == HAL_CRU_ClkGetFreq(CLK_MAC0_2TOP)) {
|
mux = 0;
|
} else {
|
mux = 1;
|
}
|
break;
|
|
case SCLK_GMAC1:
|
if (rate == HAL_CRU_ClkGetFreq(CLK_MAC1_2TOP)) {
|
mux = 0;
|
} else {
|
mux = 1;
|
}
|
break;
|
|
case SCLK_GMAC0_RX_TX:
|
if (rate == HAL_CRU_ClkGetFreq(SCLK_GMAC0_RGMII_SPEED)) {
|
mux = 0;
|
} else if (rate == HAL_CRU_ClkGetFreq(SCLK_GMAC0_RMII_SPEED)) {
|
mux = 1;
|
} else {
|
mux = 2;
|
}
|
break;
|
case SCLK_GMAC1_RX_TX:
|
if (rate == HAL_CRU_ClkGetFreq(SCLK_GMAC1_RGMII_SPEED)) {
|
mux = 0;
|
} else if (rate == HAL_CRU_ClkGetFreq(SCLK_GMAC1_RMII_SPEED)) {
|
mux = 1;
|
} else {
|
mux = 2;
|
}
|
break;
|
default:
|
|
return HAL_INVAL;
|
}
|
|
if (clkMux) {
|
HAL_CRU_ClkSetMux(clkMux, mux);
|
}
|
if (clkDiv) {
|
HAL_CRU_ClkSetDiv(clkDiv, div);
|
}
|
|
return HAL_OK;
|
}
|
|
/**
|
* @brief Get mmc clk freq.
|
* @param clockName: CLOCK_Name id
|
* @return clk rate.
|
*/
|
static uint32_t HAL_CRU_ClkMmcGetFreq(eCLOCK_Name clockName)
|
{
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
uint32_t freq;
|
|
switch (clockName) {
|
case BCLK_EMMC:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = 198000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 148500000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 125000000;
|
}
|
|
return freq;
|
case CCLK_EMMC:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = PLL_INPUT_OSC_RATE;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 198000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 148500000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 3) {
|
freq = 100000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 4) {
|
freq = 50000000;
|
} else {
|
freq = 375000;
|
}
|
|
return freq;
|
|
case DCLK_SDMMC_BUFFER:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = 99000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 74250000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 50000000;
|
}
|
|
return freq;
|
|
case CLK_SDMMC0:
|
case CLK_SDMMC1:
|
case CLK_SDMMC2:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = PLL_INPUT_OSC_RATE;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 396000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 297000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 3) {
|
freq = 100000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 4) {
|
freq = 50000000;
|
} else {
|
freq = 750000;
|
}
|
|
return freq;
|
|
default:
|
|
return 0;
|
}
|
}
|
|
/**
|
* @brief Set mmc clk freq.
|
* @param clockName: CLOCK_Name id.
|
* @param rate: clk set rate
|
* @return HAL_Status.
|
*/
|
static HAL_Status HAL_CRU_ClkMmcSetFreq(eCLOCK_Name clockName, uint32_t rate)
|
{
|
uint32_t clkMux = CLK_GET_MUX(clockName);
|
uint32_t mux = 0;
|
|
switch (clockName) {
|
case BCLK_EMMC:
|
if (rate >= 198000000) {
|
mux = 0;
|
} else if (rate >= 148000000) {
|
mux = 1;
|
} else {
|
mux = 2;
|
}
|
break;
|
|
case CCLK_EMMC:
|
if (rate >= 198000000) {
|
mux = 1;
|
} else if (rate >= 148000000) {
|
mux = 2;
|
} else if (rate >= 100000000) {
|
mux = 3;
|
} else if (rate >= 50000000) {
|
mux = 4;
|
} else if (rate >= 24000000) {
|
mux = 0;
|
} else {
|
mux = 5;
|
}
|
break;
|
|
case DCLK_SDMMC_BUFFER:
|
if (rate >= 99000000) {
|
mux = 0;
|
} else if (rate >= 74000000) {
|
mux = 1;
|
} else {
|
mux = 2;
|
}
|
break;
|
|
case CLK_SDMMC0:
|
case CLK_SDMMC1:
|
case CLK_SDMMC2:
|
if (rate >= 396000000) {
|
mux = 1;
|
} else if (rate >= 297000000) {
|
mux = 2;
|
} else if (rate >= 100000000) {
|
mux = 3;
|
} else if (rate >= 50000000) {
|
mux = 4;
|
} else if (rate >= 24000000) {
|
mux = 0;
|
} else {
|
mux = 5;
|
}
|
break;
|
|
default:
|
|
return 0;
|
}
|
if (clkMux) {
|
HAL_CRU_ClkSetMux(clkMux, mux);
|
}
|
|
return HAL_OK;
|
}
|
|
/**
|
* @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_GetPllFreq(&CPLL);
|
}
|
|
switch (clockName) {
|
case PLL_APLL:
|
freq = HAL_CRU_GetPllFreq(&APLL);
|
s_apllFreq = freq;
|
|
return freq;
|
case PLL_CPLL:
|
freq = HAL_CRU_GetPllFreq(&CPLL);
|
s_cpllFreq = freq;
|
|
return freq;
|
case PLL_NPLL:
|
freq = HAL_CRU_GetPllFreq(&NPLL);
|
s_npllFreq = freq;
|
|
return freq;
|
case PLL_VPLL:
|
freq = HAL_CRU_GetPllFreq(&VPLL);
|
s_vpllFreq = freq;
|
|
return freq;
|
case PLL_HPLL:
|
freq = HAL_CRU_GetPllFreq(&HPLL);
|
s_hpllFreq = freq;
|
|
return freq;
|
case PLL_PPLL:
|
freq = HAL_CRU_GetPllFreq(&PPLL);
|
s_ppllFreq = freq;
|
|
return freq;
|
case PLL_GPLL:
|
freq = HAL_CRU_GetPllFreq(&GPLL);
|
s_gpllFreq = freq;
|
|
return s_gpllFreq;
|
case CLK_WDT:
|
|
return PLL_INPUT_OSC_RATE;
|
case CLK_I2C:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = s_gpllFreq / 6;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = s_gpllFreq / 12;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = PLL_INPUT_OSC_RATE;
|
} else {
|
freq = s_cpllFreq / 10;
|
}
|
|
return freq;
|
case CLK_PWM1:
|
case CLK_PWM2:
|
case CLK_PWM3:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = s_gpllFreq / 12;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = PLL_INPUT_OSC_RATE;
|
} else {
|
freq = s_cpllFreq / 10;
|
}
|
|
return freq;
|
case CLK_SPI0:
|
case CLK_SPI1:
|
case CLK_SPI2:
|
case CLK_SPI3:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = s_gpllFreq / 6;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = PLL_INPUT_OSC_RATE;
|
} else {
|
freq = s_cpllFreq / 10;
|
}
|
|
return freq;
|
case CLK_UART1:
|
case CLK_UART2:
|
case CLK_UART3:
|
case CLK_UART4:
|
case CLK_UART5:
|
case CLK_UART6:
|
case CLK_UART7:
|
case CLK_UART8:
|
case CLK_UART9:
|
freq = HAL_CRU_ClkFracGetFreq(clockName);
|
|
return freq;
|
case CLK_CAN0:
|
case CLK_CAN1:
|
case CLK_CAN2:
|
if (HAL_CRU_ClkGetMux(clkMux)) {
|
pRate = s_cpllFreq;
|
} else {
|
pRate = s_gpllFreq;
|
}
|
|
break;
|
|
case CLK_TSADC_TSEN:
|
if (HAL_CRU_ClkGetMux(clkMux)) {
|
pRate = s_gpllFreq / 12;
|
} else {
|
pRate = PLL_INPUT_OSC_RATE;
|
}
|
|
break;
|
case CLK_TSADC:
|
pRate = HAL_CRU_ClkGetFreq(CLK_TSADC_TSEN);
|
|
break;
|
|
case SCLK_SFC:
|
if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = 50000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = 75000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 3) {
|
freq = 100000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 4) {
|
freq = 125000000;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 5) {
|
freq = 150000000;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
case ACLK_USB:
|
case HCLK_USB:
|
case PCLK_USB:
|
case ACLK_PHP:
|
case HCLK_PHP:
|
case PCLK_PHP:
|
case CLK_MAC0_2TOP:
|
case CLK_MAC1_2TOP:
|
case CLK_MAC0_OUT:
|
case CLK_MAC1_OUT:
|
case CLK_GMAC0_PTP_REF:
|
case CLK_GMAC1_PTP_REF:
|
case SCLK_GMAC0_RGMII_SPEED:
|
case SCLK_GMAC1_RGMII_SPEED:
|
case SCLK_GMAC0_RMII_SPEED:
|
case SCLK_GMAC1_RMII_SPEED:
|
case SCLK_GMAC0_RX_TX:
|
case SCLK_GMAC1_RX_TX:
|
freq = HAL_CRU_ClkGmacGetFreq(clockName);
|
|
return freq;
|
|
case BCLK_EMMC:
|
case CCLK_EMMC:
|
case DCLK_SDMMC_BUFFER:
|
case CLK_SDMMC0:
|
case CLK_SDMMC1:
|
case CLK_SDMMC2:
|
freq = HAL_CRU_ClkMmcGetFreq(clockName);
|
|
return freq;
|
|
case ACLK_SECURE_FLASH:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = s_gpllFreq / 6;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = s_gpllFreq / 8;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = s_gpllFreq / 10;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
|
case HCLK_SECURE_FLASH:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = s_gpllFreq / 8;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = s_gpllFreq / 10;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = s_gpllFreq / 16;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
|
case ACLK_PIPE:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
freq = s_gpllFreq / 3;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 1) {
|
freq = s_gpllFreq / 4;
|
} else if (HAL_CRU_ClkGetMux(clkMux) == 2) {
|
freq = s_gpllFreq / 6;
|
} else {
|
freq = PLL_INPUT_OSC_RATE;
|
}
|
|
return freq;
|
|
case PCLK_PIPE:
|
pRate = HAL_CRU_ClkGetFreq(ACLK_PIPE);
|
|
break;
|
|
case CLK_PCIEPHY0_REF:
|
case CLK_PCIEPHY1_REF:
|
case CLK_PCIEPHY2_REF:
|
if (HAL_CRU_ClkGetMux(clkMux) == 0) {
|
pRate = 0;
|
} else {
|
pRate = s_ppllFreq / 2;
|
}
|
|
break;
|
|
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_GetPllFreq(&CPLL);
|
}
|
|
switch (clockName) {
|
case PLL_APLL:
|
|
return error;
|
case PLL_CPLL:
|
error = HAL_CRU_SetPllFreq(&CPLL, rate);
|
s_cpllFreq = HAL_CRU_GetPllFreq(&CPLL);
|
|
return error;
|
case PLL_HPLL:
|
|
return error;
|
case PLL_GPLL:
|
error = HAL_CRU_SetPllFreq(&GPLL, rate);
|
DEBUG ((DEBUG_INIT, "GPLL set rate: %d %x\n", rate, error));
|
s_gpllFreq = HAL_CRU_GetPllFreq(&GPLL);
|
return error;
|
|
case CLK_UART1:
|
case CLK_UART2:
|
case CLK_UART3:
|
case CLK_UART4:
|
case CLK_UART5:
|
case CLK_UART6:
|
case CLK_UART7:
|
case CLK_UART8:
|
case CLK_UART9:
|
error = HAL_CRU_ClkFracSetFreq(clockName, rate);
|
|
return error;
|
|
case CLK_CAN0:
|
case CLK_CAN1:
|
case CLK_CAN2:
|
if (s_cpllFreq % rate == 0) {
|
pRate = s_cpllFreq;
|
mux = 1;
|
} else {
|
pRate = s_gpllFreq;
|
mux = 0;
|
}
|
|
break;
|
|
case CLK_TSADC_TSEN:
|
if (PLL_INPUT_OSC_RATE % rate == 0) {
|
pRate = PLL_INPUT_OSC_RATE;
|
mux = 0;
|
} else {
|
pRate = s_gpllFreq / 12;
|
mux = 1;
|
}
|
|
break;
|
case CLK_TSADC:
|
pRate = HAL_CRU_ClkGetFreq(CLK_TSADC_TSEN);
|
|
break;
|
case SCLK_SFC:
|
if (rate == 50000000) {
|
mux = 1;
|
} else if (rate == 75000000) {
|
mux = 2;
|
} else if (rate == 100000000) {
|
mux = 3;
|
} else if (rate == 125000000) {
|
mux = 4;
|
} else if (rate == 150000000) {
|
mux = 5;
|
} else {
|
mux = 0;
|
}
|
|
break;
|
case ACLK_USB:
|
case HCLK_USB:
|
case PCLK_USB:
|
case ACLK_PHP:
|
case HCLK_PHP:
|
case PCLK_PHP:
|
case CLK_MAC0_2TOP:
|
case CLK_MAC1_2TOP:
|
case CLK_MAC0_OUT:
|
case CLK_MAC1_OUT:
|
case CLK_GMAC0_PTP_REF:
|
case CLK_GMAC1_PTP_REF:
|
case SCLK_GMAC0_RGMII_SPEED:
|
case SCLK_GMAC1_RGMII_SPEED:
|
case SCLK_GMAC0_RMII_SPEED:
|
case SCLK_GMAC1_RMII_SPEED:
|
case SCLK_GMAC0_RX_TX:
|
case SCLK_GMAC1_RX_TX:
|
error = HAL_CRU_ClkGmacSetFreq(clockName, rate);
|
|
return error;
|
|
case BCLK_EMMC:
|
case CCLK_EMMC:
|
case DCLK_SDMMC_BUFFER:
|
case CLK_SDMMC0:
|
case CLK_SDMMC1:
|
case CLK_SDMMC2:
|
error = HAL_CRU_ClkMmcSetFreq(clockName, rate);
|
|
return error;
|
|
case ACLK_SECURE_FLASH:
|
if (rate >= 198000000) {
|
mux = 0;
|
} else if (rate >= 148000000) {
|
mux = 1;
|
} else if (rate >= 99000000) {
|
mux = 2;
|
} else {
|
mux = 3;
|
}
|
|
break;
|
|
case HCLK_SECURE_FLASH:
|
if (rate >= 148000000) {
|
mux = 0;
|
} else if (rate >= 99000000) {
|
mux = 1;
|
} else if (rate >= 74000000) {
|
mux = 2;
|
} else {
|
mux = 3;
|
}
|
|
break;
|
|
case ACLK_PIPE:
|
if (rate >= 396000000) {
|
mux = 0;
|
} else if (rate >= 297000000) {
|
mux = 1;
|
} else if (rate >= 198000000) {
|
mux = 2;
|
} else {
|
mux = 3;
|
}
|
|
break;
|
|
case PCLK_PIPE:
|
pRate = HAL_CRU_ClkGetFreq(ACLK_PIPE);
|
|
break;
|
|
case CLK_PCIEPHY0_REF:
|
case CLK_PCIEPHY1_REF:
|
case CLK_PCIEPHY2_REF:
|
pRate = s_ppllFreq / 2;
|
mux = 1;
|
|
break;
|
|
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;
|
}
|
|
/**
|
* @brief wdt glbrst enable.
|
* @param wdtType: wdt reset type.
|
* @return HAL_OK.
|
* @attention these APIs allow direct use in the HAL layer.
|
*/
|
HAL_Status
|
EFIAPI
|
HAL_CRU_WdtGlbRstEnable(eCRU_WdtRstType wdtType)
|
{
|
uint32_t mask = CRU_GLB_RST_CON_WDT_GLB_SRST_CTRL_MASK;
|
uint32_t val = 0;
|
|
switch (wdtType) {
|
case GLB_RST_FST_WDT0:
|
val |= (1 << CRU_GLB_RST_CON_WDT_GLB_SRST_CTRL_SHIFT);
|
break;
|
case GLB_RST_SND_WDT0:
|
break;
|
default:
|
|
return HAL_INVAL;
|
}
|
|
CRU->GLB_RST_CON = VAL_MASK_WE(mask, val);
|
|
return HAL_OK;
|
}
|
|
/** @} */
|
|
/** @} */
|
|
/** @} */
|