Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
0004  */
0005 
0006 #include <linux/clk-provider.h>
0007 #include <linux/clkdev.h>
0008 #include <linux/clk/at91_pmc.h>
0009 #include <linux/of.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/regmap.h>
0012 
0013 #include "pmc.h"
0014 
0015 #define PLL_STATUS_MASK(id) (1 << (1 + (id)))
0016 #define PLL_REG(id)     (AT91_CKGR_PLLAR + ((id) * 4))
0017 #define PLL_DIV_MASK        0xff
0018 #define PLL_DIV_MAX     PLL_DIV_MASK
0019 #define PLL_DIV(reg)        ((reg) & PLL_DIV_MASK)
0020 #define PLL_MUL(reg, layout)    (((reg) >> (layout)->mul_shift) & \
0021                  (layout)->mul_mask)
0022 #define PLL_MUL_MIN     2
0023 #define PLL_MUL_MASK(layout)    ((layout)->mul_mask)
0024 #define PLL_MUL_MAX(layout) (PLL_MUL_MASK(layout) + 1)
0025 #define PLL_ICPR_SHIFT(id)  ((id) * 16)
0026 #define PLL_ICPR_MASK(id)   (0xffff << PLL_ICPR_SHIFT(id))
0027 #define PLL_MAX_COUNT       0x3f
0028 #define PLL_COUNT_SHIFT     8
0029 #define PLL_OUT_SHIFT       14
0030 #define PLL_MAX_ID      1
0031 
0032 #define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
0033 
0034 struct clk_pll {
0035     struct clk_hw hw;
0036     struct regmap *regmap;
0037     u8 id;
0038     u8 div;
0039     u8 range;
0040     u16 mul;
0041     const struct clk_pll_layout *layout;
0042     const struct clk_pll_characteristics *characteristics;
0043     struct at91_clk_pms pms;
0044 };
0045 
0046 static inline bool clk_pll_ready(struct regmap *regmap, int id)
0047 {
0048     unsigned int status;
0049 
0050     regmap_read(regmap, AT91_PMC_SR, &status);
0051 
0052     return status & PLL_STATUS_MASK(id) ? 1 : 0;
0053 }
0054 
0055 static int clk_pll_prepare(struct clk_hw *hw)
0056 {
0057     struct clk_pll *pll = to_clk_pll(hw);
0058     struct regmap *regmap = pll->regmap;
0059     const struct clk_pll_layout *layout = pll->layout;
0060     const struct clk_pll_characteristics *characteristics =
0061                             pll->characteristics;
0062     u8 id = pll->id;
0063     u32 mask = PLL_STATUS_MASK(id);
0064     int offset = PLL_REG(id);
0065     u8 out = 0;
0066     unsigned int pllr;
0067     unsigned int status;
0068     u8 div;
0069     u16 mul;
0070 
0071     regmap_read(regmap, offset, &pllr);
0072     div = PLL_DIV(pllr);
0073     mul = PLL_MUL(pllr, layout);
0074 
0075     regmap_read(regmap, AT91_PMC_SR, &status);
0076     if ((status & mask) &&
0077         (div == pll->div && mul == pll->mul))
0078         return 0;
0079 
0080     if (characteristics->out)
0081         out = characteristics->out[pll->range];
0082 
0083     if (characteristics->icpll)
0084         regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id),
0085             characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id));
0086 
0087     regmap_update_bits(regmap, offset, layout->pllr_mask,
0088             pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
0089             (out << PLL_OUT_SHIFT) |
0090             ((pll->mul & layout->mul_mask) << layout->mul_shift));
0091 
0092     while (!clk_pll_ready(regmap, pll->id))
0093         cpu_relax();
0094 
0095     return 0;
0096 }
0097 
0098 static int clk_pll_is_prepared(struct clk_hw *hw)
0099 {
0100     struct clk_pll *pll = to_clk_pll(hw);
0101 
0102     return clk_pll_ready(pll->regmap, pll->id);
0103 }
0104 
0105 static void clk_pll_unprepare(struct clk_hw *hw)
0106 {
0107     struct clk_pll *pll = to_clk_pll(hw);
0108     unsigned int mask = pll->layout->pllr_mask;
0109 
0110     regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask);
0111 }
0112 
0113 static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
0114                      unsigned long parent_rate)
0115 {
0116     struct clk_pll *pll = to_clk_pll(hw);
0117 
0118     if (!pll->div || !pll->mul)
0119         return 0;
0120 
0121     return (parent_rate / pll->div) * (pll->mul + 1);
0122 }
0123 
0124 static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
0125                      unsigned long parent_rate,
0126                      u32 *div, u32 *mul,
0127                      u32 *index) {
0128     const struct clk_pll_layout *layout = pll->layout;
0129     const struct clk_pll_characteristics *characteristics =
0130                             pll->characteristics;
0131     unsigned long bestremainder = ULONG_MAX;
0132     unsigned long maxdiv, mindiv, tmpdiv;
0133     long bestrate = -ERANGE;
0134     unsigned long bestdiv;
0135     unsigned long bestmul;
0136     int i = 0;
0137 
0138     /* Check if parent_rate is a valid input rate */
0139     if (parent_rate < characteristics->input.min)
0140         return -ERANGE;
0141 
0142     /*
0143      * Calculate minimum divider based on the minimum multiplier, the
0144      * parent_rate and the requested rate.
0145      * Should always be 2 according to the input and output characteristics
0146      * of the PLL blocks.
0147      */
0148     mindiv = (parent_rate * PLL_MUL_MIN) / rate;
0149     if (!mindiv)
0150         mindiv = 1;
0151 
0152     if (parent_rate > characteristics->input.max) {
0153         tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max);
0154         if (tmpdiv > PLL_DIV_MAX)
0155             return -ERANGE;
0156 
0157         if (tmpdiv > mindiv)
0158             mindiv = tmpdiv;
0159     }
0160 
0161     /*
0162      * Calculate the maximum divider which is limited by PLL register
0163      * layout (limited by the MUL or DIV field size).
0164      */
0165     maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate);
0166     if (maxdiv > PLL_DIV_MAX)
0167         maxdiv = PLL_DIV_MAX;
0168 
0169     /*
0170      * Iterate over the acceptable divider values to find the best
0171      * divider/multiplier pair (the one that generates the closest
0172      * rate to the requested one).
0173      */
0174     for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
0175         unsigned long remainder;
0176         unsigned long tmprate;
0177         unsigned long tmpmul;
0178 
0179         /*
0180          * Calculate the multiplier associated with the current
0181          * divider that provide the closest rate to the requested one.
0182          */
0183         tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv);
0184         tmprate = (parent_rate / tmpdiv) * tmpmul;
0185         if (tmprate > rate)
0186             remainder = tmprate - rate;
0187         else
0188             remainder = rate - tmprate;
0189 
0190         /*
0191          * Compare the remainder with the best remainder found until
0192          * now and elect a new best multiplier/divider pair if the
0193          * current remainder is smaller than the best one.
0194          */
0195         if (remainder < bestremainder) {
0196             bestremainder = remainder;
0197             bestdiv = tmpdiv;
0198             bestmul = tmpmul;
0199             bestrate = tmprate;
0200         }
0201 
0202         /*
0203          * We've found a perfect match!
0204          * Stop searching now and use this multiplier/divider pair.
0205          */
0206         if (!remainder)
0207             break;
0208     }
0209 
0210     /* We haven't found any multiplier/divider pair => return -ERANGE */
0211     if (bestrate < 0)
0212         return bestrate;
0213 
0214     /* Check if bestrate is a valid output rate  */
0215     for (i = 0; i < characteristics->num_output; i++) {
0216         if (bestrate >= characteristics->output[i].min &&
0217             bestrate <= characteristics->output[i].max)
0218             break;
0219     }
0220 
0221     if (i >= characteristics->num_output)
0222         return -ERANGE;
0223 
0224     if (div)
0225         *div = bestdiv;
0226     if (mul)
0227         *mul = bestmul - 1;
0228     if (index)
0229         *index = i;
0230 
0231     return bestrate;
0232 }
0233 
0234 static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
0235                     unsigned long *parent_rate)
0236 {
0237     struct clk_pll *pll = to_clk_pll(hw);
0238 
0239     return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
0240                     NULL, NULL, NULL);
0241 }
0242 
0243 static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
0244                 unsigned long parent_rate)
0245 {
0246     struct clk_pll *pll = to_clk_pll(hw);
0247     long ret;
0248     u32 div;
0249     u32 mul;
0250     u32 index;
0251 
0252     ret = clk_pll_get_best_div_mul(pll, rate, parent_rate,
0253                        &div, &mul, &index);
0254     if (ret < 0)
0255         return ret;
0256 
0257     pll->range = index;
0258     pll->div = div;
0259     pll->mul = mul;
0260 
0261     return 0;
0262 }
0263 
0264 static int clk_pll_save_context(struct clk_hw *hw)
0265 {
0266     struct clk_pll *pll = to_clk_pll(hw);
0267     struct clk_hw *parent_hw = clk_hw_get_parent(hw);
0268 
0269     pll->pms.parent_rate = clk_hw_get_rate(parent_hw);
0270     pll->pms.rate = clk_pll_recalc_rate(&pll->hw, pll->pms.parent_rate);
0271     pll->pms.status = clk_pll_ready(pll->regmap, PLL_REG(pll->id));
0272 
0273     return 0;
0274 }
0275 
0276 static void clk_pll_restore_context(struct clk_hw *hw)
0277 {
0278     struct clk_pll *pll = to_clk_pll(hw);
0279     unsigned long calc_rate;
0280     unsigned int pllr, pllr_out, pllr_count;
0281     u8 out = 0;
0282 
0283     if (pll->characteristics->out)
0284         out = pll->characteristics->out[pll->range];
0285 
0286     regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
0287 
0288     calc_rate = (pll->pms.parent_rate / PLL_DIV(pllr)) *
0289              (PLL_MUL(pllr, pll->layout) + 1);
0290     pllr_count = (pllr >> PLL_COUNT_SHIFT) & PLL_MAX_COUNT;
0291     pllr_out = (pllr >> PLL_OUT_SHIFT) & out;
0292 
0293     if (pll->pms.rate != calc_rate ||
0294         pll->pms.status != clk_pll_ready(pll->regmap, PLL_REG(pll->id)) ||
0295         pllr_count != PLL_MAX_COUNT ||
0296         (out && pllr_out != out))
0297         pr_warn("PLLAR was not configured properly by firmware\n");
0298 }
0299 
0300 static const struct clk_ops pll_ops = {
0301     .prepare = clk_pll_prepare,
0302     .unprepare = clk_pll_unprepare,
0303     .is_prepared = clk_pll_is_prepared,
0304     .recalc_rate = clk_pll_recalc_rate,
0305     .round_rate = clk_pll_round_rate,
0306     .set_rate = clk_pll_set_rate,
0307     .save_context = clk_pll_save_context,
0308     .restore_context = clk_pll_restore_context,
0309 };
0310 
0311 struct clk_hw * __init
0312 at91_clk_register_pll(struct regmap *regmap, const char *name,
0313               const char *parent_name, u8 id,
0314               const struct clk_pll_layout *layout,
0315               const struct clk_pll_characteristics *characteristics)
0316 {
0317     struct clk_pll *pll;
0318     struct clk_hw *hw;
0319     struct clk_init_data init;
0320     int offset = PLL_REG(id);
0321     unsigned int pllr;
0322     int ret;
0323 
0324     if (id > PLL_MAX_ID)
0325         return ERR_PTR(-EINVAL);
0326 
0327     pll = kzalloc(sizeof(*pll), GFP_KERNEL);
0328     if (!pll)
0329         return ERR_PTR(-ENOMEM);
0330 
0331     init.name = name;
0332     init.ops = &pll_ops;
0333     init.parent_names = &parent_name;
0334     init.num_parents = 1;
0335     init.flags = CLK_SET_RATE_GATE;
0336 
0337     pll->id = id;
0338     pll->hw.init = &init;
0339     pll->layout = layout;
0340     pll->characteristics = characteristics;
0341     pll->regmap = regmap;
0342     regmap_read(regmap, offset, &pllr);
0343     pll->div = PLL_DIV(pllr);
0344     pll->mul = PLL_MUL(pllr, layout);
0345 
0346     hw = &pll->hw;
0347     ret = clk_hw_register(NULL, &pll->hw);
0348     if (ret) {
0349         kfree(pll);
0350         hw = ERR_PTR(ret);
0351     }
0352 
0353     return hw;
0354 }
0355 
0356 
0357 const struct clk_pll_layout at91rm9200_pll_layout = {
0358     .pllr_mask = 0x7FFFFFF,
0359     .mul_shift = 16,
0360     .mul_mask = 0x7FF,
0361 };
0362 
0363 const struct clk_pll_layout at91sam9g45_pll_layout = {
0364     .pllr_mask = 0xFFFFFF,
0365     .mul_shift = 16,
0366     .mul_mask = 0xFF,
0367 };
0368 
0369 const struct clk_pll_layout at91sam9g20_pllb_layout = {
0370     .pllr_mask = 0x3FFFFF,
0371     .mul_shift = 16,
0372     .mul_mask = 0x3F,
0373 };
0374 
0375 const struct clk_pll_layout sama5d3_pll_layout = {
0376     .pllr_mask = 0x1FFFFFF,
0377     .mul_shift = 18,
0378     .mul_mask = 0x7F,
0379 };