linux/drivers/clk/qcom/clk-pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/bitops.h>
   8#include <linux/err.h>
   9#include <linux/bug.h>
  10#include <linux/delay.h>
  11#include <linux/export.h>
  12#include <linux/clk-provider.h>
  13#include <linux/regmap.h>
  14
  15#include <asm/div64.h>
  16
  17#include "clk-pll.h"
  18#include "common.h"
  19
  20#define PLL_OUTCTRL             BIT(0)
  21#define PLL_BYPASSNL            BIT(1)
  22#define PLL_RESET_N             BIT(2)
  23
  24static int clk_pll_enable(struct clk_hw *hw)
  25{
  26        struct clk_pll *pll = to_clk_pll(hw);
  27        int ret;
  28        u32 mask, val;
  29
  30        mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
  31        ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
  32        if (ret)
  33                return ret;
  34
  35        /* Skip if already enabled or in FSM mode */
  36        if ((val & mask) == mask || val & PLL_VOTE_FSM_ENA)
  37                return 0;
  38
  39        /* Disable PLL bypass mode. */
  40        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
  41                                 PLL_BYPASSNL);
  42        if (ret)
  43                return ret;
  44
  45        /*
  46         * H/W requires a 5us delay between disabling the bypass and
  47         * de-asserting the reset. Delay 10us just to be safe.
  48         */
  49        udelay(10);
  50
  51        /* De-assert active-low PLL reset. */
  52        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
  53                                 PLL_RESET_N);
  54        if (ret)
  55                return ret;
  56
  57        /* Wait until PLL is locked. */
  58        udelay(50);
  59
  60        /* Enable PLL output. */
  61        return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
  62                                 PLL_OUTCTRL);
  63}
  64
  65static void clk_pll_disable(struct clk_hw *hw)
  66{
  67        struct clk_pll *pll = to_clk_pll(hw);
  68        u32 mask;
  69        u32 val;
  70
  71        regmap_read(pll->clkr.regmap, pll->mode_reg, &val);
  72        /* Skip if in FSM mode */
  73        if (val & PLL_VOTE_FSM_ENA)
  74                return;
  75        mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
  76        regmap_update_bits(pll->clkr.regmap, pll->mode_reg, mask, 0);
  77}
  78
  79static unsigned long
  80clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
  81{
  82        struct clk_pll *pll = to_clk_pll(hw);
  83        u32 l, m, n, config;
  84        unsigned long rate;
  85        u64 tmp;
  86
  87        regmap_read(pll->clkr.regmap, pll->l_reg, &l);
  88        regmap_read(pll->clkr.regmap, pll->m_reg, &m);
  89        regmap_read(pll->clkr.regmap, pll->n_reg, &n);
  90
  91        l &= 0x3ff;
  92        m &= 0x7ffff;
  93        n &= 0x7ffff;
  94
  95        rate = parent_rate * l;
  96        if (n) {
  97                tmp = parent_rate;
  98                tmp *= m;
  99                do_div(tmp, n);
 100                rate += tmp;
 101        }
 102        if (pll->post_div_width) {
 103                regmap_read(pll->clkr.regmap, pll->config_reg, &config);
 104                config >>= pll->post_div_shift;
 105                config &= BIT(pll->post_div_width) - 1;
 106                rate /= config + 1;
 107        }
 108
 109        return rate;
 110}
 111
 112static const
 113struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
 114{
 115        if (!f)
 116                return NULL;
 117
 118        for (; f->freq; f++)
 119                if (rate <= f->freq)
 120                        return f;
 121
 122        return NULL;
 123}
 124
 125static int
 126clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 127{
 128        struct clk_pll *pll = to_clk_pll(hw);
 129        const struct pll_freq_tbl *f;
 130
 131        f = find_freq(pll->freq_tbl, req->rate);
 132        if (!f)
 133                req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate);
 134        else
 135                req->rate = f->freq;
 136
 137        return 0;
 138}
 139
 140static int
 141clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
 142{
 143        struct clk_pll *pll = to_clk_pll(hw);
 144        const struct pll_freq_tbl *f;
 145        bool enabled;
 146        u32 mode;
 147        u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
 148
 149        f = find_freq(pll->freq_tbl, rate);
 150        if (!f)
 151                return -EINVAL;
 152
 153        regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
 154        enabled = (mode & enable_mask) == enable_mask;
 155
 156        if (enabled)
 157                clk_pll_disable(hw);
 158
 159        regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
 160        regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
 161        regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
 162        regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits);
 163
 164        if (enabled)
 165                clk_pll_enable(hw);
 166
 167        return 0;
 168}
 169
 170const struct clk_ops clk_pll_ops = {
 171        .enable = clk_pll_enable,
 172        .disable = clk_pll_disable,
 173        .recalc_rate = clk_pll_recalc_rate,
 174        .determine_rate = clk_pll_determine_rate,
 175        .set_rate = clk_pll_set_rate,
 176};
 177EXPORT_SYMBOL_GPL(clk_pll_ops);
 178
 179static int wait_for_pll(struct clk_pll *pll)
 180{
 181        u32 val;
 182        int count;
 183        int ret;
 184        const char *name = clk_hw_get_name(&pll->clkr.hw);
 185
 186        /* Wait for pll to enable. */
 187        for (count = 200; count > 0; count--) {
 188                ret = regmap_read(pll->clkr.regmap, pll->status_reg, &val);
 189                if (ret)
 190                        return ret;
 191                if (val & BIT(pll->status_bit))
 192                        return 0;
 193                udelay(1);
 194        }
 195
 196        WARN(1, "%s didn't enable after voting for it!\n", name);
 197        return -ETIMEDOUT;
 198}
 199
 200static int clk_pll_vote_enable(struct clk_hw *hw)
 201{
 202        int ret;
 203        struct clk_pll *p = to_clk_pll(clk_hw_get_parent(hw));
 204
 205        ret = clk_enable_regmap(hw);
 206        if (ret)
 207                return ret;
 208
 209        return wait_for_pll(p);
 210}
 211
 212const struct clk_ops clk_pll_vote_ops = {
 213        .enable = clk_pll_vote_enable,
 214        .disable = clk_disable_regmap,
 215};
 216EXPORT_SYMBOL_GPL(clk_pll_vote_ops);
 217
 218static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap,
 219        const struct pll_config *config)
 220{
 221        u32 val;
 222        u32 mask;
 223
 224        regmap_write(regmap, pll->l_reg, config->l);
 225        regmap_write(regmap, pll->m_reg, config->m);
 226        regmap_write(regmap, pll->n_reg, config->n);
 227
 228        val = config->vco_val;
 229        val |= config->pre_div_val;
 230        val |= config->post_div_val;
 231        val |= config->mn_ena_mask;
 232        val |= config->main_output_mask;
 233        val |= config->aux_output_mask;
 234
 235        mask = config->vco_mask;
 236        mask |= config->pre_div_mask;
 237        mask |= config->post_div_mask;
 238        mask |= config->mn_ena_mask;
 239        mask |= config->main_output_mask;
 240        mask |= config->aux_output_mask;
 241
 242        regmap_update_bits(regmap, pll->config_reg, mask, val);
 243}
 244
 245void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap,
 246                const struct pll_config *config, bool fsm_mode)
 247{
 248        clk_pll_configure(pll, regmap, config);
 249        if (fsm_mode)
 250                qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 8);
 251}
 252EXPORT_SYMBOL_GPL(clk_pll_configure_sr);
 253
 254void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap,
 255                const struct pll_config *config, bool fsm_mode)
 256{
 257        clk_pll_configure(pll, regmap, config);
 258        if (fsm_mode)
 259                qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 0);
 260}
 261EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp);
 262
 263static int clk_pll_sr2_enable(struct clk_hw *hw)
 264{
 265        struct clk_pll *pll = to_clk_pll(hw);
 266        int ret;
 267        u32 mode;
 268
 269        ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
 270        if (ret)
 271                return ret;
 272
 273        /* Disable PLL bypass mode. */
 274        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL,
 275                                 PLL_BYPASSNL);
 276        if (ret)
 277                return ret;
 278
 279        /*
 280         * H/W requires a 5us delay between disabling the bypass and
 281         * de-asserting the reset. Delay 10us just to be safe.
 282         */
 283        udelay(10);
 284
 285        /* De-assert active-low PLL reset. */
 286        ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N,
 287                                 PLL_RESET_N);
 288        if (ret)
 289                return ret;
 290
 291        ret = wait_for_pll(pll);
 292        if (ret)
 293                return ret;
 294
 295        /* Enable PLL output. */
 296        return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL,
 297                                 PLL_OUTCTRL);
 298}
 299
 300static int
 301clk_pll_sr2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
 302{
 303        struct clk_pll *pll = to_clk_pll(hw);
 304        const struct pll_freq_tbl *f;
 305        bool enabled;
 306        u32 mode;
 307        u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
 308
 309        f = find_freq(pll->freq_tbl, rate);
 310        if (!f)
 311                return -EINVAL;
 312
 313        regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
 314        enabled = (mode & enable_mask) == enable_mask;
 315
 316        if (enabled)
 317                clk_pll_disable(hw);
 318
 319        regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
 320        regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
 321        regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
 322
 323        if (enabled)
 324                clk_pll_sr2_enable(hw);
 325
 326        return 0;
 327}
 328
 329const struct clk_ops clk_pll_sr2_ops = {
 330        .enable = clk_pll_sr2_enable,
 331        .disable = clk_pll_disable,
 332        .set_rate = clk_pll_sr2_set_rate,
 333        .recalc_rate = clk_pll_recalc_rate,
 334        .determine_rate = clk_pll_determine_rate,
 335};
 336EXPORT_SYMBOL_GPL(clk_pll_sr2_ops);
 337