1 // SPDX-License-Identifier: GPL-2.0
3 * Zynq UltraScale+ MPSoC PLL driver
5 * Copyright (C) 2016-2018 Xilinx
9 #include <linux/clk-provider.h>
10 #include <linux/slab.h>
11 #include "clk-zynqmp.h"
14 * struct zynqmp_pll - PLL clock
15 * @hw: Handle between common and hardware-specific interfaces
16 * @clk_id: PLL clock ID
23 #define to_zynqmp_pll(_hw) container_of(_hw, struct zynqmp_pll, hw)
25 #define PLL_FBDIV_MIN 25
26 #define PLL_FBDIV_MAX 125
28 #define PS_PLL_VCO_MIN 1500000000
29 #define PS_PLL_VCO_MAX 3000000000UL
36 #define FRAC_OFFSET 0x8
37 #define PLLFCFG_FRAC_EN BIT(31)
38 #define FRAC_DIV BIT(16) /* 2^16 */
41 * zynqmp_pll_get_mode() - Get mode of PLL
42 * @hw: Handle between common and hardware-specific interfaces
46 static inline enum pll_mode
zynqmp_pll_get_mode(struct clk_hw
*hw
)
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
];
53 const struct zynqmp_eemi_ops
*eemi_ops
= zynqmp_pm_get_eemi_ops();
55 ret
= eemi_ops
->ioctl(0, IOCTL_GET_PLL_FRAC_MODE
, clk_id
, 0,
58 pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n",
59 __func__
, clk_name
, ret
);
61 return ret_payload
[1];
65 * zynqmp_pll_set_mode() - Set the PLL mode
66 * @hw: Handle between common and hardware-specific interfaces
67 * @on: Flag to determine the mode
69 static inline void zynqmp_pll_set_mode(struct clk_hw
*hw
, bool on
)
71 struct zynqmp_pll
*clk
= to_zynqmp_pll(hw
);
72 u32 clk_id
= clk
->clk_id
;
73 const char *clk_name
= clk_hw_get_name(hw
);
76 const struct zynqmp_eemi_ops
*eemi_ops
= zynqmp_pm_get_eemi_ops();
83 ret
= eemi_ops
->ioctl(0, IOCTL_SET_PLL_FRAC_MODE
, clk_id
, mode
, NULL
);
85 pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n",
86 __func__
, clk_name
, ret
);
90 * zynqmp_pll_round_rate() - Round a clock frequency
91 * @hw: Handle between common and hardware-specific interfaces
92 * @rate: Desired clock frequency
93 * @prate: Clock frequency of parent clock
95 * Return: Frequency closest to @rate the hardware can generate
97 static long zynqmp_pll_round_rate(struct clk_hw
*hw
, unsigned long rate
,
103 /* Enable the fractional mode if needed */
104 rate_div
= (rate
* FRAC_DIV
) / *prate
;
105 f
= rate_div
% FRAC_DIV
;
106 zynqmp_pll_set_mode(hw
, !!f
);
108 if (zynqmp_pll_get_mode(hw
) == PLL_MODE_FRAC
) {
109 if (rate
> PS_PLL_VCO_MAX
) {
110 fbdiv
= rate
/ PS_PLL_VCO_MAX
;
111 rate
= rate
/ (fbdiv
+ 1);
113 if (rate
< PS_PLL_VCO_MIN
) {
114 fbdiv
= DIV_ROUND_UP(PS_PLL_VCO_MIN
, rate
);
120 fbdiv
= DIV_ROUND_CLOSEST(rate
, *prate
);
121 fbdiv
= clamp_t(u32
, fbdiv
, PLL_FBDIV_MIN
, PLL_FBDIV_MAX
);
122 return *prate
* fbdiv
;
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
130 * Return: Current clock frequency
132 static unsigned long zynqmp_pll_recalc_rate(struct clk_hw
*hw
,
133 unsigned long parent_rate
)
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
);
139 unsigned long rate
, frac
;
140 u32 ret_payload
[PAYLOAD_ARG_CNT
];
142 const struct zynqmp_eemi_ops
*eemi_ops
= zynqmp_pm_get_eemi_ops();
144 ret
= eemi_ops
->clock_getdivider(clk_id
, &fbdiv
);
146 pr_warn_once("%s() get divider failed for %s, ret = %d\n",
147 __func__
, clk_name
, ret
);
149 rate
= parent_rate
* fbdiv
;
150 if (zynqmp_pll_get_mode(hw
) == PLL_MODE_FRAC
) {
151 eemi_ops
->ioctl(0, IOCTL_GET_PLL_FRAC_DATA
, clk_id
, 0,
153 data
= ret_payload
[1];
154 frac
= (parent_rate
* data
) / FRAC_DIV
;
162 * zynqmp_pll_set_rate() - Set rate of PLL
163 * @hw: Handle between common and hardware-specific interfaces
164 * @rate: Frequency of clock to be set
165 * @parent_rate: Clock frequency of parent clock
167 * Set PLL divider to set desired rate.
169 * Returns: rate which is set on success else error code
171 static int zynqmp_pll_set_rate(struct clk_hw
*hw
, unsigned long rate
,
172 unsigned long parent_rate
)
174 struct zynqmp_pll
*clk
= to_zynqmp_pll(hw
);
175 u32 clk_id
= clk
->clk_id
;
176 const char *clk_name
= clk_hw_get_name(hw
);
178 long rate_div
, frac
, m
, f
;
180 const struct zynqmp_eemi_ops
*eemi_ops
= zynqmp_pm_get_eemi_ops();
182 if (zynqmp_pll_get_mode(hw
) == PLL_MODE_FRAC
) {
183 rate_div
= (rate
* FRAC_DIV
) / parent_rate
;
184 m
= rate_div
/ FRAC_DIV
;
185 f
= rate_div
% FRAC_DIV
;
186 m
= clamp_t(u32
, m
, (PLL_FBDIV_MIN
), (PLL_FBDIV_MAX
));
187 rate
= parent_rate
* m
;
188 frac
= (parent_rate
* f
) / FRAC_DIV
;
190 ret
= eemi_ops
->clock_setdivider(clk_id
, m
);
192 pr_warn_once("%s() set divider failed for %s, ret = %d\n",
193 __func__
, clk_name
, ret
);
195 eemi_ops
->ioctl(0, IOCTL_SET_PLL_FRAC_DATA
, clk_id
, f
, NULL
);
200 fbdiv
= DIV_ROUND_CLOSEST(rate
, parent_rate
);
201 fbdiv
= clamp_t(u32
, fbdiv
, PLL_FBDIV_MIN
, PLL_FBDIV_MAX
);
202 ret
= eemi_ops
->clock_setdivider(clk_id
, fbdiv
);
204 pr_warn_once("%s() set divider failed for %s, ret = %d\n",
205 __func__
, clk_name
, ret
);
207 return parent_rate
* fbdiv
;
211 * zynqmp_pll_is_enabled() - Check if a clock is enabled
212 * @hw: Handle between common and hardware-specific interfaces
214 * Return: 1 if the clock is enabled, 0 otherwise
216 static int zynqmp_pll_is_enabled(struct clk_hw
*hw
)
218 struct zynqmp_pll
*clk
= to_zynqmp_pll(hw
);
219 const char *clk_name
= clk_hw_get_name(hw
);
220 u32 clk_id
= clk
->clk_id
;
223 const struct zynqmp_eemi_ops
*eemi_ops
= zynqmp_pm_get_eemi_ops();
225 ret
= eemi_ops
->clock_getstate(clk_id
, &state
);
227 pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
228 __func__
, clk_name
, ret
);
232 return state
? 1 : 0;
236 * zynqmp_pll_enable() - Enable clock
237 * @hw: Handle between common and hardware-specific interfaces
239 * Return: 0 on success else error code
241 static int zynqmp_pll_enable(struct clk_hw
*hw
)
243 struct zynqmp_pll
*clk
= to_zynqmp_pll(hw
);
244 const char *clk_name
= clk_hw_get_name(hw
);
245 u32 clk_id
= clk
->clk_id
;
247 const struct zynqmp_eemi_ops
*eemi_ops
= zynqmp_pm_get_eemi_ops();
249 if (zynqmp_pll_is_enabled(hw
))
252 ret
= eemi_ops
->clock_enable(clk_id
);
254 pr_warn_once("%s() clock enable failed for %s, ret = %d\n",
255 __func__
, clk_name
, ret
);
261 * zynqmp_pll_disable() - Disable clock
262 * @hw: Handle between common and hardware-specific interfaces
264 static void zynqmp_pll_disable(struct clk_hw
*hw
)
266 struct zynqmp_pll
*clk
= to_zynqmp_pll(hw
);
267 const char *clk_name
= clk_hw_get_name(hw
);
268 u32 clk_id
= clk
->clk_id
;
270 const struct zynqmp_eemi_ops
*eemi_ops
= zynqmp_pm_get_eemi_ops();
272 if (!zynqmp_pll_is_enabled(hw
))
275 ret
= eemi_ops
->clock_disable(clk_id
);
277 pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
278 __func__
, clk_name
, ret
);
281 static const struct clk_ops zynqmp_pll_ops
= {
282 .enable
= zynqmp_pll_enable
,
283 .disable
= zynqmp_pll_disable
,
284 .is_enabled
= zynqmp_pll_is_enabled
,
285 .round_rate
= zynqmp_pll_round_rate
,
286 .recalc_rate
= zynqmp_pll_recalc_rate
,
287 .set_rate
= zynqmp_pll_set_rate
,
291 * zynqmp_clk_register_pll() - Register PLL with the clock framework
294 * @parents: Name of this clock's parents
295 * @num_parents: Number of parents
296 * @nodes: Clock topology node
298 * Return: clock hardware to the registered clock
300 struct clk_hw
*zynqmp_clk_register_pll(const char *name
, u32 clk_id
,
301 const char * const *parents
,
303 const struct clock_topology
*nodes
)
305 struct zynqmp_pll
*pll
;
307 struct clk_init_data init
;
311 init
.ops
= &zynqmp_pll_ops
;
312 init
.flags
= nodes
->flag
;
313 init
.parent_names
= parents
;
314 init
.num_parents
= 1;
316 pll
= kzalloc(sizeof(*pll
), GFP_KERNEL
);
318 return ERR_PTR(-ENOMEM
);
320 pll
->hw
.init
= &init
;
321 pll
->clk_id
= clk_id
;
324 ret
= clk_hw_register(NULL
, hw
);
330 clk_hw_set_rate_range(hw
, PS_PLL_VCO_MIN
, PS_PLL_VCO_MAX
);
332 pr_err("%s:ERROR clk_set_rate_range failed %d\n", name
, ret
);