0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/clk-provider.h>
0013 #include <linux/io.h>
0014 #include <linux/of_address.h>
0015 #include <linux/slab.h>
0016 #include <linux/delay.h>
0017 #include "common.h"
0018
0019 #define CORE_CLK_DIV_RATIO_MASK 0xff
0020
0021
0022
0023
0024
0025
0026
0027
0028 struct clk_corediv_desc {
0029 unsigned int mask;
0030 unsigned int offset;
0031 unsigned int fieldbit;
0032 };
0033
0034
0035
0036
0037
0038
0039
0040 struct clk_corediv_soc_desc {
0041 const struct clk_corediv_desc *descs;
0042 unsigned int ndescs;
0043 const struct clk_ops ops;
0044 u32 ratio_reload;
0045 u32 enable_bit_offset;
0046 u32 ratio_offset;
0047 };
0048
0049
0050
0051
0052
0053
0054 struct clk_corediv {
0055 struct clk_hw hw;
0056 void __iomem *reg;
0057 const struct clk_corediv_desc *desc;
0058 const struct clk_corediv_soc_desc *soc_desc;
0059 spinlock_t lock;
0060 };
0061
0062 static struct clk_onecell_data clk_data;
0063
0064
0065
0066
0067
0068
0069 static const struct clk_corediv_desc mvebu_corediv_desc[] = {
0070 { .mask = 0x3f, .offset = 8, .fieldbit = 1 },
0071 };
0072
0073 static const struct clk_corediv_desc mv98dx3236_corediv_desc[] = {
0074 { .mask = 0x0f, .offset = 6, .fieldbit = 27 },
0075 };
0076
0077 #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw)
0078
0079 static int clk_corediv_is_enabled(struct clk_hw *hwclk)
0080 {
0081 struct clk_corediv *corediv = to_corediv_clk(hwclk);
0082 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0083 const struct clk_corediv_desc *desc = corediv->desc;
0084 u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset;
0085
0086 return !!(readl(corediv->reg) & enable_mask);
0087 }
0088
0089 static int clk_corediv_enable(struct clk_hw *hwclk)
0090 {
0091 struct clk_corediv *corediv = to_corediv_clk(hwclk);
0092 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0093 const struct clk_corediv_desc *desc = corediv->desc;
0094 unsigned long flags = 0;
0095 u32 reg;
0096
0097 spin_lock_irqsave(&corediv->lock, flags);
0098
0099 reg = readl(corediv->reg);
0100 reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
0101 writel(reg, corediv->reg);
0102
0103 spin_unlock_irqrestore(&corediv->lock, flags);
0104
0105 return 0;
0106 }
0107
0108 static void clk_corediv_disable(struct clk_hw *hwclk)
0109 {
0110 struct clk_corediv *corediv = to_corediv_clk(hwclk);
0111 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0112 const struct clk_corediv_desc *desc = corediv->desc;
0113 unsigned long flags = 0;
0114 u32 reg;
0115
0116 spin_lock_irqsave(&corediv->lock, flags);
0117
0118 reg = readl(corediv->reg);
0119 reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
0120 writel(reg, corediv->reg);
0121
0122 spin_unlock_irqrestore(&corediv->lock, flags);
0123 }
0124
0125 static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
0126 unsigned long parent_rate)
0127 {
0128 struct clk_corediv *corediv = to_corediv_clk(hwclk);
0129 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0130 const struct clk_corediv_desc *desc = corediv->desc;
0131 u32 reg, div;
0132
0133 reg = readl(corediv->reg + soc_desc->ratio_offset);
0134 div = (reg >> desc->offset) & desc->mask;
0135 return parent_rate / div;
0136 }
0137
0138 static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate,
0139 unsigned long *parent_rate)
0140 {
0141
0142 u32 div;
0143
0144 div = *parent_rate / rate;
0145 if (div < 4)
0146 div = 4;
0147 else if (div > 6)
0148 div = 8;
0149
0150 return *parent_rate / div;
0151 }
0152
0153 static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
0154 unsigned long parent_rate)
0155 {
0156 struct clk_corediv *corediv = to_corediv_clk(hwclk);
0157 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0158 const struct clk_corediv_desc *desc = corediv->desc;
0159 unsigned long flags = 0;
0160 u32 reg, div;
0161
0162 div = parent_rate / rate;
0163
0164 spin_lock_irqsave(&corediv->lock, flags);
0165
0166
0167 reg = readl(corediv->reg + soc_desc->ratio_offset);
0168 reg &= ~(desc->mask << desc->offset);
0169 reg |= (div & desc->mask) << desc->offset;
0170 writel(reg, corediv->reg + soc_desc->ratio_offset);
0171
0172
0173 reg = readl(corediv->reg) | BIT(desc->fieldbit);
0174 writel(reg, corediv->reg);
0175
0176
0177 reg = readl(corediv->reg) | soc_desc->ratio_reload;
0178 writel(reg, corediv->reg);
0179
0180
0181
0182
0183
0184 udelay(1000);
0185 reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload);
0186 writel(reg, corediv->reg);
0187 udelay(1000);
0188
0189 spin_unlock_irqrestore(&corediv->lock, flags);
0190
0191 return 0;
0192 }
0193
0194 static const struct clk_corediv_soc_desc armada370_corediv_soc = {
0195 .descs = mvebu_corediv_desc,
0196 .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
0197 .ops = {
0198 .enable = clk_corediv_enable,
0199 .disable = clk_corediv_disable,
0200 .is_enabled = clk_corediv_is_enabled,
0201 .recalc_rate = clk_corediv_recalc_rate,
0202 .round_rate = clk_corediv_round_rate,
0203 .set_rate = clk_corediv_set_rate,
0204 },
0205 .ratio_reload = BIT(8),
0206 .enable_bit_offset = 24,
0207 .ratio_offset = 0x8,
0208 };
0209
0210 static const struct clk_corediv_soc_desc armada380_corediv_soc = {
0211 .descs = mvebu_corediv_desc,
0212 .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
0213 .ops = {
0214 .enable = clk_corediv_enable,
0215 .disable = clk_corediv_disable,
0216 .is_enabled = clk_corediv_is_enabled,
0217 .recalc_rate = clk_corediv_recalc_rate,
0218 .round_rate = clk_corediv_round_rate,
0219 .set_rate = clk_corediv_set_rate,
0220 },
0221 .ratio_reload = BIT(8),
0222 .enable_bit_offset = 16,
0223 .ratio_offset = 0x4,
0224 };
0225
0226 static const struct clk_corediv_soc_desc armada375_corediv_soc = {
0227 .descs = mvebu_corediv_desc,
0228 .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
0229 .ops = {
0230 .recalc_rate = clk_corediv_recalc_rate,
0231 .round_rate = clk_corediv_round_rate,
0232 .set_rate = clk_corediv_set_rate,
0233 },
0234 .ratio_reload = BIT(8),
0235 .ratio_offset = 0x4,
0236 };
0237
0238 static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc = {
0239 .descs = mv98dx3236_corediv_desc,
0240 .ndescs = ARRAY_SIZE(mv98dx3236_corediv_desc),
0241 .ops = {
0242 .recalc_rate = clk_corediv_recalc_rate,
0243 .round_rate = clk_corediv_round_rate,
0244 .set_rate = clk_corediv_set_rate,
0245 },
0246 .ratio_reload = BIT(10),
0247 .ratio_offset = 0x8,
0248 };
0249
0250 static void __init
0251 mvebu_corediv_clk_init(struct device_node *node,
0252 const struct clk_corediv_soc_desc *soc_desc)
0253 {
0254 struct clk_init_data init;
0255 struct clk_corediv *corediv;
0256 struct clk **clks;
0257 void __iomem *base;
0258 const char *parent_name;
0259 const char *clk_name;
0260 int i;
0261
0262 base = of_iomap(node, 0);
0263 if (WARN_ON(!base))
0264 return;
0265
0266 parent_name = of_clk_get_parent_name(node, 0);
0267
0268 clk_data.clk_num = soc_desc->ndescs;
0269
0270
0271 clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
0272 GFP_KERNEL);
0273 if (WARN_ON(!clks))
0274 goto err_unmap;
0275
0276 corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv),
0277 GFP_KERNEL);
0278 if (WARN_ON(!corediv))
0279 goto err_free_clks;
0280
0281 spin_lock_init(&corediv->lock);
0282
0283 for (i = 0; i < clk_data.clk_num; i++) {
0284 of_property_read_string_index(node, "clock-output-names",
0285 i, &clk_name);
0286 init.num_parents = 1;
0287 init.parent_names = &parent_name;
0288 init.name = clk_name;
0289 init.ops = &soc_desc->ops;
0290 init.flags = 0;
0291
0292 corediv[i].soc_desc = soc_desc;
0293 corediv[i].desc = soc_desc->descs + i;
0294 corediv[i].reg = base;
0295 corediv[i].hw.init = &init;
0296
0297 clks[i] = clk_register(NULL, &corediv[i].hw);
0298 WARN_ON(IS_ERR(clks[i]));
0299 }
0300
0301 clk_data.clks = clks;
0302 of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
0303 return;
0304
0305 err_free_clks:
0306 kfree(clks);
0307 err_unmap:
0308 iounmap(base);
0309 }
0310
0311 static void __init armada370_corediv_clk_init(struct device_node *node)
0312 {
0313 return mvebu_corediv_clk_init(node, &armada370_corediv_soc);
0314 }
0315 CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock",
0316 armada370_corediv_clk_init);
0317
0318 static void __init armada375_corediv_clk_init(struct device_node *node)
0319 {
0320 return mvebu_corediv_clk_init(node, &armada375_corediv_soc);
0321 }
0322 CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock",
0323 armada375_corediv_clk_init);
0324
0325 static void __init armada380_corediv_clk_init(struct device_node *node)
0326 {
0327 return mvebu_corediv_clk_init(node, &armada380_corediv_soc);
0328 }
0329 CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock",
0330 armada380_corediv_clk_init);
0331
0332 static void __init mv98dx3236_corediv_clk_init(struct device_node *node)
0333 {
0334 return mvebu_corediv_clk_init(node, &mv98dx3236_corediv_soc);
0335 }
0336 CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock",
0337 mv98dx3236_corediv_clk_init);