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