tcu.c (13173B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * JZ47xx SoCs TCU clocks driver 4 * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net> 5 */ 6 7#include <linux/clk.h> 8#include <linux/clk-provider.h> 9#include <linux/clockchips.h> 10#include <linux/mfd/ingenic-tcu.h> 11#include <linux/mfd/syscon.h> 12#include <linux/regmap.h> 13#include <linux/slab.h> 14#include <linux/syscore_ops.h> 15 16#include <dt-bindings/clock/ingenic,tcu.h> 17 18/* 8 channels max + watchdog + OST */ 19#define TCU_CLK_COUNT 10 20 21#undef pr_fmt 22#define pr_fmt(fmt) "ingenic-tcu-clk: " fmt 23 24enum tcu_clk_parent { 25 TCU_PARENT_PCLK, 26 TCU_PARENT_RTC, 27 TCU_PARENT_EXT, 28}; 29 30struct ingenic_soc_info { 31 unsigned int num_channels; 32 bool has_ost; 33 bool has_tcu_clk; 34 bool allow_missing_tcu_clk; 35}; 36 37struct ingenic_tcu_clk_info { 38 struct clk_init_data init_data; 39 u8 gate_bit; 40 u8 tcsr_reg; 41}; 42 43struct ingenic_tcu_clk { 44 struct clk_hw hw; 45 unsigned int idx; 46 struct ingenic_tcu *tcu; 47 const struct ingenic_tcu_clk_info *info; 48}; 49 50struct ingenic_tcu { 51 const struct ingenic_soc_info *soc_info; 52 struct regmap *map; 53 struct clk *clk; 54 55 struct clk_hw_onecell_data *clocks; 56}; 57 58static struct ingenic_tcu *ingenic_tcu; 59 60static inline struct ingenic_tcu_clk *to_tcu_clk(struct clk_hw *hw) 61{ 62 return container_of(hw, struct ingenic_tcu_clk, hw); 63} 64 65static int ingenic_tcu_enable(struct clk_hw *hw) 66{ 67 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 68 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 69 struct ingenic_tcu *tcu = tcu_clk->tcu; 70 71 regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit)); 72 73 return 0; 74} 75 76static void ingenic_tcu_disable(struct clk_hw *hw) 77{ 78 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 79 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 80 struct ingenic_tcu *tcu = tcu_clk->tcu; 81 82 regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit)); 83} 84 85static int ingenic_tcu_is_enabled(struct clk_hw *hw) 86{ 87 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 88 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 89 unsigned int value; 90 91 regmap_read(tcu_clk->tcu->map, TCU_REG_TSR, &value); 92 93 return !(value & BIT(info->gate_bit)); 94} 95 96static bool ingenic_tcu_enable_regs(struct clk_hw *hw) 97{ 98 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 99 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 100 struct ingenic_tcu *tcu = tcu_clk->tcu; 101 bool enabled = false; 102 103 /* 104 * If the SoC has no global TCU clock, we must ungate the channel's 105 * clock to be able to access its registers. 106 * If we have a TCU clock, it will be enabled automatically as it has 107 * been attached to the regmap. 108 */ 109 if (!tcu->clk) { 110 enabled = !!ingenic_tcu_is_enabled(hw); 111 regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit)); 112 } 113 114 return enabled; 115} 116 117static void ingenic_tcu_disable_regs(struct clk_hw *hw) 118{ 119 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 120 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 121 struct ingenic_tcu *tcu = tcu_clk->tcu; 122 123 if (!tcu->clk) 124 regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit)); 125} 126 127static u8 ingenic_tcu_get_parent(struct clk_hw *hw) 128{ 129 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 130 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 131 unsigned int val = 0; 132 int ret; 133 134 ret = regmap_read(tcu_clk->tcu->map, info->tcsr_reg, &val); 135 WARN_ONCE(ret < 0, "Unable to read TCSR %d", tcu_clk->idx); 136 137 return ffs(val & TCU_TCSR_PARENT_CLOCK_MASK) - 1; 138} 139 140static int ingenic_tcu_set_parent(struct clk_hw *hw, u8 idx) 141{ 142 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 143 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 144 bool was_enabled; 145 int ret; 146 147 was_enabled = ingenic_tcu_enable_regs(hw); 148 149 ret = regmap_update_bits(tcu_clk->tcu->map, info->tcsr_reg, 150 TCU_TCSR_PARENT_CLOCK_MASK, BIT(idx)); 151 WARN_ONCE(ret < 0, "Unable to update TCSR %d", tcu_clk->idx); 152 153 if (!was_enabled) 154 ingenic_tcu_disable_regs(hw); 155 156 return 0; 157} 158 159static unsigned long ingenic_tcu_recalc_rate(struct clk_hw *hw, 160 unsigned long parent_rate) 161{ 162 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 163 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 164 unsigned int prescale; 165 int ret; 166 167 ret = regmap_read(tcu_clk->tcu->map, info->tcsr_reg, &prescale); 168 WARN_ONCE(ret < 0, "Unable to read TCSR %d", tcu_clk->idx); 169 170 prescale = (prescale & TCU_TCSR_PRESCALE_MASK) >> TCU_TCSR_PRESCALE_LSB; 171 172 return parent_rate >> (prescale * 2); 173} 174 175static u8 ingenic_tcu_get_prescale(unsigned long rate, unsigned long req_rate) 176{ 177 u8 prescale; 178 179 for (prescale = 0; prescale < 5; prescale++) 180 if ((rate >> (prescale * 2)) <= req_rate) 181 return prescale; 182 183 return 5; /* /1024 divider */ 184} 185 186static long ingenic_tcu_round_rate(struct clk_hw *hw, unsigned long req_rate, 187 unsigned long *parent_rate) 188{ 189 unsigned long rate = *parent_rate; 190 u8 prescale; 191 192 if (req_rate > rate) 193 return rate; 194 195 prescale = ingenic_tcu_get_prescale(rate, req_rate); 196 197 return rate >> (prescale * 2); 198} 199 200static int ingenic_tcu_set_rate(struct clk_hw *hw, unsigned long req_rate, 201 unsigned long parent_rate) 202{ 203 struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw); 204 const struct ingenic_tcu_clk_info *info = tcu_clk->info; 205 u8 prescale = ingenic_tcu_get_prescale(parent_rate, req_rate); 206 bool was_enabled; 207 int ret; 208 209 was_enabled = ingenic_tcu_enable_regs(hw); 210 211 ret = regmap_update_bits(tcu_clk->tcu->map, info->tcsr_reg, 212 TCU_TCSR_PRESCALE_MASK, 213 prescale << TCU_TCSR_PRESCALE_LSB); 214 WARN_ONCE(ret < 0, "Unable to update TCSR %d", tcu_clk->idx); 215 216 if (!was_enabled) 217 ingenic_tcu_disable_regs(hw); 218 219 return 0; 220} 221 222static const struct clk_ops ingenic_tcu_clk_ops = { 223 .get_parent = ingenic_tcu_get_parent, 224 .set_parent = ingenic_tcu_set_parent, 225 226 .recalc_rate = ingenic_tcu_recalc_rate, 227 .round_rate = ingenic_tcu_round_rate, 228 .set_rate = ingenic_tcu_set_rate, 229 230 .enable = ingenic_tcu_enable, 231 .disable = ingenic_tcu_disable, 232 .is_enabled = ingenic_tcu_is_enabled, 233}; 234 235static const char * const ingenic_tcu_timer_parents[] = { 236 [TCU_PARENT_PCLK] = "pclk", 237 [TCU_PARENT_RTC] = "rtc", 238 [TCU_PARENT_EXT] = "ext", 239}; 240 241#define DEF_TIMER(_name, _gate_bit, _tcsr) \ 242 { \ 243 .init_data = { \ 244 .name = _name, \ 245 .parent_names = ingenic_tcu_timer_parents, \ 246 .num_parents = ARRAY_SIZE(ingenic_tcu_timer_parents),\ 247 .ops = &ingenic_tcu_clk_ops, \ 248 .flags = CLK_SET_RATE_UNGATE, \ 249 }, \ 250 .gate_bit = _gate_bit, \ 251 .tcsr_reg = _tcsr, \ 252 } 253static const struct ingenic_tcu_clk_info ingenic_tcu_clk_info[] = { 254 [TCU_CLK_TIMER0] = DEF_TIMER("timer0", 0, TCU_REG_TCSRc(0)), 255 [TCU_CLK_TIMER1] = DEF_TIMER("timer1", 1, TCU_REG_TCSRc(1)), 256 [TCU_CLK_TIMER2] = DEF_TIMER("timer2", 2, TCU_REG_TCSRc(2)), 257 [TCU_CLK_TIMER3] = DEF_TIMER("timer3", 3, TCU_REG_TCSRc(3)), 258 [TCU_CLK_TIMER4] = DEF_TIMER("timer4", 4, TCU_REG_TCSRc(4)), 259 [TCU_CLK_TIMER5] = DEF_TIMER("timer5", 5, TCU_REG_TCSRc(5)), 260 [TCU_CLK_TIMER6] = DEF_TIMER("timer6", 6, TCU_REG_TCSRc(6)), 261 [TCU_CLK_TIMER7] = DEF_TIMER("timer7", 7, TCU_REG_TCSRc(7)), 262}; 263 264static const struct ingenic_tcu_clk_info ingenic_tcu_watchdog_clk_info = 265 DEF_TIMER("wdt", 16, TCU_REG_WDT_TCSR); 266static const struct ingenic_tcu_clk_info ingenic_tcu_ost_clk_info = 267 DEF_TIMER("ost", 15, TCU_REG_OST_TCSR); 268#undef DEF_TIMER 269 270static int __init ingenic_tcu_register_clock(struct ingenic_tcu *tcu, 271 unsigned int idx, enum tcu_clk_parent parent, 272 const struct ingenic_tcu_clk_info *info, 273 struct clk_hw_onecell_data *clocks) 274{ 275 struct ingenic_tcu_clk *tcu_clk; 276 int err; 277 278 tcu_clk = kzalloc(sizeof(*tcu_clk), GFP_KERNEL); 279 if (!tcu_clk) 280 return -ENOMEM; 281 282 tcu_clk->hw.init = &info->init_data; 283 tcu_clk->idx = idx; 284 tcu_clk->info = info; 285 tcu_clk->tcu = tcu; 286 287 /* Reset channel and clock divider, set default parent */ 288 ingenic_tcu_enable_regs(&tcu_clk->hw); 289 regmap_update_bits(tcu->map, info->tcsr_reg, 0xffff, BIT(parent)); 290 ingenic_tcu_disable_regs(&tcu_clk->hw); 291 292 err = clk_hw_register(NULL, &tcu_clk->hw); 293 if (err) { 294 kfree(tcu_clk); 295 return err; 296 } 297 298 clocks->hws[idx] = &tcu_clk->hw; 299 300 return 0; 301} 302 303static const struct ingenic_soc_info jz4740_soc_info = { 304 .num_channels = 8, 305 .has_ost = false, 306 .has_tcu_clk = true, 307}; 308 309static const struct ingenic_soc_info jz4725b_soc_info = { 310 .num_channels = 6, 311 .has_ost = true, 312 .has_tcu_clk = true, 313}; 314 315static const struct ingenic_soc_info jz4770_soc_info = { 316 .num_channels = 8, 317 .has_ost = true, 318 .has_tcu_clk = false, 319}; 320 321static const struct ingenic_soc_info x1000_soc_info = { 322 .num_channels = 8, 323 .has_ost = false, /* X1000 has OST, but it not belong TCU */ 324 .has_tcu_clk = true, 325 .allow_missing_tcu_clk = true, 326}; 327 328static const struct of_device_id __maybe_unused ingenic_tcu_of_match[] __initconst = { 329 { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, }, 330 { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, }, 331 { .compatible = "ingenic,jz4760-tcu", .data = &jz4770_soc_info, }, 332 { .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, }, 333 { .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, }, 334 { /* sentinel */ } 335}; 336 337static int __init ingenic_tcu_probe(struct device_node *np) 338{ 339 const struct of_device_id *id = of_match_node(ingenic_tcu_of_match, np); 340 struct ingenic_tcu *tcu; 341 struct regmap *map; 342 unsigned int i; 343 int ret; 344 345 map = device_node_to_regmap(np); 346 if (IS_ERR(map)) 347 return PTR_ERR(map); 348 349 tcu = kzalloc(sizeof(*tcu), GFP_KERNEL); 350 if (!tcu) 351 return -ENOMEM; 352 353 tcu->map = map; 354 tcu->soc_info = id->data; 355 356 if (tcu->soc_info->has_tcu_clk) { 357 tcu->clk = of_clk_get_by_name(np, "tcu"); 358 if (IS_ERR(tcu->clk)) { 359 ret = PTR_ERR(tcu->clk); 360 361 /* 362 * Old device trees for some SoCs did not include the 363 * TCU clock because this driver (incorrectly) didn't 364 * use it. In this case we complain loudly and attempt 365 * to continue without the clock, which might work if 366 * booting with workarounds like "clk_ignore_unused". 367 */ 368 if (tcu->soc_info->allow_missing_tcu_clk && ret == -EINVAL) { 369 pr_warn("TCU clock missing from device tree, please update your device tree\n"); 370 tcu->clk = NULL; 371 } else { 372 pr_crit("Cannot get TCU clock from device tree\n"); 373 goto err_free_tcu; 374 } 375 } else { 376 ret = clk_prepare_enable(tcu->clk); 377 if (ret) { 378 pr_crit("Unable to enable TCU clock\n"); 379 goto err_put_clk; 380 } 381 } 382 } 383 384 tcu->clocks = kzalloc(struct_size(tcu->clocks, hws, TCU_CLK_COUNT), 385 GFP_KERNEL); 386 if (!tcu->clocks) { 387 ret = -ENOMEM; 388 goto err_clk_disable; 389 } 390 391 tcu->clocks->num = TCU_CLK_COUNT; 392 393 for (i = 0; i < tcu->soc_info->num_channels; i++) { 394 ret = ingenic_tcu_register_clock(tcu, i, TCU_PARENT_EXT, 395 &ingenic_tcu_clk_info[i], 396 tcu->clocks); 397 if (ret) { 398 pr_crit("cannot register clock %d\n", i); 399 goto err_unregister_timer_clocks; 400 } 401 } 402 403 /* 404 * We set EXT as the default parent clock for all the TCU clocks 405 * except for the watchdog one, where we set the RTC clock as the 406 * parent. Since the EXT and PCLK are much faster than the RTC clock, 407 * the watchdog would kick after a maximum time of 5s, and we might 408 * want a slower kicking time. 409 */ 410 ret = ingenic_tcu_register_clock(tcu, TCU_CLK_WDT, TCU_PARENT_RTC, 411 &ingenic_tcu_watchdog_clk_info, 412 tcu->clocks); 413 if (ret) { 414 pr_crit("cannot register watchdog clock\n"); 415 goto err_unregister_timer_clocks; 416 } 417 418 if (tcu->soc_info->has_ost) { 419 ret = ingenic_tcu_register_clock(tcu, TCU_CLK_OST, 420 TCU_PARENT_EXT, 421 &ingenic_tcu_ost_clk_info, 422 tcu->clocks); 423 if (ret) { 424 pr_crit("cannot register ost clock\n"); 425 goto err_unregister_watchdog_clock; 426 } 427 } 428 429 ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, tcu->clocks); 430 if (ret) { 431 pr_crit("cannot add OF clock provider\n"); 432 goto err_unregister_ost_clock; 433 } 434 435 ingenic_tcu = tcu; 436 437 return 0; 438 439err_unregister_ost_clock: 440 if (tcu->soc_info->has_ost) 441 clk_hw_unregister(tcu->clocks->hws[i + 1]); 442err_unregister_watchdog_clock: 443 clk_hw_unregister(tcu->clocks->hws[i]); 444err_unregister_timer_clocks: 445 for (i = 0; i < tcu->clocks->num; i++) 446 if (tcu->clocks->hws[i]) 447 clk_hw_unregister(tcu->clocks->hws[i]); 448 kfree(tcu->clocks); 449err_clk_disable: 450 if (tcu->clk) 451 clk_disable_unprepare(tcu->clk); 452err_put_clk: 453 if (tcu->clk) 454 clk_put(tcu->clk); 455err_free_tcu: 456 kfree(tcu); 457 return ret; 458} 459 460static int __maybe_unused tcu_pm_suspend(void) 461{ 462 struct ingenic_tcu *tcu = ingenic_tcu; 463 464 if (tcu->clk) 465 clk_disable(tcu->clk); 466 467 return 0; 468} 469 470static void __maybe_unused tcu_pm_resume(void) 471{ 472 struct ingenic_tcu *tcu = ingenic_tcu; 473 474 if (tcu->clk) 475 clk_enable(tcu->clk); 476} 477 478static struct syscore_ops __maybe_unused tcu_pm_ops = { 479 .suspend = tcu_pm_suspend, 480 .resume = tcu_pm_resume, 481}; 482 483static void __init ingenic_tcu_init(struct device_node *np) 484{ 485 int ret = ingenic_tcu_probe(np); 486 487 if (ret) 488 pr_crit("Failed to initialize TCU clocks: %d\n", ret); 489 490 if (IS_ENABLED(CONFIG_PM_SLEEP)) 491 register_syscore_ops(&tcu_pm_ops); 492} 493 494CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init); 495CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", ingenic_tcu_init); 496CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-tcu", ingenic_tcu_init); 497CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", ingenic_tcu_init); 498CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", ingenic_tcu_init);