Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright (C) 2014 Broadcom Corporation
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/slab.h>
0006 #include <linux/err.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/io.h>
0009 #include <linux/of.h>
0010 #include <linux/clkdev.h>
0011 #include <linux/of_address.h>
0012 
0013 #include "clk-iproc.h"
0014 
0015 #define IPROC_CLK_MAX_FREQ_POLICY                    0x3
0016 #define IPROC_CLK_POLICY_FREQ_OFFSET                 0x008
0017 #define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT      8
0018 #define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK       0x7
0019 
0020 #define IPROC_CLK_PLLARMA_OFFSET                     0xc00
0021 #define IPROC_CLK_PLLARMA_LOCK_SHIFT                 28
0022 #define IPROC_CLK_PLLARMA_PDIV_SHIFT                 24
0023 #define IPROC_CLK_PLLARMA_PDIV_MASK                  0xf
0024 #define IPROC_CLK_PLLARMA_NDIV_INT_SHIFT             8
0025 #define IPROC_CLK_PLLARMA_NDIV_INT_MASK              0x3ff
0026 
0027 #define IPROC_CLK_PLLARMB_OFFSET                     0xc04
0028 #define IPROC_CLK_PLLARMB_NDIV_FRAC_MASK             0xfffff
0029 
0030 #define IPROC_CLK_PLLARMC_OFFSET                     0xc08
0031 #define IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT            8
0032 #define IPROC_CLK_PLLARMC_MDIV_MASK                  0xff
0033 
0034 #define IPROC_CLK_PLLARMCTL5_OFFSET                  0xc20
0035 #define IPROC_CLK_PLLARMCTL5_H_MDIV_MASK             0xff
0036 
0037 #define IPROC_CLK_PLLARM_OFFSET_OFFSET               0xc24
0038 #define IPROC_CLK_PLLARM_SW_CTL_SHIFT                29
0039 #define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT       20
0040 #define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK        0xff
0041 #define IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK       0xfffff
0042 
0043 #define IPROC_CLK_ARM_DIV_OFFSET                     0xe00
0044 #define IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT  4
0045 #define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK        0xf
0046 
0047 #define IPROC_CLK_POLICY_DBG_OFFSET                  0xec0
0048 #define IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT          12
0049 #define IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK           0x7
0050 
0051 enum iproc_arm_pll_fid {
0052     ARM_PLL_FID_CRYSTAL_CLK   = 0,
0053     ARM_PLL_FID_SYS_CLK       = 2,
0054     ARM_PLL_FID_CH0_SLOW_CLK  = 6,
0055     ARM_PLL_FID_CH1_FAST_CLK  = 7
0056 };
0057 
0058 struct iproc_arm_pll {
0059     struct clk_hw hw;
0060     void __iomem *base;
0061     unsigned long rate;
0062 };
0063 
0064 #define to_iproc_arm_pll(hw) container_of(hw, struct iproc_arm_pll, hw)
0065 
0066 static unsigned int __get_fid(struct iproc_arm_pll *pll)
0067 {
0068     u32 val;
0069     unsigned int policy, fid, active_fid;
0070 
0071     val = readl(pll->base + IPROC_CLK_ARM_DIV_OFFSET);
0072     if (val & (1 << IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT))
0073         policy = val & IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK;
0074     else
0075         policy = 0;
0076 
0077     /* something is seriously wrong */
0078     BUG_ON(policy > IPROC_CLK_MAX_FREQ_POLICY);
0079 
0080     val = readl(pll->base + IPROC_CLK_POLICY_FREQ_OFFSET);
0081     fid = (val >> (IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT * policy)) &
0082         IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK;
0083 
0084     val = readl(pll->base + IPROC_CLK_POLICY_DBG_OFFSET);
0085     active_fid = IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK &
0086         (val >> IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT);
0087     if (fid != active_fid) {
0088         pr_debug("%s: fid override %u->%u\n", __func__, fid,
0089                 active_fid);
0090         fid = active_fid;
0091     }
0092 
0093     pr_debug("%s: active fid: %u\n", __func__, fid);
0094 
0095     return fid;
0096 }
0097 
0098 /*
0099  * Determine the mdiv (post divider) based on the frequency ID being used.
0100  * There are 4 sources that can be used to derive the output clock rate:
0101  *    - 25 MHz Crystal
0102  *    - System clock
0103  *    - PLL channel 0 (slow clock)
0104  *    - PLL channel 1 (fast clock)
0105  */
0106 static int __get_mdiv(struct iproc_arm_pll *pll)
0107 {
0108     unsigned int fid;
0109     int mdiv;
0110     u32 val;
0111 
0112     fid = __get_fid(pll);
0113 
0114     switch (fid) {
0115     case ARM_PLL_FID_CRYSTAL_CLK:
0116     case ARM_PLL_FID_SYS_CLK:
0117         mdiv = 1;
0118         break;
0119 
0120     case ARM_PLL_FID_CH0_SLOW_CLK:
0121         val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
0122         mdiv = val & IPROC_CLK_PLLARMC_MDIV_MASK;
0123         if (mdiv == 0)
0124             mdiv = 256;
0125         break;
0126 
0127     case ARM_PLL_FID_CH1_FAST_CLK:
0128         val = readl(pll->base + IPROC_CLK_PLLARMCTL5_OFFSET);
0129         mdiv = val & IPROC_CLK_PLLARMCTL5_H_MDIV_MASK;
0130         if (mdiv == 0)
0131             mdiv = 256;
0132         break;
0133 
0134     default:
0135         mdiv = -EFAULT;
0136     }
0137 
0138     return mdiv;
0139 }
0140 
0141 static unsigned int __get_ndiv(struct iproc_arm_pll *pll)
0142 {
0143     u32 val;
0144     unsigned int ndiv_int, ndiv_frac, ndiv;
0145 
0146     val = readl(pll->base + IPROC_CLK_PLLARM_OFFSET_OFFSET);
0147     if (val & (1 << IPROC_CLK_PLLARM_SW_CTL_SHIFT)) {
0148         /*
0149          * offset mode is active. Read the ndiv from the PLLARM OFFSET
0150          * register
0151          */
0152         ndiv_int = (val >> IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT) &
0153             IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK;
0154         if (ndiv_int == 0)
0155             ndiv_int = 256;
0156 
0157         ndiv_frac = val & IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK;
0158     } else {
0159         /* offset mode not active */
0160         val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
0161         ndiv_int = (val >> IPROC_CLK_PLLARMA_NDIV_INT_SHIFT) &
0162             IPROC_CLK_PLLARMA_NDIV_INT_MASK;
0163         if (ndiv_int == 0)
0164             ndiv_int = 1024;
0165 
0166         val = readl(pll->base + IPROC_CLK_PLLARMB_OFFSET);
0167         ndiv_frac = val & IPROC_CLK_PLLARMB_NDIV_FRAC_MASK;
0168     }
0169 
0170     ndiv = (ndiv_int << 20) | ndiv_frac;
0171 
0172     return ndiv;
0173 }
0174 
0175 /*
0176  * The output frequency of the ARM PLL is calculated based on the ARM PLL
0177  * divider values:
0178  *   pdiv = ARM PLL pre-divider
0179  *   ndiv = ARM PLL multiplier
0180  *   mdiv = ARM PLL post divider
0181  *
0182  * The frequency is calculated by:
0183  *   ((ndiv * parent clock rate) / pdiv) / mdiv
0184  */
0185 static unsigned long iproc_arm_pll_recalc_rate(struct clk_hw *hw,
0186         unsigned long parent_rate)
0187 {
0188     struct iproc_arm_pll *pll = to_iproc_arm_pll(hw);
0189     u32 val;
0190     int mdiv;
0191     u64 ndiv;
0192     unsigned int pdiv;
0193 
0194     /* in bypass mode, use parent rate */
0195     val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
0196     if (val & (1 << IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT)) {
0197         pll->rate = parent_rate;
0198         return pll->rate;
0199     }
0200 
0201     /* PLL needs to be locked */
0202     val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
0203     if (!(val & (1 << IPROC_CLK_PLLARMA_LOCK_SHIFT))) {
0204         pll->rate = 0;
0205         return 0;
0206     }
0207 
0208     pdiv = (val >> IPROC_CLK_PLLARMA_PDIV_SHIFT) &
0209         IPROC_CLK_PLLARMA_PDIV_MASK;
0210     if (pdiv == 0)
0211         pdiv = 16;
0212 
0213     ndiv = __get_ndiv(pll);
0214     mdiv = __get_mdiv(pll);
0215     if (mdiv <= 0) {
0216         pll->rate = 0;
0217         return 0;
0218     }
0219     pll->rate = (ndiv * parent_rate) >> 20;
0220     pll->rate = (pll->rate / pdiv) / mdiv;
0221 
0222     pr_debug("%s: ARM PLL rate: %lu. parent rate: %lu\n", __func__,
0223          pll->rate, parent_rate);
0224     pr_debug("%s: ndiv_int: %u, pdiv: %u, mdiv: %d\n", __func__,
0225          (unsigned int)(ndiv >> 20), pdiv, mdiv);
0226 
0227     return pll->rate;
0228 }
0229 
0230 static const struct clk_ops iproc_arm_pll_ops = {
0231     .recalc_rate = iproc_arm_pll_recalc_rate,
0232 };
0233 
0234 void __init iproc_armpll_setup(struct device_node *node)
0235 {
0236     int ret;
0237     struct iproc_arm_pll *pll;
0238     struct clk_init_data init;
0239     const char *parent_name;
0240 
0241     pll = kzalloc(sizeof(*pll), GFP_KERNEL);
0242     if (WARN_ON(!pll))
0243         return;
0244 
0245     pll->base = of_iomap(node, 0);
0246     if (WARN_ON(!pll->base))
0247         goto err_free_pll;
0248 
0249     init.name = node->name;
0250     init.ops = &iproc_arm_pll_ops;
0251     init.flags = 0;
0252     parent_name = of_clk_get_parent_name(node, 0);
0253     init.parent_names = (parent_name ? &parent_name : NULL);
0254     init.num_parents = (parent_name ? 1 : 0);
0255     pll->hw.init = &init;
0256 
0257     ret = clk_hw_register(NULL, &pll->hw);
0258     if (WARN_ON(ret))
0259         goto err_iounmap;
0260 
0261     ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll->hw);
0262     if (WARN_ON(ret))
0263         goto err_clk_unregister;
0264 
0265     return;
0266 
0267 err_clk_unregister:
0268     clk_hw_unregister(&pll->hw);
0269 err_iounmap:
0270     iounmap(pll->base);
0271 err_free_pll:
0272     kfree(pll);
0273 }