162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2017-2018 NXP.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) "pll14xx: " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitfield.h>
962306a36Sopenharmony_ci#include <linux/bits.h>
1062306a36Sopenharmony_ci#include <linux/clk-provider.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/export.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/iopoll.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/jiffies.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "clk.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define GNRL_CTL	0x0
2162306a36Sopenharmony_ci#define DIV_CTL0	0x4
2262306a36Sopenharmony_ci#define DIV_CTL1	0x8
2362306a36Sopenharmony_ci#define LOCK_STATUS	BIT(31)
2462306a36Sopenharmony_ci#define LOCK_SEL_MASK	BIT(29)
2562306a36Sopenharmony_ci#define CLKE_MASK	BIT(11)
2662306a36Sopenharmony_ci#define RST_MASK	BIT(9)
2762306a36Sopenharmony_ci#define BYPASS_MASK	BIT(4)
2862306a36Sopenharmony_ci#define MDIV_MASK	GENMASK(21, 12)
2962306a36Sopenharmony_ci#define PDIV_MASK	GENMASK(9, 4)
3062306a36Sopenharmony_ci#define SDIV_MASK	GENMASK(2, 0)
3162306a36Sopenharmony_ci#define KDIV_MASK	GENMASK(15, 0)
3262306a36Sopenharmony_ci#define KDIV_MIN	SHRT_MIN
3362306a36Sopenharmony_ci#define KDIV_MAX	SHRT_MAX
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define LOCK_TIMEOUT_US		10000
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistruct clk_pll14xx {
3862306a36Sopenharmony_ci	struct clk_hw			hw;
3962306a36Sopenharmony_ci	void __iomem			*base;
4062306a36Sopenharmony_ci	enum imx_pll14xx_type		type;
4162306a36Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate_table;
4262306a36Sopenharmony_ci	int rate_count;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = {
4862306a36Sopenharmony_ci	PLL_1416X_RATE(1800000000U, 225, 3, 0),
4962306a36Sopenharmony_ci	PLL_1416X_RATE(1600000000U, 200, 3, 0),
5062306a36Sopenharmony_ci	PLL_1416X_RATE(1500000000U, 375, 3, 1),
5162306a36Sopenharmony_ci	PLL_1416X_RATE(1400000000U, 350, 3, 1),
5262306a36Sopenharmony_ci	PLL_1416X_RATE(1200000000U, 300, 3, 1),
5362306a36Sopenharmony_ci	PLL_1416X_RATE(1000000000U, 250, 3, 1),
5462306a36Sopenharmony_ci	PLL_1416X_RATE(800000000U,  200, 3, 1),
5562306a36Sopenharmony_ci	PLL_1416X_RATE(750000000U,  250, 2, 2),
5662306a36Sopenharmony_ci	PLL_1416X_RATE(700000000U,  350, 3, 2),
5762306a36Sopenharmony_ci	PLL_1416X_RATE(640000000U,  320, 3, 2),
5862306a36Sopenharmony_ci	PLL_1416X_RATE(600000000U,  300, 3, 2),
5962306a36Sopenharmony_ci	PLL_1416X_RATE(320000000U,  160, 3, 2),
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {
6362306a36Sopenharmony_ci	PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384),
6462306a36Sopenharmony_ci	PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
6562306a36Sopenharmony_ci	PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
6662306a36Sopenharmony_ci	PLL_1443X_RATE(519750000U, 173, 2, 2, 16384),
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct imx_pll14xx_clk imx_1443x_pll = {
7062306a36Sopenharmony_ci	.type = PLL_1443X,
7162306a36Sopenharmony_ci	.rate_table = imx_pll1443x_tbl,
7262306a36Sopenharmony_ci	.rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1443x_pll);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistruct imx_pll14xx_clk imx_1443x_dram_pll = {
7762306a36Sopenharmony_ci	.type = PLL_1443X,
7862306a36Sopenharmony_ci	.rate_table = imx_pll1443x_tbl,
7962306a36Sopenharmony_ci	.rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
8062306a36Sopenharmony_ci	.flags = CLK_GET_RATE_NOCACHE,
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1443x_dram_pll);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct imx_pll14xx_clk imx_1416x_pll = {
8562306a36Sopenharmony_ci	.type = PLL_1416X,
8662306a36Sopenharmony_ci	.rate_table = imx_pll1416x_tbl,
8762306a36Sopenharmony_ci	.rate_count = ARRAY_SIZE(imx_pll1416x_tbl),
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_1416x_pll);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic const struct imx_pll14xx_rate_table *imx_get_pll_settings(
9262306a36Sopenharmony_ci		struct clk_pll14xx *pll, unsigned long rate)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
9562306a36Sopenharmony_ci	int i;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++)
9862306a36Sopenharmony_ci		if (rate == rate_table[i].rate)
9962306a36Sopenharmony_ci			return &rate_table[i];
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return NULL;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic long pll14xx_calc_rate(struct clk_pll14xx *pll, int mdiv, int pdiv,
10562306a36Sopenharmony_ci			      int sdiv, int kdiv, unsigned long prate)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	u64 fvco = prate;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
11062306a36Sopenharmony_ci	fvco *= (mdiv * 65536 + kdiv);
11162306a36Sopenharmony_ci	pdiv *= 65536;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	do_div(fvco, pdiv << sdiv);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return fvco;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic long pll1443x_calc_kdiv(int mdiv, int pdiv, int sdiv,
11962306a36Sopenharmony_ci		unsigned long rate, unsigned long prate)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	long kdiv;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* calc kdiv = round(rate * pdiv * 65536 * 2^sdiv / prate) - (mdiv * 65536) */
12462306a36Sopenharmony_ci	kdiv = ((rate * ((pdiv * 65536) << sdiv) + prate / 2) / prate) - (mdiv * 65536);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return clamp_t(short, kdiv, KDIV_MIN, KDIV_MAX);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rate,
13062306a36Sopenharmony_ci				      unsigned long prate, struct imx_pll14xx_rate_table *t)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	u32 pll_div_ctl0, pll_div_ctl1;
13362306a36Sopenharmony_ci	int mdiv, pdiv, sdiv, kdiv;
13462306a36Sopenharmony_ci	long fvco, rate_min, rate_max, dist, best = LONG_MAX;
13562306a36Sopenharmony_ci	const struct imx_pll14xx_rate_table *tt;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/*
13862306a36Sopenharmony_ci	 * Fractional PLL constrains:
13962306a36Sopenharmony_ci	 *
14062306a36Sopenharmony_ci	 * a) 1 <= p <= 63
14162306a36Sopenharmony_ci	 * b) 64 <= m <= 1023
14262306a36Sopenharmony_ci	 * c) 0 <= s <= 6
14362306a36Sopenharmony_ci	 * d) -32768 <= k <= 32767
14462306a36Sopenharmony_ci	 *
14562306a36Sopenharmony_ci	 * fvco = (m * 65536 + k) * prate / (p * 65536)
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* First try if we can get the desired rate from one of the static entries */
14962306a36Sopenharmony_ci	tt = imx_get_pll_settings(pll, rate);
15062306a36Sopenharmony_ci	if (tt) {
15162306a36Sopenharmony_ci		pr_debug("%s: in=%ld, want=%ld, Using PLL setting from table\n",
15262306a36Sopenharmony_ci			 clk_hw_get_name(&pll->hw), prate, rate);
15362306a36Sopenharmony_ci		t->rate = tt->rate;
15462306a36Sopenharmony_ci		t->mdiv = tt->mdiv;
15562306a36Sopenharmony_ci		t->pdiv = tt->pdiv;
15662306a36Sopenharmony_ci		t->sdiv = tt->sdiv;
15762306a36Sopenharmony_ci		t->kdiv = tt->kdiv;
15862306a36Sopenharmony_ci		return;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
16262306a36Sopenharmony_ci	mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
16362306a36Sopenharmony_ci	pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
16462306a36Sopenharmony_ci	sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
16562306a36Sopenharmony_ci	pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* Then see if we can get the desired rate by only adjusting kdiv (glitch free) */
16862306a36Sopenharmony_ci	rate_min = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MIN, prate);
16962306a36Sopenharmony_ci	rate_max = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MAX, prate);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (rate >= rate_min && rate <= rate_max) {
17262306a36Sopenharmony_ci		kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate);
17362306a36Sopenharmony_ci		pr_debug("%s: in=%ld, want=%ld Only adjust kdiv %ld -> %d\n",
17462306a36Sopenharmony_ci			 clk_hw_get_name(&pll->hw), prate, rate,
17562306a36Sopenharmony_ci			 FIELD_GET(KDIV_MASK, pll_div_ctl1), kdiv);
17662306a36Sopenharmony_ci		fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
17762306a36Sopenharmony_ci		t->rate = (unsigned int)fvco;
17862306a36Sopenharmony_ci		t->mdiv = mdiv;
17962306a36Sopenharmony_ci		t->pdiv = pdiv;
18062306a36Sopenharmony_ci		t->sdiv = sdiv;
18162306a36Sopenharmony_ci		t->kdiv = kdiv;
18262306a36Sopenharmony_ci		return;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Finally calculate best values */
18662306a36Sopenharmony_ci	for (pdiv = 1; pdiv <= 63; pdiv++) {
18762306a36Sopenharmony_ci		for (sdiv = 0; sdiv <= 6; sdiv++) {
18862306a36Sopenharmony_ci			/* calc mdiv = round(rate * pdiv * 2^sdiv) / prate) */
18962306a36Sopenharmony_ci			mdiv = DIV_ROUND_CLOSEST(rate * (pdiv << sdiv), prate);
19062306a36Sopenharmony_ci			mdiv = clamp(mdiv, 64, 1023);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci			kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate);
19362306a36Sopenharmony_ci			fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci			/* best match */
19662306a36Sopenharmony_ci			dist = abs((long)rate - (long)fvco);
19762306a36Sopenharmony_ci			if (dist < best) {
19862306a36Sopenharmony_ci				best = dist;
19962306a36Sopenharmony_ci				t->rate = (unsigned int)fvco;
20062306a36Sopenharmony_ci				t->mdiv = mdiv;
20162306a36Sopenharmony_ci				t->pdiv = pdiv;
20262306a36Sopenharmony_ci				t->sdiv = sdiv;
20362306a36Sopenharmony_ci				t->kdiv = kdiv;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci				if (!dist)
20662306a36Sopenharmony_ci					goto found;
20762306a36Sopenharmony_ci			}
20862306a36Sopenharmony_ci		}
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_cifound:
21162306a36Sopenharmony_ci	pr_debug("%s: in=%ld, want=%ld got=%d (pdiv=%d sdiv=%d mdiv=%d kdiv=%d)\n",
21262306a36Sopenharmony_ci		 clk_hw_get_name(&pll->hw), prate, rate, t->rate, t->pdiv, t->sdiv,
21362306a36Sopenharmony_ci		 t->mdiv, t->kdiv);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic long clk_pll1416x_round_rate(struct clk_hw *hw, unsigned long rate,
21762306a36Sopenharmony_ci			unsigned long *prate)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
22062306a36Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
22162306a36Sopenharmony_ci	int i;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* Assuming rate_table is in descending order */
22462306a36Sopenharmony_ci	for (i = 0; i < pll->rate_count; i++)
22562306a36Sopenharmony_ci		if (rate >= rate_table[i].rate)
22662306a36Sopenharmony_ci			return rate_table[i].rate;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* return minimum supported value */
22962306a36Sopenharmony_ci	return rate_table[pll->rate_count - 1].rate;
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic long clk_pll1443x_round_rate(struct clk_hw *hw, unsigned long rate,
23362306a36Sopenharmony_ci			unsigned long *prate)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
23662306a36Sopenharmony_ci	struct imx_pll14xx_rate_table t;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	imx_pll14xx_calc_settings(pll, rate, *prate, &t);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	return t.rate;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic unsigned long clk_pll14xx_recalc_rate(struct clk_hw *hw,
24462306a36Sopenharmony_ci						  unsigned long parent_rate)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
24762306a36Sopenharmony_ci	u32 mdiv, pdiv, sdiv, kdiv, pll_div_ctl0, pll_div_ctl1;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
25062306a36Sopenharmony_ci	mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
25162306a36Sopenharmony_ci	pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
25262306a36Sopenharmony_ci	sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (pll->type == PLL_1443X) {
25562306a36Sopenharmony_ci		pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
25662306a36Sopenharmony_ci		kdiv = (s16)FIELD_GET(KDIV_MASK, pll_div_ctl1);
25762306a36Sopenharmony_ci	} else {
25862306a36Sopenharmony_ci		kdiv = 0;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, parent_rate);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *rate,
26562306a36Sopenharmony_ci					  u32 pll_div)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	u32 old_mdiv, old_pdiv;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	old_mdiv = FIELD_GET(MDIV_MASK, pll_div);
27062306a36Sopenharmony_ci	old_pdiv = FIELD_GET(PDIV_MASK, pll_div);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	u32 val;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return readl_poll_timeout(pll->base + GNRL_CTL, val, val & LOCK_STATUS, 0,
28062306a36Sopenharmony_ci			LOCK_TIMEOUT_US);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
28462306a36Sopenharmony_ci				 unsigned long prate)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
28762306a36Sopenharmony_ci	const struct imx_pll14xx_rate_table *rate;
28862306a36Sopenharmony_ci	u32 tmp, div_val;
28962306a36Sopenharmony_ci	int ret;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	rate = imx_get_pll_settings(pll, drate);
29262306a36Sopenharmony_ci	if (!rate) {
29362306a36Sopenharmony_ci		pr_err("Invalid rate %lu for pll clk %s\n", drate,
29462306a36Sopenharmony_ci		       clk_hw_get_name(hw));
29562306a36Sopenharmony_ci		return -EINVAL;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	tmp = readl_relaxed(pll->base + DIV_CTL0);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (!clk_pll14xx_mp_change(rate, tmp)) {
30162306a36Sopenharmony_ci		tmp &= ~SDIV_MASK;
30262306a36Sopenharmony_ci		tmp |= FIELD_PREP(SDIV_MASK, rate->sdiv);
30362306a36Sopenharmony_ci		writel_relaxed(tmp, pll->base + DIV_CTL0);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		return 0;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* Bypass clock and set lock to pll output lock */
30962306a36Sopenharmony_ci	tmp = readl_relaxed(pll->base + GNRL_CTL);
31062306a36Sopenharmony_ci	tmp |= LOCK_SEL_MASK;
31162306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + GNRL_CTL);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Enable RST */
31462306a36Sopenharmony_ci	tmp &= ~RST_MASK;
31562306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + GNRL_CTL);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Enable BYPASS */
31862306a36Sopenharmony_ci	tmp |= BYPASS_MASK;
31962306a36Sopenharmony_ci	writel(tmp, pll->base + GNRL_CTL);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	div_val = FIELD_PREP(MDIV_MASK, rate->mdiv) | FIELD_PREP(PDIV_MASK, rate->pdiv) |
32262306a36Sopenharmony_ci		FIELD_PREP(SDIV_MASK, rate->sdiv);
32362306a36Sopenharmony_ci	writel_relaxed(div_val, pll->base + DIV_CTL0);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/*
32662306a36Sopenharmony_ci	 * According to SPEC, t3 - t2 need to be greater than
32762306a36Sopenharmony_ci	 * 1us and 1/FREF, respectively.
32862306a36Sopenharmony_ci	 * FREF is FIN / Prediv, the prediv is [1, 63], so choose
32962306a36Sopenharmony_ci	 * 3us.
33062306a36Sopenharmony_ci	 */
33162306a36Sopenharmony_ci	udelay(3);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Disable RST */
33462306a36Sopenharmony_ci	tmp |= RST_MASK;
33562306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + GNRL_CTL);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* Wait Lock */
33862306a36Sopenharmony_ci	ret = clk_pll14xx_wait_lock(pll);
33962306a36Sopenharmony_ci	if (ret)
34062306a36Sopenharmony_ci		return ret;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Bypass */
34362306a36Sopenharmony_ci	tmp &= ~BYPASS_MASK;
34462306a36Sopenharmony_ci	writel_relaxed(tmp, pll->base + GNRL_CTL);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
35062306a36Sopenharmony_ci				 unsigned long prate)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
35362306a36Sopenharmony_ci	struct imx_pll14xx_rate_table rate;
35462306a36Sopenharmony_ci	u32 gnrl_ctl, div_ctl0;
35562306a36Sopenharmony_ci	int ret;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	imx_pll14xx_calc_settings(pll, drate, prate, &rate);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (!clk_pll14xx_mp_change(&rate, div_ctl0)) {
36262306a36Sopenharmony_ci		/* only sdiv and/or kdiv changed - no need to RESET PLL */
36362306a36Sopenharmony_ci		div_ctl0 &= ~SDIV_MASK;
36462306a36Sopenharmony_ci		div_ctl0 |= FIELD_PREP(SDIV_MASK, rate.sdiv);
36562306a36Sopenharmony_ci		writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv),
36862306a36Sopenharmony_ci			       pll->base + DIV_CTL1);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		return 0;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Enable RST */
37462306a36Sopenharmony_ci	gnrl_ctl = readl_relaxed(pll->base + GNRL_CTL);
37562306a36Sopenharmony_ci	gnrl_ctl &= ~RST_MASK;
37662306a36Sopenharmony_ci	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Enable BYPASS */
37962306a36Sopenharmony_ci	gnrl_ctl |= BYPASS_MASK;
38062306a36Sopenharmony_ci	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	div_ctl0 = FIELD_PREP(MDIV_MASK, rate.mdiv) |
38362306a36Sopenharmony_ci		   FIELD_PREP(PDIV_MASK, rate.pdiv) |
38462306a36Sopenharmony_ci		   FIELD_PREP(SDIV_MASK, rate.sdiv);
38562306a36Sopenharmony_ci	writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/*
39062306a36Sopenharmony_ci	 * According to SPEC, t3 - t2 need to be greater than
39162306a36Sopenharmony_ci	 * 1us and 1/FREF, respectively.
39262306a36Sopenharmony_ci	 * FREF is FIN / Prediv, the prediv is [1, 63], so choose
39362306a36Sopenharmony_ci	 * 3us.
39462306a36Sopenharmony_ci	 */
39562306a36Sopenharmony_ci	udelay(3);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* Disable RST */
39862306a36Sopenharmony_ci	gnrl_ctl |= RST_MASK;
39962306a36Sopenharmony_ci	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* Wait Lock*/
40262306a36Sopenharmony_ci	ret = clk_pll14xx_wait_lock(pll);
40362306a36Sopenharmony_ci	if (ret)
40462306a36Sopenharmony_ci		return ret;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Bypass */
40762306a36Sopenharmony_ci	gnrl_ctl &= ~BYPASS_MASK;
40862306a36Sopenharmony_ci	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic int clk_pll14xx_prepare(struct clk_hw *hw)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
41662306a36Sopenharmony_ci	u32 val;
41762306a36Sopenharmony_ci	int ret;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/*
42062306a36Sopenharmony_ci	 * RESETB = 1 from 0, PLL starts its normal
42162306a36Sopenharmony_ci	 * operation after lock time
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
42462306a36Sopenharmony_ci	if (val & RST_MASK)
42562306a36Sopenharmony_ci		return 0;
42662306a36Sopenharmony_ci	val |= BYPASS_MASK;
42762306a36Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
42862306a36Sopenharmony_ci	val |= RST_MASK;
42962306a36Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	ret = clk_pll14xx_wait_lock(pll);
43262306a36Sopenharmony_ci	if (ret)
43362306a36Sopenharmony_ci		return ret;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	val &= ~BYPASS_MASK;
43662306a36Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return 0;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic int clk_pll14xx_is_prepared(struct clk_hw *hw)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
44462306a36Sopenharmony_ci	u32 val;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return (val & RST_MASK) ? 1 : 0;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic void clk_pll14xx_unprepare(struct clk_hw *hw)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
45462306a36Sopenharmony_ci	u32 val;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/*
45762306a36Sopenharmony_ci	 * Set RST to 0, power down mode is enabled and
45862306a36Sopenharmony_ci	 * every digital block is reset
45962306a36Sopenharmony_ci	 */
46062306a36Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
46162306a36Sopenharmony_ci	val &= ~RST_MASK;
46262306a36Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic const struct clk_ops clk_pll1416x_ops = {
46662306a36Sopenharmony_ci	.prepare	= clk_pll14xx_prepare,
46762306a36Sopenharmony_ci	.unprepare	= clk_pll14xx_unprepare,
46862306a36Sopenharmony_ci	.is_prepared	= clk_pll14xx_is_prepared,
46962306a36Sopenharmony_ci	.recalc_rate	= clk_pll14xx_recalc_rate,
47062306a36Sopenharmony_ci	.round_rate	= clk_pll1416x_round_rate,
47162306a36Sopenharmony_ci	.set_rate	= clk_pll1416x_set_rate,
47262306a36Sopenharmony_ci};
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic const struct clk_ops clk_pll1416x_min_ops = {
47562306a36Sopenharmony_ci	.recalc_rate	= clk_pll14xx_recalc_rate,
47662306a36Sopenharmony_ci};
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic const struct clk_ops clk_pll1443x_ops = {
47962306a36Sopenharmony_ci	.prepare	= clk_pll14xx_prepare,
48062306a36Sopenharmony_ci	.unprepare	= clk_pll14xx_unprepare,
48162306a36Sopenharmony_ci	.is_prepared	= clk_pll14xx_is_prepared,
48262306a36Sopenharmony_ci	.recalc_rate	= clk_pll14xx_recalc_rate,
48362306a36Sopenharmony_ci	.round_rate	= clk_pll1443x_round_rate,
48462306a36Sopenharmony_ci	.set_rate	= clk_pll1443x_set_rate,
48562306a36Sopenharmony_ci};
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistruct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
48862306a36Sopenharmony_ci				const char *parent_name, void __iomem *base,
48962306a36Sopenharmony_ci				const struct imx_pll14xx_clk *pll_clk)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	struct clk_pll14xx *pll;
49262306a36Sopenharmony_ci	struct clk_hw *hw;
49362306a36Sopenharmony_ci	struct clk_init_data init;
49462306a36Sopenharmony_ci	int ret;
49562306a36Sopenharmony_ci	u32 val;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
49862306a36Sopenharmony_ci	if (!pll)
49962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	init.name = name;
50262306a36Sopenharmony_ci	init.flags = pll_clk->flags;
50362306a36Sopenharmony_ci	init.parent_names = &parent_name;
50462306a36Sopenharmony_ci	init.num_parents = 1;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	switch (pll_clk->type) {
50762306a36Sopenharmony_ci	case PLL_1416X:
50862306a36Sopenharmony_ci		if (!pll_clk->rate_table)
50962306a36Sopenharmony_ci			init.ops = &clk_pll1416x_min_ops;
51062306a36Sopenharmony_ci		else
51162306a36Sopenharmony_ci			init.ops = &clk_pll1416x_ops;
51262306a36Sopenharmony_ci		break;
51362306a36Sopenharmony_ci	case PLL_1443X:
51462306a36Sopenharmony_ci		init.ops = &clk_pll1443x_ops;
51562306a36Sopenharmony_ci		break;
51662306a36Sopenharmony_ci	default:
51762306a36Sopenharmony_ci		pr_err("Unknown pll type for pll clk %s\n", name);
51862306a36Sopenharmony_ci		kfree(pll);
51962306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	pll->base = base;
52362306a36Sopenharmony_ci	pll->hw.init = &init;
52462306a36Sopenharmony_ci	pll->type = pll_clk->type;
52562306a36Sopenharmony_ci	pll->rate_table = pll_clk->rate_table;
52662306a36Sopenharmony_ci	pll->rate_count = pll_clk->rate_count;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	val = readl_relaxed(pll->base + GNRL_CTL);
52962306a36Sopenharmony_ci	val &= ~BYPASS_MASK;
53062306a36Sopenharmony_ci	writel_relaxed(val, pll->base + GNRL_CTL);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	hw = &pll->hw;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ret = clk_hw_register(dev, hw);
53562306a36Sopenharmony_ci	if (ret) {
53662306a36Sopenharmony_ci		pr_err("failed to register pll %s %d\n", name, ret);
53762306a36Sopenharmony_ci		kfree(pll);
53862306a36Sopenharmony_ci		return ERR_PTR(ret);
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	return hw;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx);
544