xiuos/Ubiquitous/XiZi_AIoT/services/drivers/rk-3568/ethernet/hal_cru.c

1251 lines
35 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
*/
#include "hal_base.h"
#include "hal_def.h"
#include "hal_cru.h"
/** @addtogroup RK_HAL_Driver
* @{
*/
/** @addtogroup CRU
* @{
*/
/** @defgroup CRU_How_To_Use How To Use
* @{
The CRU driver can be used as follows:
- Invoke cru functions to set clk rate, enable or disable clk, reset clk in each device.
- The gate and soft reset id is include register offset and shift information:
con_offset: id /16
shift: id %16
- The mux and div id is include register offset, shift, mask information:
[15:0]: con
[23:16]: shift
[31:24]: width
- CRU driver is just responsible for passing simple command data, And
the usecount is the user's responsibility. Protection the usecount at the driver layer.
- More details refer to APIs' descriptions as below.
@} */
/** @defgroup CRU_Private_Definition Private Definition
* @{
*/
/********************* Private MACRO Definition ******************************/
#define PWRDOWN_SHIFT 13
#define PWRDOWN_MASK 1 << PWRDOWN_SHIFT
#define PLL_POSTDIV1_SHIFT 12
#define PLL_POSTDIV1_MASK 0x7 << PLL_POSTDIV1_SHIFT
#define PLL_FBDIV_SHIFT 0
#define PLL_FBDIV_MASK 0xfff << PLL_FBDIV_SHIFT
#define PLL_POSTDIV2_SHIFT 6
#define PLL_POSTDIV2_MASK 0x7 << PLL_POSTDIV2_SHIFT
#define PLL_REFDIV_SHIFT 0
#define PLL_REFDIV_MASK 0x3f << PLL_REFDIV_SHIFT
#define PLL_DSMPD_SHIFT 12
#define PLL_DSMPD_MASK 1 << PLL_DSMPD_SHIFT
#define PLL_FRAC_SHIFT 0
#define PLL_FRAC_MASK 0xffffff << PLL_FRAC_SHIFT
#define MIN_FOUTVCO_FREQ (800 * MHZ)
#define MAX_FOUTVCO_FREQ (2000 * MHZ)
#define MIN_FOUT_FREQ (24 * MHZ)
#define MAX_FOUT_FREQ (1600 * MHZ)
#define EXPONENT_OF_FRAC_PLL 24
#define RK_PLL_MODE_SLOW 0
#define RK_PLL_MODE_NORMAL 1
#define RK_PLL_MODE_DEEP 2
#define PLL_GET_PLLMODE(val, shift, mask) (((uint32_t)(val) & mask) >> shift)
#define PLL_GET_FBDIV(x) (((uint32_t)(x) & (PLL_FBDIV_MASK)) >> PLL_FBDIV_SHIFT)
#define PLL_GET_REFDIV(x) \
(((uint32_t)(x) & (PLL_REFDIV_MASK)) >> PLL_REFDIV_SHIFT)
#define PLL_GET_POSTDIV1(x) \
(((uint32_t)(x) & (PLL_POSTDIV1_MASK)) >> PLL_POSTDIV1_SHIFT)
#define PLL_GET_POSTDIV2(x) \
(((uint32_t)(x) & (PLL_POSTDIV2_MASK)) >> PLL_POSTDIV2_SHIFT)
#define PLL_GET_DSMPD(x) (((uint32_t)(x) & (PLL_DSMPD_MASK)) >> PLL_DSMPD_SHIFT)
#define PLL_GET_FRAC(x) (((uint32_t)(x) & (PLL_FRAC_MASK)) >> PLL_FRAC_SHIFT)
#define CRU_PLL_ROUND_UP_TO_KHZ(x) (HAL_DIV_ROUND_UP((x), KHZ) * KHZ)
#define CRU_READ(r) (*(volatile uint32_t *)(r))
#define CRU_WRITE(r, b, w, v) (*(volatile uint32_t *)(r) = ((w) << (16) | (v) << (b)))
/********************* Private Structure Definition **************************/
static struct PLL_CONFIG g_rockchipAutoTable;
__attribute__((weak)) const struct HAL_CRU_DEV g_cruDev;
/********************* Private Variable Definition ***************************/
/********************* Private Function Definition ***************************/
/** Calculate the greatest common divisor */
static uint32_t CRU_Gcd(uint32_t m, uint32_t n)
{
int t;
while (m > 0) {
if (n > m) {
t = m;
m = n;
n = t;
}
m -= n;
}
return n;
}
static int isBetterFreq(uint32_t now, uint32_t new, uint32_t best)
{
return (new <= now && new > best);
}
int HAL_CRU_FreqGetMux4(uint32_t freq, uint32_t freq0, uint32_t freq1,
uint32_t freq2, uint32_t freq3)
{
uint32_t best = 0;
if (isBetterFreq(freq, freq0, best)) {
best = freq0;
}
if (isBetterFreq(freq, freq1, best)) {
best = freq1;
}
if (isBetterFreq(freq, freq2, best)) {
best = freq2;
}
if (isBetterFreq(freq, freq3, best)) {
best = freq3;
}
if (best == freq0) {
return 0;
} else if (best == freq1) {
return 1;
} else if (best == freq2) {
return 2;
} else if (best == freq3) {
return 3;
}
return HAL_INVAL;
}
int HAL_CRU_FreqGetMux3(uint32_t freq, uint32_t freq0, uint32_t freq1, uint32_t freq2)
{
return HAL_CRU_FreqGetMux4(freq, freq0, freq1, freq2, freq2);
}
int HAL_CRU_FreqGetMux2(uint32_t freq, uint32_t freq0, uint32_t freq1)
{
return HAL_CRU_FreqGetMux4(freq, freq0, freq1, freq1, freq1);
}
uint32_t HAL_CRU_MuxGetFreq4(uint32_t muxName, uint32_t freq0, uint32_t freq1,
uint32_t freq2, uint32_t freq3)
{
switch (HAL_CRU_ClkGetMux(muxName)) {
case 0:
return freq0;
case 1:
return freq1;
case 2:
return freq2;
case 3:
return freq3;
}
return HAL_INVAL;
}
uint32_t HAL_CRU_MuxGetFreq3(uint32_t muxName, uint32_t freq0,
uint32_t freq1, uint32_t freq2)
{
return HAL_CRU_MuxGetFreq4(muxName, freq0, freq1, freq2, freq2);
}
uint32_t HAL_CRU_MuxGetFreq2(uint32_t muxName, uint32_t freq0, uint32_t freq1)
{
return HAL_CRU_MuxGetFreq4(muxName, freq0, freq1, freq1, freq1);
}
int HAL_CRU_RoundFreqGetMux4(uint32_t freq, uint32_t pFreq0,
uint32_t pFreq1, uint32_t pFreq2,
uint32_t pFreq3, uint32_t *pFreqOut)
{
uint32_t mux;
if (pFreq3 && (pFreq3 % freq == 0)) {
*pFreqOut = pFreq3;
mux = 3;
} else if (pFreq2 && (pFreq2 % freq == 0)) {
*pFreqOut = pFreq2;
mux = 2;
} else if (pFreq1 % freq == 0) {
*pFreqOut = pFreq1;
mux = 1;
} else {
*pFreqOut = pFreq0;
mux = 0;
}
return mux;
}
int HAL_CRU_RoundFreqGetMux3(uint32_t freq, uint32_t pFreq0,
uint32_t pFreq1, uint32_t pFreq2, uint32_t *pFreqOut)
{
return HAL_CRU_RoundFreqGetMux4(freq, pFreq0, pFreq1, pFreq2, 0, pFreqOut);
}
int HAL_CRU_RoundFreqGetMux2(uint32_t freq, uint32_t pFreq0, uint32_t pFreq1, uint32_t *pFreqOut)
{
return HAL_CRU_RoundFreqGetMux4(freq, pFreq0, pFreq1, 0, 0, pFreqOut);
}
/**
* @brief Rockchip pll clk set postdiv.
* @param foutHz: output freq
* @param *postDiv1: pll postDiv1
* @param *postDiv2: pll postDiv2
* @param *foutVco: pll vco
* @return HAL_Status.
* How to calculate the PLL:
* Formulas also embedded within the fractional PLL Verilog model:
* If DSMPD = 1 (DSM is disabled, "integer mode")
* FOUTVCO = FREF / REFDIV * FBDIV
* FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
* Where:
* FOUTVCO = fractional PLL non-divided output frequency
* FOUTPOSTDIV = fractional PLL divided output frequency
* (output of second post divider)
*/
static HAL_Status CRU_PllSetPostDiv(uint32_t foutHz, uint32_t *postDiv1,
uint32_t *postDiv2, uint32_t *foutVco)
{
uint32_t freq;
if (foutHz < MIN_FOUTVCO_FREQ) {
for (*postDiv1 = 1; *postDiv1 <= 7; (*postDiv1)++) {
for (*postDiv2 = 1; *postDiv2 <= 7; (*postDiv2)++) {
freq = foutHz * (*postDiv1) * (*postDiv2);
if (freq >= MIN_FOUTVCO_FREQ && freq <= MAX_FOUTVCO_FREQ) {
*foutVco = freq;
return HAL_OK;
}
}
}
return HAL_ERROR;
} else {
*postDiv1 = 1;
*postDiv2 = 1;
return HAL_OK;
}
}
/**
* @brief Get pll parameter by auto.
* @param finHz: pll intput freq
* @param foutHz: pll output freq
* @return struct PLL_CONFIG.
* How to calculate the PLL:
* Formulas also embedded within the fractional PLL Verilog model:
* If DSMPD = 1 (DSM is disabled, "integer mode")
* FOUTVCO = FREF / REFDIV * FBDIV
* FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
* Where:
* FOUTVCO = fractional PLL non-divided output frequency
* FOUTPOSTDIV = fractional PLL divided output frequency
* (output of second post divider)
* FREF = fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
* REFDIV = fractional PLL input reference clock divider
* FBDIV = Integer value programmed into feedback divide
*/
static const struct PLL_CONFIG *CRU_PllSetByAuto(uint32_t finHz,
uint32_t foutHz)
{
struct PLL_CONFIG *rateTable = &g_rockchipAutoTable;
uint32_t foutVco = foutHz;
uint64_t fin64, frac64;
uint32_t postDiv1, postDiv2;
uint32_t clkGcd = 0;
HAL_Status error;
if (finHz == 0 || foutHz == 0 || foutHz == finHz) {
return NULL;
}
error = CRU_PllSetPostDiv(foutHz, &postDiv1, &postDiv2, &foutVco);
if (error) {
return NULL;
}
rateTable->postDiv1 = postDiv1;
rateTable->postDiv2 = postDiv2;
rateTable->dsmpd = 1;
if (finHz / MHZ * MHZ == finHz && foutHz / MHZ * MHZ == foutHz) {
finHz /= MHZ;
foutVco /= MHZ;
clkGcd = CRU_Gcd(finHz, foutVco);
rateTable->refDiv = finHz / clkGcd;
rateTable->fbDiv = foutVco / clkGcd;
rateTable->frac = 0;
} else if (finHz / MHZ * MHZ != finHz) {
clkGcd = foutHz / finHz;
rateTable->fbDiv = clkGcd;
rateTable->refDiv = 1;
rateTable->postDiv1 = 1;
rateTable->postDiv2 = 1;
fin64 = foutHz * rateTable->refDiv;
fin64 = HAL_DivU64(fin64 << EXPONENT_OF_FRAC_PLL, finHz);
frac64 = rateTable->fbDiv;
frac64 = rateTable->fbDiv << EXPONENT_OF_FRAC_PLL;
frac64 = fin64 - frac64;
rateTable->frac = frac64;
if (rateTable->frac > 0) {
rateTable->dsmpd = 0;
}
} else {
clkGcd = CRU_Gcd(finHz / MHZ, foutVco / MHZ);
rateTable->refDiv = finHz / MHZ / clkGcd;
rateTable->fbDiv = foutVco / MHZ / clkGcd;
rateTable->frac = 0;
frac64 = (foutVco % MHZ);
fin64 = finHz;
frac64 = frac64 * rateTable->refDiv;
frac64 = HAL_DivU64(frac64 << EXPONENT_OF_FRAC_PLL, fin64);
rateTable->frac = frac64;
if (rateTable->frac > 0) {
rateTable->dsmpd = 0;
}
}
return rateTable;
}
/**
* @brief Get pll parameter by rateTable.
* @param *pSetup: struct PLL_SETUP struct, Contains PLL register parameters
* @param rate: pll target rate.
* @return struct PLL_CONFIG.
* How to calculate the PLL:
* Look up the rateTable to get the PLL config parameter
*/
static const struct PLL_CONFIG *CRU_PllGetSettings(struct PLL_SETUP *pSetup,
uint32_t rate)
{
const struct PLL_CONFIG *rateTable = pSetup->rateTable;
if (rateTable == NULL) {
return CRU_PllSetByAuto(PLL_INPUT_OSC_RATE, rate);
}
while (rateTable->rate) {
if (rateTable->rate == rate) {
break;
}
rateTable++;
}
if (rateTable->rate != rate) {
return CRU_PllSetByAuto(PLL_INPUT_OSC_RATE, rate);
} else {
return rateTable;
}
}
/** @} */
/********************* Public Function Definition ****************************/
/** @defgroup CRU_Exported_Functions_Group5 Other Functions
* @attention these APIs allow direct use in the HAL layer.
* @{
*/
/*
* Formulas also embedded within the fractional PLL Verilog model:
* If DSMPD = 1 (DSM is disabled, "integer mode")
* FOUTVCO = FREF / REFDIV * FBDIV
* FOUT = FOUTVCO / POSTDIV1 / POSTDIV2
* If DSMPD = 0 (DSM is enabled, "fractional mode")
* FOUTVCO = (FREF / REFDIV) * (FBDIV + FRAC / (2^24))
* FOUTPOSTDIV = FOUTVCO / (POSTDIV1*POSTDIV2)
* FOUT = FOUTVCO / POSTDIV1 / POSTDIV2
*/
uint32_t HAL_CRU_GetPllFreq(struct PLL_SETUP *pSetup)
{
uint32_t refDiv, fbDiv, postdDv1, postDiv2, frac, dsmpd;
uint32_t mode = 0, rate = PLL_INPUT_OSC_RATE;
mode = PLL_GET_PLLMODE(READ_REG(*(pSetup->modeOffset)), pSetup->modeShift,
pSetup->modeMask);
switch (mode) {
case RK_PLL_MODE_SLOW:
rate = PLL_INPUT_OSC_RATE;
break;
case RK_PLL_MODE_NORMAL:
postdDv1 = PLL_GET_POSTDIV1(READ_REG(*(pSetup->conOffset0)));
fbDiv = PLL_GET_FBDIV(READ_REG(*(pSetup->conOffset0)));
postDiv2 = PLL_GET_POSTDIV2(READ_REG(*(pSetup->conOffset1)));
refDiv = PLL_GET_REFDIV(READ_REG(*(pSetup->conOffset1)));
dsmpd = PLL_GET_DSMPD(READ_REG(*(pSetup->conOffset1)));
frac = PLL_GET_FRAC(READ_REG(*(pSetup->conOffset2)));
rate = (rate / refDiv) * fbDiv;
if (dsmpd == 0) {
uint64_t fracRate = PLL_INPUT_OSC_RATE;
fracRate *= frac;
fracRate = fracRate >> EXPONENT_OF_FRAC_PLL;
fracRate = fracRate / refDiv;
rate += fracRate;
}
rate = rate / (postdDv1 * postDiv2);
rate = CRU_PLL_ROUND_UP_TO_KHZ(rate);
break;
case RK_PLL_MODE_DEEP:
default:
rate = 32768;
break;
}
return rate;
}
/*
* Force PLL into slow mode
* Pll Power down
* Pll Config fbDiv, refDiv, postdDv1, postDiv2, dsmpd, frac
* Pll Power up
* Waiting for pll lock
* Force PLL into normal mode
*/
HAL_Status HAL_CRU_SetPllFreq(struct PLL_SETUP *pSetup, uint32_t rate)
{
const struct PLL_CONFIG *pConfig;
int delay = 2400;
if (rate == HAL_CRU_GetPllFreq(pSetup)) {
return HAL_OK;
} else if (rate < MIN_FOUT_FREQ) {
return HAL_INVAL;
} else if (rate > MAX_FOUT_FREQ) {
return HAL_INVAL;
}
pConfig = CRU_PllGetSettings(pSetup, rate);
if (!pConfig) {
return HAL_ERROR;
}
/* Force PLL into slow mode to ensure output stable clock */
WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_SLOW << pSetup->modeShift);
/* Pll Power down */
WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 1 << PWRDOWN_SHIFT);
/* Pll Config */
WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_POSTDIV2_MASK, pConfig->postDiv2 << PLL_POSTDIV2_SHIFT);
WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_REFDIV_MASK, pConfig->refDiv << PLL_REFDIV_SHIFT);
WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLL_POSTDIV1_MASK, pConfig->postDiv1 << PLL_POSTDIV1_SHIFT);
WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLL_FBDIV_MASK, pConfig->fbDiv << PLL_FBDIV_SHIFT);
WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_DSMPD_MASK, pConfig->dsmpd << PLL_DSMPD_SHIFT);
if (pConfig->frac) {
WRITE_REG(*(pSetup->conOffset2), (READ_REG(*(pSetup->conOffset2)) & 0xff000000) | pConfig->frac);
}
/* Pll Power up */
WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 0 << PWRDOWN_SHIFT);
/* Waiting for pll lock */
while (delay > 0) {
if (pSetup->stat0) {
if (READ_REG(*(pSetup->stat0)) & (1 << pSetup->lockShift)) {
break;
}
} else {
if (READ_REG(*(pSetup->conOffset1)) & (1 << pSetup->lockShift)) {
break;
}
}
HAL_CPUDelayUs(1000);
delay--;
}
if (delay == 0) {
return HAL_TIMEOUT;
}
/* Force PLL into normal mode */
WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_NORMAL << pSetup->modeShift);
return HAL_OK;
}
HAL_Status HAL_CRU_SetPllPowerUp(struct PLL_SETUP *pSetup)
{
int delay = 2400;
/* Pll Power up */
WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 0 << PWRDOWN_SHIFT);
/* Waiting for pll lock */
while (delay > 0) {
if (pSetup->stat0) {
if (READ_REG(*(pSetup->stat0)) & (1 << pSetup->lockShift)) {
break;
}
} else {
if (READ_REG(*(pSetup->conOffset1)) & (1 << pSetup->lockShift)) {
break;
}
}
HAL_CPUDelayUs(1000);
delay--;
}
if (delay == 0) {
return HAL_TIMEOUT;
}
return HAL_OK;
}
HAL_Status HAL_CRU_SetPllPowerDown(struct PLL_SETUP *pSetup)
{
/* Pll Power down */
WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 1 << PWRDOWN_SHIFT);
return HAL_OK;
}
#ifdef CRU_CLK_USE_CON_BANK
static const struct HAL_CRU_DEV *CRU_GetInfo(void)
{
return &g_cruDev;
}
HAL_Check HAL_CRU_ClkIsEnabled(uint32_t clk)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
uint32_t bank = CLK_GATE_GET_REG_BANK(clk);
uint32_t reg;
HAL_Check ret;
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].gateOffset + index * 4;
ret = (HAL_Check)(!((CRU_READ(reg) & (1 << shift)) >> shift));
return ret;
}
HAL_Status HAL_CRU_ClkEnable(uint32_t clk)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
uint32_t bank = CLK_GATE_GET_REG_BANK(clk);
uint32_t reg;
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].gateOffset + index * 4;
CRU_WRITE(reg, shift, 1U << shift, 0U);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkDisable(uint32_t clk)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
uint32_t bank = CLK_GATE_GET_REG_BANK(clk);
uint32_t reg;
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].gateOffset + index * 4;
CRU_WRITE(reg, shift, 1U << shift, 1U);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkDisableUnused(uint32_t bank, uint32_t index, uint32_t val)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t reg;
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].gateOffset + index * 4;
CRU_WRITE(reg, 0, 0, val);
return HAL_OK;
}
HAL_Check HAL_CRU_ClkIsReset(uint32_t clk)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
uint32_t bank = CLK_GATE_GET_REG_BANK(clk);
uint32_t reg;
HAL_Check ret;
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].softOffset + index * 4;
ret = (HAL_Check)((CRU_READ(reg) & (1 << shift)) >> shift);
return ret;
}
HAL_Status HAL_CRU_ClkResetAssert(uint32_t clk)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_RESET_GET_REG_OFFSET(clk);
uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk);
uint32_t bank = CLK_GATE_GET_REG_BANK(clk);
uint32_t reg;
HAL_ASSERT(shift < 16);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].softOffset + index * 4;
CRU_WRITE(reg, shift, 1U << shift, 1U);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkResetDeassert(uint32_t clk)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_RESET_GET_REG_OFFSET(clk);
uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk);
uint32_t bank = CLK_GATE_GET_REG_BANK(clk);
uint32_t reg;
HAL_ASSERT(shift < 16);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].softOffset + index * 4;
CRU_WRITE(reg, shift, 1U << shift, 0U);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkResetSyncAssert(int numClks, uint32_t *clks)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_RESET_GET_REG_OFFSET(clks[0]);
uint32_t bank = CLK_GATE_GET_REG_BANK(clks[0]);
uint32_t val = 0;
uint32_t reg;
int i;
for (i = 0; i < numClks; i++) {
val |= HAL_BIT(CLK_RESET_GET_BITS_SHIFT(clks[i]));
if (index != CLK_RESET_GET_REG_OFFSET(clks[i])) {
return HAL_ERROR;
}
}
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].softOffset + index * 4;
CRU_WRITE(reg, 0, val, val);
HAL_DBG("%s: index: 0x%lx, val: 0x%lx\n", __func__, index, val);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkResetSyncDeassert(int numClks, uint32_t *clks)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t index = CLK_RESET_GET_REG_OFFSET(clks[0]);
uint32_t bank = CLK_GATE_GET_REG_BANK(clks[0]);
uint32_t val = 0;
uint32_t reg;
int i;
for (i = 0; i < numClks; i++) {
val |= HAL_BIT(CLK_RESET_GET_BITS_SHIFT(clks[i]));
if (index != CLK_RESET_GET_REG_OFFSET(clks[i])) {
return HAL_ERROR;
}
}
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].softOffset + index * 4;
CRU_WRITE(reg, 0, val, 0);
HAL_DBG("%s: index: 0x%lx, val: 0x%lx\n", __func__, index, val);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkSetDiv(uint32_t divName, uint32_t divValue)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t shift, mask, index;
uint32_t reg, bank;
index = CLK_DIV_GET_REG_OFFSET(divName);
shift = CLK_DIV_GET_BITS_SHIFT(divName);
HAL_ASSERT(shift < 16);
mask = CLK_DIV_GET_MASK(divName);
if (divValue > mask) {
divValue = mask;
}
bank = CLK_DIV_GET_BANK(divName);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].selOffset + index * 4;
CRU_WRITE(reg, shift, mask, (divValue - 1U));
return HAL_OK;
}
uint32_t HAL_CRU_ClkGetDiv(uint32_t divName)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t shift, mask, index, divValue;
uint32_t reg, bank;
index = CLK_DIV_GET_REG_OFFSET(divName);
shift = CLK_DIV_GET_BITS_SHIFT(divName);
HAL_ASSERT(shift < 16);
mask = CLK_DIV_GET_MASK(divName);
bank = CLK_DIV_GET_BANK(divName);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].selOffset + index * 4;
divValue = ((CRU_READ(reg) & mask) >> shift) + 1;
return divValue;
}
HAL_SECTION_SRAM_CODE
HAL_Status HAL_CRU_ClkSetMux(uint32_t muxName, uint32_t muxValue)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t shift, mask, index;
uint32_t reg, bank;
index = CLK_MUX_GET_REG_OFFSET(muxName);
shift = CLK_MUX_GET_BITS_SHIFT(muxName);
HAL_ASSERT(shift < 16);
mask = CLK_MUX_GET_MASK(muxName);
bank = CLK_MUX_GET_BANK(muxName);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].selOffset + index * 4;
CRU_WRITE(reg, shift, mask, muxValue);
return HAL_OK;
}
HAL_SECTION_SRAM_CODE
uint32_t HAL_CRU_ClkGetMux(uint32_t muxName)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t shift, mask, index, muxValue;
uint32_t reg, bank;
index = CLK_MUX_GET_REG_OFFSET(muxName);
shift = CLK_MUX_GET_BITS_SHIFT(muxName);
HAL_ASSERT(shift < 16);
mask = CLK_MUX_GET_MASK(muxName);
bank = CLK_MUX_GET_BANK(muxName);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].selOffset + index * 4;
muxValue = ((CRU_READ(reg) & mask) >> shift);
return muxValue;
}
HAL_Status HAL_CRU_ClkSetFracDiv(uint32_t fracDivName,
uint32_t numerator,
uint32_t denominator)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t reg, bank;
uint32_t index;
index = CLK_DIV_GET_REG_OFFSET(fracDivName);
bank = CLK_DIV_GET_BANK(fracDivName);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].selOffset + index * 4;
CRU_WRITE(reg, 0, 0, ((numerator << 16) | denominator));
return HAL_OK;
}
HAL_Status HAL_CRU_ClkGetFracDiv(uint32_t fracDivName,
uint32_t *numerator,
uint32_t *denominator)
{
const struct HAL_CRU_DEV *ctrl = CRU_GetInfo();
uint32_t reg, bank;
uint32_t index;
uint32_t val;
index = CLK_DIV_GET_REG_OFFSET(fracDivName);
bank = CLK_DIV_GET_BANK(fracDivName);
reg = ctrl->banks[bank].cruBase + ctrl->banks[bank].selOffset + index * 4;
val = CRU_READ(reg);
*numerator = (val & 0xffff0000) >> 16;
*denominator = (val & 0x0000ffff);
return HAL_OK;
}
#else /* CRU_CLK_USE_CON_BANK */
HAL_Check HAL_CRU_ClkIsEnabled(uint32_t clk)
{
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
HAL_Check ret;
#ifdef CRU_GATE_CON_CNT
if (index < CRU_GATE_CON_CNT) {
ret = (HAL_Check)(!((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift));
} else {
#ifdef PMUCRU_BASE
ret = (HAL_Check)(!((PMUCRU->CRU_CLKGATE_CON[index - CRU_GATE_CON_CNT] & (1 << shift)) >> shift));
#else
ret = (HAL_Check)(!((CRU->PMU_CLKGATE_CON[index - CRU_GATE_CON_CNT] & (1 << shift)) >> shift));
#endif
}
#else
ret = (HAL_Check)(!((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift));
#endif
return ret;
}
HAL_Status HAL_CRU_ClkEnable(uint32_t clk)
{
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
#ifdef CRU_GATE_CON_CNT
if (index < CRU_GATE_CON_CNT) {
CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
} else {
#ifdef PMUCRU_BASE
PMUCRU->CRU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 0U << shift);
#else
CRU->PMU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 0U << shift);
#endif
}
#else
CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
#endif
return HAL_OK;
}
HAL_Status HAL_CRU_ClkDisable(uint32_t clk)
{
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
#ifdef CRU_GATE_CON_CNT
if (index < CRU_GATE_CON_CNT) {
CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
} else {
#ifdef PMUCRU_BASE
PMUCRU->CRU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 1U << shift);
#else
CRU->PMU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 1U << shift);
#endif
}
#else
CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
#endif
return HAL_OK;
}
HAL_Status HAL_CRU_ClkDisableUnused(uint32_t bank, uint32_t index, uint32_t val)
{
#ifdef CRU_GATE_CON_CNT
if (index < CRU_GATE_CON_CNT) {
CRU->CRU_CLKGATE_CON[index] = val;
} else {
#ifdef PMUCRU_BASE
PMUCRU->CRU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = val;
#else
CRU->PMU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = val;
#endif
}
#else
CRU->CRU_CLKGATE_CON[index] = val;
#endif
return HAL_OK;
}
HAL_Check HAL_CRU_ClkIsReset(uint32_t clk)
{
uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
HAL_Check ret;
#ifdef CRU_SRST_CON_CNT
if (index < CRU_SRST_CON_CNT) {
ret = (HAL_Check)((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift);
} else {
ret = (HAL_Check)((PMUCRU->CRU_CLKGATE_CON[index - CRU_SRST_CON_CNT] & (1 << shift)) >> shift);
}
#else
ret = (HAL_Check)((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift);
#endif
return ret;
}
HAL_Status HAL_CRU_ClkResetAssert(uint32_t clk)
{
uint32_t index = CLK_RESET_GET_REG_OFFSET(clk);
uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk);
HAL_ASSERT(shift < 16);
#ifdef CRU_SRST_CON_CNT
if (index < CRU_SRST_CON_CNT) {
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
} else {
PMUCRU->CRU_SOFTRST_CON[index - CRU_SRST_CON_CNT] = VAL_MASK_WE(1U << shift, 1U << shift);
}
#else
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
#endif
return HAL_OK;
}
HAL_Status HAL_CRU_ClkResetDeassert(uint32_t clk)
{
uint32_t index = CLK_RESET_GET_REG_OFFSET(clk);
uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk);
HAL_ASSERT(shift < 16);
#ifdef CRU_SRST_CON_CNT
if (index < CRU_SRST_CON_CNT) {
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
} else {
PMUCRU->CRU_SOFTRST_CON[index - CRU_SRST_CON_CNT] = VAL_MASK_WE(1U << shift, 0U << shift);
}
#else
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
#endif
return HAL_OK;
}
HAL_Status HAL_CRU_ClkResetSyncAssert(int numClks, uint32_t *clks)
{
uint32_t index = CLK_RESET_GET_REG_OFFSET(clks[0]);
uint32_t val = 0;
int i;
for (i = 0; i < numClks; i++) {
val |= HAL_BIT(CLK_RESET_GET_BITS_SHIFT(clks[i]));
if (index != CLK_RESET_GET_REG_OFFSET(clks[i])) {
return HAL_ERROR;
}
}
#ifdef CRU_SRST_CON_CNT
if (index < CRU_SRST_CON_CNT) {
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(val, val);
} else {
PMUCRU->CRU_SOFTRST_CON[index - CRU_SRST_CON_CNT] = VAL_MASK_WE(val, val);
}
#else
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(val, val);
#endif
HAL_DBG("%s: index: 0x%lx, val: 0x%lx\n", __func__, index, val);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkResetSyncDeassert(int numClks, uint32_t *clks)
{
uint32_t index = CLK_RESET_GET_REG_OFFSET(clks[0]);
uint32_t val = 0;
int i;
for (i = 0; i < numClks; i++) {
val |= HAL_BIT(CLK_RESET_GET_BITS_SHIFT(clks[i]));
if (index != CLK_RESET_GET_REG_OFFSET(clks[i])) {
return HAL_ERROR;
}
}
#ifdef CRU_SRST_CON_CNT
if (index < CRU_SRST_CON_CNT) {
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(val, 0);
} else {
PMUCRU->CRU_SOFTRST_CON[index - CRU_SRST_CON_CNT] = VAL_MASK_WE(val, 0);
}
#else
CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(val, 0);
#endif
HAL_DBG("%s: index: 0x%lx, val: 0x%lx\n", __func__, index, val);
return HAL_OK;
}
HAL_Status HAL_CRU_ClkSetDiv(uint32_t divName, uint32_t divValue)
{
uint32_t shift, mask, index;
index = CLK_DIV_GET_REG_OFFSET(divName);
shift = CLK_DIV_GET_BITS_SHIFT(divName);
HAL_ASSERT(shift < 16);
mask = CLK_DIV_GET_MASK(divName);
if (divValue > mask) {
divValue = mask;
}
#ifdef CRU_CLK_DIV_CON_CNT
if (index < CRU_CLK_DIV_CON_CNT) {
CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
} else {
#ifdef PMUCRU_BASE
PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
#else
CRU->PMU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
#endif
}
#else
CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
#endif
return HAL_OK;
}
uint32_t HAL_CRU_ClkGetDiv(uint32_t divName)
{
uint32_t shift, mask, index, divValue;
index = CLK_DIV_GET_REG_OFFSET(divName);
shift = CLK_DIV_GET_BITS_SHIFT(divName);
HAL_ASSERT(shift < 16);
mask = CLK_DIV_GET_MASK(divName);
#ifdef CRU_CLK_DIV_CON_CNT
if (index < CRU_CLK_DIV_CON_CNT) {
divValue = ((((CRU->CRU_CLKSEL_CON[index]) & mask) >> shift) + 1);
} else {
#ifdef PMUCRU_BASE
divValue = ((((PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT]) & mask) >> shift) + 1);
#else
divValue = ((((CRU->PMU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT]) & mask) >> shift) + 1);
#endif
}
#else
divValue = ((((CRU->CRU_CLKSEL_CON[index]) & mask) >> shift) + 1);
#endif
return divValue;
}
HAL_SECTION_SRAM_CODE
HAL_Status HAL_CRU_ClkSetMux(uint32_t muxName, uint32_t muxValue)
{
uint32_t shift, mask, index;
index = CLK_MUX_GET_REG_OFFSET(muxName);
shift = CLK_MUX_GET_BITS_SHIFT(muxName);
HAL_ASSERT(shift < 16);
mask = CLK_MUX_GET_MASK(muxName);
#ifdef CRU_CLK_SEL_CON_CNT
if (index < CRU_CLK_DIV_CON_CNT) {
CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, muxValue << shift);
} else {
#ifdef PMUCRU_BASE
PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] = VAL_MASK_WE(mask, muxValue << shift);
#else
CRU->PMU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] = VAL_MASK_WE(mask, muxValue << shift);
#endif
}
#else
CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, muxValue << shift);
#endif
return HAL_OK;
}
HAL_SECTION_SRAM_CODE
uint32_t HAL_CRU_ClkGetMux(uint32_t muxName)
{
uint32_t shift, mask, index, muxValue;
index = CLK_MUX_GET_REG_OFFSET(muxName);
shift = CLK_MUX_GET_BITS_SHIFT(muxName);
HAL_ASSERT(shift < 16);
mask = CLK_MUX_GET_MASK(muxName);
#ifdef CRU_CLK_SEL_CON_CNT
if (index < CRU_CLK_SEL_CON_CNT) {
muxValue = ((CRU->CRU_CLKSEL_CON[index] & mask) >> shift);
} else {
#ifdef PMUCRU_BASE
muxValue = ((PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] & mask) >> shift);
#else
muxValue = ((CRU->PMU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] & mask) >> shift);
#endif
}
#else
muxValue = ((CRU->CRU_CLKSEL_CON[index] & mask) >> shift);
#endif
return muxValue;
}
HAL_Status HAL_CRU_ClkSetFracDiv(uint32_t fracDivName,
uint32_t numerator,
uint32_t denominator)
{
uint32_t index;
index = CLK_DIV_GET_REG_OFFSET(fracDivName);
#ifdef CRU_CLK_DIV_CON_CNT
if (index < CRU_CLK_DIV_CON_CNT) {
CRU->CRU_CLKSEL_CON[index] = (numerator << 16) | denominator;
} else {
#ifdef PMUCRU_BASE
PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT] = (numerator << 16) | denominator;
#else
CRU->PMU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT] = (numerator << 16) | denominator;
#endif
}
#else
CRU->CRU_CLKSEL_CON[index] = (numerator << 16) | denominator;
#endif
return HAL_OK;
}
HAL_Status HAL_CRU_ClkGetFracDiv(uint32_t fracDivName,
uint32_t *numerator,
uint32_t *denominator)
{
uint32_t index;
uint32_t val;
index = CLK_DIV_GET_REG_OFFSET(fracDivName);
#ifdef CRU_CLK_DIV_CON_CNT
if (index < CRU_CLK_DIV_CON_CNT) {
val = CRU->CRU_CLKSEL_CON[index];
} else {
#ifdef PMUCRU_BASE
val = PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT];
#else
val = CRU->CRU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT];
#endif
}
#else
val = CRU->CRU_CLKSEL_CON[index];
#endif
*numerator = (val & 0xffff0000) >> 16;
*denominator = (val & 0x0000ffff);
return HAL_OK;
}
#endif /* CRU_CLK_USE_CON_BANK */
HAL_Status HAL_CRU_FracdivGetConfig(uint32_t rateOut, uint32_t rate,
uint32_t *numerator,
uint32_t *denominator)
{
uint32_t gcdVal;
gcdVal = CRU_Gcd(rate, rateOut);
if (!gcdVal) {
return HAL_ERROR;
}
*numerator = rateOut / gcdVal;
*denominator = rate / gcdVal;
if (*numerator < 4) {
*numerator *= 4;
*denominator *= 4;
}
if (*numerator > 0xffff || *denominator > 0xffff) {
return HAL_INVAL;
}
return HAL_OK;
}
HAL_Status HAL_CRU_ClkNp5BestDiv(eCLOCK_Name clockName, uint32_t rate, uint32_t pRate, uint32_t *bestdiv)
{
uint32_t div = CLK_GET_DIV(clockName);
uint32_t maxDiv = CLK_DIV_GET_MASK(div);
uint32_t i;
for (i = 0; i < maxDiv; i++) {
if (((pRate * 2) == (rate * (i * 2 + 3)))) {
*bestdiv = i;
return HAL_OK;
}
}
return HAL_ERROR;
}
__attribute__((weak)) HAL_Status HAL_CRU_VopDclkEnable(uint32_t gateId)
{
HAL_CRU_ClkEnable(gateId);
return HAL_OK;
}
__attribute__((weak)) HAL_Status HAL_CRU_VopDclkDisable(uint32_t gateId)
{
HAL_CRU_ClkDisable(gateId);
return HAL_OK;
}
HAL_Status HAL_CRU_SetGlbSrst(eCRU_GlbSrstType type)
{
#ifdef CRU_GLB_SRST_FST_VALUE_OFFSET
if (type == GLB_SRST_FST) {
CRU->GLB_SRST_FST_VALUE = GLB_SRST_FST;
}
#endif
#ifdef CRU_GLB_SRST_SND_VALUE_OFFSET
if (type == GLB_SRST_SND) {
CRU->GLB_SRST_SND_VALUE = GLB_SRST_SND;
}
#endif
return HAL_INVAL;
}
/** @} */
/** @} */
/** @} */