clk: rockchip: add pll type for RK3588
Add RK3588 PLL support fully relying on lookup tables like the other upstream supported rockchip platforms. Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com> [rebase and modify code to avoid PLL parameter calculation] Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> Link: https://lore.kernel.org/r/20221018151407.63395-6-sebastian.reichel@collabora.com Signed-off-by: Heiko Stuebner <heiko@sntech.de>
This commit is contained in:
parent
cf87691f14
commit
8f6594494b
|
@ -842,6 +842,213 @@ static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
|
|||
.init = rockchip_rk3399_pll_init,
|
||||
};
|
||||
|
||||
/*
|
||||
* PLL used in RK3588
|
||||
*/
|
||||
|
||||
#define RK3588_PLLCON(i) (i * 0x4)
|
||||
#define RK3588_PLLCON0_M_MASK 0x3ff
|
||||
#define RK3588_PLLCON0_M_SHIFT 0
|
||||
#define RK3588_PLLCON1_P_MASK 0x3f
|
||||
#define RK3588_PLLCON1_P_SHIFT 0
|
||||
#define RK3588_PLLCON1_S_MASK 0x7
|
||||
#define RK3588_PLLCON1_S_SHIFT 6
|
||||
#define RK3588_PLLCON2_K_MASK 0xffff
|
||||
#define RK3588_PLLCON2_K_SHIFT 0
|
||||
#define RK3588_PLLCON1_PWRDOWN BIT(13)
|
||||
#define RK3588_PLLCON6_LOCK_STATUS BIT(15)
|
||||
|
||||
static int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll)
|
||||
{
|
||||
u32 pllcon;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Lock time typical 250, max 500 input clock cycles @24MHz
|
||||
* So define a very safe maximum of 1000us, meaning 24000 cycles.
|
||||
*/
|
||||
ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6),
|
||||
pllcon,
|
||||
pllcon & RK3588_PLLCON6_LOCK_STATUS,
|
||||
0, 1000);
|
||||
if (ret)
|
||||
pr_err("%s: timeout waiting for pll to lock\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll,
|
||||
struct rockchip_pll_rate_table *rate)
|
||||
{
|
||||
u32 pllcon;
|
||||
|
||||
pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0));
|
||||
rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT) & RK3588_PLLCON0_M_MASK);
|
||||
|
||||
pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
|
||||
rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) & RK3588_PLLCON1_P_MASK);
|
||||
rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) & RK3588_PLLCON1_S_MASK);
|
||||
|
||||
pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2));
|
||||
rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT) & RK3588_PLLCON2_K_MASK);
|
||||
}
|
||||
|
||||
static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
|
||||
{
|
||||
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
||||
struct rockchip_pll_rate_table cur;
|
||||
u64 rate64 = prate, postdiv;
|
||||
|
||||
rockchip_rk3588_pll_get_params(pll, &cur);
|
||||
|
||||
rate64 *= cur.m;
|
||||
do_div(rate64, cur.p);
|
||||
|
||||
if (cur.k) {
|
||||
/* fractional mode */
|
||||
u64 frac_rate64 = prate * cur.k;
|
||||
|
||||
postdiv = cur.p * 65535;
|
||||
do_div(frac_rate64, postdiv);
|
||||
rate64 += frac_rate64;
|
||||
}
|
||||
rate64 = rate64 >> cur.s;
|
||||
|
||||
return (unsigned long)rate64;
|
||||
}
|
||||
|
||||
static int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll,
|
||||
const struct rockchip_pll_rate_table *rate)
|
||||
{
|
||||
const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
|
||||
struct clk_mux *pll_mux = &pll->pll_mux;
|
||||
struct rockchip_pll_rate_table cur;
|
||||
int rate_change_remuxed = 0;
|
||||
int cur_parent;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n",
|
||||
__func__, rate->rate, rate->p, rate->m, rate->s, rate->k);
|
||||
|
||||
rockchip_rk3588_pll_get_params(pll, &cur);
|
||||
cur.rate = 0;
|
||||
|
||||
if (pll->type == pll_rk3588) {
|
||||
cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
|
||||
if (cur_parent == PLL_MODE_NORM) {
|
||||
pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
|
||||
rate_change_remuxed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* set pll power down */
|
||||
writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN,
|
||||
RK3588_PLLCON1_PWRDOWN, 0),
|
||||
pll->reg_base + RK3399_PLLCON(1));
|
||||
|
||||
/* update pll values */
|
||||
writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK, RK3588_PLLCON0_M_SHIFT),
|
||||
pll->reg_base + RK3399_PLLCON(0));
|
||||
|
||||
writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK, RK3588_PLLCON1_P_SHIFT) |
|
||||
HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK, RK3588_PLLCON1_S_SHIFT),
|
||||
pll->reg_base + RK3399_PLLCON(1));
|
||||
|
||||
writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK, RK3588_PLLCON2_K_SHIFT),
|
||||
pll->reg_base + RK3399_PLLCON(2));
|
||||
|
||||
/* set pll power up */
|
||||
writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
|
||||
pll->reg_base + RK3588_PLLCON(1));
|
||||
|
||||
/* wait for the pll to lock */
|
||||
ret = rockchip_rk3588_pll_wait_lock(pll);
|
||||
if (ret) {
|
||||
pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
|
||||
__func__);
|
||||
rockchip_rk3588_pll_set_params(pll, &cur);
|
||||
}
|
||||
|
||||
if ((pll->type == pll_rk3588) && rate_change_remuxed)
|
||||
pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
||||
const struct rockchip_pll_rate_table *rate;
|
||||
|
||||
pr_debug("%s: changing %s to %lu with a parent rate of %lu\n",
|
||||
__func__, __clk_get_name(hw->clk), drate, prate);
|
||||
|
||||
/* Get required rate settings from table */
|
||||
rate = rockchip_get_pll_settings(pll, drate);
|
||||
if (!rate) {
|
||||
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
|
||||
drate, __clk_get_name(hw->clk));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return rockchip_rk3588_pll_set_params(pll, rate);
|
||||
}
|
||||
|
||||
static int rockchip_rk3588_pll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
||||
|
||||
writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
|
||||
pll->reg_base + RK3588_PLLCON(1));
|
||||
rockchip_rk3588_pll_wait_lock(pll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_rk3588_pll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
||||
|
||||
writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, RK3588_PLLCON1_PWRDOWN, 0),
|
||||
pll->reg_base + RK3588_PLLCON(1));
|
||||
}
|
||||
|
||||
static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
||||
u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1));
|
||||
|
||||
return !(pllcon & RK3588_PLLCON1_PWRDOWN);
|
||||
}
|
||||
|
||||
static int rockchip_rk3588_pll_init(struct clk_hw *hw)
|
||||
{
|
||||
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
||||
|
||||
if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = {
|
||||
.recalc_rate = rockchip_rk3588_pll_recalc_rate,
|
||||
.enable = rockchip_rk3588_pll_enable,
|
||||
.disable = rockchip_rk3588_pll_disable,
|
||||
.is_enabled = rockchip_rk3588_pll_is_enabled,
|
||||
};
|
||||
|
||||
static const struct clk_ops rockchip_rk3588_pll_clk_ops = {
|
||||
.recalc_rate = rockchip_rk3588_pll_recalc_rate,
|
||||
.round_rate = rockchip_pll_round_rate,
|
||||
.set_rate = rockchip_rk3588_pll_set_rate,
|
||||
.enable = rockchip_rk3588_pll_enable,
|
||||
.disable = rockchip_rk3588_pll_disable,
|
||||
.is_enabled = rockchip_rk3588_pll_is_enabled,
|
||||
.init = rockchip_rk3588_pll_init,
|
||||
};
|
||||
|
||||
/*
|
||||
* Common registering of pll clocks
|
||||
*/
|
||||
|
@ -890,7 +1097,8 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
|
|||
if (pll_type == pll_rk3036 ||
|
||||
pll_type == pll_rk3066 ||
|
||||
pll_type == pll_rk3328 ||
|
||||
pll_type == pll_rk3399)
|
||||
pll_type == pll_rk3399 ||
|
||||
pll_type == pll_rk3588)
|
||||
pll_mux->flags |= CLK_MUX_HIWORD_MASK;
|
||||
|
||||
/* the actual muxing is xin24m, pll-output, xin32k */
|
||||
|
@ -957,6 +1165,14 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
|
|||
else
|
||||
init.ops = &rockchip_rk3399_pll_clk_ops;
|
||||
break;
|
||||
case pll_rk3588:
|
||||
case pll_rk3588_core:
|
||||
if (!pll->rate_table)
|
||||
init.ops = &rockchip_rk3588_pll_clk_norate_ops;
|
||||
else
|
||||
init.ops = &rockchip_rk3588_pll_clk_ops;
|
||||
init.flags = flags;
|
||||
break;
|
||||
default:
|
||||
pr_warn("%s: Unknown pll type for pll clk %s\n",
|
||||
__func__, name);
|
||||
|
|
|
@ -240,6 +240,8 @@ enum rockchip_pll_type {
|
|||
pll_rk3066,
|
||||
pll_rk3328,
|
||||
pll_rk3399,
|
||||
pll_rk3588,
|
||||
pll_rk3588_core,
|
||||
};
|
||||
|
||||
#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \
|
||||
|
@ -272,6 +274,15 @@ enum rockchip_pll_type {
|
|||
.nb = _nb, \
|
||||
}
|
||||
|
||||
#define RK3588_PLL_RATE(_rate, _p, _m, _s, _k) \
|
||||
{ \
|
||||
.rate = _rate##U, \
|
||||
.p = _p, \
|
||||
.m = _m, \
|
||||
.s = _s, \
|
||||
.k = _k, \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct rockchip_clk_provider - information about clock provider
|
||||
* @reg_base: virtual address for the register base.
|
||||
|
@ -307,6 +318,13 @@ struct rockchip_pll_rate_table {
|
|||
unsigned int dsmpd;
|
||||
unsigned int frac;
|
||||
};
|
||||
struct {
|
||||
/* for RK3588 */
|
||||
unsigned int m;
|
||||
unsigned int p;
|
||||
unsigned int s;
|
||||
unsigned int k;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue