Commit 238cc631 authored by Yao Zi's avatar Yao Zi Committed by Drew Fustini
Browse files

clk: thead: th1520-ap: Support setting PLL rates



TH1520 ships several PLLs that could operate in either integer or
fractional mode. However, the TRM only lists a few configuration whose
stability is considered guaranteed.

Add a table-lookup rate determination logic to support PLL rate setting,
and fill up frequency-configuration tables for AP-subsystem PLLs.

Reviewed-by: default avatarDrew Fustini <fustini@kernel.org>
Signed-off-by: default avatarYao Zi <ziyao@disroot.org>
Signed-off-by: default avatarDrew Fustini <fustini@kernel.org>
parent b436f8a8
Loading
Loading
Loading
Loading
+142 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#define TH1520_PLL_REFDIV	GENMASK(5, 0)
#define TH1520_PLL_BYPASS	BIT(30)
#define TH1520_PLL_VCO_RST	BIT(29)
#define TH1520_PLL_DACPD	BIT(25)
#define TH1520_PLL_DSMPD	BIT(24)
#define TH1520_PLL_FRAC		GENMASK(23, 0)
#define TH1520_PLL_FRAC_BITS    24
@@ -72,9 +73,19 @@ struct ccu_div {
	struct ccu_common	common;
};

struct ccu_pll_cfg {
	unsigned long		freq;
	u32			fbdiv;
	u32			frac;
	u32			postdiv1;
	u32			postdiv2;
};

struct ccu_pll {
	struct ccu_common	common;
	u32			lock_sts_mask;
	int			cfgnum;
	const struct ccu_pll_cfg *cfgs;
};

#define TH_CCU_ARG(_shift, _width)					\
@@ -391,17 +402,102 @@ static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw,
	return rate;
}

static const struct ccu_pll_cfg *ccu_pll_lookup_best_cfg(struct ccu_pll *pll,
							 unsigned long rate)
{
	unsigned long best_delta = ULONG_MAX;
	const struct ccu_pll_cfg *best_cfg;
	int i;

	for (i = 0; i < pll->cfgnum; i++) {
		const struct ccu_pll_cfg *cfg = &pll->cfgs[i];
		unsigned long delta;

		delta = abs_diff(cfg->freq, rate);
		if (delta < best_delta) {
			best_delta	= delta;
			best_cfg	= cfg;
		}
	}

	return best_cfg;
}

static int ccu_pll_determine_rate(struct clk_hw *hw,
				  struct clk_rate_request *req)
{
	struct ccu_pll *pll = hw_to_ccu_pll(hw);

	req->rate = ccu_pll_lookup_best_cfg(pll, req->rate)->freq;

	return 0;
}

static int ccu_pll_set_rate(struct clk_hw *hw, unsigned long rate,
			    unsigned long parent_rate)
{
	struct ccu_pll *pll = hw_to_ccu_pll(hw);
	const struct ccu_pll_cfg *cfg;

	cfg = ccu_pll_lookup_best_cfg(pll, rate);

	ccu_pll_disable(hw);

	regmap_write(pll->common.map, pll->common.cfg0,
		     FIELD_PREP(TH1520_PLL_REFDIV,	1)		|
		     FIELD_PREP(TH1520_PLL_FBDIV,	cfg->fbdiv)	|
		     FIELD_PREP(TH1520_PLL_POSTDIV1,	cfg->postdiv1)	|
		     FIELD_PREP(TH1520_PLL_POSTDIV2,	cfg->postdiv2));

	regmap_update_bits(pll->common.map, pll->common.cfg1,
			   TH1520_PLL_DACPD | TH1520_PLL_DSMPD |
			   TH1520_PLL_FRAC,
			   cfg->frac ? cfg->frac :
				TH1520_PLL_DACPD | TH1520_PLL_DSMPD);

	return ccu_pll_enable(hw);
}

static const struct clk_ops clk_pll_ops = {
	.disable	= ccu_pll_disable,
	.enable		= ccu_pll_enable,
	.is_enabled	= ccu_pll_is_enabled,
	.recalc_rate	= ccu_pll_recalc_rate,
	.determine_rate	= ccu_pll_determine_rate,
	.set_rate	= ccu_pll_set_rate,
};

static const struct clk_parent_data osc_24m_clk[] = {
	{ .index = 0 }
};

static const struct ccu_pll_cfg cpu_pll_cfgs[] = {
	{ 125000000,	125,	0, 6, 4 },
	{ 200000000,	125,	0, 5, 3 },
	{ 300000000,	125,	0, 5, 2 },
	{ 400000000,	100,	0, 3, 2 },
	{ 500000000,	125,	0, 6, 1 },
	{ 600000000,	125,	0, 5, 1 },
	{ 702000000,	117,	0, 4, 1 },
	{ 800000000,	100,	0, 3, 1 },
	{ 900000000,	75,	0, 2, 1 },
	{ 1000000000,	125,	0, 3, 1 },
	{ 1104000000,	92,	0, 2, 1 },
	{ 1200000000,	100,	0, 2, 1 },
	{ 1296000000,	108,	0, 2, 1 },
	{ 1404000000,	117,	0, 2, 1 },
	{ 1500000000,	125,	0, 2, 1 },
	{ 1608000000,	67,	0, 1, 1 },
	{ 1704000000,	71,	0, 1, 1 },
	{ 1800000000,	75,	0, 1, 1 },
	{ 1896000000,	79,	0, 1, 1 },
	{ 1992000000,	83,	0, 1, 1 },
	{ 2112000000,	88,	0, 1, 1 },
	{ 2208000000,	92,	0, 1, 1 },
	{ 2304000000,	96,	0, 1, 1 },
	{ 2400000000,	100,	0, 1, 1 },
};

static struct ccu_pll cpu_pll0_clk = {
	.common		= {
		.clkid		= CLK_CPU_PLL0,
@@ -413,6 +509,8 @@ static struct ccu_pll cpu_pll0_clk = {
					      CLK_IS_CRITICAL),
	},
	.lock_sts_mask		= BIT(1),
	.cfgnum			= ARRAY_SIZE(cpu_pll_cfgs),
	.cfgs			= cpu_pll_cfgs,
};

static struct ccu_pll cpu_pll1_clk = {
@@ -426,6 +524,16 @@ static struct ccu_pll cpu_pll1_clk = {
					      CLK_IS_CRITICAL),
	},
	.lock_sts_mask		= BIT(4),
	.cfgnum			= ARRAY_SIZE(cpu_pll_cfgs),
	.cfgs			= cpu_pll_cfgs,
};

static const struct ccu_pll_cfg gmac_pll_cfg = {
	.freq		= 1000000000,
	.fbdiv		= 125,
	.frac		= 0,
	.postdiv1	= 3,
	.postdiv2	= 1,
};

static struct ccu_pll gmac_pll_clk = {
@@ -439,6 +547,8 @@ static struct ccu_pll gmac_pll_clk = {
					      CLK_IS_CRITICAL),
	},
	.lock_sts_mask		= BIT(3),
	.cfgnum			= 1,
	.cfgs			= &gmac_pll_cfg,
};

static const struct clk_hw *gmac_pll_clk_parent[] = {
@@ -449,6 +559,14 @@ static const struct clk_parent_data gmac_pll_clk_pd[] = {
	{ .hw = &gmac_pll_clk.common.hw }
};

static const struct ccu_pll_cfg video_pll_cfg = {
	.freq		= 792000000,
	.fbdiv		= 99,
	.frac		= 0,
	.postdiv1	= 3,
	.postdiv2	= 1,
};

static struct ccu_pll video_pll_clk = {
	.common		= {
		.clkid		= CLK_VIDEO_PLL,
@@ -460,6 +578,8 @@ static struct ccu_pll video_pll_clk = {
					      CLK_IS_CRITICAL),
	},
	.lock_sts_mask		= BIT(7),
	.cfgnum			= 1,
	.cfgs			= &video_pll_cfg,
};

static const struct clk_hw *video_pll_clk_parent[] = {
@@ -470,6 +590,14 @@ static const struct clk_parent_data video_pll_clk_pd[] = {
	{ .hw = &video_pll_clk.common.hw }
};

static const struct ccu_pll_cfg dpu_pll_cfg = {
	.freq		= 1188000000,
	.fbdiv		= 99,
	.frac		= 0,
	.postdiv1	= 2,
	.postdiv2	= 1,
};

static struct ccu_pll dpu0_pll_clk = {
	.common		= {
		.clkid		= CLK_DPU0_PLL,
@@ -481,6 +609,8 @@ static struct ccu_pll dpu0_pll_clk = {
					      0),
	},
	.lock_sts_mask		= BIT(8),
	.cfgnum			= 1,
	.cfgs			= &dpu_pll_cfg,
};

static const struct clk_hw *dpu0_pll_clk_parent[] = {
@@ -498,12 +628,22 @@ static struct ccu_pll dpu1_pll_clk = {
					      0),
	},
	.lock_sts_mask		= BIT(9),
	.cfgnum			= 1,
	.cfgs			= &dpu_pll_cfg,
};

static const struct clk_hw *dpu1_pll_clk_parent[] = {
	&dpu1_pll_clk.common.hw
};

static const struct ccu_pll_cfg tee_pll_cfg = {
	.freq		= 792000000,
	.fbdiv		= 99,
	.frac		= 0,
	.postdiv1	= 3,
	.postdiv2	= 1,
};

static struct ccu_pll tee_pll_clk = {
	.common		= {
		.clkid		= CLK_TEE_PLL,
@@ -515,6 +655,8 @@ static struct ccu_pll tee_pll_clk = {
					      CLK_IS_CRITICAL),
	},
	.lock_sts_mask		= BIT(10),
	.cfgnum			= 1,
	.cfgs			= &tee_pll_cfg,
};

static const struct clk_parent_data c910_i0_parents[] = {