0001
0002
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
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
0100
0101
0102
0103
0104
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
0150
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
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
0177
0178
0179
0180
0181
0182
0183
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
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
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 }