linux/drivers/clk/zynqmp/pll.c
<<
>>
Prefs
   1/*
   2 * Zynq UltraScale+ MPSoC PLL driver
   3 *
   4 *  Copyright (C) 2016 Xilinx
   5 *
   6 * This program is free software: you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License v2 as published by
   8 * the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 *
  18 */
  19#include <linux/clk/zynqmp.h>
  20#include <linux/clk-provider.h>
  21#include <linux/slab.h>
  22#include <linux/io.h>
  23
  24/**
  25 * struct zynqmp_pll - Structure for PLL clock
  26 * @hw:         Handle between common and hardware-specific interfaces
  27 * @pll_ctrl:   PLL control register
  28 * @pll_status: PLL status register
  29 * @lockbit:    Indicates the associated PLL_LOCKED bit in the PLL status
  30 *              register
  31 */
  32struct zynqmp_pll {
  33        struct clk_hw   hw;
  34        resource_size_t *pll_ctrl;
  35        resource_size_t *pll_status;
  36        u8              lockbit;
  37};
  38#define to_zynqmp_pll(_hw)      container_of(_hw, struct zynqmp_pll, hw)
  39
  40/* Register bitfield defines */
  41#define PLLCTRL_FBDIV_MASK      0x7f00
  42#define PLLCTRL_FBDIV_SHIFT     8
  43#define PLLCTRL_BP_MASK         (1 << 3)
  44#define PLLCTRL_DIV2_MASK       (1 << 16)
  45#define PLLCTRL_RESET_MASK      1
  46#define PLLCTRL_RESET_VAL       1
  47#define PLL_STATUS_LOCKED       1
  48#define PLLCTRL_RESET_SHIFT     0
  49#define PLLCTRL_DIV2_SHIFT      16
  50
  51#define PLL_FBDIV_MIN   25
  52#define PLL_FBDIV_MAX   125
  53
  54enum pll_mode {
  55        PLL_MODE_FRAC,
  56        PLL_MODE_INT,
  57};
  58
  59#define FRAC_OFFSET 0x8
  60#define PLLFCFG_FRAC_EN BIT(31)
  61#define FRAC_DIV  0x10000  /* 2^16 */
  62
  63static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
  64{
  65        struct zynqmp_pll *clk = to_zynqmp_pll(hw);
  66        u32 reg;
  67
  68        reg = zynqmp_pm_mmio_readl(clk->pll_ctrl + FRAC_OFFSET);
  69        reg = reg & PLLFCFG_FRAC_EN;
  70        return reg ? PLL_MODE_FRAC : PLL_MODE_INT;
  71}
  72
  73/**
  74 * zynqmp_pll_round_rate - Round a clock frequency
  75 * @hw:         Handle between common and hardware-specific interfaces
  76 * @rate:       Desired clock frequency
  77 * @prate:      Clock frequency of parent clock
  78 *
  79 * Return:      Frequency closest to @rate the hardware can generate
  80 */
  81static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
  82                unsigned long *prate)
  83{
  84        u32 fbdiv;
  85        long rate_div, frac, m, f;
  86
  87        if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
  88                rate_div = ((rate*100) / *prate);
  89                m = rate_div / 100;
  90                f = rate_div % 100;
  91                m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
  92                rate = *prate * m;
  93                frac = (*prate * f) / 100;
  94                return (rate + frac);
  95        }
  96
  97        fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
  98        fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
  99        return *prate * fbdiv;
 100}
 101
 102/**
 103 * zynqmp_pll_recalc_rate - Recalculate clock frequency
 104 * @hw:                 Handle between common and hardware-specific interfaces
 105 * @parent_rate:        Clock frequency of parent clock
 106 * Return:              Current clock frequency
 107 */
 108static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
 109                unsigned long parent_rate)
 110{
 111        struct zynqmp_pll *clk = to_zynqmp_pll(hw);
 112        u32 fbdiv, div2, data;
 113        unsigned long rate, frac;
 114
 115        /*
 116         * makes probably sense to redundantly save fbdiv in the struct
 117         * zynqmp_pll to save the IO access.
 118         */
 119        fbdiv = (zynqmp_pm_mmio_readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
 120                        PLLCTRL_FBDIV_SHIFT;
 121        div2 = (zynqmp_pm_mmio_readl(clk->pll_ctrl) & PLLCTRL_DIV2_MASK) >>
 122                        PLLCTRL_DIV2_SHIFT;
 123        if (div2)
 124                fbdiv = fbdiv * 2;
 125
 126        rate =  parent_rate * fbdiv;
 127        if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
 128                data = (zynqmp_pm_mmio_readl(clk->pll_ctrl + FRAC_OFFSET) &
 129                        0xffff);
 130                frac = (rate * data) / FRAC_DIV;
 131                rate = rate + frac;
 132        }
 133        return rate;
 134}
 135
 136/**
 137 * zynqmp_pll_is_enabled - Check if a clock is enabled
 138 * @hw:         Handle between common and hardware-specific interfaces
 139 *
 140 * Return:      1 if the clock is enabled, 0 otherwise
 141 */
 142static int zynqmp_pll_is_enabled(struct clk_hw *hw)
 143{
 144        u32 reg;
 145        struct zynqmp_pll *clk = to_zynqmp_pll(hw);
 146
 147        reg = zynqmp_pm_mmio_readl(clk->pll_ctrl);
 148
 149        return !(reg & (PLLCTRL_RESET_MASK));
 150}
 151
 152/**
 153 * zynqmp_pll_enable - Enable clock
 154 * @hw:         Handle between common and hardware-specific interfaces
 155 *
 156 * Return:      0 always
 157 */
 158static int zynqmp_pll_enable(struct clk_hw *hw)
 159{
 160        u32 reg;
 161        struct zynqmp_pll *clk = to_zynqmp_pll(hw);
 162
 163        if (zynqmp_pll_is_enabled(hw))
 164                return 0;
 165
 166        pr_info("PLL: enable\n");
 167
 168        reg = zynqmp_pm_mmio_readl(clk->pll_ctrl);
 169        reg &= ~(PLLCTRL_RESET_MASK);
 170        zynqmp_pm_mmio_writel(reg, clk->pll_ctrl);
 171        while (!(zynqmp_pm_mmio_readl(clk->pll_status) & (1 << clk->lockbit)))
 172                cpu_relax();
 173
 174        return 0;
 175}
 176
 177/**
 178 * zynqmp_pll_disable - Disable clock
 179 * @hw:         Handle between common and hardware-specific interfaces
 180 *
 181 */
 182static void zynqmp_pll_disable(struct clk_hw *hw)
 183{
 184        struct zynqmp_pll *clk = to_zynqmp_pll(hw);
 185
 186        if (!zynqmp_pll_is_enabled(hw))
 187                return;
 188
 189        pr_info("PLL: shutdown\n");
 190
 191        /* shut down PLL */
 192        zynqmp_pm_mmio_write((u32)(ulong)clk->pll_ctrl, PLLCTRL_RESET_MASK,
 193                                PLLCTRL_RESET_VAL);
 194}
 195
 196static const struct clk_ops zynqmp_pll_ops = {
 197        .enable = zynqmp_pll_enable,
 198        .disable = zynqmp_pll_disable,
 199        .is_enabled = zynqmp_pll_is_enabled,
 200        .round_rate = zynqmp_pll_round_rate,
 201        .recalc_rate = zynqmp_pll_recalc_rate
 202};
 203
 204/**
 205 * clk_register_zynqmp_pll - Register PLL with the clock framework
 206 * @name:       PLL name
 207 * @flag:       PLL flags
 208 * @parent:     Parent clock name
 209 * @pll_ctrl:   Pointer to PLL control register
 210 * @pll_status: Pointer to PLL status register
 211 * @lock_index: Bit index to this PLL's lock status bit in @pll_status
 212 *
 213 * Return:      Handle to the registered clock
 214 */
 215struct clk *clk_register_zynqmp_pll(const char *name, const char *parent,
 216                unsigned long flag, resource_size_t *pll_ctrl,
 217                resource_size_t *pll_status, u8 lock_index)
 218{
 219        struct zynqmp_pll *pll;
 220        struct clk *clk;
 221        struct clk_init_data init;
 222
 223        init.name = name;
 224        init.ops = &zynqmp_pll_ops;
 225        init.flags = flag;
 226        init.parent_names = &parent;
 227        init.num_parents = 1;
 228
 229        pll = kmalloc(sizeof(*pll), GFP_KERNEL);
 230        if (!pll)
 231                return ERR_PTR(-ENOMEM);
 232
 233        /* Populate the struct */
 234        pll->hw.init = &init;
 235        pll->pll_ctrl = pll_ctrl;
 236        pll->pll_status = pll_status;
 237        pll->lockbit = lock_index;
 238
 239        clk = clk_register(NULL, &pll->hw);
 240        if (WARN_ON(IS_ERR(clk)))
 241                kfree(pll);
 242
 243        return clk;
 244}
 245