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