linux/drivers/clk/pistachio/clk-pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2014 Google, Inc.
   4 */
   5
   6#define pr_fmt(fmt) "%s: " fmt, __func__
   7
   8#include <linux/clk-provider.h>
   9#include <linux/io.h>
  10#include <linux/kernel.h>
  11#include <linux/printk.h>
  12#include <linux/slab.h>
  13
  14#include "clk.h"
  15
  16#define PLL_STATUS                      0x0
  17#define PLL_STATUS_LOCK                 BIT(0)
  18
  19#define PLL_CTRL1                       0x4
  20#define PLL_CTRL1_REFDIV_SHIFT          0
  21#define PLL_CTRL1_REFDIV_MASK           0x3f
  22#define PLL_CTRL1_FBDIV_SHIFT           6
  23#define PLL_CTRL1_FBDIV_MASK            0xfff
  24#define PLL_INT_CTRL1_POSTDIV1_SHIFT    18
  25#define PLL_INT_CTRL1_POSTDIV1_MASK     0x7
  26#define PLL_INT_CTRL1_POSTDIV2_SHIFT    21
  27#define PLL_INT_CTRL1_POSTDIV2_MASK     0x7
  28#define PLL_INT_CTRL1_PD                BIT(24)
  29#define PLL_INT_CTRL1_DSMPD             BIT(25)
  30#define PLL_INT_CTRL1_FOUTPOSTDIVPD     BIT(26)
  31#define PLL_INT_CTRL1_FOUTVCOPD         BIT(27)
  32
  33#define PLL_CTRL2                       0x8
  34#define PLL_FRAC_CTRL2_FRAC_SHIFT       0
  35#define PLL_FRAC_CTRL2_FRAC_MASK        0xffffff
  36#define PLL_FRAC_CTRL2_POSTDIV1_SHIFT   24
  37#define PLL_FRAC_CTRL2_POSTDIV1_MASK    0x7
  38#define PLL_FRAC_CTRL2_POSTDIV2_SHIFT   27
  39#define PLL_FRAC_CTRL2_POSTDIV2_MASK    0x7
  40#define PLL_INT_CTRL2_BYPASS            BIT(28)
  41
  42#define PLL_CTRL3                       0xc
  43#define PLL_FRAC_CTRL3_PD               BIT(0)
  44#define PLL_FRAC_CTRL3_DACPD            BIT(1)
  45#define PLL_FRAC_CTRL3_DSMPD            BIT(2)
  46#define PLL_FRAC_CTRL3_FOUTPOSTDIVPD    BIT(3)
  47#define PLL_FRAC_CTRL3_FOUT4PHASEPD     BIT(4)
  48#define PLL_FRAC_CTRL3_FOUTVCOPD        BIT(5)
  49
  50#define PLL_CTRL4                       0x10
  51#define PLL_FRAC_CTRL4_BYPASS           BIT(28)
  52
  53#define MIN_PFD                         9600000UL
  54#define MIN_VCO_LA                      400000000UL
  55#define MAX_VCO_LA                      1600000000UL
  56#define MIN_VCO_FRAC_INT                600000000UL
  57#define MAX_VCO_FRAC_INT                1600000000UL
  58#define MIN_VCO_FRAC_FRAC               600000000UL
  59#define MAX_VCO_FRAC_FRAC               2400000000UL
  60#define MIN_OUTPUT_LA                   8000000UL
  61#define MAX_OUTPUT_LA                   1600000000UL
  62#define MIN_OUTPUT_FRAC                 12000000UL
  63#define MAX_OUTPUT_FRAC                 1600000000UL
  64
  65/* Fractional PLL operating modes */
  66enum pll_mode {
  67        PLL_MODE_FRAC,
  68        PLL_MODE_INT,
  69};
  70
  71struct pistachio_clk_pll {
  72        struct clk_hw hw;
  73        void __iomem *base;
  74        struct pistachio_pll_rate_table *rates;
  75        unsigned int nr_rates;
  76};
  77
  78static inline u32 pll_readl(struct pistachio_clk_pll *pll, u32 reg)
  79{
  80        return readl(pll->base + reg);
  81}
  82
  83static inline void pll_writel(struct pistachio_clk_pll *pll, u32 val, u32 reg)
  84{
  85        writel(val, pll->base + reg);
  86}
  87
  88static inline void pll_lock(struct pistachio_clk_pll *pll)
  89{
  90        while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK))
  91                cpu_relax();
  92}
  93
  94static inline u64 do_div_round_closest(u64 dividend, u64 divisor)
  95{
  96        dividend += divisor / 2;
  97        return div64_u64(dividend, divisor);
  98}
  99
 100static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
 101{
 102        return container_of(hw, struct pistachio_clk_pll, hw);
 103}
 104
 105static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
 106{
 107        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 108        u32 val;
 109
 110        val = pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_DSMPD;
 111        return val ? PLL_MODE_INT : PLL_MODE_FRAC;
 112}
 113
 114static inline void pll_frac_set_mode(struct clk_hw *hw, enum pll_mode mode)
 115{
 116        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 117        u32 val;
 118
 119        val = pll_readl(pll, PLL_CTRL3);
 120        if (mode == PLL_MODE_INT)
 121                val |= PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD;
 122        else
 123                val &= ~(PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_DACPD);
 124
 125        pll_writel(pll, val, PLL_CTRL3);
 126}
 127
 128static struct pistachio_pll_rate_table *
 129pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref,
 130               unsigned long fout)
 131{
 132        unsigned int i;
 133
 134        for (i = 0; i < pll->nr_rates; i++) {
 135                if (pll->rates[i].fref == fref && pll->rates[i].fout == fout)
 136                        return &pll->rates[i];
 137        }
 138
 139        return NULL;
 140}
 141
 142static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
 143                           unsigned long *parent_rate)
 144{
 145        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 146        unsigned int i;
 147
 148        for (i = 0; i < pll->nr_rates; i++) {
 149                if (i > 0 && pll->rates[i].fref == *parent_rate &&
 150                    pll->rates[i].fout <= rate)
 151                        return pll->rates[i - 1].fout;
 152        }
 153
 154        return pll->rates[0].fout;
 155}
 156
 157static int pll_gf40lp_frac_enable(struct clk_hw *hw)
 158{
 159        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 160        u32 val;
 161
 162        val = pll_readl(pll, PLL_CTRL3);
 163        val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD |
 164                 PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD);
 165        pll_writel(pll, val, PLL_CTRL3);
 166
 167        val = pll_readl(pll, PLL_CTRL4);
 168        val &= ~PLL_FRAC_CTRL4_BYPASS;
 169        pll_writel(pll, val, PLL_CTRL4);
 170
 171        pll_lock(pll);
 172
 173        return 0;
 174}
 175
 176static void pll_gf40lp_frac_disable(struct clk_hw *hw)
 177{
 178        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 179        u32 val;
 180
 181        val = pll_readl(pll, PLL_CTRL3);
 182        val |= PLL_FRAC_CTRL3_PD;
 183        pll_writel(pll, val, PLL_CTRL3);
 184}
 185
 186static int pll_gf40lp_frac_is_enabled(struct clk_hw *hw)
 187{
 188        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 189
 190        return !(pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_PD);
 191}
 192
 193static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
 194                                    unsigned long parent_rate)
 195{
 196        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 197        struct pistachio_pll_rate_table *params;
 198        int enabled = pll_gf40lp_frac_is_enabled(hw);
 199        u64 val, vco, old_postdiv1, old_postdiv2;
 200        const char *name = clk_hw_get_name(hw);
 201
 202        if (rate < MIN_OUTPUT_FRAC || rate > MAX_OUTPUT_FRAC)
 203                return -EINVAL;
 204
 205        params = pll_get_params(pll, parent_rate, rate);
 206        if (!params || !params->refdiv)
 207                return -EINVAL;
 208
 209        /* calculate vco */
 210        vco = params->fref;
 211        vco *= (params->fbdiv << 24) + params->frac;
 212        vco = div64_u64(vco, params->refdiv << 24);
 213
 214        if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC)
 215                pr_warn("%s: VCO %llu is out of range %lu..%lu\n", name, vco,
 216                        MIN_VCO_FRAC_FRAC, MAX_VCO_FRAC_FRAC);
 217
 218        val = div64_u64(params->fref, params->refdiv);
 219        if (val < MIN_PFD)
 220                pr_warn("%s: PFD %llu is too low (min %lu)\n",
 221                        name, val, MIN_PFD);
 222        if (val > vco / 16)
 223                pr_warn("%s: PFD %llu is too high (max %llu)\n",
 224                        name, val, vco / 16);
 225
 226        val = pll_readl(pll, PLL_CTRL1);
 227        val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
 228                 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT));
 229        val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) |
 230                (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT);
 231        pll_writel(pll, val, PLL_CTRL1);
 232
 233        val = pll_readl(pll, PLL_CTRL2);
 234
 235        old_postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) &
 236                       PLL_FRAC_CTRL2_POSTDIV1_MASK;
 237        old_postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) &
 238                       PLL_FRAC_CTRL2_POSTDIV2_MASK;
 239        if (enabled &&
 240            (params->postdiv1 != old_postdiv1 ||
 241             params->postdiv2 != old_postdiv2))
 242                pr_warn("%s: changing postdiv while PLL is enabled\n", name);
 243
 244        if (params->postdiv2 > params->postdiv1)
 245                pr_warn("%s: postdiv2 should not exceed postdiv1\n", name);
 246
 247        val &= ~((PLL_FRAC_CTRL2_FRAC_MASK << PLL_FRAC_CTRL2_FRAC_SHIFT) |
 248                 (PLL_FRAC_CTRL2_POSTDIV1_MASK <<
 249                  PLL_FRAC_CTRL2_POSTDIV1_SHIFT) |
 250                 (PLL_FRAC_CTRL2_POSTDIV2_MASK <<
 251                  PLL_FRAC_CTRL2_POSTDIV2_SHIFT));
 252        val |= (params->frac << PLL_FRAC_CTRL2_FRAC_SHIFT) |
 253                (params->postdiv1 << PLL_FRAC_CTRL2_POSTDIV1_SHIFT) |
 254                (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT);
 255        pll_writel(pll, val, PLL_CTRL2);
 256
 257        /* set operating mode */
 258        if (params->frac)
 259                pll_frac_set_mode(hw, PLL_MODE_FRAC);
 260        else
 261                pll_frac_set_mode(hw, PLL_MODE_INT);
 262
 263        if (enabled)
 264                pll_lock(pll);
 265
 266        return 0;
 267}
 268
 269static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
 270                                                 unsigned long parent_rate)
 271{
 272        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 273        u64 val, prediv, fbdiv, frac, postdiv1, postdiv2, rate;
 274
 275        val = pll_readl(pll, PLL_CTRL1);
 276        prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
 277        fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK;
 278
 279        val = pll_readl(pll, PLL_CTRL2);
 280        postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) &
 281                PLL_FRAC_CTRL2_POSTDIV1_MASK;
 282        postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) &
 283                PLL_FRAC_CTRL2_POSTDIV2_MASK;
 284        frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK;
 285
 286        /* get operating mode (int/frac) and calculate rate accordingly */
 287        rate = parent_rate;
 288        if (pll_frac_get_mode(hw) == PLL_MODE_FRAC)
 289                rate *= (fbdiv << 24) + frac;
 290        else
 291                rate *= (fbdiv << 24);
 292
 293        rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24);
 294
 295        return rate;
 296}
 297
 298static const struct clk_ops pll_gf40lp_frac_ops = {
 299        .enable = pll_gf40lp_frac_enable,
 300        .disable = pll_gf40lp_frac_disable,
 301        .is_enabled = pll_gf40lp_frac_is_enabled,
 302        .recalc_rate = pll_gf40lp_frac_recalc_rate,
 303        .round_rate = pll_round_rate,
 304        .set_rate = pll_gf40lp_frac_set_rate,
 305};
 306
 307static const struct clk_ops pll_gf40lp_frac_fixed_ops = {
 308        .enable = pll_gf40lp_frac_enable,
 309        .disable = pll_gf40lp_frac_disable,
 310        .is_enabled = pll_gf40lp_frac_is_enabled,
 311        .recalc_rate = pll_gf40lp_frac_recalc_rate,
 312};
 313
 314static int pll_gf40lp_laint_enable(struct clk_hw *hw)
 315{
 316        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 317        u32 val;
 318
 319        val = pll_readl(pll, PLL_CTRL1);
 320        val &= ~(PLL_INT_CTRL1_PD |
 321                 PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD);
 322        pll_writel(pll, val, PLL_CTRL1);
 323
 324        val = pll_readl(pll, PLL_CTRL2);
 325        val &= ~PLL_INT_CTRL2_BYPASS;
 326        pll_writel(pll, val, PLL_CTRL2);
 327
 328        pll_lock(pll);
 329
 330        return 0;
 331}
 332
 333static void pll_gf40lp_laint_disable(struct clk_hw *hw)
 334{
 335        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 336        u32 val;
 337
 338        val = pll_readl(pll, PLL_CTRL1);
 339        val |= PLL_INT_CTRL1_PD;
 340        pll_writel(pll, val, PLL_CTRL1);
 341}
 342
 343static int pll_gf40lp_laint_is_enabled(struct clk_hw *hw)
 344{
 345        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 346
 347        return !(pll_readl(pll, PLL_CTRL1) & PLL_INT_CTRL1_PD);
 348}
 349
 350static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
 351                                     unsigned long parent_rate)
 352{
 353        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 354        struct pistachio_pll_rate_table *params;
 355        int enabled = pll_gf40lp_laint_is_enabled(hw);
 356        u32 val, vco, old_postdiv1, old_postdiv2;
 357        const char *name = clk_hw_get_name(hw);
 358
 359        if (rate < MIN_OUTPUT_LA || rate > MAX_OUTPUT_LA)
 360                return -EINVAL;
 361
 362        params = pll_get_params(pll, parent_rate, rate);
 363        if (!params || !params->refdiv)
 364                return -EINVAL;
 365
 366        vco = div_u64(params->fref * params->fbdiv, params->refdiv);
 367        if (vco < MIN_VCO_LA || vco > MAX_VCO_LA)
 368                pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco,
 369                        MIN_VCO_LA, MAX_VCO_LA);
 370
 371        val = div_u64(params->fref, params->refdiv);
 372        if (val < MIN_PFD)
 373                pr_warn("%s: PFD %u is too low (min %lu)\n",
 374                        name, val, MIN_PFD);
 375        if (val > vco / 16)
 376                pr_warn("%s: PFD %u is too high (max %u)\n",
 377                        name, val, vco / 16);
 378
 379        val = pll_readl(pll, PLL_CTRL1);
 380
 381        old_postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) &
 382                       PLL_INT_CTRL1_POSTDIV1_MASK;
 383        old_postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) &
 384                       PLL_INT_CTRL1_POSTDIV2_MASK;
 385        if (enabled &&
 386            (params->postdiv1 != old_postdiv1 ||
 387             params->postdiv2 != old_postdiv2))
 388                pr_warn("%s: changing postdiv while PLL is enabled\n", name);
 389
 390        if (params->postdiv2 > params->postdiv1)
 391                pr_warn("%s: postdiv2 should not exceed postdiv1\n", name);
 392
 393        val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
 394                 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT) |
 395                 (PLL_INT_CTRL1_POSTDIV1_MASK << PLL_INT_CTRL1_POSTDIV1_SHIFT) |
 396                 (PLL_INT_CTRL1_POSTDIV2_MASK << PLL_INT_CTRL1_POSTDIV2_SHIFT));
 397        val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) |
 398                (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT) |
 399                (params->postdiv1 << PLL_INT_CTRL1_POSTDIV1_SHIFT) |
 400                (params->postdiv2 << PLL_INT_CTRL1_POSTDIV2_SHIFT);
 401        pll_writel(pll, val, PLL_CTRL1);
 402
 403        if (enabled)
 404                pll_lock(pll);
 405
 406        return 0;
 407}
 408
 409static unsigned long pll_gf40lp_laint_recalc_rate(struct clk_hw *hw,
 410                                                  unsigned long parent_rate)
 411{
 412        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
 413        u32 val, prediv, fbdiv, postdiv1, postdiv2;
 414        u64 rate = parent_rate;
 415
 416        val = pll_readl(pll, PLL_CTRL1);
 417        prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
 418        fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK;
 419        postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) &
 420                PLL_INT_CTRL1_POSTDIV1_MASK;
 421        postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) &
 422                PLL_INT_CTRL1_POSTDIV2_MASK;
 423
 424        rate *= fbdiv;
 425        rate = do_div_round_closest(rate, prediv * postdiv1 * postdiv2);
 426
 427        return rate;
 428}
 429
 430static const struct clk_ops pll_gf40lp_laint_ops = {
 431        .enable = pll_gf40lp_laint_enable,
 432        .disable = pll_gf40lp_laint_disable,
 433        .is_enabled = pll_gf40lp_laint_is_enabled,
 434        .recalc_rate = pll_gf40lp_laint_recalc_rate,
 435        .round_rate = pll_round_rate,
 436        .set_rate = pll_gf40lp_laint_set_rate,
 437};
 438
 439static const struct clk_ops pll_gf40lp_laint_fixed_ops = {
 440        .enable = pll_gf40lp_laint_enable,
 441        .disable = pll_gf40lp_laint_disable,
 442        .is_enabled = pll_gf40lp_laint_is_enabled,
 443        .recalc_rate = pll_gf40lp_laint_recalc_rate,
 444};
 445
 446static struct clk *pll_register(const char *name, const char *parent_name,
 447                                unsigned long flags, void __iomem *base,
 448                                enum pistachio_pll_type type,
 449                                struct pistachio_pll_rate_table *rates,
 450                                unsigned int nr_rates)
 451{
 452        struct pistachio_clk_pll *pll;
 453        struct clk_init_data init;
 454        struct clk *clk;
 455
 456        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 457        if (!pll)
 458                return ERR_PTR(-ENOMEM);
 459
 460        init.name = name;
 461        init.flags = flags | CLK_GET_RATE_NOCACHE;
 462        init.parent_names = &parent_name;
 463        init.num_parents = 1;
 464
 465        switch (type) {
 466        case PLL_GF40LP_FRAC:
 467                if (rates)
 468                        init.ops = &pll_gf40lp_frac_ops;
 469                else
 470                        init.ops = &pll_gf40lp_frac_fixed_ops;
 471                break;
 472        case PLL_GF40LP_LAINT:
 473                if (rates)
 474                        init.ops = &pll_gf40lp_laint_ops;
 475                else
 476                        init.ops = &pll_gf40lp_laint_fixed_ops;
 477                break;
 478        default:
 479                pr_err("Unrecognized PLL type %u\n", type);
 480                kfree(pll);
 481                return ERR_PTR(-EINVAL);
 482        }
 483
 484        pll->hw.init = &init;
 485        pll->base = base;
 486        pll->rates = rates;
 487        pll->nr_rates = nr_rates;
 488
 489        clk = clk_register(NULL, &pll->hw);
 490        if (IS_ERR(clk))
 491                kfree(pll);
 492
 493        return clk;
 494}
 495
 496void pistachio_clk_register_pll(struct pistachio_clk_provider *p,
 497                                struct pistachio_pll *pll,
 498                                unsigned int num)
 499{
 500        struct clk *clk;
 501        unsigned int i;
 502
 503        for (i = 0; i < num; i++) {
 504                clk = pll_register(pll[i].name, pll[i].parent,
 505                                   0, p->base + pll[i].reg_base,
 506                                   pll[i].type, pll[i].rates,
 507                                   pll[i].nr_rates);
 508                p->clk_data.clks[pll[i].id] = clk;
 509        }
 510}
 511