162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014 MundoReader S.L.
462306a36Sopenharmony_ci * Author: Heiko Stuebner <heiko@sntech.de>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
762306a36Sopenharmony_ci * Author: Xing Zheng <zhengxing@rock-chips.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/div64.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/clk-provider.h>
1562306a36Sopenharmony_ci#include <linux/iopoll.h>
1662306a36Sopenharmony_ci#include <linux/regmap.h>
1762306a36Sopenharmony_ci#include <linux/clk.h>
1862306a36Sopenharmony_ci#include "clk.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define PLL_MODE_MASK		0x3
2162306a36Sopenharmony_ci#define PLL_MODE_SLOW		0x0
2262306a36Sopenharmony_ci#define PLL_MODE_NORM		0x1
2362306a36Sopenharmony_ci#define PLL_MODE_DEEP		0x2
2462306a36Sopenharmony_ci#define PLL_RK3328_MODE_MASK	0x1
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct rockchip_clk_pll {
2762306a36Sopenharmony_ci	struct clk_hw		hw;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	struct clk_mux		pll_mux;
3062306a36Sopenharmony_ci	const struct clk_ops	*pll_mux_ops;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	struct notifier_block	clk_nb;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	void __iomem		*reg_base;
3562306a36Sopenharmony_ci	int			lock_offset;
3662306a36Sopenharmony_ci	unsigned int		lock_shift;
3762306a36Sopenharmony_ci	enum rockchip_pll_type	type;
3862306a36Sopenharmony_ci	u8			flags;
3962306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate_table;
4062306a36Sopenharmony_ci	unsigned int		rate_count;
4162306a36Sopenharmony_ci	spinlock_t		*lock;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	struct rockchip_clk_provider *ctx;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define to_rockchip_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
4762306a36Sopenharmony_ci#define to_rockchip_clk_pll_nb(nb) \
4862306a36Sopenharmony_ci			container_of(nb, struct rockchip_clk_pll, clk_nb)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
5162306a36Sopenharmony_ci			    struct rockchip_clk_pll *pll, unsigned long rate)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	const struct rockchip_pll_rate_table  *rate_table = pll->rate_table;
5462306a36Sopenharmony_ci	int i;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++) {
5762306a36Sopenharmony_ci		if (rate == rate_table[i].rate)
5862306a36Sopenharmony_ci			return &rate_table[i];
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return NULL;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic long rockchip_pll_round_rate(struct clk_hw *hw,
6562306a36Sopenharmony_ci			    unsigned long drate, unsigned long *prate)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
6862306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
6962306a36Sopenharmony_ci	int i;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Assumming rate_table is in descending order */
7262306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++) {
7362306a36Sopenharmony_ci		if (drate >= rate_table[i].rate)
7462306a36Sopenharmony_ci			return rate_table[i].rate;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* return minimum supported value */
7862306a36Sopenharmony_ci	return rate_table[i - 1].rate;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/*
8262306a36Sopenharmony_ci * Wait for the pll to reach the locked state.
8362306a36Sopenharmony_ci * The calling set_rate function is responsible for making sure the
8462306a36Sopenharmony_ci * grf regmap is available.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct regmap *grf = pll->ctx->grf;
8962306a36Sopenharmony_ci	unsigned int val;
9062306a36Sopenharmony_ci	int ret;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(grf, pll->lock_offset, val,
9362306a36Sopenharmony_ci				       val & BIT(pll->lock_shift), 0, 1000);
9462306a36Sopenharmony_ci	if (ret)
9562306a36Sopenharmony_ci		pr_err("%s: timeout waiting for pll to lock\n", __func__);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return ret;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci * PLL used in RK3036
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define RK3036_PLLCON(i)			(i * 0x4)
10562306a36Sopenharmony_ci#define RK3036_PLLCON0_FBDIV_MASK		0xfff
10662306a36Sopenharmony_ci#define RK3036_PLLCON0_FBDIV_SHIFT		0
10762306a36Sopenharmony_ci#define RK3036_PLLCON0_POSTDIV1_MASK		0x7
10862306a36Sopenharmony_ci#define RK3036_PLLCON0_POSTDIV1_SHIFT		12
10962306a36Sopenharmony_ci#define RK3036_PLLCON1_REFDIV_MASK		0x3f
11062306a36Sopenharmony_ci#define RK3036_PLLCON1_REFDIV_SHIFT		0
11162306a36Sopenharmony_ci#define RK3036_PLLCON1_POSTDIV2_MASK		0x7
11262306a36Sopenharmony_ci#define RK3036_PLLCON1_POSTDIV2_SHIFT		6
11362306a36Sopenharmony_ci#define RK3036_PLLCON1_LOCK_STATUS		BIT(10)
11462306a36Sopenharmony_ci#define RK3036_PLLCON1_DSMPD_MASK		0x1
11562306a36Sopenharmony_ci#define RK3036_PLLCON1_DSMPD_SHIFT		12
11662306a36Sopenharmony_ci#define RK3036_PLLCON1_PWRDOWN			BIT(13)
11762306a36Sopenharmony_ci#define RK3036_PLLCON2_FRAC_MASK		0xffffff
11862306a36Sopenharmony_ci#define RK3036_PLLCON2_FRAC_SHIFT		0
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int rockchip_rk3036_pll_wait_lock(struct rockchip_clk_pll *pll)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	u32 pllcon;
12362306a36Sopenharmony_ci	int ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/*
12662306a36Sopenharmony_ci	 * Lock time typical 250, max 500 input clock cycles @24MHz
12762306a36Sopenharmony_ci	 * So define a very safe maximum of 1000us, meaning 24000 cycles.
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(pll->reg_base + RK3036_PLLCON(1),
13062306a36Sopenharmony_ci					 pllcon,
13162306a36Sopenharmony_ci					 pllcon & RK3036_PLLCON1_LOCK_STATUS,
13262306a36Sopenharmony_ci					 0, 1000);
13362306a36Sopenharmony_ci	if (ret)
13462306a36Sopenharmony_ci		pr_err("%s: timeout waiting for pll to lock\n", __func__);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return ret;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll,
14062306a36Sopenharmony_ci					struct rockchip_pll_rate_table *rate)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	u32 pllcon;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(0));
14562306a36Sopenharmony_ci	rate->fbdiv = ((pllcon >> RK3036_PLLCON0_FBDIV_SHIFT)
14662306a36Sopenharmony_ci				& RK3036_PLLCON0_FBDIV_MASK);
14762306a36Sopenharmony_ci	rate->postdiv1 = ((pllcon >> RK3036_PLLCON0_POSTDIV1_SHIFT)
14862306a36Sopenharmony_ci				& RK3036_PLLCON0_POSTDIV1_MASK);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(1));
15162306a36Sopenharmony_ci	rate->refdiv = ((pllcon >> RK3036_PLLCON1_REFDIV_SHIFT)
15262306a36Sopenharmony_ci				& RK3036_PLLCON1_REFDIV_MASK);
15362306a36Sopenharmony_ci	rate->postdiv2 = ((pllcon >> RK3036_PLLCON1_POSTDIV2_SHIFT)
15462306a36Sopenharmony_ci				& RK3036_PLLCON1_POSTDIV2_MASK);
15562306a36Sopenharmony_ci	rate->dsmpd = ((pllcon >> RK3036_PLLCON1_DSMPD_SHIFT)
15662306a36Sopenharmony_ci				& RK3036_PLLCON1_DSMPD_MASK);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
15962306a36Sopenharmony_ci	rate->frac = ((pllcon >> RK3036_PLLCON2_FRAC_SHIFT)
16062306a36Sopenharmony_ci				& RK3036_PLLCON2_FRAC_MASK);
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
16462306a36Sopenharmony_ci						     unsigned long prate)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
16762306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
16862306a36Sopenharmony_ci	u64 rate64 = prate;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	rockchip_rk3036_pll_get_params(pll, &cur);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	rate64 *= cur.fbdiv;
17362306a36Sopenharmony_ci	do_div(rate64, cur.refdiv);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (cur.dsmpd == 0) {
17662306a36Sopenharmony_ci		/* fractional mode */
17762306a36Sopenharmony_ci		u64 frac_rate64 = prate * cur.frac;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		do_div(frac_rate64, cur.refdiv);
18062306a36Sopenharmony_ci		rate64 += frac_rate64 >> 24;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	do_div(rate64, cur.postdiv1);
18462306a36Sopenharmony_ci	do_div(rate64, cur.postdiv2);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return (unsigned long)rate64;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
19062306a36Sopenharmony_ci				const struct rockchip_pll_rate_table *rate)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
19362306a36Sopenharmony_ci	struct clk_mux *pll_mux = &pll->pll_mux;
19462306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
19562306a36Sopenharmony_ci	u32 pllcon;
19662306a36Sopenharmony_ci	int rate_change_remuxed = 0;
19762306a36Sopenharmony_ci	int cur_parent;
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
20162306a36Sopenharmony_ci		__func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
20262306a36Sopenharmony_ci		rate->postdiv2, rate->dsmpd, rate->frac);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	rockchip_rk3036_pll_get_params(pll, &cur);
20562306a36Sopenharmony_ci	cur.rate = 0;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
20862306a36Sopenharmony_ci	if (cur_parent == PLL_MODE_NORM) {
20962306a36Sopenharmony_ci		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
21062306a36Sopenharmony_ci		rate_change_remuxed = 1;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* update pll values */
21462306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK,
21562306a36Sopenharmony_ci					  RK3036_PLLCON0_FBDIV_SHIFT) |
21662306a36Sopenharmony_ci		       HIWORD_UPDATE(rate->postdiv1, RK3036_PLLCON0_POSTDIV1_MASK,
21762306a36Sopenharmony_ci					     RK3036_PLLCON0_POSTDIV1_SHIFT),
21862306a36Sopenharmony_ci		       pll->reg_base + RK3036_PLLCON(0));
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3036_PLLCON1_REFDIV_MASK,
22162306a36Sopenharmony_ci						   RK3036_PLLCON1_REFDIV_SHIFT) |
22262306a36Sopenharmony_ci		       HIWORD_UPDATE(rate->postdiv2, RK3036_PLLCON1_POSTDIV2_MASK,
22362306a36Sopenharmony_ci						     RK3036_PLLCON1_POSTDIV2_SHIFT) |
22462306a36Sopenharmony_ci		       HIWORD_UPDATE(rate->dsmpd, RK3036_PLLCON1_DSMPD_MASK,
22562306a36Sopenharmony_ci						  RK3036_PLLCON1_DSMPD_SHIFT),
22662306a36Sopenharmony_ci		       pll->reg_base + RK3036_PLLCON(1));
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* GPLL CON2 is not HIWORD_MASK */
22962306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
23062306a36Sopenharmony_ci	pllcon &= ~(RK3036_PLLCON2_FRAC_MASK << RK3036_PLLCON2_FRAC_SHIFT);
23162306a36Sopenharmony_ci	pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT;
23262306a36Sopenharmony_ci	writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* wait for the pll to lock */
23562306a36Sopenharmony_ci	ret = rockchip_rk3036_pll_wait_lock(pll);
23662306a36Sopenharmony_ci	if (ret) {
23762306a36Sopenharmony_ci		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
23862306a36Sopenharmony_ci			__func__);
23962306a36Sopenharmony_ci		rockchip_rk3036_pll_set_params(pll, &cur);
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (rate_change_remuxed)
24362306a36Sopenharmony_ci		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return ret;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate,
24962306a36Sopenharmony_ci					unsigned long prate)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
25262306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	pr_debug("%s: changing %s to %lu with a parent rate of %lu\n",
25562306a36Sopenharmony_ci		 __func__, __clk_get_name(hw->clk), drate, prate);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* Get required rate settings from table */
25862306a36Sopenharmony_ci	rate = rockchip_get_pll_settings(pll, drate);
25962306a36Sopenharmony_ci	if (!rate) {
26062306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
26162306a36Sopenharmony_ci			drate, __clk_get_name(hw->clk));
26262306a36Sopenharmony_ci		return -EINVAL;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return rockchip_rk3036_pll_set_params(pll, rate);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic int rockchip_rk3036_pll_enable(struct clk_hw *hw)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
27362306a36Sopenharmony_ci	       pll->reg_base + RK3036_PLLCON(1));
27462306a36Sopenharmony_ci	rockchip_rk3036_pll_wait_lock(pll);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return 0;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void rockchip_rk3036_pll_disable(struct clk_hw *hw)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
28462306a36Sopenharmony_ci			     RK3036_PLLCON1_PWRDOWN, 0),
28562306a36Sopenharmony_ci	       pll->reg_base + RK3036_PLLCON(1));
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int rockchip_rk3036_pll_is_enabled(struct clk_hw *hw)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
29162306a36Sopenharmony_ci	u32 pllcon = readl(pll->reg_base + RK3036_PLLCON(1));
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return !(pllcon & RK3036_PLLCON1_PWRDOWN);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int rockchip_rk3036_pll_init(struct clk_hw *hw)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
29962306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate;
30062306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
30162306a36Sopenharmony_ci	unsigned long drate;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
30462306a36Sopenharmony_ci		return 0;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	drate = clk_hw_get_rate(hw);
30762306a36Sopenharmony_ci	rate = rockchip_get_pll_settings(pll, drate);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* when no rate setting for the current rate, rely on clk_set_rate */
31062306a36Sopenharmony_ci	if (!rate)
31162306a36Sopenharmony_ci		return 0;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	rockchip_rk3036_pll_get_params(pll, &cur);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
31662306a36Sopenharmony_ci		 drate);
31762306a36Sopenharmony_ci	pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
31862306a36Sopenharmony_ci		 cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
31962306a36Sopenharmony_ci		 cur.dsmpd, cur.frac);
32062306a36Sopenharmony_ci	pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
32162306a36Sopenharmony_ci		 rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
32262306a36Sopenharmony_ci		 rate->dsmpd, rate->frac);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
32562306a36Sopenharmony_ci		rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
32662306a36Sopenharmony_ci		rate->dsmpd != cur.dsmpd ||
32762306a36Sopenharmony_ci		(!cur.dsmpd && (rate->frac != cur.frac))) {
32862306a36Sopenharmony_ci		struct clk *parent = clk_get_parent(hw->clk);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		if (!parent) {
33162306a36Sopenharmony_ci			pr_warn("%s: parent of %s not available\n",
33262306a36Sopenharmony_ci				__func__, __clk_get_name(hw->clk));
33362306a36Sopenharmony_ci			return 0;
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
33762306a36Sopenharmony_ci			 __func__, __clk_get_name(hw->clk));
33862306a36Sopenharmony_ci		rockchip_rk3036_pll_set_params(pll, rate);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = {
34562306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3036_pll_recalc_rate,
34662306a36Sopenharmony_ci	.enable = rockchip_rk3036_pll_enable,
34762306a36Sopenharmony_ci	.disable = rockchip_rk3036_pll_disable,
34862306a36Sopenharmony_ci	.is_enabled = rockchip_rk3036_pll_is_enabled,
34962306a36Sopenharmony_ci};
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3036_pll_clk_ops = {
35262306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3036_pll_recalc_rate,
35362306a36Sopenharmony_ci	.round_rate = rockchip_pll_round_rate,
35462306a36Sopenharmony_ci	.set_rate = rockchip_rk3036_pll_set_rate,
35562306a36Sopenharmony_ci	.enable = rockchip_rk3036_pll_enable,
35662306a36Sopenharmony_ci	.disable = rockchip_rk3036_pll_disable,
35762306a36Sopenharmony_ci	.is_enabled = rockchip_rk3036_pll_is_enabled,
35862306a36Sopenharmony_ci	.init = rockchip_rk3036_pll_init,
35962306a36Sopenharmony_ci};
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci/*
36262306a36Sopenharmony_ci * PLL used in RK3066, RK3188 and RK3288
36362306a36Sopenharmony_ci */
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci#define RK3066_PLL_RESET_DELAY(nr)	((nr * 500) / 24 + 1)
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci#define RK3066_PLLCON(i)		(i * 0x4)
36862306a36Sopenharmony_ci#define RK3066_PLLCON0_OD_MASK		0xf
36962306a36Sopenharmony_ci#define RK3066_PLLCON0_OD_SHIFT		0
37062306a36Sopenharmony_ci#define RK3066_PLLCON0_NR_MASK		0x3f
37162306a36Sopenharmony_ci#define RK3066_PLLCON0_NR_SHIFT		8
37262306a36Sopenharmony_ci#define RK3066_PLLCON1_NF_MASK		0x1fff
37362306a36Sopenharmony_ci#define RK3066_PLLCON1_NF_SHIFT		0
37462306a36Sopenharmony_ci#define RK3066_PLLCON2_NB_MASK		0xfff
37562306a36Sopenharmony_ci#define RK3066_PLLCON2_NB_SHIFT		0
37662306a36Sopenharmony_ci#define RK3066_PLLCON3_RESET		(1 << 5)
37762306a36Sopenharmony_ci#define RK3066_PLLCON3_PWRDOWN		(1 << 1)
37862306a36Sopenharmony_ci#define RK3066_PLLCON3_BYPASS		(1 << 0)
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void rockchip_rk3066_pll_get_params(struct rockchip_clk_pll *pll,
38162306a36Sopenharmony_ci					struct rockchip_pll_rate_table *rate)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	u32 pllcon;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(0));
38662306a36Sopenharmony_ci	rate->nr = ((pllcon >> RK3066_PLLCON0_NR_SHIFT)
38762306a36Sopenharmony_ci				& RK3066_PLLCON0_NR_MASK) + 1;
38862306a36Sopenharmony_ci	rate->no = ((pllcon >> RK3066_PLLCON0_OD_SHIFT)
38962306a36Sopenharmony_ci				& RK3066_PLLCON0_OD_MASK) + 1;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(1));
39262306a36Sopenharmony_ci	rate->nf = ((pllcon >> RK3066_PLLCON1_NF_SHIFT)
39362306a36Sopenharmony_ci				& RK3066_PLLCON1_NF_MASK) + 1;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(2));
39662306a36Sopenharmony_ci	rate->nb = ((pllcon >> RK3066_PLLCON2_NB_SHIFT)
39762306a36Sopenharmony_ci				& RK3066_PLLCON2_NB_MASK) + 1;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic unsigned long rockchip_rk3066_pll_recalc_rate(struct clk_hw *hw,
40162306a36Sopenharmony_ci						     unsigned long prate)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
40462306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
40562306a36Sopenharmony_ci	u64 rate64 = prate;
40662306a36Sopenharmony_ci	u32 pllcon;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(3));
40962306a36Sopenharmony_ci	if (pllcon & RK3066_PLLCON3_BYPASS) {
41062306a36Sopenharmony_ci		pr_debug("%s: pll %s is bypassed\n", __func__,
41162306a36Sopenharmony_ci			clk_hw_get_name(hw));
41262306a36Sopenharmony_ci		return prate;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	rockchip_rk3066_pll_get_params(pll, &cur);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	rate64 *= cur.nf;
41862306a36Sopenharmony_ci	do_div(rate64, cur.nr);
41962306a36Sopenharmony_ci	do_div(rate64, cur.no);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	return (unsigned long)rate64;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int rockchip_rk3066_pll_set_params(struct rockchip_clk_pll *pll,
42562306a36Sopenharmony_ci				const struct rockchip_pll_rate_table *rate)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
42862306a36Sopenharmony_ci	struct clk_mux *pll_mux = &pll->pll_mux;
42962306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
43062306a36Sopenharmony_ci	int rate_change_remuxed = 0;
43162306a36Sopenharmony_ci	int cur_parent;
43262306a36Sopenharmony_ci	int ret;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n",
43562306a36Sopenharmony_ci		 __func__, rate->rate, rate->nr, rate->no, rate->nf);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	rockchip_rk3066_pll_get_params(pll, &cur);
43862306a36Sopenharmony_ci	cur.rate = 0;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
44162306a36Sopenharmony_ci	if (cur_parent == PLL_MODE_NORM) {
44262306a36Sopenharmony_ci		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
44362306a36Sopenharmony_ci		rate_change_remuxed = 1;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/* enter reset mode */
44762306a36Sopenharmony_ci	writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0),
44862306a36Sopenharmony_ci	       pll->reg_base + RK3066_PLLCON(3));
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* update pll values */
45162306a36Sopenharmony_ci	writel(HIWORD_UPDATE(rate->nr - 1, RK3066_PLLCON0_NR_MASK,
45262306a36Sopenharmony_ci					   RK3066_PLLCON0_NR_SHIFT) |
45362306a36Sopenharmony_ci	       HIWORD_UPDATE(rate->no - 1, RK3066_PLLCON0_OD_MASK,
45462306a36Sopenharmony_ci					   RK3066_PLLCON0_OD_SHIFT),
45562306a36Sopenharmony_ci	       pll->reg_base + RK3066_PLLCON(0));
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->nf - 1, RK3066_PLLCON1_NF_MASK,
45862306a36Sopenharmony_ci						   RK3066_PLLCON1_NF_SHIFT),
45962306a36Sopenharmony_ci		       pll->reg_base + RK3066_PLLCON(1));
46062306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->nb - 1, RK3066_PLLCON2_NB_MASK,
46162306a36Sopenharmony_ci						   RK3066_PLLCON2_NB_SHIFT),
46262306a36Sopenharmony_ci		       pll->reg_base + RK3066_PLLCON(2));
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* leave reset and wait the reset_delay */
46562306a36Sopenharmony_ci	writel(HIWORD_UPDATE(0, RK3066_PLLCON3_RESET, 0),
46662306a36Sopenharmony_ci	       pll->reg_base + RK3066_PLLCON(3));
46762306a36Sopenharmony_ci	udelay(RK3066_PLL_RESET_DELAY(rate->nr));
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* wait for the pll to lock */
47062306a36Sopenharmony_ci	ret = rockchip_pll_wait_lock(pll);
47162306a36Sopenharmony_ci	if (ret) {
47262306a36Sopenharmony_ci		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
47362306a36Sopenharmony_ci			__func__);
47462306a36Sopenharmony_ci		rockchip_rk3066_pll_set_params(pll, &cur);
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (rate_change_remuxed)
47862306a36Sopenharmony_ci		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return ret;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
48462306a36Sopenharmony_ci					unsigned long prate)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
48762306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	pr_debug("%s: changing %s to %lu with a parent rate of %lu\n",
49062306a36Sopenharmony_ci		 __func__, clk_hw_get_name(hw), drate, prate);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* Get required rate settings from table */
49362306a36Sopenharmony_ci	rate = rockchip_get_pll_settings(pll, drate);
49462306a36Sopenharmony_ci	if (!rate) {
49562306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
49662306a36Sopenharmony_ci			drate, clk_hw_get_name(hw));
49762306a36Sopenharmony_ci		return -EINVAL;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	return rockchip_rk3066_pll_set_params(pll, rate);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int rockchip_rk3066_pll_enable(struct clk_hw *hw)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	writel(HIWORD_UPDATE(0, RK3066_PLLCON3_PWRDOWN, 0),
50862306a36Sopenharmony_ci	       pll->reg_base + RK3066_PLLCON(3));
50962306a36Sopenharmony_ci	rockchip_pll_wait_lock(pll);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	return 0;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic void rockchip_rk3066_pll_disable(struct clk_hw *hw)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	writel(HIWORD_UPDATE(RK3066_PLLCON3_PWRDOWN,
51962306a36Sopenharmony_ci			     RK3066_PLLCON3_PWRDOWN, 0),
52062306a36Sopenharmony_ci	       pll->reg_base + RK3066_PLLCON(3));
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic int rockchip_rk3066_pll_is_enabled(struct clk_hw *hw)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
52662306a36Sopenharmony_ci	u32 pllcon = readl(pll->reg_base + RK3066_PLLCON(3));
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return !(pllcon & RK3066_PLLCON3_PWRDOWN);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int rockchip_rk3066_pll_init(struct clk_hw *hw)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
53462306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate;
53562306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
53662306a36Sopenharmony_ci	unsigned long drate;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
53962306a36Sopenharmony_ci		return 0;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	drate = clk_hw_get_rate(hw);
54262306a36Sopenharmony_ci	rate = rockchip_get_pll_settings(pll, drate);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* when no rate setting for the current rate, rely on clk_set_rate */
54562306a36Sopenharmony_ci	if (!rate)
54662306a36Sopenharmony_ci		return 0;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	rockchip_rk3066_pll_get_params(pll, &cur);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), nb(%d:%d)\n",
55162306a36Sopenharmony_ci		 __func__, clk_hw_get_name(hw), drate, rate->nr, cur.nr,
55262306a36Sopenharmony_ci		 rate->no, cur.no, rate->nf, cur.nf, rate->nb, cur.nb);
55362306a36Sopenharmony_ci	if (rate->nr != cur.nr || rate->no != cur.no || rate->nf != cur.nf
55462306a36Sopenharmony_ci						     || rate->nb != cur.nb) {
55562306a36Sopenharmony_ci		pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
55662306a36Sopenharmony_ci			 __func__, clk_hw_get_name(hw));
55762306a36Sopenharmony_ci		rockchip_rk3066_pll_set_params(pll, rate);
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	return 0;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = {
56462306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3066_pll_recalc_rate,
56562306a36Sopenharmony_ci	.enable = rockchip_rk3066_pll_enable,
56662306a36Sopenharmony_ci	.disable = rockchip_rk3066_pll_disable,
56762306a36Sopenharmony_ci	.is_enabled = rockchip_rk3066_pll_is_enabled,
56862306a36Sopenharmony_ci};
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3066_pll_clk_ops = {
57162306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3066_pll_recalc_rate,
57262306a36Sopenharmony_ci	.round_rate = rockchip_pll_round_rate,
57362306a36Sopenharmony_ci	.set_rate = rockchip_rk3066_pll_set_rate,
57462306a36Sopenharmony_ci	.enable = rockchip_rk3066_pll_enable,
57562306a36Sopenharmony_ci	.disable = rockchip_rk3066_pll_disable,
57662306a36Sopenharmony_ci	.is_enabled = rockchip_rk3066_pll_is_enabled,
57762306a36Sopenharmony_ci	.init = rockchip_rk3066_pll_init,
57862306a36Sopenharmony_ci};
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci/*
58162306a36Sopenharmony_ci * PLL used in RK3399
58262306a36Sopenharmony_ci */
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci#define RK3399_PLLCON(i)			(i * 0x4)
58562306a36Sopenharmony_ci#define RK3399_PLLCON0_FBDIV_MASK		0xfff
58662306a36Sopenharmony_ci#define RK3399_PLLCON0_FBDIV_SHIFT		0
58762306a36Sopenharmony_ci#define RK3399_PLLCON1_REFDIV_MASK		0x3f
58862306a36Sopenharmony_ci#define RK3399_PLLCON1_REFDIV_SHIFT		0
58962306a36Sopenharmony_ci#define RK3399_PLLCON1_POSTDIV1_MASK		0x7
59062306a36Sopenharmony_ci#define RK3399_PLLCON1_POSTDIV1_SHIFT		8
59162306a36Sopenharmony_ci#define RK3399_PLLCON1_POSTDIV2_MASK		0x7
59262306a36Sopenharmony_ci#define RK3399_PLLCON1_POSTDIV2_SHIFT		12
59362306a36Sopenharmony_ci#define RK3399_PLLCON2_FRAC_MASK		0xffffff
59462306a36Sopenharmony_ci#define RK3399_PLLCON2_FRAC_SHIFT		0
59562306a36Sopenharmony_ci#define RK3399_PLLCON2_LOCK_STATUS		BIT(31)
59662306a36Sopenharmony_ci#define RK3399_PLLCON3_PWRDOWN			BIT(0)
59762306a36Sopenharmony_ci#define RK3399_PLLCON3_DSMPD_MASK		0x1
59862306a36Sopenharmony_ci#define RK3399_PLLCON3_DSMPD_SHIFT		3
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	u32 pllcon;
60362306a36Sopenharmony_ci	int ret;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/*
60662306a36Sopenharmony_ci	 * Lock time typical 250, max 500 input clock cycles @24MHz
60762306a36Sopenharmony_ci	 * So define a very safe maximum of 1000us, meaning 24000 cycles.
60862306a36Sopenharmony_ci	 */
60962306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(pll->reg_base + RK3399_PLLCON(2),
61062306a36Sopenharmony_ci					 pllcon,
61162306a36Sopenharmony_ci					 pllcon & RK3399_PLLCON2_LOCK_STATUS,
61262306a36Sopenharmony_ci					 0, 1000);
61362306a36Sopenharmony_ci	if (ret)
61462306a36Sopenharmony_ci		pr_err("%s: timeout waiting for pll to lock\n", __func__);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	return ret;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll,
62062306a36Sopenharmony_ci					struct rockchip_pll_rate_table *rate)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	u32 pllcon;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(0));
62562306a36Sopenharmony_ci	rate->fbdiv = ((pllcon >> RK3399_PLLCON0_FBDIV_SHIFT)
62662306a36Sopenharmony_ci				& RK3399_PLLCON0_FBDIV_MASK);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(1));
62962306a36Sopenharmony_ci	rate->refdiv = ((pllcon >> RK3399_PLLCON1_REFDIV_SHIFT)
63062306a36Sopenharmony_ci				& RK3399_PLLCON1_REFDIV_MASK);
63162306a36Sopenharmony_ci	rate->postdiv1 = ((pllcon >> RK3399_PLLCON1_POSTDIV1_SHIFT)
63262306a36Sopenharmony_ci				& RK3399_PLLCON1_POSTDIV1_MASK);
63362306a36Sopenharmony_ci	rate->postdiv2 = ((pllcon >> RK3399_PLLCON1_POSTDIV2_SHIFT)
63462306a36Sopenharmony_ci				& RK3399_PLLCON1_POSTDIV2_MASK);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
63762306a36Sopenharmony_ci	rate->frac = ((pllcon >> RK3399_PLLCON2_FRAC_SHIFT)
63862306a36Sopenharmony_ci				& RK3399_PLLCON2_FRAC_MASK);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(3));
64162306a36Sopenharmony_ci	rate->dsmpd = ((pllcon >> RK3399_PLLCON3_DSMPD_SHIFT)
64262306a36Sopenharmony_ci				& RK3399_PLLCON3_DSMPD_MASK);
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic unsigned long rockchip_rk3399_pll_recalc_rate(struct clk_hw *hw,
64662306a36Sopenharmony_ci						     unsigned long prate)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
64962306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
65062306a36Sopenharmony_ci	u64 rate64 = prate;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	rockchip_rk3399_pll_get_params(pll, &cur);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	rate64 *= cur.fbdiv;
65562306a36Sopenharmony_ci	do_div(rate64, cur.refdiv);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (cur.dsmpd == 0) {
65862306a36Sopenharmony_ci		/* fractional mode */
65962306a36Sopenharmony_ci		u64 frac_rate64 = prate * cur.frac;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		do_div(frac_rate64, cur.refdiv);
66262306a36Sopenharmony_ci		rate64 += frac_rate64 >> 24;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	do_div(rate64, cur.postdiv1);
66662306a36Sopenharmony_ci	do_div(rate64, cur.postdiv2);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return (unsigned long)rate64;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll,
67262306a36Sopenharmony_ci				const struct rockchip_pll_rate_table *rate)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
67562306a36Sopenharmony_ci	struct clk_mux *pll_mux = &pll->pll_mux;
67662306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
67762306a36Sopenharmony_ci	u32 pllcon;
67862306a36Sopenharmony_ci	int rate_change_remuxed = 0;
67962306a36Sopenharmony_ci	int cur_parent;
68062306a36Sopenharmony_ci	int ret;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
68362306a36Sopenharmony_ci		__func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
68462306a36Sopenharmony_ci		rate->postdiv2, rate->dsmpd, rate->frac);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	rockchip_rk3399_pll_get_params(pll, &cur);
68762306a36Sopenharmony_ci	cur.rate = 0;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
69062306a36Sopenharmony_ci	if (cur_parent == PLL_MODE_NORM) {
69162306a36Sopenharmony_ci		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
69262306a36Sopenharmony_ci		rate_change_remuxed = 1;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/* update pll values */
69662306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3399_PLLCON0_FBDIV_MASK,
69762306a36Sopenharmony_ci						  RK3399_PLLCON0_FBDIV_SHIFT),
69862306a36Sopenharmony_ci		       pll->reg_base + RK3399_PLLCON(0));
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3399_PLLCON1_REFDIV_MASK,
70162306a36Sopenharmony_ci						   RK3399_PLLCON1_REFDIV_SHIFT) |
70262306a36Sopenharmony_ci		       HIWORD_UPDATE(rate->postdiv1, RK3399_PLLCON1_POSTDIV1_MASK,
70362306a36Sopenharmony_ci						     RK3399_PLLCON1_POSTDIV1_SHIFT) |
70462306a36Sopenharmony_ci		       HIWORD_UPDATE(rate->postdiv2, RK3399_PLLCON1_POSTDIV2_MASK,
70562306a36Sopenharmony_ci						     RK3399_PLLCON1_POSTDIV2_SHIFT),
70662306a36Sopenharmony_ci		       pll->reg_base + RK3399_PLLCON(1));
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* xPLL CON2 is not HIWORD_MASK */
70962306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
71062306a36Sopenharmony_ci	pllcon &= ~(RK3399_PLLCON2_FRAC_MASK << RK3399_PLLCON2_FRAC_SHIFT);
71162306a36Sopenharmony_ci	pllcon |= rate->frac << RK3399_PLLCON2_FRAC_SHIFT;
71262306a36Sopenharmony_ci	writel_relaxed(pllcon, pll->reg_base + RK3399_PLLCON(2));
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->dsmpd, RK3399_PLLCON3_DSMPD_MASK,
71562306a36Sopenharmony_ci					    RK3399_PLLCON3_DSMPD_SHIFT),
71662306a36Sopenharmony_ci		       pll->reg_base + RK3399_PLLCON(3));
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* wait for the pll to lock */
71962306a36Sopenharmony_ci	ret = rockchip_rk3399_pll_wait_lock(pll);
72062306a36Sopenharmony_ci	if (ret) {
72162306a36Sopenharmony_ci		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
72262306a36Sopenharmony_ci			__func__);
72362306a36Sopenharmony_ci		rockchip_rk3399_pll_set_params(pll, &cur);
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (rate_change_remuxed)
72762306a36Sopenharmony_ci		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	return ret;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic int rockchip_rk3399_pll_set_rate(struct clk_hw *hw, unsigned long drate,
73362306a36Sopenharmony_ci					unsigned long prate)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
73662306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	pr_debug("%s: changing %s to %lu with a parent rate of %lu\n",
73962306a36Sopenharmony_ci		 __func__, __clk_get_name(hw->clk), drate, prate);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* Get required rate settings from table */
74262306a36Sopenharmony_ci	rate = rockchip_get_pll_settings(pll, drate);
74362306a36Sopenharmony_ci	if (!rate) {
74462306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
74562306a36Sopenharmony_ci			drate, __clk_get_name(hw->clk));
74662306a36Sopenharmony_ci		return -EINVAL;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return rockchip_rk3399_pll_set_params(pll, rate);
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic int rockchip_rk3399_pll_enable(struct clk_hw *hw)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	writel(HIWORD_UPDATE(0, RK3399_PLLCON3_PWRDOWN, 0),
75762306a36Sopenharmony_ci	       pll->reg_base + RK3399_PLLCON(3));
75862306a36Sopenharmony_ci	rockchip_rk3399_pll_wait_lock(pll);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	return 0;
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic void rockchip_rk3399_pll_disable(struct clk_hw *hw)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	writel(HIWORD_UPDATE(RK3399_PLLCON3_PWRDOWN,
76862306a36Sopenharmony_ci			     RK3399_PLLCON3_PWRDOWN, 0),
76962306a36Sopenharmony_ci	       pll->reg_base + RK3399_PLLCON(3));
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic int rockchip_rk3399_pll_is_enabled(struct clk_hw *hw)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
77562306a36Sopenharmony_ci	u32 pllcon = readl(pll->reg_base + RK3399_PLLCON(3));
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return !(pllcon & RK3399_PLLCON3_PWRDOWN);
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic int rockchip_rk3399_pll_init(struct clk_hw *hw)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
78362306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate;
78462306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
78562306a36Sopenharmony_ci	unsigned long drate;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
78862306a36Sopenharmony_ci		return 0;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	drate = clk_hw_get_rate(hw);
79162306a36Sopenharmony_ci	rate = rockchip_get_pll_settings(pll, drate);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/* when no rate setting for the current rate, rely on clk_set_rate */
79462306a36Sopenharmony_ci	if (!rate)
79562306a36Sopenharmony_ci		return 0;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	rockchip_rk3399_pll_get_params(pll, &cur);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
80062306a36Sopenharmony_ci		 drate);
80162306a36Sopenharmony_ci	pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
80262306a36Sopenharmony_ci		 cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
80362306a36Sopenharmony_ci		 cur.dsmpd, cur.frac);
80462306a36Sopenharmony_ci	pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
80562306a36Sopenharmony_ci		 rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
80662306a36Sopenharmony_ci		 rate->dsmpd, rate->frac);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
80962306a36Sopenharmony_ci		rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
81062306a36Sopenharmony_ci		rate->dsmpd != cur.dsmpd ||
81162306a36Sopenharmony_ci		(!cur.dsmpd && (rate->frac != cur.frac))) {
81262306a36Sopenharmony_ci		struct clk *parent = clk_get_parent(hw->clk);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		if (!parent) {
81562306a36Sopenharmony_ci			pr_warn("%s: parent of %s not available\n",
81662306a36Sopenharmony_ci				__func__, __clk_get_name(hw->clk));
81762306a36Sopenharmony_ci			return 0;
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci		pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
82162306a36Sopenharmony_ci			 __func__, __clk_get_name(hw->clk));
82262306a36Sopenharmony_ci		rockchip_rk3399_pll_set_params(pll, rate);
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	return 0;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = {
82962306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3399_pll_recalc_rate,
83062306a36Sopenharmony_ci	.enable = rockchip_rk3399_pll_enable,
83162306a36Sopenharmony_ci	.disable = rockchip_rk3399_pll_disable,
83262306a36Sopenharmony_ci	.is_enabled = rockchip_rk3399_pll_is_enabled,
83362306a36Sopenharmony_ci};
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3399_pll_clk_ops = {
83662306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3399_pll_recalc_rate,
83762306a36Sopenharmony_ci	.round_rate = rockchip_pll_round_rate,
83862306a36Sopenharmony_ci	.set_rate = rockchip_rk3399_pll_set_rate,
83962306a36Sopenharmony_ci	.enable = rockchip_rk3399_pll_enable,
84062306a36Sopenharmony_ci	.disable = rockchip_rk3399_pll_disable,
84162306a36Sopenharmony_ci	.is_enabled = rockchip_rk3399_pll_is_enabled,
84262306a36Sopenharmony_ci	.init = rockchip_rk3399_pll_init,
84362306a36Sopenharmony_ci};
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci/*
84662306a36Sopenharmony_ci * PLL used in RK3588
84762306a36Sopenharmony_ci */
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci#define RK3588_PLLCON(i)               (i * 0x4)
85062306a36Sopenharmony_ci#define RK3588_PLLCON0_M_MASK          0x3ff
85162306a36Sopenharmony_ci#define RK3588_PLLCON0_M_SHIFT         0
85262306a36Sopenharmony_ci#define RK3588_PLLCON1_P_MASK          0x3f
85362306a36Sopenharmony_ci#define RK3588_PLLCON1_P_SHIFT         0
85462306a36Sopenharmony_ci#define RK3588_PLLCON1_S_MASK          0x7
85562306a36Sopenharmony_ci#define RK3588_PLLCON1_S_SHIFT         6
85662306a36Sopenharmony_ci#define RK3588_PLLCON2_K_MASK          0xffff
85762306a36Sopenharmony_ci#define RK3588_PLLCON2_K_SHIFT         0
85862306a36Sopenharmony_ci#define RK3588_PLLCON1_PWRDOWN         BIT(13)
85962306a36Sopenharmony_ci#define RK3588_PLLCON6_LOCK_STATUS     BIT(15)
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_cistatic int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	u32 pllcon;
86462306a36Sopenharmony_ci	int ret;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/*
86762306a36Sopenharmony_ci	 * Lock time typical 250, max 500 input clock cycles @24MHz
86862306a36Sopenharmony_ci	 * So define a very safe maximum of 1000us, meaning 24000 cycles.
86962306a36Sopenharmony_ci	 */
87062306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6),
87162306a36Sopenharmony_ci					 pllcon,
87262306a36Sopenharmony_ci					 pllcon & RK3588_PLLCON6_LOCK_STATUS,
87362306a36Sopenharmony_ci					 0, 1000);
87462306a36Sopenharmony_ci	if (ret)
87562306a36Sopenharmony_ci		pr_err("%s: timeout waiting for pll to lock\n", __func__);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	return ret;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll,
88162306a36Sopenharmony_ci					   struct rockchip_pll_rate_table *rate)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	u32 pllcon;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0));
88662306a36Sopenharmony_ci	rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT) & RK3588_PLLCON0_M_MASK);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
88962306a36Sopenharmony_ci	rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) & RK3588_PLLCON1_P_MASK);
89062306a36Sopenharmony_ci	rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) & RK3588_PLLCON1_S_MASK);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2));
89362306a36Sopenharmony_ci	rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT) & RK3588_PLLCON2_K_MASK);
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
89962306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
90062306a36Sopenharmony_ci	u64 rate64 = prate, postdiv;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	rockchip_rk3588_pll_get_params(pll, &cur);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	rate64 *= cur.m;
90562306a36Sopenharmony_ci	do_div(rate64, cur.p);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	if (cur.k) {
90862306a36Sopenharmony_ci		/* fractional mode */
90962306a36Sopenharmony_ci		u64 frac_rate64 = prate * cur.k;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci		postdiv = cur.p * 65535;
91262306a36Sopenharmony_ci		do_div(frac_rate64, postdiv);
91362306a36Sopenharmony_ci		rate64 += frac_rate64;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci	rate64 = rate64 >> cur.s;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	return (unsigned long)rate64;
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cistatic int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll,
92162306a36Sopenharmony_ci					  const struct rockchip_pll_rate_table *rate)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
92462306a36Sopenharmony_ci	struct clk_mux *pll_mux = &pll->pll_mux;
92562306a36Sopenharmony_ci	struct rockchip_pll_rate_table cur;
92662306a36Sopenharmony_ci	int rate_change_remuxed = 0;
92762306a36Sopenharmony_ci	int cur_parent;
92862306a36Sopenharmony_ci	int ret;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n",
93162306a36Sopenharmony_ci		 __func__, rate->rate, rate->p, rate->m, rate->s, rate->k);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	rockchip_rk3588_pll_get_params(pll, &cur);
93462306a36Sopenharmony_ci	cur.rate = 0;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	if (pll->type == pll_rk3588) {
93762306a36Sopenharmony_ci		cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
93862306a36Sopenharmony_ci		if (cur_parent == PLL_MODE_NORM) {
93962306a36Sopenharmony_ci			pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
94062306a36Sopenharmony_ci			rate_change_remuxed = 1;
94162306a36Sopenharmony_ci		}
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* set pll power down */
94562306a36Sopenharmony_ci	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN,
94662306a36Sopenharmony_ci			     RK3588_PLLCON1_PWRDOWN, 0),
94762306a36Sopenharmony_ci	       pll->reg_base + RK3399_PLLCON(1));
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/* update pll values */
95062306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK, RK3588_PLLCON0_M_SHIFT),
95162306a36Sopenharmony_ci		       pll->reg_base + RK3399_PLLCON(0));
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK, RK3588_PLLCON1_P_SHIFT) |
95462306a36Sopenharmony_ci		       HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK, RK3588_PLLCON1_S_SHIFT),
95562306a36Sopenharmony_ci		       pll->reg_base + RK3399_PLLCON(1));
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK, RK3588_PLLCON2_K_SHIFT),
95862306a36Sopenharmony_ci		       pll->reg_base + RK3399_PLLCON(2));
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	/* set pll power up */
96162306a36Sopenharmony_ci	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
96262306a36Sopenharmony_ci	       pll->reg_base + RK3588_PLLCON(1));
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	/* wait for the pll to lock */
96562306a36Sopenharmony_ci	ret = rockchip_rk3588_pll_wait_lock(pll);
96662306a36Sopenharmony_ci	if (ret) {
96762306a36Sopenharmony_ci		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
96862306a36Sopenharmony_ci			__func__);
96962306a36Sopenharmony_ci		rockchip_rk3588_pll_set_params(pll, &cur);
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if ((pll->type == pll_rk3588) && rate_change_remuxed)
97362306a36Sopenharmony_ci		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	return ret;
97662306a36Sopenharmony_ci}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_cistatic int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate,
97962306a36Sopenharmony_ci					unsigned long prate)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
98262306a36Sopenharmony_ci	const struct rockchip_pll_rate_table *rate;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	pr_debug("%s: changing %s to %lu with a parent rate of %lu\n",
98562306a36Sopenharmony_ci		 __func__, __clk_get_name(hw->clk), drate, prate);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* Get required rate settings from table */
98862306a36Sopenharmony_ci	rate = rockchip_get_pll_settings(pll, drate);
98962306a36Sopenharmony_ci	if (!rate) {
99062306a36Sopenharmony_ci		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
99162306a36Sopenharmony_ci			drate, __clk_get_name(hw->clk));
99262306a36Sopenharmony_ci		return -EINVAL;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	return rockchip_rk3588_pll_set_params(pll, rate);
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int rockchip_rk3588_pll_enable(struct clk_hw *hw)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
100362306a36Sopenharmony_ci	       pll->reg_base + RK3588_PLLCON(1));
100462306a36Sopenharmony_ci	rockchip_rk3588_pll_wait_lock(pll);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	return 0;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void rockchip_rk3588_pll_disable(struct clk_hw *hw)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, RK3588_PLLCON1_PWRDOWN, 0),
101462306a36Sopenharmony_ci	       pll->reg_base + RK3588_PLLCON(1));
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
102062306a36Sopenharmony_ci	u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1));
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	return !(pllcon & RK3588_PLLCON1_PWRDOWN);
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic int rockchip_rk3588_pll_init(struct clk_hw *hw)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
103062306a36Sopenharmony_ci		return 0;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	return 0;
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = {
103662306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
103762306a36Sopenharmony_ci	.enable = rockchip_rk3588_pll_enable,
103862306a36Sopenharmony_ci	.disable = rockchip_rk3588_pll_disable,
103962306a36Sopenharmony_ci	.is_enabled = rockchip_rk3588_pll_is_enabled,
104062306a36Sopenharmony_ci};
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic const struct clk_ops rockchip_rk3588_pll_clk_ops = {
104362306a36Sopenharmony_ci	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
104462306a36Sopenharmony_ci	.round_rate = rockchip_pll_round_rate,
104562306a36Sopenharmony_ci	.set_rate = rockchip_rk3588_pll_set_rate,
104662306a36Sopenharmony_ci	.enable = rockchip_rk3588_pll_enable,
104762306a36Sopenharmony_ci	.disable = rockchip_rk3588_pll_disable,
104862306a36Sopenharmony_ci	.is_enabled = rockchip_rk3588_pll_is_enabled,
104962306a36Sopenharmony_ci	.init = rockchip_rk3588_pll_init,
105062306a36Sopenharmony_ci};
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci/*
105362306a36Sopenharmony_ci * Common registering of pll clocks
105462306a36Sopenharmony_ci */
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistruct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
105762306a36Sopenharmony_ci		enum rockchip_pll_type pll_type,
105862306a36Sopenharmony_ci		const char *name, const char *const *parent_names,
105962306a36Sopenharmony_ci		u8 num_parents, int con_offset, int grf_lock_offset,
106062306a36Sopenharmony_ci		int lock_shift, int mode_offset, int mode_shift,
106162306a36Sopenharmony_ci		struct rockchip_pll_rate_table *rate_table,
106262306a36Sopenharmony_ci		unsigned long flags, u8 clk_pll_flags)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	const char *pll_parents[3];
106562306a36Sopenharmony_ci	struct clk_init_data init;
106662306a36Sopenharmony_ci	struct rockchip_clk_pll *pll;
106762306a36Sopenharmony_ci	struct clk_mux *pll_mux;
106862306a36Sopenharmony_ci	struct clk *pll_clk, *mux_clk;
106962306a36Sopenharmony_ci	char pll_name[20];
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	if ((pll_type != pll_rk3328 && num_parents != 2) ||
107262306a36Sopenharmony_ci	    (pll_type == pll_rk3328 && num_parents != 1)) {
107362306a36Sopenharmony_ci		pr_err("%s: needs two parent clocks\n", __func__);
107462306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	/* name the actual pll */
107862306a36Sopenharmony_ci	snprintf(pll_name, sizeof(pll_name), "pll_%s", name);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
108162306a36Sopenharmony_ci	if (!pll)
108262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	/* create the mux on top of the real pll */
108562306a36Sopenharmony_ci	pll->pll_mux_ops = &clk_mux_ops;
108662306a36Sopenharmony_ci	pll_mux = &pll->pll_mux;
108762306a36Sopenharmony_ci	pll_mux->reg = ctx->reg_base + mode_offset;
108862306a36Sopenharmony_ci	pll_mux->shift = mode_shift;
108962306a36Sopenharmony_ci	if (pll_type == pll_rk3328)
109062306a36Sopenharmony_ci		pll_mux->mask = PLL_RK3328_MODE_MASK;
109162306a36Sopenharmony_ci	else
109262306a36Sopenharmony_ci		pll_mux->mask = PLL_MODE_MASK;
109362306a36Sopenharmony_ci	pll_mux->flags = 0;
109462306a36Sopenharmony_ci	pll_mux->lock = &ctx->lock;
109562306a36Sopenharmony_ci	pll_mux->hw.init = &init;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (pll_type == pll_rk3036 ||
109862306a36Sopenharmony_ci	    pll_type == pll_rk3066 ||
109962306a36Sopenharmony_ci	    pll_type == pll_rk3328 ||
110062306a36Sopenharmony_ci	    pll_type == pll_rk3399 ||
110162306a36Sopenharmony_ci	    pll_type == pll_rk3588)
110262306a36Sopenharmony_ci		pll_mux->flags |= CLK_MUX_HIWORD_MASK;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	/* the actual muxing is xin24m, pll-output, xin32k */
110562306a36Sopenharmony_ci	pll_parents[0] = parent_names[0];
110662306a36Sopenharmony_ci	pll_parents[1] = pll_name;
110762306a36Sopenharmony_ci	pll_parents[2] = parent_names[1];
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	init.name = name;
111062306a36Sopenharmony_ci	init.flags = CLK_SET_RATE_PARENT;
111162306a36Sopenharmony_ci	init.ops = pll->pll_mux_ops;
111262306a36Sopenharmony_ci	init.parent_names = pll_parents;
111362306a36Sopenharmony_ci	if (pll_type == pll_rk3328)
111462306a36Sopenharmony_ci		init.num_parents = 2;
111562306a36Sopenharmony_ci	else
111662306a36Sopenharmony_ci		init.num_parents = ARRAY_SIZE(pll_parents);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	mux_clk = clk_register(NULL, &pll_mux->hw);
111962306a36Sopenharmony_ci	if (IS_ERR(mux_clk))
112062306a36Sopenharmony_ci		goto err_mux;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/* now create the actual pll */
112362306a36Sopenharmony_ci	init.name = pll_name;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	/* keep all plls untouched for now */
112662306a36Sopenharmony_ci	init.flags = flags | CLK_IGNORE_UNUSED;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	init.parent_names = &parent_names[0];
112962306a36Sopenharmony_ci	init.num_parents = 1;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (rate_table) {
113262306a36Sopenharmony_ci		int len;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci		/* find count of rates in rate_table */
113562306a36Sopenharmony_ci		for (len = 0; rate_table[len].rate != 0; )
113662306a36Sopenharmony_ci			len++;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		pll->rate_count = len;
113962306a36Sopenharmony_ci		pll->rate_table = kmemdup(rate_table,
114062306a36Sopenharmony_ci					pll->rate_count *
114162306a36Sopenharmony_ci					sizeof(struct rockchip_pll_rate_table),
114262306a36Sopenharmony_ci					GFP_KERNEL);
114362306a36Sopenharmony_ci		WARN(!pll->rate_table,
114462306a36Sopenharmony_ci			"%s: could not allocate rate table for %s\n",
114562306a36Sopenharmony_ci			__func__, name);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	switch (pll_type) {
114962306a36Sopenharmony_ci	case pll_rk3036:
115062306a36Sopenharmony_ci	case pll_rk3328:
115162306a36Sopenharmony_ci		if (!pll->rate_table)
115262306a36Sopenharmony_ci			init.ops = &rockchip_rk3036_pll_clk_norate_ops;
115362306a36Sopenharmony_ci		else
115462306a36Sopenharmony_ci			init.ops = &rockchip_rk3036_pll_clk_ops;
115562306a36Sopenharmony_ci		break;
115662306a36Sopenharmony_ci	case pll_rk3066:
115762306a36Sopenharmony_ci		if (!pll->rate_table || IS_ERR(ctx->grf))
115862306a36Sopenharmony_ci			init.ops = &rockchip_rk3066_pll_clk_norate_ops;
115962306a36Sopenharmony_ci		else
116062306a36Sopenharmony_ci			init.ops = &rockchip_rk3066_pll_clk_ops;
116162306a36Sopenharmony_ci		break;
116262306a36Sopenharmony_ci	case pll_rk3399:
116362306a36Sopenharmony_ci		if (!pll->rate_table)
116462306a36Sopenharmony_ci			init.ops = &rockchip_rk3399_pll_clk_norate_ops;
116562306a36Sopenharmony_ci		else
116662306a36Sopenharmony_ci			init.ops = &rockchip_rk3399_pll_clk_ops;
116762306a36Sopenharmony_ci		break;
116862306a36Sopenharmony_ci	case pll_rk3588:
116962306a36Sopenharmony_ci	case pll_rk3588_core:
117062306a36Sopenharmony_ci		if (!pll->rate_table)
117162306a36Sopenharmony_ci			init.ops = &rockchip_rk3588_pll_clk_norate_ops;
117262306a36Sopenharmony_ci		else
117362306a36Sopenharmony_ci			init.ops = &rockchip_rk3588_pll_clk_ops;
117462306a36Sopenharmony_ci		init.flags = flags;
117562306a36Sopenharmony_ci		break;
117662306a36Sopenharmony_ci	default:
117762306a36Sopenharmony_ci		pr_warn("%s: Unknown pll type for pll clk %s\n",
117862306a36Sopenharmony_ci			__func__, name);
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	pll->hw.init = &init;
118262306a36Sopenharmony_ci	pll->type = pll_type;
118362306a36Sopenharmony_ci	pll->reg_base = ctx->reg_base + con_offset;
118462306a36Sopenharmony_ci	pll->lock_offset = grf_lock_offset;
118562306a36Sopenharmony_ci	pll->lock_shift = lock_shift;
118662306a36Sopenharmony_ci	pll->flags = clk_pll_flags;
118762306a36Sopenharmony_ci	pll->lock = &ctx->lock;
118862306a36Sopenharmony_ci	pll->ctx = ctx;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	pll_clk = clk_register(NULL, &pll->hw);
119162306a36Sopenharmony_ci	if (IS_ERR(pll_clk)) {
119262306a36Sopenharmony_ci		pr_err("%s: failed to register pll clock %s : %ld\n",
119362306a36Sopenharmony_ci			__func__, name, PTR_ERR(pll_clk));
119462306a36Sopenharmony_ci		goto err_pll;
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	return mux_clk;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cierr_pll:
120062306a36Sopenharmony_ci	kfree(pll->rate_table);
120162306a36Sopenharmony_ci	clk_unregister(mux_clk);
120262306a36Sopenharmony_ci	mux_clk = pll_clk;
120362306a36Sopenharmony_cierr_mux:
120462306a36Sopenharmony_ci	kfree(pll);
120562306a36Sopenharmony_ci	return mux_clk;
120662306a36Sopenharmony_ci}
1207