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
];
54 ret
= zynqmp_pm_get_pll_frac_mode(clk_id
, ret_payload
);
56 pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n",
57 __func__
, clk_name
, ret
);
59 return ret_payload
[1];
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
67 static inline void zynqmp_pll_set_mode(struct clk_hw
*hw
, bool on
)
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
);
80 ret
= zynqmp_pm_set_pll_frac_mode(clk_id
, mode
);
82 pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n",
83 __func__
, clk_name
, ret
);
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
92 * Return: Frequency closest to @rate the hardware can generate
94 static long zynqmp_pll_round_rate(struct clk_hw
*hw
, unsigned long rate
,
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
);
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);
110 if (rate
< PS_PLL_VCO_MIN
) {
111 fbdiv
= DIV_ROUND_UP(PS_PLL_VCO_MIN
, rate
);
117 fbdiv
= DIV_ROUND_CLOSEST(rate
, *prate
);
118 fbdiv
= clamp_t(u32
, fbdiv
, PLL_FBDIV_MIN
, PLL_FBDIV_MAX
);
119 return *prate
* fbdiv
;
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
127 * Return: Current clock frequency
129 static unsigned long zynqmp_pll_recalc_rate(struct clk_hw
*hw
,
130 unsigned long parent_rate
)
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
);
136 unsigned long rate
, frac
;
137 u32 ret_payload
[PAYLOAD_ARG_CNT
];
140 ret
= zynqmp_pm_clock_getdivider(clk_id
, &fbdiv
);
142 pr_warn_once("%s() get divider failed for %s, ret = %d\n",
143 __func__
, clk_name
, ret
);
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
;
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
162 * Set PLL divider to set desired rate.
164 * Returns: rate which is set on success else error code
166 static int zynqmp_pll_set_rate(struct clk_hw
*hw
, unsigned long rate
,
167 unsigned long parent_rate
)
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
);
173 long rate_div
, frac
, m
, f
;
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
;
184 ret
= zynqmp_pm_clock_setdivider(clk_id
, m
);
186 WARN(1, "More than allowed devices are using the %s, which is forbidden\n",
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
);
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
);
200 pr_warn_once("%s() set divider failed for %s, ret = %d\n",
201 __func__
, clk_name
, ret
);
203 return parent_rate
* fbdiv
;
207 * zynqmp_pll_is_enabled() - Check if a clock is enabled
208 * @hw: Handle between common and hardware-specific interfaces
210 * Return: 1 if the clock is enabled, 0 otherwise
212 static int zynqmp_pll_is_enabled(struct clk_hw
*hw
)
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
;
220 ret
= zynqmp_pm_clock_getstate(clk_id
, &state
);
222 pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
223 __func__
, clk_name
, ret
);
227 return state
? 1 : 0;
231 * zynqmp_pll_enable() - Enable clock
232 * @hw: Handle between common and hardware-specific interfaces
234 * Return: 0 on success else error code
236 static int zynqmp_pll_enable(struct clk_hw
*hw
)
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
;
243 if (zynqmp_pll_is_enabled(hw
))
246 ret
= zynqmp_pm_clock_enable(clk_id
);
248 pr_warn_once("%s() clock enable failed for %s, ret = %d\n",
249 __func__
, clk_name
, ret
);
255 * zynqmp_pll_disable() - Disable clock
256 * @hw: Handle between common and hardware-specific interfaces
258 static void zynqmp_pll_disable(struct clk_hw
*hw
)
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
;
265 if (!zynqmp_pll_is_enabled(hw
))
268 ret
= zynqmp_pm_clock_disable(clk_id
);
270 pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
271 __func__
, clk_name
, ret
);
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
,
284 * zynqmp_clk_register_pll() - Register PLL with the clock framework
287 * @parents: Name of this clock's parents
288 * @num_parents: Number of parents
289 * @nodes: Clock topology node
291 * Return: clock hardware to the registered clock
293 struct clk_hw
*zynqmp_clk_register_pll(const char *name
, u32 clk_id
,
294 const char * const *parents
,
296 const struct clock_topology
*nodes
)
298 struct zynqmp_pll
*pll
;
300 struct clk_init_data init
;
304 init
.ops
= &zynqmp_pll_ops
;
305 init
.flags
= nodes
->flag
;
306 init
.parent_names
= parents
;
307 init
.num_parents
= 1;
309 pll
= kzalloc(sizeof(*pll
), GFP_KERNEL
);
311 return ERR_PTR(-ENOMEM
);
313 pll
->hw
.init
= &init
;
314 pll
->clk_id
= clk_id
;
317 ret
= clk_hw_register(NULL
, hw
);
323 clk_hw_set_rate_range(hw
, PS_PLL_VCO_MIN
, PS_PLL_VCO_MAX
);
325 pr_err("%s:ERROR clk_set_rate_range failed %d\n", name
, ret
);