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