0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/bits.h>
0011 #include <linux/clk-provider.h>
0012 #include <linux/err.h>
0013 #include <linux/io.h>
0014 #include <linux/iopoll.h>
0015 #include <linux/slab.h>
0016
0017 #include "clk.h"
0018
0019
0020 #define PLL_CSR_OFFSET 0x0
0021 #define PLL_VLD BIT(24)
0022 #define PLL_EN BIT(0)
0023
0024
0025 #define PLL_CFG_OFFSET 0x08
0026 #define IMX8ULP_PLL_CFG_OFFSET 0x10
0027 #define BP_PLL_MULT 16
0028 #define BM_PLL_MULT (0x7f << 16)
0029
0030
0031 #define PLL_NUM_OFFSET 0x10
0032 #define IMX8ULP_PLL_NUM_OFFSET 0x1c
0033
0034
0035 #define PLL_DENOM_OFFSET 0x14
0036 #define IMX8ULP_PLL_DENOM_OFFSET 0x18
0037
0038 #define MAX_MFD 0x3fffffff
0039 #define DEFAULT_MFD 1000000
0040
0041 struct clk_pllv4 {
0042 struct clk_hw hw;
0043 void __iomem *base;
0044 u32 cfg_offset;
0045 u32 num_offset;
0046 u32 denom_offset;
0047 };
0048
0049
0050 static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16};
0051
0052 #define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw)
0053
0054 #define LOCK_TIMEOUT_US USEC_PER_MSEC
0055
0056 static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll)
0057 {
0058 u32 csr;
0059
0060 return readl_poll_timeout(pll->base + PLL_CSR_OFFSET,
0061 csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US);
0062 }
0063
0064 static int clk_pllv4_is_prepared(struct clk_hw *hw)
0065 {
0066 struct clk_pllv4 *pll = to_clk_pllv4(hw);
0067
0068 if (readl_relaxed(pll->base) & PLL_EN)
0069 return 1;
0070
0071 return 0;
0072 }
0073
0074 static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw,
0075 unsigned long parent_rate)
0076 {
0077 struct clk_pllv4 *pll = to_clk_pllv4(hw);
0078 u32 mult, mfn, mfd;
0079 u64 temp64;
0080
0081 mult = readl_relaxed(pll->base + pll->cfg_offset);
0082 mult &= BM_PLL_MULT;
0083 mult >>= BP_PLL_MULT;
0084
0085 mfn = readl_relaxed(pll->base + pll->num_offset);
0086 mfd = readl_relaxed(pll->base + pll->denom_offset);
0087 temp64 = parent_rate;
0088 temp64 *= mfn;
0089 do_div(temp64, mfd);
0090
0091 return (parent_rate * mult) + (u32)temp64;
0092 }
0093
0094 static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate,
0095 unsigned long *prate)
0096 {
0097 unsigned long parent_rate = *prate;
0098 unsigned long round_rate, i;
0099 u32 mfn, mfd = DEFAULT_MFD;
0100 bool found = false;
0101 u64 temp64;
0102
0103 for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
0104 round_rate = parent_rate * pllv4_mult_table[i];
0105 if (rate >= round_rate) {
0106 found = true;
0107 break;
0108 }
0109 }
0110
0111 if (!found) {
0112 pr_warn("%s: unable to round rate %lu, parent rate %lu\n",
0113 clk_hw_get_name(hw), rate, parent_rate);
0114 return 0;
0115 }
0116
0117 if (parent_rate <= MAX_MFD)
0118 mfd = parent_rate;
0119
0120 temp64 = (u64)(rate - round_rate);
0121 temp64 *= mfd;
0122 do_div(temp64, parent_rate);
0123 mfn = temp64;
0124
0125
0126
0127
0128
0129
0130
0131 if (mfn >= mfd)
0132 return round_rate;
0133
0134 temp64 = (u64)parent_rate;
0135 temp64 *= mfn;
0136 do_div(temp64, mfd);
0137
0138 return round_rate + (u32)temp64;
0139 }
0140
0141 static bool clk_pllv4_is_valid_mult(unsigned int mult)
0142 {
0143 int i;
0144
0145
0146 for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
0147 if (pllv4_mult_table[i] == mult)
0148 return true;
0149 }
0150
0151 return false;
0152 }
0153
0154 static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate,
0155 unsigned long parent_rate)
0156 {
0157 struct clk_pllv4 *pll = to_clk_pllv4(hw);
0158 u32 val, mult, mfn, mfd = DEFAULT_MFD;
0159 u64 temp64;
0160
0161 mult = rate / parent_rate;
0162
0163 if (!clk_pllv4_is_valid_mult(mult))
0164 return -EINVAL;
0165
0166 if (parent_rate <= MAX_MFD)
0167 mfd = parent_rate;
0168
0169 temp64 = (u64)(rate - mult * parent_rate);
0170 temp64 *= mfd;
0171 do_div(temp64, parent_rate);
0172 mfn = temp64;
0173
0174 val = readl_relaxed(pll->base + pll->cfg_offset);
0175 val &= ~BM_PLL_MULT;
0176 val |= mult << BP_PLL_MULT;
0177 writel_relaxed(val, pll->base + pll->cfg_offset);
0178
0179 writel_relaxed(mfn, pll->base + pll->num_offset);
0180 writel_relaxed(mfd, pll->base + pll->denom_offset);
0181
0182 return 0;
0183 }
0184
0185 static int clk_pllv4_prepare(struct clk_hw *hw)
0186 {
0187 u32 val;
0188 struct clk_pllv4 *pll = to_clk_pllv4(hw);
0189
0190 val = readl_relaxed(pll->base);
0191 val |= PLL_EN;
0192 writel_relaxed(val, pll->base);
0193
0194 return clk_pllv4_wait_lock(pll);
0195 }
0196
0197 static void clk_pllv4_unprepare(struct clk_hw *hw)
0198 {
0199 u32 val;
0200 struct clk_pllv4 *pll = to_clk_pllv4(hw);
0201
0202 val = readl_relaxed(pll->base);
0203 val &= ~PLL_EN;
0204 writel_relaxed(val, pll->base);
0205 }
0206
0207 static const struct clk_ops clk_pllv4_ops = {
0208 .recalc_rate = clk_pllv4_recalc_rate,
0209 .round_rate = clk_pllv4_round_rate,
0210 .set_rate = clk_pllv4_set_rate,
0211 .prepare = clk_pllv4_prepare,
0212 .unprepare = clk_pllv4_unprepare,
0213 .is_prepared = clk_pllv4_is_prepared,
0214 };
0215
0216 struct clk_hw *imx_clk_hw_pllv4(enum imx_pllv4_type type, const char *name,
0217 const char *parent_name, void __iomem *base)
0218 {
0219 struct clk_pllv4 *pll;
0220 struct clk_hw *hw;
0221 struct clk_init_data init;
0222 int ret;
0223
0224 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
0225 if (!pll)
0226 return ERR_PTR(-ENOMEM);
0227
0228 pll->base = base;
0229
0230 if (type == IMX_PLLV4_IMX8ULP) {
0231 pll->cfg_offset = IMX8ULP_PLL_CFG_OFFSET;
0232 pll->num_offset = IMX8ULP_PLL_NUM_OFFSET;
0233 pll->denom_offset = IMX8ULP_PLL_DENOM_OFFSET;
0234 } else {
0235 pll->cfg_offset = PLL_CFG_OFFSET;
0236 pll->num_offset = PLL_NUM_OFFSET;
0237 pll->denom_offset = PLL_DENOM_OFFSET;
0238 }
0239
0240 init.name = name;
0241 init.ops = &clk_pllv4_ops;
0242 init.parent_names = &parent_name;
0243 init.num_parents = 1;
0244 init.flags = CLK_SET_RATE_GATE;
0245
0246 pll->hw.init = &init;
0247
0248 hw = &pll->hw;
0249 ret = clk_hw_register(NULL, hw);
0250 if (ret) {
0251 kfree(pll);
0252 hw = ERR_PTR(ret);
0253 }
0254
0255 return hw;
0256 }
0257 EXPORT_SYMBOL_GPL(imx_clk_hw_pllv4);