xref: /OK3568_Linux_fs/kernel/drivers/clk/imx/clk-sscg-pll.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2018 NXP.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This driver supports the SCCG plls found in the imx8m SOCs
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Documentation for this SCCG pll can be found at:
8*4882a593Smuzhiyun  *   https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/clk-provider.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <linux/export.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include <linux/iopoll.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/bitfield.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include "clk.h"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* PLL CFGs */
22*4882a593Smuzhiyun #define PLL_CFG0		0x0
23*4882a593Smuzhiyun #define PLL_CFG1		0x4
24*4882a593Smuzhiyun #define PLL_CFG2		0x8
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define PLL_DIVF1_MASK		GENMASK(18, 13)
27*4882a593Smuzhiyun #define PLL_DIVF2_MASK		GENMASK(12, 7)
28*4882a593Smuzhiyun #define PLL_DIVR1_MASK		GENMASK(27, 25)
29*4882a593Smuzhiyun #define PLL_DIVR2_MASK		GENMASK(24, 19)
30*4882a593Smuzhiyun #define PLL_DIVQ_MASK           GENMASK(6, 1)
31*4882a593Smuzhiyun #define PLL_REF_MASK		GENMASK(2, 0)
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define PLL_LOCK_MASK		BIT(31)
34*4882a593Smuzhiyun #define PLL_PD_MASK		BIT(7)
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* These are the specification limits for the SSCG PLL */
37*4882a593Smuzhiyun #define PLL_REF_MIN_FREQ		25000000UL
38*4882a593Smuzhiyun #define PLL_REF_MAX_FREQ		235000000UL
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define PLL_STAGE1_MIN_FREQ		1600000000UL
41*4882a593Smuzhiyun #define PLL_STAGE1_MAX_FREQ		2400000000UL
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define PLL_STAGE1_REF_MIN_FREQ		25000000UL
44*4882a593Smuzhiyun #define PLL_STAGE1_REF_MAX_FREQ		54000000UL
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define PLL_STAGE2_MIN_FREQ		1200000000UL
47*4882a593Smuzhiyun #define PLL_STAGE2_MAX_FREQ		2400000000UL
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #define PLL_STAGE2_REF_MIN_FREQ		54000000UL
50*4882a593Smuzhiyun #define PLL_STAGE2_REF_MAX_FREQ		75000000UL
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define PLL_OUT_MIN_FREQ		20000000UL
53*4882a593Smuzhiyun #define PLL_OUT_MAX_FREQ		1200000000UL
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define PLL_DIVR1_MAX			7
56*4882a593Smuzhiyun #define PLL_DIVR2_MAX			63
57*4882a593Smuzhiyun #define PLL_DIVF1_MAX			63
58*4882a593Smuzhiyun #define PLL_DIVF2_MAX			63
59*4882a593Smuzhiyun #define PLL_DIVQ_MAX			63
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define PLL_BYPASS_NONE			0x0
62*4882a593Smuzhiyun #define PLL_BYPASS1			0x2
63*4882a593Smuzhiyun #define PLL_BYPASS2			0x1
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun #define SSCG_PLL_BYPASS1_MASK           BIT(5)
66*4882a593Smuzhiyun #define SSCG_PLL_BYPASS2_MASK           BIT(4)
67*4882a593Smuzhiyun #define SSCG_PLL_BYPASS_MASK		GENMASK(5, 4)
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #define PLL_SCCG_LOCK_TIMEOUT		70
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun struct clk_sscg_pll_setup {
72*4882a593Smuzhiyun 	int divr1, divf1;
73*4882a593Smuzhiyun 	int divr2, divf2;
74*4882a593Smuzhiyun 	int divq;
75*4882a593Smuzhiyun 	int bypass;
76*4882a593Smuzhiyun 	uint64_t vco1;
77*4882a593Smuzhiyun 	uint64_t vco2;
78*4882a593Smuzhiyun 	uint64_t fout;
79*4882a593Smuzhiyun 	uint64_t ref;
80*4882a593Smuzhiyun 	uint64_t ref_div1;
81*4882a593Smuzhiyun 	uint64_t ref_div2;
82*4882a593Smuzhiyun 	uint64_t fout_request;
83*4882a593Smuzhiyun 	int fout_error;
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun struct clk_sscg_pll {
87*4882a593Smuzhiyun 	struct clk_hw	hw;
88*4882a593Smuzhiyun 	const struct clk_ops  ops;
89*4882a593Smuzhiyun 	void __iomem *base;
90*4882a593Smuzhiyun 	struct clk_sscg_pll_setup setup;
91*4882a593Smuzhiyun 	u8 parent;
92*4882a593Smuzhiyun 	u8 bypass1;
93*4882a593Smuzhiyun 	u8 bypass2;
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define to_clk_sscg_pll(_hw) container_of(_hw, struct clk_sscg_pll, hw)
97*4882a593Smuzhiyun 
clk_sscg_pll_wait_lock(struct clk_sscg_pll * pll)98*4882a593Smuzhiyun static int clk_sscg_pll_wait_lock(struct clk_sscg_pll *pll)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	u32 val;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	val = readl_relaxed(pll->base + PLL_CFG0);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	/* don't wait for lock if all plls are bypassed */
105*4882a593Smuzhiyun 	if (!(val & SSCG_PLL_BYPASS2_MASK))
106*4882a593Smuzhiyun 		return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK,
107*4882a593Smuzhiyun 						0, PLL_SCCG_LOCK_TIMEOUT);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
clk_sscg_pll2_check_match(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup)112*4882a593Smuzhiyun static int clk_sscg_pll2_check_match(struct clk_sscg_pll_setup *setup,
113*4882a593Smuzhiyun 					struct clk_sscg_pll_setup *temp_setup)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	int new_diff = temp_setup->fout - temp_setup->fout_request;
116*4882a593Smuzhiyun 	int diff = temp_setup->fout_error;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (abs(diff) > abs(new_diff)) {
119*4882a593Smuzhiyun 		temp_setup->fout_error = new_diff;
120*4882a593Smuzhiyun 		memcpy(setup, temp_setup, sizeof(struct clk_sscg_pll_setup));
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		if (temp_setup->fout_request == temp_setup->fout)
123*4882a593Smuzhiyun 			return 0;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	return -1;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
clk_sscg_divq_lookup(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup)128*4882a593Smuzhiyun static int clk_sscg_divq_lookup(struct clk_sscg_pll_setup *setup,
129*4882a593Smuzhiyun 				struct clk_sscg_pll_setup *temp_setup)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	int ret = -EINVAL;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX;
134*4882a593Smuzhiyun 	     temp_setup->divq++) {
135*4882a593Smuzhiyun 		temp_setup->vco2 = temp_setup->vco1;
136*4882a593Smuzhiyun 		do_div(temp_setup->vco2, temp_setup->divr2 + 1);
137*4882a593Smuzhiyun 		temp_setup->vco2 *= 2;
138*4882a593Smuzhiyun 		temp_setup->vco2 *= temp_setup->divf2 + 1;
139*4882a593Smuzhiyun 		if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ &&
140*4882a593Smuzhiyun 				temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) {
141*4882a593Smuzhiyun 			temp_setup->fout = temp_setup->vco2;
142*4882a593Smuzhiyun 			do_div(temp_setup->fout, 2 * (temp_setup->divq + 1));
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 			ret = clk_sscg_pll2_check_match(setup, temp_setup);
145*4882a593Smuzhiyun 			if (!ret) {
146*4882a593Smuzhiyun 				temp_setup->bypass = PLL_BYPASS1;
147*4882a593Smuzhiyun 				return ret;
148*4882a593Smuzhiyun 			}
149*4882a593Smuzhiyun 		}
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	return ret;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
clk_sscg_divf2_lookup(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup)155*4882a593Smuzhiyun static int clk_sscg_divf2_lookup(struct clk_sscg_pll_setup *setup,
156*4882a593Smuzhiyun 					struct clk_sscg_pll_setup *temp_setup)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	int ret = -EINVAL;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX;
161*4882a593Smuzhiyun 	     temp_setup->divf2++) {
162*4882a593Smuzhiyun 		ret = clk_sscg_divq_lookup(setup, temp_setup);
163*4882a593Smuzhiyun 		if (!ret)
164*4882a593Smuzhiyun 			return ret;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	return ret;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
clk_sscg_divr2_lookup(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup)170*4882a593Smuzhiyun static int clk_sscg_divr2_lookup(struct clk_sscg_pll_setup *setup,
171*4882a593Smuzhiyun 				struct clk_sscg_pll_setup *temp_setup)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	int ret = -EINVAL;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX;
176*4882a593Smuzhiyun 	     temp_setup->divr2++) {
177*4882a593Smuzhiyun 		temp_setup->ref_div2 = temp_setup->vco1;
178*4882a593Smuzhiyun 		do_div(temp_setup->ref_div2, temp_setup->divr2 + 1);
179*4882a593Smuzhiyun 		if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ &&
180*4882a593Smuzhiyun 		    temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) {
181*4882a593Smuzhiyun 			ret = clk_sscg_divf2_lookup(setup, temp_setup);
182*4882a593Smuzhiyun 			if (!ret)
183*4882a593Smuzhiyun 				return ret;
184*4882a593Smuzhiyun 		}
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	return ret;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup,uint64_t ref)190*4882a593Smuzhiyun static int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup,
191*4882a593Smuzhiyun 					struct clk_sscg_pll_setup *temp_setup,
192*4882a593Smuzhiyun 					uint64_t ref)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	int ret;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)
197*4882a593Smuzhiyun 		return -EINVAL;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	temp_setup->vco1 = ref;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	ret = clk_sscg_divr2_lookup(setup, temp_setup);
202*4882a593Smuzhiyun 	return ret;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
clk_sscg_divf1_lookup(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup)205*4882a593Smuzhiyun static int clk_sscg_divf1_lookup(struct clk_sscg_pll_setup *setup,
206*4882a593Smuzhiyun 				struct clk_sscg_pll_setup *temp_setup)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	int ret = -EINVAL;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX;
211*4882a593Smuzhiyun 	     temp_setup->divf1++) {
212*4882a593Smuzhiyun 		uint64_t vco1 = temp_setup->ref;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 		do_div(vco1, temp_setup->divr1 + 1);
215*4882a593Smuzhiyun 		vco1 *= 2;
216*4882a593Smuzhiyun 		vco1 *= temp_setup->divf1 + 1;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 		ret = clk_sscg_pll2_find_setup(setup, temp_setup, vco1);
219*4882a593Smuzhiyun 		if (!ret) {
220*4882a593Smuzhiyun 			temp_setup->bypass = PLL_BYPASS_NONE;
221*4882a593Smuzhiyun 			return ret;
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	return ret;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
clk_sscg_divr1_lookup(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup)228*4882a593Smuzhiyun static int clk_sscg_divr1_lookup(struct clk_sscg_pll_setup *setup,
229*4882a593Smuzhiyun 				struct clk_sscg_pll_setup *temp_setup)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	int ret = -EINVAL;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX;
234*4882a593Smuzhiyun 	     temp_setup->divr1++) {
235*4882a593Smuzhiyun 		temp_setup->ref_div1 = temp_setup->ref;
236*4882a593Smuzhiyun 		do_div(temp_setup->ref_div1, temp_setup->divr1 + 1);
237*4882a593Smuzhiyun 		if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ &&
238*4882a593Smuzhiyun 		    temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) {
239*4882a593Smuzhiyun 			ret = clk_sscg_divf1_lookup(setup, temp_setup);
240*4882a593Smuzhiyun 			if (!ret)
241*4882a593Smuzhiyun 				return ret;
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	return ret;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup * setup,struct clk_sscg_pll_setup * temp_setup,uint64_t ref)248*4882a593Smuzhiyun static int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup,
249*4882a593Smuzhiyun 					struct clk_sscg_pll_setup *temp_setup,
250*4882a593Smuzhiyun 					uint64_t ref)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	int ret;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)
255*4882a593Smuzhiyun 		return -EINVAL;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	temp_setup->ref = ref;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	ret = clk_sscg_divr1_lookup(setup, temp_setup);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	return ret;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
clk_sscg_pll_find_setup(struct clk_sscg_pll_setup * setup,uint64_t prate,uint64_t rate,int try_bypass)264*4882a593Smuzhiyun static int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup,
265*4882a593Smuzhiyun 					uint64_t prate,
266*4882a593Smuzhiyun 					uint64_t rate, int try_bypass)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	struct clk_sscg_pll_setup temp_setup;
269*4882a593Smuzhiyun 	int ret = -EINVAL;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	memset(&temp_setup, 0, sizeof(struct clk_sscg_pll_setup));
272*4882a593Smuzhiyun 	memset(setup, 0, sizeof(struct clk_sscg_pll_setup));
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	temp_setup.fout_error = PLL_OUT_MAX_FREQ;
275*4882a593Smuzhiyun 	temp_setup.fout_request = rate;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	switch (try_bypass) {
278*4882a593Smuzhiyun 	case PLL_BYPASS2:
279*4882a593Smuzhiyun 		if (prate == rate) {
280*4882a593Smuzhiyun 			setup->bypass = PLL_BYPASS2;
281*4882a593Smuzhiyun 			setup->fout = rate;
282*4882a593Smuzhiyun 			ret = 0;
283*4882a593Smuzhiyun 		}
284*4882a593Smuzhiyun 		break;
285*4882a593Smuzhiyun 	case PLL_BYPASS1:
286*4882a593Smuzhiyun 		ret = clk_sscg_pll2_find_setup(setup, &temp_setup, prate);
287*4882a593Smuzhiyun 		break;
288*4882a593Smuzhiyun 	case PLL_BYPASS_NONE:
289*4882a593Smuzhiyun 		ret = clk_sscg_pll1_find_setup(setup, &temp_setup, prate);
290*4882a593Smuzhiyun 		break;
291*4882a593Smuzhiyun 	}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	return ret;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
clk_sscg_pll_is_prepared(struct clk_hw * hw)296*4882a593Smuzhiyun static int clk_sscg_pll_is_prepared(struct clk_hw *hw)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	u32 val = readl_relaxed(pll->base + PLL_CFG0);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	return (val & PLL_PD_MASK) ? 0 : 1;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun 
clk_sscg_pll_prepare(struct clk_hw * hw)305*4882a593Smuzhiyun static int clk_sscg_pll_prepare(struct clk_hw *hw)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
308*4882a593Smuzhiyun 	u32 val;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	val = readl_relaxed(pll->base + PLL_CFG0);
311*4882a593Smuzhiyun 	val &= ~PLL_PD_MASK;
312*4882a593Smuzhiyun 	writel_relaxed(val, pll->base + PLL_CFG0);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	return clk_sscg_pll_wait_lock(pll);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
clk_sscg_pll_unprepare(struct clk_hw * hw)317*4882a593Smuzhiyun static void clk_sscg_pll_unprepare(struct clk_hw *hw)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
320*4882a593Smuzhiyun 	u32 val;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	val = readl_relaxed(pll->base + PLL_CFG0);
323*4882a593Smuzhiyun 	val |= PLL_PD_MASK;
324*4882a593Smuzhiyun 	writel_relaxed(val, pll->base + PLL_CFG0);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
clk_sscg_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)327*4882a593Smuzhiyun static unsigned long clk_sscg_pll_recalc_rate(struct clk_hw *hw,
328*4882a593Smuzhiyun 					 unsigned long parent_rate)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
331*4882a593Smuzhiyun 	u32 val, divr1, divf1, divr2, divf2, divq;
332*4882a593Smuzhiyun 	u64 temp64;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	val = readl_relaxed(pll->base + PLL_CFG2);
335*4882a593Smuzhiyun 	divr1 = FIELD_GET(PLL_DIVR1_MASK, val);
336*4882a593Smuzhiyun 	divr2 = FIELD_GET(PLL_DIVR2_MASK, val);
337*4882a593Smuzhiyun 	divf1 = FIELD_GET(PLL_DIVF1_MASK, val);
338*4882a593Smuzhiyun 	divf2 = FIELD_GET(PLL_DIVF2_MASK, val);
339*4882a593Smuzhiyun 	divq = FIELD_GET(PLL_DIVQ_MASK, val);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	temp64 = parent_rate;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	val = readl(pll->base + PLL_CFG0);
344*4882a593Smuzhiyun 	if (val & SSCG_PLL_BYPASS2_MASK) {
345*4882a593Smuzhiyun 		temp64 = parent_rate;
346*4882a593Smuzhiyun 	} else if (val & SSCG_PLL_BYPASS1_MASK) {
347*4882a593Smuzhiyun 		temp64 *= divf2;
348*4882a593Smuzhiyun 		do_div(temp64, (divr2 + 1) * (divq + 1));
349*4882a593Smuzhiyun 	} else {
350*4882a593Smuzhiyun 		temp64 *= 2;
351*4882a593Smuzhiyun 		temp64 *= (divf1 + 1) * (divf2 + 1);
352*4882a593Smuzhiyun 		do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1));
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	return temp64;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
clk_sscg_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)358*4882a593Smuzhiyun static int clk_sscg_pll_set_rate(struct clk_hw *hw, unsigned long rate,
359*4882a593Smuzhiyun 			    unsigned long parent_rate)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
362*4882a593Smuzhiyun 	struct clk_sscg_pll_setup *setup = &pll->setup;
363*4882a593Smuzhiyun 	u32 val;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	/* set bypass here too since the parent might be the same */
366*4882a593Smuzhiyun 	val = readl(pll->base + PLL_CFG0);
367*4882a593Smuzhiyun 	val &= ~SSCG_PLL_BYPASS_MASK;
368*4882a593Smuzhiyun 	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass);
369*4882a593Smuzhiyun 	writel(val, pll->base + PLL_CFG0);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	val = readl_relaxed(pll->base + PLL_CFG2);
372*4882a593Smuzhiyun 	val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK);
373*4882a593Smuzhiyun 	val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK);
374*4882a593Smuzhiyun 	val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1);
375*4882a593Smuzhiyun 	val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2);
376*4882a593Smuzhiyun 	val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1);
377*4882a593Smuzhiyun 	val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2);
378*4882a593Smuzhiyun 	val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq);
379*4882a593Smuzhiyun 	writel_relaxed(val, pll->base + PLL_CFG2);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	return clk_sscg_pll_wait_lock(pll);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
clk_sscg_pll_get_parent(struct clk_hw * hw)384*4882a593Smuzhiyun static u8 clk_sscg_pll_get_parent(struct clk_hw *hw)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
387*4882a593Smuzhiyun 	u32 val;
388*4882a593Smuzhiyun 	u8 ret = pll->parent;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	val = readl(pll->base + PLL_CFG0);
391*4882a593Smuzhiyun 	if (val & SSCG_PLL_BYPASS2_MASK)
392*4882a593Smuzhiyun 		ret = pll->bypass2;
393*4882a593Smuzhiyun 	else if (val & SSCG_PLL_BYPASS1_MASK)
394*4882a593Smuzhiyun 		ret = pll->bypass1;
395*4882a593Smuzhiyun 	return ret;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
clk_sscg_pll_set_parent(struct clk_hw * hw,u8 index)398*4882a593Smuzhiyun static int clk_sscg_pll_set_parent(struct clk_hw *hw, u8 index)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
401*4882a593Smuzhiyun 	u32 val;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	val = readl(pll->base + PLL_CFG0);
404*4882a593Smuzhiyun 	val &= ~SSCG_PLL_BYPASS_MASK;
405*4882a593Smuzhiyun 	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass);
406*4882a593Smuzhiyun 	writel(val, pll->base + PLL_CFG0);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	return clk_sscg_pll_wait_lock(pll);
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun 
__clk_sscg_pll_determine_rate(struct clk_hw * hw,struct clk_rate_request * req,uint64_t min,uint64_t max,uint64_t rate,int bypass)411*4882a593Smuzhiyun static int __clk_sscg_pll_determine_rate(struct clk_hw *hw,
412*4882a593Smuzhiyun 					struct clk_rate_request *req,
413*4882a593Smuzhiyun 					uint64_t min,
414*4882a593Smuzhiyun 					uint64_t max,
415*4882a593Smuzhiyun 					uint64_t rate,
416*4882a593Smuzhiyun 					int bypass)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
419*4882a593Smuzhiyun 	struct clk_sscg_pll_setup *setup = &pll->setup;
420*4882a593Smuzhiyun 	struct clk_hw *parent_hw = NULL;
421*4882a593Smuzhiyun 	int bypass_parent_index;
422*4882a593Smuzhiyun 	int ret;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	req->max_rate = max;
425*4882a593Smuzhiyun 	req->min_rate = min;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	switch (bypass) {
428*4882a593Smuzhiyun 	case PLL_BYPASS2:
429*4882a593Smuzhiyun 		bypass_parent_index = pll->bypass2;
430*4882a593Smuzhiyun 		break;
431*4882a593Smuzhiyun 	case PLL_BYPASS1:
432*4882a593Smuzhiyun 		bypass_parent_index = pll->bypass1;
433*4882a593Smuzhiyun 		break;
434*4882a593Smuzhiyun 	default:
435*4882a593Smuzhiyun 		bypass_parent_index = pll->parent;
436*4882a593Smuzhiyun 		break;
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index);
440*4882a593Smuzhiyun 	ret = __clk_determine_rate(parent_hw, req);
441*4882a593Smuzhiyun 	if (!ret) {
442*4882a593Smuzhiyun 		ret = clk_sscg_pll_find_setup(setup, req->rate,
443*4882a593Smuzhiyun 						rate, bypass);
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	req->best_parent_hw = parent_hw;
447*4882a593Smuzhiyun 	req->best_parent_rate = req->rate;
448*4882a593Smuzhiyun 	req->rate = setup->fout;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	return ret;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
clk_sscg_pll_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)453*4882a593Smuzhiyun static int clk_sscg_pll_determine_rate(struct clk_hw *hw,
454*4882a593Smuzhiyun 				       struct clk_rate_request *req)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);
457*4882a593Smuzhiyun 	struct clk_sscg_pll_setup *setup = &pll->setup;
458*4882a593Smuzhiyun 	uint64_t rate = req->rate;
459*4882a593Smuzhiyun 	uint64_t min = req->min_rate;
460*4882a593Smuzhiyun 	uint64_t max = req->max_rate;
461*4882a593Smuzhiyun 	int ret;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ)
464*4882a593Smuzhiyun 		return -EINVAL;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	ret = __clk_sscg_pll_determine_rate(hw, req, req->rate, req->rate,
467*4882a593Smuzhiyun 						rate, PLL_BYPASS2);
468*4882a593Smuzhiyun 	if (!ret)
469*4882a593Smuzhiyun 		return ret;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ,
472*4882a593Smuzhiyun 						PLL_STAGE1_REF_MAX_FREQ, rate,
473*4882a593Smuzhiyun 						PLL_BYPASS1);
474*4882a593Smuzhiyun 	if (!ret)
475*4882a593Smuzhiyun 		return ret;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ,
478*4882a593Smuzhiyun 						PLL_REF_MAX_FREQ, rate,
479*4882a593Smuzhiyun 						PLL_BYPASS_NONE);
480*4882a593Smuzhiyun 	if (!ret)
481*4882a593Smuzhiyun 		return ret;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	if (setup->fout >= min && setup->fout <= max)
484*4882a593Smuzhiyun 		ret = 0;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	return ret;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun static const struct clk_ops clk_sscg_pll_ops = {
490*4882a593Smuzhiyun 	.prepare	= clk_sscg_pll_prepare,
491*4882a593Smuzhiyun 	.unprepare	= clk_sscg_pll_unprepare,
492*4882a593Smuzhiyun 	.is_prepared	= clk_sscg_pll_is_prepared,
493*4882a593Smuzhiyun 	.recalc_rate	= clk_sscg_pll_recalc_rate,
494*4882a593Smuzhiyun 	.set_rate	= clk_sscg_pll_set_rate,
495*4882a593Smuzhiyun 	.set_parent	= clk_sscg_pll_set_parent,
496*4882a593Smuzhiyun 	.get_parent	= clk_sscg_pll_get_parent,
497*4882a593Smuzhiyun 	.determine_rate	= clk_sscg_pll_determine_rate,
498*4882a593Smuzhiyun };
499*4882a593Smuzhiyun 
imx_clk_hw_sscg_pll(const char * name,const char * const * parent_names,u8 num_parents,u8 parent,u8 bypass1,u8 bypass2,void __iomem * base,unsigned long flags)500*4882a593Smuzhiyun struct clk_hw *imx_clk_hw_sscg_pll(const char *name,
501*4882a593Smuzhiyun 				const char * const *parent_names,
502*4882a593Smuzhiyun 				u8 num_parents,
503*4882a593Smuzhiyun 				u8 parent, u8 bypass1, u8 bypass2,
504*4882a593Smuzhiyun 				void __iomem *base,
505*4882a593Smuzhiyun 				unsigned long flags)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	struct clk_sscg_pll *pll;
508*4882a593Smuzhiyun 	struct clk_init_data init;
509*4882a593Smuzhiyun 	struct clk_hw *hw;
510*4882a593Smuzhiyun 	int ret;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
513*4882a593Smuzhiyun 	if (!pll)
514*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	pll->parent = parent;
517*4882a593Smuzhiyun 	pll->bypass1 = bypass1;
518*4882a593Smuzhiyun 	pll->bypass2 = bypass2;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	pll->base = base;
521*4882a593Smuzhiyun 	init.name = name;
522*4882a593Smuzhiyun 	init.ops = &clk_sscg_pll_ops;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	init.flags = flags;
525*4882a593Smuzhiyun 	init.parent_names = parent_names;
526*4882a593Smuzhiyun 	init.num_parents = num_parents;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	pll->base = base;
529*4882a593Smuzhiyun 	pll->hw.init = &init;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	hw = &pll->hw;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	ret = clk_hw_register(NULL, hw);
534*4882a593Smuzhiyun 	if (ret) {
535*4882a593Smuzhiyun 		kfree(pll);
536*4882a593Smuzhiyun 		return ERR_PTR(ret);
537*4882a593Smuzhiyun 	}
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	return hw;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(imx_clk_hw_sscg_pll);
542