Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 */
19struct 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
33enum 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 */
49static 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 */
72static 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_determine_rate() - Round a clock frequency
95 * @hw: Handle between common and hardware-specific interfaces
96 * @req: Desired clock frequency
97 *
98 * Return: Frequency closest to @rate the hardware can generate
99 */
100static int zynqmp_pll_determine_rate(struct clk_hw *hw,
101 struct clk_rate_request *req)
102{
103 u32 fbdiv;
104 u32 mult, div;
105
106 /* Let rate fall inside the range PS_PLL_VCO_MIN ~ PS_PLL_VCO_MAX */
107 if (req->rate > PS_PLL_VCO_MAX) {
108 div = DIV_ROUND_UP(req->rate, PS_PLL_VCO_MAX);
109 req->rate = req->rate / div;
110 }
111 if (req->rate < PS_PLL_VCO_MIN) {
112 mult = DIV_ROUND_UP(PS_PLL_VCO_MIN, req->rate);
113 req->rate = req->rate * mult;
114 }
115
116 fbdiv = DIV_ROUND_CLOSEST(req->rate, req->best_parent_rate);
117 if (fbdiv < PLL_FBDIV_MIN || fbdiv > PLL_FBDIV_MAX) {
118 fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
119 req->rate = req->best_parent_rate * fbdiv;
120 }
121
122 return 0;
123}
124
125/**
126 * zynqmp_pll_recalc_rate() - Recalculate clock frequency
127 * @hw: Handle between common and hardware-specific interfaces
128 * @parent_rate: Clock frequency of parent clock
129 *
130 * Return: Current clock frequency or 0 in case of error
131 */
132static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
133 unsigned long parent_rate)
134{
135 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
136 u32 clk_id = clk->clk_id;
137 const char *clk_name = clk_hw_get_name(hw);
138 u32 fbdiv, data;
139 unsigned long rate, frac;
140 u32 ret_payload[PAYLOAD_ARG_CNT];
141 int ret;
142 enum pll_mode mode;
143
144 ret = zynqmp_pm_clock_getdivider(clk_id, &fbdiv);
145 if (ret) {
146 pr_debug("%s() get divider failed for %s, ret = %d\n",
147 __func__, clk_name, ret);
148 return 0ul;
149 }
150
151 mode = zynqmp_pll_get_mode(hw);
152 if (mode == PLL_MODE_ERROR)
153 return 0ul;
154
155 rate = parent_rate * fbdiv;
156 if (mode == PLL_MODE_FRAC) {
157 zynqmp_pm_get_pll_frac_data(clk_id, ret_payload);
158 data = ret_payload[1];
159 frac = (parent_rate * data) / FRAC_DIV;
160 rate = rate + frac;
161 }
162
163 return rate;
164}
165
166/**
167 * zynqmp_pll_set_rate() - Set rate of PLL
168 * @hw: Handle between common and hardware-specific interfaces
169 * @rate: Frequency of clock to be set
170 * @parent_rate: Clock frequency of parent clock
171 *
172 * Set PLL divider to set desired rate.
173 *
174 * Returns: rate which is set on success else error code
175 */
176static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
177 unsigned long parent_rate)
178{
179 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
180 u32 clk_id = clk->clk_id;
181 const char *clk_name = clk_hw_get_name(hw);
182 u32 fbdiv;
183 long rate_div, frac, m, f;
184 int ret;
185
186 rate_div = (rate * FRAC_DIV) / parent_rate;
187 f = rate_div % FRAC_DIV;
188 zynqmp_pll_set_mode(hw, !!f);
189
190 if (f) {
191 m = rate_div / FRAC_DIV;
192 m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
193 rate = parent_rate * m;
194 frac = (parent_rate * f) / FRAC_DIV;
195
196 ret = zynqmp_pm_clock_setdivider(clk_id, m);
197 if (ret == -EUSERS)
198 WARN(1, "More than allowed devices are using the %s, which is forbidden\n",
199 clk_name);
200 else if (ret)
201 pr_debug("%s() set divider failed for %s, ret = %d\n",
202 __func__, clk_name, ret);
203 zynqmp_pm_set_pll_frac_data(clk_id, f);
204
205 return rate + frac;
206 }
207
208 fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate);
209 fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
210 ret = zynqmp_pm_clock_setdivider(clk_id, fbdiv);
211 if (ret)
212 pr_debug("%s() set divider failed for %s, ret = %d\n",
213 __func__, clk_name, ret);
214
215 return parent_rate * fbdiv;
216}
217
218/**
219 * zynqmp_pll_is_enabled() - Check if a clock is enabled
220 * @hw: Handle between common and hardware-specific interfaces
221 *
222 * Return: 1 if the clock is enabled, 0 otherwise
223 */
224static int zynqmp_pll_is_enabled(struct clk_hw *hw)
225{
226 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
227 const char *clk_name = clk_hw_get_name(hw);
228 u32 clk_id = clk->clk_id;
229 unsigned int state;
230 int ret;
231
232 ret = zynqmp_pm_clock_getstate(clk_id, &state);
233 if (ret) {
234 pr_debug("%s() clock get state failed for %s, ret = %d\n",
235 __func__, clk_name, ret);
236 return -EIO;
237 }
238
239 return state ? 1 : 0;
240}
241
242/**
243 * zynqmp_pll_enable() - Enable clock
244 * @hw: Handle between common and hardware-specific interfaces
245 *
246 * Return: 0 on success else error code
247 */
248static int zynqmp_pll_enable(struct clk_hw *hw)
249{
250 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
251 const char *clk_name = clk_hw_get_name(hw);
252 u32 clk_id = clk->clk_id;
253 int ret;
254
255 /*
256 * Don't skip enabling clock if there is an IOCTL_SET_PLL_FRAC_MODE request
257 * that has been sent to ATF.
258 */
259 if (zynqmp_pll_is_enabled(hw) && (!clk->set_pll_mode))
260 return 0;
261
262 clk->set_pll_mode = false;
263
264 ret = zynqmp_pm_clock_enable(clk_id);
265 if (ret)
266 pr_debug("%s() clock enable failed for %s, ret = %d\n",
267 __func__, clk_name, ret);
268
269 return ret;
270}
271
272/**
273 * zynqmp_pll_disable() - Disable clock
274 * @hw: Handle between common and hardware-specific interfaces
275 */
276static void zynqmp_pll_disable(struct clk_hw *hw)
277{
278 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
279 const char *clk_name = clk_hw_get_name(hw);
280 u32 clk_id = clk->clk_id;
281 int ret;
282
283 if (!zynqmp_pll_is_enabled(hw))
284 return;
285
286 ret = zynqmp_pm_clock_disable(clk_id);
287 if (ret)
288 pr_debug("%s() clock disable failed for %s, ret = %d\n",
289 __func__, clk_name, ret);
290}
291
292static const struct clk_ops zynqmp_pll_ops = {
293 .enable = zynqmp_pll_enable,
294 .disable = zynqmp_pll_disable,
295 .is_enabled = zynqmp_pll_is_enabled,
296 .determine_rate = zynqmp_pll_determine_rate,
297 .recalc_rate = zynqmp_pll_recalc_rate,
298 .set_rate = zynqmp_pll_set_rate,
299};
300
301/**
302 * zynqmp_clk_register_pll() - Register PLL with the clock framework
303 * @name: PLL name
304 * @clk_id: Clock ID
305 * @parents: Name of this clock's parents
306 * @num_parents: Number of parents
307 * @nodes: Clock topology node
308 *
309 * Return: clock hardware to the registered clock
310 */
311struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
312 const char * const *parents,
313 u8 num_parents,
314 const struct clock_topology *nodes)
315{
316 struct zynqmp_pll *pll;
317 struct clk_hw *hw;
318 struct clk_init_data init;
319 int ret;
320
321 init.name = name;
322 init.ops = &zynqmp_pll_ops;
323
324 init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
325
326 init.parent_names = parents;
327 init.num_parents = 1;
328
329 pll = kzalloc_obj(*pll);
330 if (!pll)
331 return ERR_PTR(-ENOMEM);
332
333 pll->hw.init = &init;
334 pll->clk_id = clk_id;
335
336 hw = &pll->hw;
337 ret = clk_hw_register(NULL, hw);
338 if (ret) {
339 kfree(pll);
340 return ERR_PTR(ret);
341 }
342
343 return hw;
344}