mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 09:34:18 +00:00
feat(nxp-clk): add get_rate for s32cc_pll
Add the option to obtain the rate of an s32cc_pll object. The rate of the PLL can be obtained regardless of its hardware state. The targeted frequency is returned in case the PLL is off. Otherwise, the frequency is determined based on settings found in its registers. Change-Id: Id200d0eff149109a724eee69b063bf750d5cba2e Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
This commit is contained in:
parent
46de0b9c99
commit
fbebafa518
2 changed files with 82 additions and 1 deletions
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright 2020-2021, 2023-2024 NXP
|
* Copyright 2020-2021, 2023-2025 NXP
|
||||||
*/
|
*/
|
||||||
#ifndef S32CC_CLK_REGS_H
|
#ifndef S32CC_CLK_REGS_H
|
||||||
#define S32CC_CLK_REGS_H
|
#define S32CC_CLK_REGS_H
|
||||||
|
@ -48,6 +48,8 @@
|
||||||
#define PLLDIG_PLLDV_RDIV_MASK GENMASK_32(14U, PLLDIG_PLLDV_RDIV_OFFSET)
|
#define PLLDIG_PLLDV_RDIV_MASK GENMASK_32(14U, PLLDIG_PLLDV_RDIV_OFFSET)
|
||||||
#define PLLDIG_PLLDV_RDIV_SET(VAL) (PLLDIG_PLLDV_RDIV_MASK & \
|
#define PLLDIG_PLLDV_RDIV_SET(VAL) (PLLDIG_PLLDV_RDIV_MASK & \
|
||||||
((VAL) << PLLDIG_PLLDV_RDIV_OFFSET))
|
((VAL) << PLLDIG_PLLDV_RDIV_OFFSET))
|
||||||
|
#define PLLDIG_PLLDV_RDIV(VAL) (((VAL) & PLLDIG_PLLDV_RDIV_MASK) >> \
|
||||||
|
PLLDIG_PLLDV_RDIV_OFFSET)
|
||||||
#define PLLDIG_PLLDV_MFI_MASK GENMASK_32(7U, 0U)
|
#define PLLDIG_PLLDV_MFI_MASK GENMASK_32(7U, 0U)
|
||||||
#define PLLDIG_PLLDV_MFI(DIV) (PLLDIG_PLLDV_MFI_MASK & (DIV))
|
#define PLLDIG_PLLDV_MFI(DIV) (PLLDIG_PLLDV_MFI_MASK & (DIV))
|
||||||
|
|
||||||
|
|
|
@ -1194,6 +1194,82 @@ static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_pll_freq(const struct s32cc_clk_obj *module,
|
||||||
|
const struct s32cc_clk_drv *drv,
|
||||||
|
unsigned long *rate, unsigned int depth)
|
||||||
|
{
|
||||||
|
const struct s32cc_pll *pll = s32cc_obj2pll(module);
|
||||||
|
const struct s32cc_clk *source;
|
||||||
|
uint32_t mfi, mfn, rdiv, plldv;
|
||||||
|
unsigned long prate, clk_src;
|
||||||
|
unsigned int ldepth = depth;
|
||||||
|
uintptr_t pll_addr = 0UL;
|
||||||
|
uint64_t t1, t2;
|
||||||
|
uint32_t pllpd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = update_stack_depth(&ldepth);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = get_base_addr(pll->instance, drv, &pll_addr);
|
||||||
|
if (ret != 0) {
|
||||||
|
ERROR("Failed to detect PLL instance\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disabled PLL */
|
||||||
|
pllpd = mmio_read_32(PLLDIG_PLLCR(pll_addr)) & PLLDIG_PLLCR_PLLPD;
|
||||||
|
if (pllpd != 0U) {
|
||||||
|
*rate = pll->vco_freq;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
clk_src = mmio_read_32(PLLDIG_PLLCLKMUX(pll_addr));
|
||||||
|
switch (clk_src) {
|
||||||
|
case 0:
|
||||||
|
clk_src = S32CC_CLK_FIRC;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
clk_src = S32CC_CLK_FXOSC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Failed to identify PLL source id %" PRIu64 "\n", clk_src);
|
||||||
|
return -EINVAL;
|
||||||
|
};
|
||||||
|
|
||||||
|
source = s32cc_get_arch_clk(clk_src);
|
||||||
|
if (source == NULL) {
|
||||||
|
ERROR("Failed to get PLL source clock\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = get_module_rate(&source->desc, drv, &prate, ldepth);
|
||||||
|
if (ret != 0) {
|
||||||
|
ERROR("Failed to get PLL's parent frequency\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
plldv = mmio_read_32(PLLDIG_PLLDV(pll_addr));
|
||||||
|
mfi = PLLDIG_PLLDV_MFI(plldv);
|
||||||
|
rdiv = PLLDIG_PLLDV_RDIV(plldv);
|
||||||
|
if (rdiv == 0U) {
|
||||||
|
rdiv = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Frac-N mode */
|
||||||
|
mfn = PLLDIG_PLLFD_MFN_SET(mmio_read_32(PLLDIG_PLLFD(pll_addr)));
|
||||||
|
|
||||||
|
/* PLL VCO frequency in Fractional mode when PLLDV[RDIV] is not 0 */
|
||||||
|
t1 = prate / rdiv;
|
||||||
|
t2 = (mfi * FP_PRECISION) + (mfn * FP_PRECISION / 18432U);
|
||||||
|
|
||||||
|
*rate = t1 * t2 / FP_PRECISION;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
|
static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
|
||||||
unsigned long *orate, unsigned int *depth)
|
unsigned long *orate, unsigned int *depth)
|
||||||
{
|
{
|
||||||
|
@ -1391,6 +1467,9 @@ static int get_module_rate(const struct s32cc_clk_obj *module,
|
||||||
case s32cc_clk_t:
|
case s32cc_clk_t:
|
||||||
ret = get_clk_freq(module, drv, rate, ldepth);
|
ret = get_clk_freq(module, drv, rate, ldepth);
|
||||||
break;
|
break;
|
||||||
|
case s32cc_pll_t:
|
||||||
|
ret = get_pll_freq(module, drv, rate, ldepth);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Reference in a new issue