linux/drivers/clk/zynqmp/pll.c
<<
>>
Prefs
   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_warn_once("%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_warn_once("%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_warn_once("%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_warn_once("%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_warn_once("%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_warn_once("%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_warn_once("%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_warn_once("%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}
 349