xref: /openbmc/linux/drivers/clk/zynqmp/pll.c (revision 55fd7e02)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Zynq UltraScale+ MPSoC PLL driver
4  *
5  *  Copyright (C) 2016-2018 Xilinx
6  */
7 
8 #include <linux/clk.h>
9 #include <linux/clk-provider.h>
10 #include <linux/slab.h>
11 #include "clk-zynqmp.h"
12 
13 /**
14  * struct zynqmp_pll - PLL clock
15  * @hw:		Handle between common and hardware-specific interfaces
16  * @clk_id:	PLL clock ID
17  */
18 struct zynqmp_pll {
19 	struct clk_hw hw;
20 	u32 clk_id;
21 };
22 
23 #define to_zynqmp_pll(_hw)	container_of(_hw, struct zynqmp_pll, hw)
24 
25 #define PLL_FBDIV_MIN	25
26 #define PLL_FBDIV_MAX	125
27 
28 #define PS_PLL_VCO_MIN 1500000000
29 #define PS_PLL_VCO_MAX 3000000000UL
30 
31 enum pll_mode {
32 	PLL_MODE_INT,
33 	PLL_MODE_FRAC,
34 };
35 
36 #define FRAC_OFFSET 0x8
37 #define PLLFCFG_FRAC_EN	BIT(31)
38 #define FRAC_DIV  BIT(16)  /* 2^16 */
39 
40 /**
41  * zynqmp_pll_get_mode() - Get mode of PLL
42  * @hw:		Handle between common and hardware-specific interfaces
43  *
44  * Return: Mode of PLL
45  */
46 static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw)
47 {
48 	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
49 	u32 clk_id = clk->clk_id;
50 	const char *clk_name = clk_hw_get_name(hw);
51 	u32 ret_payload[PAYLOAD_ARG_CNT];
52 	int ret;
53 
54 	ret = zynqmp_pm_get_pll_frac_mode(clk_id, ret_payload);
55 	if (ret)
56 		pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n",
57 			     __func__, clk_name, ret);
58 
59 	return ret_payload[1];
60 }
61 
62 /**
63  * zynqmp_pll_set_mode() - Set the PLL mode
64  * @hw:		Handle between common and hardware-specific interfaces
65  * @on:		Flag to determine the mode
66  */
67 static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on)
68 {
69 	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
70 	u32 clk_id = clk->clk_id;
71 	const char *clk_name = clk_hw_get_name(hw);
72 	int ret;
73 	u32 mode;
74 
75 	if (on)
76 		mode = PLL_MODE_FRAC;
77 	else
78 		mode = PLL_MODE_INT;
79 
80 	ret = zynqmp_pm_set_pll_frac_mode(clk_id, mode);
81 	if (ret)
82 		pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n",
83 			     __func__, clk_name, ret);
84 }
85 
86 /**
87  * zynqmp_pll_round_rate() - Round a clock frequency
88  * @hw:		Handle between common and hardware-specific interfaces
89  * @rate:	Desired clock frequency
90  * @prate:	Clock frequency of parent clock
91  *
92  * Return: Frequency closest to @rate the hardware can generate
93  */
94 static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
95 				  unsigned long *prate)
96 {
97 	u32 fbdiv;
98 	long rate_div, f;
99 
100 	/* Enable the fractional mode if needed */
101 	rate_div = (rate * FRAC_DIV) / *prate;
102 	f = rate_div % FRAC_DIV;
103 	zynqmp_pll_set_mode(hw, !!f);
104 
105 	if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
106 		if (rate > PS_PLL_VCO_MAX) {
107 			fbdiv = rate / PS_PLL_VCO_MAX;
108 			rate = rate / (fbdiv + 1);
109 		}
110 		if (rate < PS_PLL_VCO_MIN) {
111 			fbdiv = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate);
112 			rate = rate * fbdiv;
113 		}
114 		return rate;
115 	}
116 
117 	fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
118 	fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
119 	return *prate * fbdiv;
120 }
121 
122 /**
123  * zynqmp_pll_recalc_rate() - Recalculate clock frequency
124  * @hw:			Handle between common and hardware-specific interfaces
125  * @parent_rate:	Clock frequency of parent clock
126  *
127  * Return: Current clock frequency
128  */
129 static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
130 					    unsigned long parent_rate)
131 {
132 	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
133 	u32 clk_id = clk->clk_id;
134 	const char *clk_name = clk_hw_get_name(hw);
135 	u32 fbdiv, data;
136 	unsigned long rate, frac;
137 	u32 ret_payload[PAYLOAD_ARG_CNT];
138 	int ret;
139 
140 	ret = zynqmp_pm_clock_getdivider(clk_id, &fbdiv);
141 	if (ret)
142 		pr_warn_once("%s() get divider failed for %s, ret = %d\n",
143 			     __func__, clk_name, ret);
144 
145 	rate =  parent_rate * fbdiv;
146 	if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
147 		zynqmp_pm_get_pll_frac_data(clk_id, ret_payload);
148 		data = ret_payload[1];
149 		frac = (parent_rate * data) / FRAC_DIV;
150 		rate = rate + frac;
151 	}
152 
153 	return rate;
154 }
155 
156 /**
157  * zynqmp_pll_set_rate() - Set rate of PLL
158  * @hw:			Handle between common and hardware-specific interfaces
159  * @rate:		Frequency of clock to be set
160  * @parent_rate:	Clock frequency of parent clock
161  *
162  * Set PLL divider to set desired rate.
163  *
164  * Returns:            rate which is set on success else error code
165  */
166 static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
167 			       unsigned long parent_rate)
168 {
169 	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
170 	u32 clk_id = clk->clk_id;
171 	const char *clk_name = clk_hw_get_name(hw);
172 	u32 fbdiv;
173 	long rate_div, frac, m, f;
174 	int ret;
175 
176 	if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
177 		rate_div = (rate * FRAC_DIV) / parent_rate;
178 		m = rate_div / FRAC_DIV;
179 		f = rate_div % FRAC_DIV;
180 		m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
181 		rate = parent_rate * m;
182 		frac = (parent_rate * f) / FRAC_DIV;
183 
184 		ret = zynqmp_pm_clock_setdivider(clk_id, m);
185 		if (ret == -EUSERS)
186 			WARN(1, "More than allowed devices are using the %s, which is forbidden\n",
187 			     clk_name);
188 		else if (ret)
189 			pr_warn_once("%s() set divider failed for %s, ret = %d\n",
190 				     __func__, clk_name, ret);
191 		zynqmp_pm_set_pll_frac_data(clk_id, f);
192 
193 		return rate + frac;
194 	}
195 
196 	fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate);
197 	fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
198 	ret = zynqmp_pm_clock_setdivider(clk_id, fbdiv);
199 	if (ret)
200 		pr_warn_once("%s() set divider failed for %s, ret = %d\n",
201 			     __func__, clk_name, ret);
202 
203 	return parent_rate * fbdiv;
204 }
205 
206 /**
207  * zynqmp_pll_is_enabled() - Check if a clock is enabled
208  * @hw:		Handle between common and hardware-specific interfaces
209  *
210  * Return: 1 if the clock is enabled, 0 otherwise
211  */
212 static int zynqmp_pll_is_enabled(struct clk_hw *hw)
213 {
214 	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
215 	const char *clk_name = clk_hw_get_name(hw);
216 	u32 clk_id = clk->clk_id;
217 	unsigned int state;
218 	int ret;
219 
220 	ret = zynqmp_pm_clock_getstate(clk_id, &state);
221 	if (ret) {
222 		pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
223 			     __func__, clk_name, ret);
224 		return -EIO;
225 	}
226 
227 	return state ? 1 : 0;
228 }
229 
230 /**
231  * zynqmp_pll_enable() - Enable clock
232  * @hw:		Handle between common and hardware-specific interfaces
233  *
234  * Return: 0 on success else error code
235  */
236 static int zynqmp_pll_enable(struct clk_hw *hw)
237 {
238 	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
239 	const char *clk_name = clk_hw_get_name(hw);
240 	u32 clk_id = clk->clk_id;
241 	int ret;
242 
243 	if (zynqmp_pll_is_enabled(hw))
244 		return 0;
245 
246 	ret = zynqmp_pm_clock_enable(clk_id);
247 	if (ret)
248 		pr_warn_once("%s() clock enable failed for %s, ret = %d\n",
249 			     __func__, clk_name, ret);
250 
251 	return ret;
252 }
253 
254 /**
255  * zynqmp_pll_disable() - Disable clock
256  * @hw:		Handle between common and hardware-specific interfaces
257  */
258 static void zynqmp_pll_disable(struct clk_hw *hw)
259 {
260 	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
261 	const char *clk_name = clk_hw_get_name(hw);
262 	u32 clk_id = clk->clk_id;
263 	int ret;
264 
265 	if (!zynqmp_pll_is_enabled(hw))
266 		return;
267 
268 	ret = zynqmp_pm_clock_disable(clk_id);
269 	if (ret)
270 		pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
271 			     __func__, clk_name, ret);
272 }
273 
274 static const struct clk_ops zynqmp_pll_ops = {
275 	.enable = zynqmp_pll_enable,
276 	.disable = zynqmp_pll_disable,
277 	.is_enabled = zynqmp_pll_is_enabled,
278 	.round_rate = zynqmp_pll_round_rate,
279 	.recalc_rate = zynqmp_pll_recalc_rate,
280 	.set_rate = zynqmp_pll_set_rate,
281 };
282 
283 /**
284  * zynqmp_clk_register_pll() - Register PLL with the clock framework
285  * @name:		PLL name
286  * @clk_id:		Clock ID
287  * @parents:		Name of this clock's parents
288  * @num_parents:	Number of parents
289  * @nodes:		Clock topology node
290  *
291  * Return: clock hardware to the registered clock
292  */
293 struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
294 				       const char * const *parents,
295 				       u8 num_parents,
296 				       const struct clock_topology *nodes)
297 {
298 	struct zynqmp_pll *pll;
299 	struct clk_hw *hw;
300 	struct clk_init_data init;
301 	int ret;
302 
303 	init.name = name;
304 	init.ops = &zynqmp_pll_ops;
305 	init.flags = nodes->flag;
306 	init.parent_names = parents;
307 	init.num_parents = 1;
308 
309 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
310 	if (!pll)
311 		return ERR_PTR(-ENOMEM);
312 
313 	pll->hw.init = &init;
314 	pll->clk_id = clk_id;
315 
316 	hw = &pll->hw;
317 	ret = clk_hw_register(NULL, hw);
318 	if (ret) {
319 		kfree(pll);
320 		return ERR_PTR(ret);
321 	}
322 
323 	clk_hw_set_rate_range(hw, PS_PLL_VCO_MIN, PS_PLL_VCO_MAX);
324 	if (ret < 0)
325 		pr_err("%s:ERROR clk_set_rate_range failed %d\n", name, ret);
326 
327 	return hw;
328 }
329