1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MVEBU Core divider clock 4 * 5 * Copyright (C) 2013 Marvell 6 * 7 * Ezequiel Garcia <ezequiel.garcia@free-electrons.com> 8 * 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/clk-provider.h> 13 #include <linux/of_address.h> 14 #include <linux/slab.h> 15 #include <linux/delay.h> 16 #include "common.h" 17 18 #define CORE_CLK_DIV_RATIO_MASK 0xff 19 20 /* 21 * This structure describes the hardware details (bit offset and mask) 22 * to configure one particular core divider clock. Those hardware 23 * details may differ from one SoC to another. This structure is 24 * therefore typically instantiated statically to describe the 25 * hardware details. 26 */ 27 struct clk_corediv_desc { 28 unsigned int mask; 29 unsigned int offset; 30 unsigned int fieldbit; 31 }; 32 33 /* 34 * This structure describes the hardware details to configure the core 35 * divider clocks on a given SoC. Amongst others, it points to the 36 * array of core divider clock descriptors for this SoC, as well as 37 * the corresponding operations to manipulate them. 38 */ 39 struct clk_corediv_soc_desc { 40 const struct clk_corediv_desc *descs; 41 unsigned int ndescs; 42 const struct clk_ops ops; 43 u32 ratio_reload; 44 u32 enable_bit_offset; 45 u32 ratio_offset; 46 }; 47 48 /* 49 * This structure represents one core divider clock for the clock 50 * framework, and is dynamically allocated for each core divider clock 51 * existing in the current SoC. 52 */ 53 struct clk_corediv { 54 struct clk_hw hw; 55 void __iomem *reg; 56 const struct clk_corediv_desc *desc; 57 const struct clk_corediv_soc_desc *soc_desc; 58 spinlock_t lock; 59 }; 60 61 static struct clk_onecell_data clk_data; 62 63 /* 64 * Description of the core divider clocks available. For now, we 65 * support only NAND, and it is available at the same register 66 * locations regardless of the SoC. 67 */ 68 static const struct clk_corediv_desc mvebu_corediv_desc[] = { 69 { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ 70 }; 71 72 static const struct clk_corediv_desc mv98dx3236_corediv_desc[] = { 73 { .mask = 0x0f, .offset = 6, .fieldbit = 27 }, /* NAND clock */ 74 }; 75 76 #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw) 77 78 static int clk_corediv_is_enabled(struct clk_hw *hwclk) 79 { 80 struct clk_corediv *corediv = to_corediv_clk(hwclk); 81 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; 82 const struct clk_corediv_desc *desc = corediv->desc; 83 u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset; 84 85 return !!(readl(corediv->reg) & enable_mask); 86 } 87 88 static int clk_corediv_enable(struct clk_hw *hwclk) 89 { 90 struct clk_corediv *corediv = to_corediv_clk(hwclk); 91 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; 92 const struct clk_corediv_desc *desc = corediv->desc; 93 unsigned long flags = 0; 94 u32 reg; 95 96 spin_lock_irqsave(&corediv->lock, flags); 97 98 reg = readl(corediv->reg); 99 reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset); 100 writel(reg, corediv->reg); 101 102 spin_unlock_irqrestore(&corediv->lock, flags); 103 104 return 0; 105 } 106 107 static void clk_corediv_disable(struct clk_hw *hwclk) 108 { 109 struct clk_corediv *corediv = to_corediv_clk(hwclk); 110 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; 111 const struct clk_corediv_desc *desc = corediv->desc; 112 unsigned long flags = 0; 113 u32 reg; 114 115 spin_lock_irqsave(&corediv->lock, flags); 116 117 reg = readl(corediv->reg); 118 reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset); 119 writel(reg, corediv->reg); 120 121 spin_unlock_irqrestore(&corediv->lock, flags); 122 } 123 124 static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk, 125 unsigned long parent_rate) 126 { 127 struct clk_corediv *corediv = to_corediv_clk(hwclk); 128 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; 129 const struct clk_corediv_desc *desc = corediv->desc; 130 u32 reg, div; 131 132 reg = readl(corediv->reg + soc_desc->ratio_offset); 133 div = (reg >> desc->offset) & desc->mask; 134 return parent_rate / div; 135 } 136 137 static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate, 138 unsigned long *parent_rate) 139 { 140 /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */ 141 u32 div; 142 143 div = *parent_rate / rate; 144 if (div < 4) 145 div = 4; 146 else if (div > 6) 147 div = 8; 148 149 return *parent_rate / div; 150 } 151 152 static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, 153 unsigned long parent_rate) 154 { 155 struct clk_corediv *corediv = to_corediv_clk(hwclk); 156 const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; 157 const struct clk_corediv_desc *desc = corediv->desc; 158 unsigned long flags = 0; 159 u32 reg, div; 160 161 div = parent_rate / rate; 162 163 spin_lock_irqsave(&corediv->lock, flags); 164 165 /* Write new divider to the divider ratio register */ 166 reg = readl(corediv->reg + soc_desc->ratio_offset); 167 reg &= ~(desc->mask << desc->offset); 168 reg |= (div & desc->mask) << desc->offset; 169 writel(reg, corediv->reg + soc_desc->ratio_offset); 170 171 /* Set reload-force for this clock */ 172 reg = readl(corediv->reg) | BIT(desc->fieldbit); 173 writel(reg, corediv->reg); 174 175 /* Now trigger the clock update */ 176 reg = readl(corediv->reg) | soc_desc->ratio_reload; 177 writel(reg, corediv->reg); 178 179 /* 180 * Wait for clocks to settle down, and then clear all the 181 * ratios request and the reload request. 182 */ 183 udelay(1000); 184 reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload); 185 writel(reg, corediv->reg); 186 udelay(1000); 187 188 spin_unlock_irqrestore(&corediv->lock, flags); 189 190 return 0; 191 } 192 193 static const struct clk_corediv_soc_desc armada370_corediv_soc = { 194 .descs = mvebu_corediv_desc, 195 .ndescs = ARRAY_SIZE(mvebu_corediv_desc), 196 .ops = { 197 .enable = clk_corediv_enable, 198 .disable = clk_corediv_disable, 199 .is_enabled = clk_corediv_is_enabled, 200 .recalc_rate = clk_corediv_recalc_rate, 201 .round_rate = clk_corediv_round_rate, 202 .set_rate = clk_corediv_set_rate, 203 }, 204 .ratio_reload = BIT(8), 205 .enable_bit_offset = 24, 206 .ratio_offset = 0x8, 207 }; 208 209 static const struct clk_corediv_soc_desc armada380_corediv_soc = { 210 .descs = mvebu_corediv_desc, 211 .ndescs = ARRAY_SIZE(mvebu_corediv_desc), 212 .ops = { 213 .enable = clk_corediv_enable, 214 .disable = clk_corediv_disable, 215 .is_enabled = clk_corediv_is_enabled, 216 .recalc_rate = clk_corediv_recalc_rate, 217 .round_rate = clk_corediv_round_rate, 218 .set_rate = clk_corediv_set_rate, 219 }, 220 .ratio_reload = BIT(8), 221 .enable_bit_offset = 16, 222 .ratio_offset = 0x4, 223 }; 224 225 static const struct clk_corediv_soc_desc armada375_corediv_soc = { 226 .descs = mvebu_corediv_desc, 227 .ndescs = ARRAY_SIZE(mvebu_corediv_desc), 228 .ops = { 229 .recalc_rate = clk_corediv_recalc_rate, 230 .round_rate = clk_corediv_round_rate, 231 .set_rate = clk_corediv_set_rate, 232 }, 233 .ratio_reload = BIT(8), 234 .ratio_offset = 0x4, 235 }; 236 237 static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc = { 238 .descs = mv98dx3236_corediv_desc, 239 .ndescs = ARRAY_SIZE(mv98dx3236_corediv_desc), 240 .ops = { 241 .recalc_rate = clk_corediv_recalc_rate, 242 .round_rate = clk_corediv_round_rate, 243 .set_rate = clk_corediv_set_rate, 244 }, 245 .ratio_reload = BIT(10), 246 .ratio_offset = 0x8, 247 }; 248 249 static void __init 250 mvebu_corediv_clk_init(struct device_node *node, 251 const struct clk_corediv_soc_desc *soc_desc) 252 { 253 struct clk_init_data init; 254 struct clk_corediv *corediv; 255 struct clk **clks; 256 void __iomem *base; 257 const char *parent_name; 258 const char *clk_name; 259 int i; 260 261 base = of_iomap(node, 0); 262 if (WARN_ON(!base)) 263 return; 264 265 parent_name = of_clk_get_parent_name(node, 0); 266 267 clk_data.clk_num = soc_desc->ndescs; 268 269 /* clks holds the clock array */ 270 clks = kcalloc(clk_data.clk_num, sizeof(struct clk *), 271 GFP_KERNEL); 272 if (WARN_ON(!clks)) 273 goto err_unmap; 274 /* corediv holds the clock specific array */ 275 corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv), 276 GFP_KERNEL); 277 if (WARN_ON(!corediv)) 278 goto err_free_clks; 279 280 spin_lock_init(&corediv->lock); 281 282 for (i = 0; i < clk_data.clk_num; i++) { 283 of_property_read_string_index(node, "clock-output-names", 284 i, &clk_name); 285 init.num_parents = 1; 286 init.parent_names = &parent_name; 287 init.name = clk_name; 288 init.ops = &soc_desc->ops; 289 init.flags = 0; 290 291 corediv[i].soc_desc = soc_desc; 292 corediv[i].desc = soc_desc->descs + i; 293 corediv[i].reg = base; 294 corediv[i].hw.init = &init; 295 296 clks[i] = clk_register(NULL, &corediv[i].hw); 297 WARN_ON(IS_ERR(clks[i])); 298 } 299 300 clk_data.clks = clks; 301 of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data); 302 return; 303 304 err_free_clks: 305 kfree(clks); 306 err_unmap: 307 iounmap(base); 308 } 309 310 static void __init armada370_corediv_clk_init(struct device_node *node) 311 { 312 return mvebu_corediv_clk_init(node, &armada370_corediv_soc); 313 } 314 CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock", 315 armada370_corediv_clk_init); 316 317 static void __init armada375_corediv_clk_init(struct device_node *node) 318 { 319 return mvebu_corediv_clk_init(node, &armada375_corediv_soc); 320 } 321 CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock", 322 armada375_corediv_clk_init); 323 324 static void __init armada380_corediv_clk_init(struct device_node *node) 325 { 326 return mvebu_corediv_clk_init(node, &armada380_corediv_soc); 327 } 328 CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock", 329 armada380_corediv_clk_init); 330 331 static void __init mv98dx3236_corediv_clk_init(struct device_node *node) 332 { 333 return mvebu_corediv_clk_init(node, &mv98dx3236_corediv_soc); 334 } 335 CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock", 336 mv98dx3236_corediv_clk_init); 337