162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT)
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2018 NXP.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This driver supports the SCCG plls found in the imx8m SOCs
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Documentation for this SCCG pll can be found at:
862306a36Sopenharmony_ci *   https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk-provider.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/export.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/iopoll.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/bitfield.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "clk.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* PLL CFGs */
2262306a36Sopenharmony_ci#define PLL_CFG0		0x0
2362306a36Sopenharmony_ci#define PLL_CFG1		0x4
2462306a36Sopenharmony_ci#define PLL_CFG2		0x8
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define PLL_DIVF1_MASK		GENMASK(18, 13)
2762306a36Sopenharmony_ci#define PLL_DIVF2_MASK		GENMASK(12, 7)
2862306a36Sopenharmony_ci#define PLL_DIVR1_MASK		GENMASK(27, 25)
2962306a36Sopenharmony_ci#define PLL_DIVR2_MASK		GENMASK(24, 19)
3062306a36Sopenharmony_ci#define PLL_DIVQ_MASK           GENMASK(6, 1)
3162306a36Sopenharmony_ci#define PLL_REF_MASK		GENMASK(2, 0)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define PLL_LOCK_MASK		BIT(31)
3462306a36Sopenharmony_ci#define PLL_PD_MASK		BIT(7)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* These are the specification limits for the SSCG PLL */
3762306a36Sopenharmony_ci#define PLL_REF_MIN_FREQ		25000000UL
3862306a36Sopenharmony_ci#define PLL_REF_MAX_FREQ		235000000UL
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define PLL_STAGE1_MIN_FREQ		1600000000UL
4162306a36Sopenharmony_ci#define PLL_STAGE1_MAX_FREQ		2400000000UL
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define PLL_STAGE1_REF_MIN_FREQ		25000000UL
4462306a36Sopenharmony_ci#define PLL_STAGE1_REF_MAX_FREQ		54000000UL
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define PLL_STAGE2_MIN_FREQ		1200000000UL
4762306a36Sopenharmony_ci#define PLL_STAGE2_MAX_FREQ		2400000000UL
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define PLL_STAGE2_REF_MIN_FREQ		54000000UL
5062306a36Sopenharmony_ci#define PLL_STAGE2_REF_MAX_FREQ		75000000UL
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define PLL_OUT_MIN_FREQ		20000000UL
5362306a36Sopenharmony_ci#define PLL_OUT_MAX_FREQ		1200000000UL
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define PLL_DIVR1_MAX			7
5662306a36Sopenharmony_ci#define PLL_DIVR2_MAX			63
5762306a36Sopenharmony_ci#define PLL_DIVF1_MAX			63
5862306a36Sopenharmony_ci#define PLL_DIVF2_MAX			63
5962306a36Sopenharmony_ci#define PLL_DIVQ_MAX			63
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define PLL_BYPASS_NONE			0x0
6262306a36Sopenharmony_ci#define PLL_BYPASS1			0x2
6362306a36Sopenharmony_ci#define PLL_BYPASS2			0x1
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define SSCG_PLL_BYPASS1_MASK           BIT(5)
6662306a36Sopenharmony_ci#define SSCG_PLL_BYPASS2_MASK           BIT(4)
6762306a36Sopenharmony_ci#define SSCG_PLL_BYPASS_MASK		GENMASK(5, 4)
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define PLL_SCCG_LOCK_TIMEOUT		70
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct clk_sscg_pll_setup {
7262306a36Sopenharmony_ci	int divr1, divf1;
7362306a36Sopenharmony_ci	int divr2, divf2;
7462306a36Sopenharmony_ci	int divq;
7562306a36Sopenharmony_ci	int bypass;
7662306a36Sopenharmony_ci	uint64_t vco1;
7762306a36Sopenharmony_ci	uint64_t vco2;
7862306a36Sopenharmony_ci	uint64_t fout;
7962306a36Sopenharmony_ci	uint64_t ref;
8062306a36Sopenharmony_ci	uint64_t ref_div1;
8162306a36Sopenharmony_ci	uint64_t ref_div2;
8262306a36Sopenharmony_ci	uint64_t fout_request;
8362306a36Sopenharmony_ci	int fout_error;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistruct clk_sscg_pll {
8762306a36Sopenharmony_ci	struct clk_hw	hw;
8862306a36Sopenharmony_ci	const struct clk_ops  ops;
8962306a36Sopenharmony_ci	void __iomem *base;
9062306a36Sopenharmony_ci	struct clk_sscg_pll_setup setup;
9162306a36Sopenharmony_ci	u8 parent;
9262306a36Sopenharmony_ci	u8 bypass1;
9362306a36Sopenharmony_ci	u8 bypass2;
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define to_clk_sscg_pll(_hw) container_of(_hw, struct clk_sscg_pll, hw)
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int clk_sscg_pll_wait_lock(struct clk_sscg_pll *pll)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	u32 val;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CFG0);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* don't wait for lock if all plls are bypassed */
10562306a36Sopenharmony_ci	if (!(val & SSCG_PLL_BYPASS2_MASK))
10662306a36Sopenharmony_ci		return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK,
10762306a36Sopenharmony_ci						0, PLL_SCCG_LOCK_TIMEOUT);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int clk_sscg_pll2_check_match(struct clk_sscg_pll_setup *setup,
11362306a36Sopenharmony_ci					struct clk_sscg_pll_setup *temp_setup)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	int new_diff = temp_setup->fout - temp_setup->fout_request;
11662306a36Sopenharmony_ci	int diff = temp_setup->fout_error;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (abs(diff) > abs(new_diff)) {
11962306a36Sopenharmony_ci		temp_setup->fout_error = new_diff;
12062306a36Sopenharmony_ci		memcpy(setup, temp_setup, sizeof(struct clk_sscg_pll_setup));
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		if (temp_setup->fout_request == temp_setup->fout)
12362306a36Sopenharmony_ci			return 0;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	return -1;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int clk_sscg_divq_lookup(struct clk_sscg_pll_setup *setup,
12962306a36Sopenharmony_ci				struct clk_sscg_pll_setup *temp_setup)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	int ret = -EINVAL;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX;
13462306a36Sopenharmony_ci	     temp_setup->divq++) {
13562306a36Sopenharmony_ci		temp_setup->vco2 = temp_setup->vco1;
13662306a36Sopenharmony_ci		do_div(temp_setup->vco2, temp_setup->divr2 + 1);
13762306a36Sopenharmony_ci		temp_setup->vco2 *= 2;
13862306a36Sopenharmony_ci		temp_setup->vco2 *= temp_setup->divf2 + 1;
13962306a36Sopenharmony_ci		if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ &&
14062306a36Sopenharmony_ci				temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) {
14162306a36Sopenharmony_ci			temp_setup->fout = temp_setup->vco2;
14262306a36Sopenharmony_ci			do_div(temp_setup->fout, 2 * (temp_setup->divq + 1));
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci			ret = clk_sscg_pll2_check_match(setup, temp_setup);
14562306a36Sopenharmony_ci			if (!ret) {
14662306a36Sopenharmony_ci				temp_setup->bypass = PLL_BYPASS1;
14762306a36Sopenharmony_ci				return ret;
14862306a36Sopenharmony_ci			}
14962306a36Sopenharmony_ci		}
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return ret;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int clk_sscg_divf2_lookup(struct clk_sscg_pll_setup *setup,
15662306a36Sopenharmony_ci					struct clk_sscg_pll_setup *temp_setup)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	int ret = -EINVAL;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX;
16162306a36Sopenharmony_ci	     temp_setup->divf2++) {
16262306a36Sopenharmony_ci		ret = clk_sscg_divq_lookup(setup, temp_setup);
16362306a36Sopenharmony_ci		if (!ret)
16462306a36Sopenharmony_ci			return ret;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return ret;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int clk_sscg_divr2_lookup(struct clk_sscg_pll_setup *setup,
17162306a36Sopenharmony_ci				struct clk_sscg_pll_setup *temp_setup)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int ret = -EINVAL;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX;
17662306a36Sopenharmony_ci	     temp_setup->divr2++) {
17762306a36Sopenharmony_ci		temp_setup->ref_div2 = temp_setup->vco1;
17862306a36Sopenharmony_ci		do_div(temp_setup->ref_div2, temp_setup->divr2 + 1);
17962306a36Sopenharmony_ci		if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ &&
18062306a36Sopenharmony_ci		    temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) {
18162306a36Sopenharmony_ci			ret = clk_sscg_divf2_lookup(setup, temp_setup);
18262306a36Sopenharmony_ci			if (!ret)
18362306a36Sopenharmony_ci				return ret;
18462306a36Sopenharmony_ci		}
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return ret;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup,
19162306a36Sopenharmony_ci					struct clk_sscg_pll_setup *temp_setup,
19262306a36Sopenharmony_ci					uint64_t ref)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	int ret;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)
19762306a36Sopenharmony_ci		return -EINVAL;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	temp_setup->vco1 = ref;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	ret = clk_sscg_divr2_lookup(setup, temp_setup);
20262306a36Sopenharmony_ci	return ret;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int clk_sscg_divf1_lookup(struct clk_sscg_pll_setup *setup,
20662306a36Sopenharmony_ci				struct clk_sscg_pll_setup *temp_setup)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	int ret = -EINVAL;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX;
21162306a36Sopenharmony_ci	     temp_setup->divf1++) {
21262306a36Sopenharmony_ci		uint64_t vco1 = temp_setup->ref;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		do_div(vco1, temp_setup->divr1 + 1);
21562306a36Sopenharmony_ci		vco1 *= 2;
21662306a36Sopenharmony_ci		vco1 *= temp_setup->divf1 + 1;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		ret = clk_sscg_pll2_find_setup(setup, temp_setup, vco1);
21962306a36Sopenharmony_ci		if (!ret) {
22062306a36Sopenharmony_ci			temp_setup->bypass = PLL_BYPASS_NONE;
22162306a36Sopenharmony_ci			return ret;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return ret;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int clk_sscg_divr1_lookup(struct clk_sscg_pll_setup *setup,
22962306a36Sopenharmony_ci				struct clk_sscg_pll_setup *temp_setup)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	int ret = -EINVAL;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX;
23462306a36Sopenharmony_ci	     temp_setup->divr1++) {
23562306a36Sopenharmony_ci		temp_setup->ref_div1 = temp_setup->ref;
23662306a36Sopenharmony_ci		do_div(temp_setup->ref_div1, temp_setup->divr1 + 1);
23762306a36Sopenharmony_ci		if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ &&
23862306a36Sopenharmony_ci		    temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) {
23962306a36Sopenharmony_ci			ret = clk_sscg_divf1_lookup(setup, temp_setup);
24062306a36Sopenharmony_ci			if (!ret)
24162306a36Sopenharmony_ci				return ret;
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return ret;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup,
24962306a36Sopenharmony_ci					struct clk_sscg_pll_setup *temp_setup,
25062306a36Sopenharmony_ci					uint64_t ref)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	int ret;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)
25562306a36Sopenharmony_ci		return -EINVAL;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	temp_setup->ref = ref;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	ret = clk_sscg_divr1_lookup(setup, temp_setup);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return ret;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup,
26562306a36Sopenharmony_ci					uint64_t prate,
26662306a36Sopenharmony_ci					uint64_t rate, int try_bypass)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	struct clk_sscg_pll_setup temp_setup;
26962306a36Sopenharmony_ci	int ret = -EINVAL;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	memset(&temp_setup, 0, sizeof(struct clk_sscg_pll_setup));
27262306a36Sopenharmony_ci	memset(setup, 0, sizeof(struct clk_sscg_pll_setup));
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	temp_setup.fout_error = PLL_OUT_MAX_FREQ;
27562306a36Sopenharmony_ci	temp_setup.fout_request = rate;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	switch (try_bypass) {
27862306a36Sopenharmony_ci	case PLL_BYPASS2:
27962306a36Sopenharmony_ci		if (prate == rate) {
28062306a36Sopenharmony_ci			setup->bypass = PLL_BYPASS2;
28162306a36Sopenharmony_ci			setup->fout = rate;
28262306a36Sopenharmony_ci			ret = 0;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	case PLL_BYPASS1:
28662306a36Sopenharmony_ci		ret = clk_sscg_pll2_find_setup(setup, &temp_setup, prate);
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci	case PLL_BYPASS_NONE:
28962306a36Sopenharmony_ci		ret = clk_sscg_pll1_find_setup(setup, &temp_setup, prate);
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return ret;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int clk_sscg_pll_is_prepared(struct clk_hw *hw)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	u32 val = readl_relaxed(pll->base + PLL_CFG0);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	return (val & PLL_PD_MASK) ? 0 : 1;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int clk_sscg_pll_prepare(struct clk_hw *hw)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
30862306a36Sopenharmony_ci	u32 val;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CFG0);
31162306a36Sopenharmony_ci	val &= ~PLL_PD_MASK;
31262306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CFG0);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return clk_sscg_pll_wait_lock(pll);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic void clk_sscg_pll_unprepare(struct clk_hw *hw)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
32062306a36Sopenharmony_ci	u32 val;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CFG0);
32362306a36Sopenharmony_ci	val |= PLL_PD_MASK;
32462306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CFG0);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic unsigned long clk_sscg_pll_recalc_rate(struct clk_hw *hw,
32862306a36Sopenharmony_ci					 unsigned long parent_rate)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
33162306a36Sopenharmony_ci	u32 val, divr1, divf1, divr2, divf2, divq;
33262306a36Sopenharmony_ci	u64 temp64;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CFG2);
33562306a36Sopenharmony_ci	divr1 = FIELD_GET(PLL_DIVR1_MASK, val);
33662306a36Sopenharmony_ci	divr2 = FIELD_GET(PLL_DIVR2_MASK, val);
33762306a36Sopenharmony_ci	divf1 = FIELD_GET(PLL_DIVF1_MASK, val);
33862306a36Sopenharmony_ci	divf2 = FIELD_GET(PLL_DIVF2_MASK, val);
33962306a36Sopenharmony_ci	divq = FIELD_GET(PLL_DIVQ_MASK, val);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	temp64 = parent_rate;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	val = readl(pll->base + PLL_CFG0);
34462306a36Sopenharmony_ci	if (val & SSCG_PLL_BYPASS2_MASK) {
34562306a36Sopenharmony_ci		temp64 = parent_rate;
34662306a36Sopenharmony_ci	} else if (val & SSCG_PLL_BYPASS1_MASK) {
34762306a36Sopenharmony_ci		temp64 *= divf2;
34862306a36Sopenharmony_ci		do_div(temp64, (divr2 + 1) * (divq + 1));
34962306a36Sopenharmony_ci	} else {
35062306a36Sopenharmony_ci		temp64 *= 2;
35162306a36Sopenharmony_ci		temp64 *= (divf1 + 1) * (divf2 + 1);
35262306a36Sopenharmony_ci		do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1));
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return temp64;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int clk_sscg_pll_set_rate(struct clk_hw *hw, unsigned long rate,
35962306a36Sopenharmony_ci			    unsigned long parent_rate)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
36262306a36Sopenharmony_ci	struct clk_sscg_pll_setup *setup = &pll->setup;
36362306a36Sopenharmony_ci	u32 val;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* set bypass here too since the parent might be the same */
36662306a36Sopenharmony_ci	val = readl(pll->base + PLL_CFG0);
36762306a36Sopenharmony_ci	val &= ~SSCG_PLL_BYPASS_MASK;
36862306a36Sopenharmony_ci	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass);
36962306a36Sopenharmony_ci	writel(val, pll->base + PLL_CFG0);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	val = readl_relaxed(pll->base + PLL_CFG2);
37262306a36Sopenharmony_ci	val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK);
37362306a36Sopenharmony_ci	val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK);
37462306a36Sopenharmony_ci	val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1);
37562306a36Sopenharmony_ci	val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2);
37662306a36Sopenharmony_ci	val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1);
37762306a36Sopenharmony_ci	val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2);
37862306a36Sopenharmony_ci	val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq);
37962306a36Sopenharmony_ci	writel_relaxed(val, pll->base + PLL_CFG2);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return clk_sscg_pll_wait_lock(pll);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic u8 clk_sscg_pll_get_parent(struct clk_hw *hw)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
38762306a36Sopenharmony_ci	u32 val;
38862306a36Sopenharmony_ci	u8 ret = pll->parent;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	val = readl(pll->base + PLL_CFG0);
39162306a36Sopenharmony_ci	if (val & SSCG_PLL_BYPASS2_MASK)
39262306a36Sopenharmony_ci		ret = pll->bypass2;
39362306a36Sopenharmony_ci	else if (val & SSCG_PLL_BYPASS1_MASK)
39462306a36Sopenharmony_ci		ret = pll->bypass1;
39562306a36Sopenharmony_ci	return ret;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int clk_sscg_pll_set_parent(struct clk_hw *hw, u8 index)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
40162306a36Sopenharmony_ci	u32 val;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	val = readl(pll->base + PLL_CFG0);
40462306a36Sopenharmony_ci	val &= ~SSCG_PLL_BYPASS_MASK;
40562306a36Sopenharmony_ci	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass);
40662306a36Sopenharmony_ci	writel(val, pll->base + PLL_CFG0);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return clk_sscg_pll_wait_lock(pll);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic int __clk_sscg_pll_determine_rate(struct clk_hw *hw,
41262306a36Sopenharmony_ci					struct clk_rate_request *req,
41362306a36Sopenharmony_ci					uint64_t min,
41462306a36Sopenharmony_ci					uint64_t max,
41562306a36Sopenharmony_ci					uint64_t rate,
41662306a36Sopenharmony_ci					int bypass)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
41962306a36Sopenharmony_ci	struct clk_sscg_pll_setup *setup = &pll->setup;
42062306a36Sopenharmony_ci	struct clk_hw *parent_hw = NULL;
42162306a36Sopenharmony_ci	int bypass_parent_index;
42262306a36Sopenharmony_ci	int ret;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	req->max_rate = max;
42562306a36Sopenharmony_ci	req->min_rate = min;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	switch (bypass) {
42862306a36Sopenharmony_ci	case PLL_BYPASS2:
42962306a36Sopenharmony_ci		bypass_parent_index = pll->bypass2;
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci	case PLL_BYPASS1:
43262306a36Sopenharmony_ci		bypass_parent_index = pll->bypass1;
43362306a36Sopenharmony_ci		break;
43462306a36Sopenharmony_ci	default:
43562306a36Sopenharmony_ci		bypass_parent_index = pll->parent;
43662306a36Sopenharmony_ci		break;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index);
44062306a36Sopenharmony_ci	ret = __clk_determine_rate(parent_hw, req);
44162306a36Sopenharmony_ci	if (!ret) {
44262306a36Sopenharmony_ci		ret = clk_sscg_pll_find_setup(setup, req->rate,
44362306a36Sopenharmony_ci						rate, bypass);
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	req->best_parent_hw = parent_hw;
44762306a36Sopenharmony_ci	req->best_parent_rate = req->rate;
44862306a36Sopenharmony_ci	req->rate = setup->fout;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return ret;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int clk_sscg_pll_determine_rate(struct clk_hw *hw,
45462306a36Sopenharmony_ci				       struct clk_rate_request *req)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
45762306a36Sopenharmony_ci	struct clk_sscg_pll_setup *setup = &pll->setup;
45862306a36Sopenharmony_ci	uint64_t rate = req->rate;
45962306a36Sopenharmony_ci	uint64_t min = req->min_rate;
46062306a36Sopenharmony_ci	uint64_t max = req->max_rate;
46162306a36Sopenharmony_ci	int ret;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ)
46462306a36Sopenharmony_ci		return -EINVAL;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	ret = __clk_sscg_pll_determine_rate(hw, req, req->rate, req->rate,
46762306a36Sopenharmony_ci						rate, PLL_BYPASS2);
46862306a36Sopenharmony_ci	if (!ret)
46962306a36Sopenharmony_ci		return ret;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ,
47262306a36Sopenharmony_ci						PLL_STAGE1_REF_MAX_FREQ, rate,
47362306a36Sopenharmony_ci						PLL_BYPASS1);
47462306a36Sopenharmony_ci	if (!ret)
47562306a36Sopenharmony_ci		return ret;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ,
47862306a36Sopenharmony_ci						PLL_REF_MAX_FREQ, rate,
47962306a36Sopenharmony_ci						PLL_BYPASS_NONE);
48062306a36Sopenharmony_ci	if (!ret)
48162306a36Sopenharmony_ci		return ret;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (setup->fout >= min && setup->fout <= max)
48462306a36Sopenharmony_ci		ret = 0;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return ret;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic const struct clk_ops clk_sscg_pll_ops = {
49062306a36Sopenharmony_ci	.prepare	= clk_sscg_pll_prepare,
49162306a36Sopenharmony_ci	.unprepare	= clk_sscg_pll_unprepare,
49262306a36Sopenharmony_ci	.is_prepared	= clk_sscg_pll_is_prepared,
49362306a36Sopenharmony_ci	.recalc_rate	= clk_sscg_pll_recalc_rate,
49462306a36Sopenharmony_ci	.set_rate	= clk_sscg_pll_set_rate,
49562306a36Sopenharmony_ci	.set_parent	= clk_sscg_pll_set_parent,
49662306a36Sopenharmony_ci	.get_parent	= clk_sscg_pll_get_parent,
49762306a36Sopenharmony_ci	.determine_rate	= clk_sscg_pll_determine_rate,
49862306a36Sopenharmony_ci};
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistruct clk_hw *imx_clk_hw_sscg_pll(const char *name,
50162306a36Sopenharmony_ci				const char * const *parent_names,
50262306a36Sopenharmony_ci				u8 num_parents,
50362306a36Sopenharmony_ci				u8 parent, u8 bypass1, u8 bypass2,
50462306a36Sopenharmony_ci				void __iomem *base,
50562306a36Sopenharmony_ci				unsigned long flags)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct clk_sscg_pll *pll;
50862306a36Sopenharmony_ci	struct clk_init_data init;
50962306a36Sopenharmony_ci	struct clk_hw *hw;
51062306a36Sopenharmony_ci	int ret;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
51362306a36Sopenharmony_ci	if (!pll)
51462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	pll->parent = parent;
51762306a36Sopenharmony_ci	pll->bypass1 = bypass1;
51862306a36Sopenharmony_ci	pll->bypass2 = bypass2;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	pll->base = base;
52162306a36Sopenharmony_ci	init.name = name;
52262306a36Sopenharmony_ci	init.ops = &clk_sscg_pll_ops;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	init.flags = flags;
52562306a36Sopenharmony_ci	init.parent_names = parent_names;
52662306a36Sopenharmony_ci	init.num_parents = num_parents;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	pll->hw.init = &init;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	hw = &pll->hw;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	ret = clk_hw_register(NULL, hw);
53362306a36Sopenharmony_ci	if (ret) {
53462306a36Sopenharmony_ci		kfree(pll);
53562306a36Sopenharmony_ci		return ERR_PTR(ret);
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return hw;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_clk_hw_sscg_pll);
541