1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2014 MundoReader S.L. 4 * Author: Heiko Stuebner <heiko@sntech.de> 5 * 6 * Copyright (c) 2016 Rockchip Electronics Co. Ltd. 7 * Author: Xing Zheng <zhengxing@rock-chips.com> 8 * 9 * based on 10 * 11 * samsung/clk.c 12 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 13 * Copyright (c) 2013 Linaro Ltd. 14 * Author: Thomas Abraham <thomas.ab@samsung.com> 15 */ 16 17 #include <linux/slab.h> 18 #include <linux/clk.h> 19 #include <linux/clk-provider.h> 20 #include <linux/io.h> 21 #include <linux/mfd/syscon.h> 22 #include <linux/platform_device.h> 23 #include <linux/regmap.h> 24 #include <linux/reboot.h> 25 26 #include "../clk-fractional-divider.h" 27 #include "clk.h" 28 29 /* 30 * Register a clock branch. 31 * Most clock branches have a form like 32 * 33 * src1 --|--\ 34 * |M |--[GATE]-[DIV]- 35 * src2 --|--/ 36 * 37 * sometimes without one of those components. 38 */ 39 static struct clk *rockchip_clk_register_branch(const char *name, 40 const char *const *parent_names, u8 num_parents, 41 void __iomem *base, 42 int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, 43 u32 *mux_table, 44 int div_offset, u8 div_shift, u8 div_width, u8 div_flags, 45 struct clk_div_table *div_table, int gate_offset, 46 u8 gate_shift, u8 gate_flags, unsigned long flags, 47 spinlock_t *lock) 48 { 49 struct clk_hw *hw; 50 struct clk_mux *mux = NULL; 51 struct clk_gate *gate = NULL; 52 struct clk_divider *div = NULL; 53 const struct clk_ops *mux_ops = NULL, *div_ops = NULL, 54 *gate_ops = NULL; 55 int ret; 56 57 if (num_parents > 1) { 58 mux = kzalloc_obj(*mux); 59 if (!mux) 60 return ERR_PTR(-ENOMEM); 61 62 mux->reg = base + muxdiv_offset; 63 mux->shift = mux_shift; 64 mux->mask = BIT(mux_width) - 1; 65 mux->flags = mux_flags; 66 mux->table = mux_table; 67 mux->lock = lock; 68 mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops 69 : &clk_mux_ops; 70 } 71 72 if (gate_offset >= 0) { 73 gate = kzalloc_obj(*gate); 74 if (!gate) { 75 ret = -ENOMEM; 76 goto err_gate; 77 } 78 79 gate->flags = gate_flags; 80 gate->reg = base + gate_offset; 81 gate->bit_idx = gate_shift; 82 gate->lock = lock; 83 gate_ops = &clk_gate_ops; 84 } 85 86 if (div_width > 0) { 87 div = kzalloc_obj(*div); 88 if (!div) { 89 ret = -ENOMEM; 90 goto err_div; 91 } 92 93 div->flags = div_flags; 94 if (div_offset) 95 div->reg = base + div_offset; 96 else 97 div->reg = base + muxdiv_offset; 98 div->shift = div_shift; 99 div->width = div_width; 100 div->lock = lock; 101 div->table = div_table; 102 div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) 103 ? &clk_divider_ro_ops 104 : &clk_divider_ops; 105 } 106 107 hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, 108 mux ? &mux->hw : NULL, mux_ops, 109 div ? &div->hw : NULL, div_ops, 110 gate ? &gate->hw : NULL, gate_ops, 111 flags); 112 if (IS_ERR(hw)) { 113 kfree(div); 114 kfree(gate); 115 return ERR_CAST(hw); 116 } 117 118 return hw->clk; 119 err_div: 120 kfree(gate); 121 err_gate: 122 kfree(mux); 123 return ERR_PTR(ret); 124 } 125 126 struct rockchip_clk_frac { 127 struct notifier_block clk_nb; 128 struct clk_fractional_divider div; 129 struct clk_gate gate; 130 131 struct clk_mux mux; 132 const struct clk_ops *mux_ops; 133 int mux_frac_idx; 134 135 bool rate_change_remuxed; 136 int rate_change_idx; 137 }; 138 139 #define to_rockchip_clk_frac_nb(nb) \ 140 container_of(nb, struct rockchip_clk_frac, clk_nb) 141 142 static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb, 143 unsigned long event, void *data) 144 { 145 struct clk_notifier_data *ndata = data; 146 struct rockchip_clk_frac *frac = to_rockchip_clk_frac_nb(nb); 147 struct clk_mux *frac_mux = &frac->mux; 148 int ret = 0; 149 150 pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n", 151 __func__, event, ndata->old_rate, ndata->new_rate); 152 if (event == PRE_RATE_CHANGE) { 153 frac->rate_change_idx = 154 frac->mux_ops->get_parent(&frac_mux->hw); 155 if (frac->rate_change_idx != frac->mux_frac_idx) { 156 frac->mux_ops->set_parent(&frac_mux->hw, 157 frac->mux_frac_idx); 158 frac->rate_change_remuxed = 1; 159 } 160 } else if (event == POST_RATE_CHANGE) { 161 /* 162 * The POST_RATE_CHANGE notifier runs directly after the 163 * divider clock is set in clk_change_rate, so we'll have 164 * remuxed back to the original parent before clk_change_rate 165 * reaches the mux itself. 166 */ 167 if (frac->rate_change_remuxed) { 168 frac->mux_ops->set_parent(&frac_mux->hw, 169 frac->rate_change_idx); 170 frac->rate_change_remuxed = 0; 171 } 172 } 173 174 return notifier_from_errno(ret); 175 } 176 177 /* 178 * fractional divider must set that denominator is 20 times larger than 179 * numerator to generate precise clock frequency. 180 */ 181 static void rockchip_fractional_approximation(struct clk_hw *hw, 182 unsigned long rate, unsigned long *parent_rate, 183 unsigned long *m, unsigned long *n) 184 { 185 struct clk_fractional_divider *fd = to_clk_fd(hw); 186 unsigned long p_rate, p_parent_rate; 187 struct clk_hw *p_parent; 188 189 p_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); 190 if ((rate * 20 > p_rate) && (p_rate % rate != 0)) { 191 p_parent = clk_hw_get_parent(clk_hw_get_parent(hw)); 192 p_parent_rate = clk_hw_get_rate(p_parent); 193 *parent_rate = p_parent_rate; 194 } 195 196 fd->flags |= CLK_FRAC_DIVIDER_POWER_OF_TWO_PS; 197 198 clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n); 199 } 200 201 static struct clk *rockchip_clk_register_frac_branch( 202 struct rockchip_clk_provider *ctx, const char *name, 203 const char *const *parent_names, u8 num_parents, 204 void __iomem *base, int muxdiv_offset, u8 div_flags, 205 int gate_offset, u8 gate_shift, u8 gate_flags, 206 unsigned long flags, struct rockchip_clk_branch *child, 207 spinlock_t *lock) 208 { 209 struct clk_hw *hw; 210 struct rockchip_clk_frac *frac; 211 struct clk_gate *gate = NULL; 212 struct clk_fractional_divider *div = NULL; 213 const struct clk_ops *div_ops = NULL, *gate_ops = NULL; 214 215 if (muxdiv_offset < 0) 216 return ERR_PTR(-EINVAL); 217 218 if (child && child->branch_type != branch_mux) { 219 pr_err("%s: fractional child clock for %s can only be a mux\n", 220 __func__, name); 221 return ERR_PTR(-EINVAL); 222 } 223 224 frac = kzalloc_obj(*frac); 225 if (!frac) 226 return ERR_PTR(-ENOMEM); 227 228 if (gate_offset >= 0) { 229 gate = &frac->gate; 230 gate->flags = gate_flags; 231 gate->reg = base + gate_offset; 232 gate->bit_idx = gate_shift; 233 gate->lock = lock; 234 gate_ops = &clk_gate_ops; 235 } 236 237 div = &frac->div; 238 div->flags = div_flags; 239 div->reg = base + muxdiv_offset; 240 div->mshift = 16; 241 div->mwidth = 16; 242 div->nshift = 0; 243 div->nwidth = 16; 244 div->lock = lock; 245 div->approximation = rockchip_fractional_approximation; 246 div_ops = &clk_fractional_divider_ops; 247 248 hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, 249 NULL, NULL, 250 &div->hw, div_ops, 251 gate ? &gate->hw : NULL, gate_ops, 252 flags | CLK_SET_RATE_UNGATE); 253 if (IS_ERR(hw)) { 254 kfree(frac); 255 return ERR_CAST(hw); 256 } 257 258 if (child) { 259 struct clk_mux *frac_mux = &frac->mux; 260 struct clk_init_data init; 261 struct clk *mux_clk; 262 int ret; 263 264 frac->mux_frac_idx = match_string(child->parent_names, 265 child->num_parents, name); 266 frac->mux_ops = &clk_mux_ops; 267 frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb; 268 269 frac_mux->reg = base + child->muxdiv_offset; 270 frac_mux->shift = child->mux_shift; 271 frac_mux->mask = BIT(child->mux_width) - 1; 272 frac_mux->flags = child->mux_flags; 273 if (child->mux_table) 274 frac_mux->table = child->mux_table; 275 frac_mux->lock = lock; 276 frac_mux->hw.init = &init; 277 278 init.name = child->name; 279 init.flags = child->flags | CLK_SET_RATE_PARENT; 280 init.ops = frac->mux_ops; 281 init.parent_names = child->parent_names; 282 init.num_parents = child->num_parents; 283 284 mux_clk = clk_register(NULL, &frac_mux->hw); 285 if (IS_ERR(mux_clk)) { 286 kfree(frac); 287 return mux_clk; 288 } 289 290 rockchip_clk_set_lookup(ctx, mux_clk, child->id); 291 292 /* notifier on the fraction divider to catch rate changes */ 293 if (frac->mux_frac_idx >= 0) { 294 pr_debug("%s: found fractional parent in mux at pos %d\n", 295 __func__, frac->mux_frac_idx); 296 ret = clk_notifier_register(hw->clk, &frac->clk_nb); 297 if (ret) 298 pr_err("%s: failed to register clock notifier for %s\n", 299 __func__, name); 300 } else { 301 pr_warn("%s: could not find %s as parent of %s, rate changes may not work\n", 302 __func__, name, child->name); 303 } 304 } 305 306 return hw->clk; 307 } 308 309 static struct clk *rockchip_clk_register_factor_branch(const char *name, 310 const char *const *parent_names, u8 num_parents, 311 void __iomem *base, unsigned int mult, unsigned int div, 312 int gate_offset, u8 gate_shift, u8 gate_flags, 313 unsigned long flags, spinlock_t *lock) 314 { 315 struct clk_hw *hw; 316 struct clk_gate *gate = NULL; 317 struct clk_fixed_factor *fix = NULL; 318 319 /* without gate, register a simple factor clock */ 320 if (gate_offset == 0) { 321 return clk_register_fixed_factor(NULL, name, 322 parent_names[0], flags, mult, 323 div); 324 } 325 326 gate = kzalloc_obj(*gate); 327 if (!gate) 328 return ERR_PTR(-ENOMEM); 329 330 gate->flags = gate_flags; 331 gate->reg = base + gate_offset; 332 gate->bit_idx = gate_shift; 333 gate->lock = lock; 334 335 fix = kzalloc_obj(*fix); 336 if (!fix) { 337 kfree(gate); 338 return ERR_PTR(-ENOMEM); 339 } 340 341 fix->mult = mult; 342 fix->div = div; 343 344 hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, 345 NULL, NULL, 346 &fix->hw, &clk_fixed_factor_ops, 347 &gate->hw, &clk_gate_ops, flags); 348 if (IS_ERR(hw)) { 349 kfree(fix); 350 kfree(gate); 351 return ERR_CAST(hw); 352 } 353 354 return hw->clk; 355 } 356 357 static struct rockchip_clk_provider *rockchip_clk_init_base( 358 struct device_node *np, void __iomem *base, 359 unsigned long nr_clks, bool has_late_clocks) 360 { 361 struct rockchip_clk_provider *ctx; 362 struct clk **clk_table; 363 struct clk *default_clk_val; 364 int i; 365 366 default_clk_val = ERR_PTR(has_late_clocks ? -EPROBE_DEFER : -ENOENT); 367 368 ctx = kzalloc_obj(struct rockchip_clk_provider); 369 if (!ctx) 370 return ERR_PTR(-ENOMEM); 371 372 clk_table = kzalloc_objs(struct clk *, nr_clks); 373 if (!clk_table) 374 goto err_free; 375 376 for (i = 0; i < nr_clks; ++i) 377 clk_table[i] = default_clk_val; 378 379 ctx->reg_base = base; 380 ctx->clk_data.clks = clk_table; 381 ctx->clk_data.clk_num = nr_clks; 382 ctx->cru_node = np; 383 spin_lock_init(&ctx->lock); 384 385 hash_init(ctx->aux_grf_table); 386 387 ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node, 388 "rockchip,grf"); 389 390 return ctx; 391 392 err_free: 393 kfree(ctx); 394 return ERR_PTR(-ENOMEM); 395 } 396 397 struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, 398 void __iomem *base, 399 unsigned long nr_clks) 400 { 401 return rockchip_clk_init_base(np, base, nr_clks, false); 402 } 403 EXPORT_SYMBOL_GPL(rockchip_clk_init); 404 405 struct rockchip_clk_provider *rockchip_clk_init_early(struct device_node *np, 406 void __iomem *base, 407 unsigned long nr_clks) 408 { 409 return rockchip_clk_init_base(np, base, nr_clks, true); 410 } 411 EXPORT_SYMBOL_GPL(rockchip_clk_init_early); 412 413 void rockchip_clk_finalize(struct rockchip_clk_provider *ctx) 414 { 415 int i; 416 417 for (i = 0; i < ctx->clk_data.clk_num; ++i) 418 if (ctx->clk_data.clks[i] == ERR_PTR(-EPROBE_DEFER)) 419 ctx->clk_data.clks[i] = ERR_PTR(-ENOENT); 420 } 421 EXPORT_SYMBOL_GPL(rockchip_clk_finalize); 422 423 void rockchip_clk_of_add_provider(struct device_node *np, 424 struct rockchip_clk_provider *ctx) 425 { 426 if (of_clk_add_provider(np, of_clk_src_onecell_get, 427 &ctx->clk_data)) 428 pr_err("%s: could not register clk provider\n", __func__); 429 } 430 EXPORT_SYMBOL_GPL(rockchip_clk_of_add_provider); 431 432 int rockchip_clk_add_grf(struct rockchip_clk_provider *ctx, 433 struct regmap *grf, 434 enum rockchip_grf_type type) 435 { 436 struct rockchip_aux_grf *aux_grf; 437 438 aux_grf = kzalloc_obj(*aux_grf); 439 if (!aux_grf) 440 return -ENOMEM; 441 442 aux_grf->grf = grf; 443 aux_grf->type = type; 444 hash_add(ctx->aux_grf_table, &aux_grf->node, type); 445 446 return 0; 447 } 448 EXPORT_SYMBOL_GPL(rockchip_clk_add_grf); 449 450 void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, 451 struct rockchip_pll_clock *list, 452 unsigned int nr_pll, int grf_lock_offset) 453 { 454 struct clk *clk; 455 int idx; 456 457 for (idx = 0; idx < nr_pll; idx++, list++) { 458 clk = rockchip_clk_register_pll(ctx, list->type, list->name, 459 list->parent_names, list->num_parents, 460 list->con_offset, grf_lock_offset, 461 list->lock_shift, list->mode_offset, 462 list->mode_shift, list->rate_table, 463 list->flags, list->pll_flags); 464 if (IS_ERR(clk)) { 465 pr_err("%s: failed to register clock %s\n", __func__, 466 list->name); 467 continue; 468 } 469 470 rockchip_clk_set_lookup(ctx, clk, list->id); 471 } 472 } 473 EXPORT_SYMBOL_GPL(rockchip_clk_register_plls); 474 475 unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list, 476 unsigned int nr_clk) 477 { 478 unsigned long max = 0; 479 unsigned int idx; 480 481 for (idx = 0; idx < nr_clk; idx++, list++) { 482 if (list->id > max) 483 max = list->id; 484 if (list->child && list->child->id > max) 485 max = list->child->id; 486 } 487 488 return max; 489 } 490 EXPORT_SYMBOL_GPL(rockchip_clk_find_max_clk_id); 491 492 static struct platform_device *rockchip_clk_register_gate_link( 493 struct device *parent_dev, 494 struct rockchip_clk_provider *ctx, 495 struct rockchip_clk_branch *clkbr) 496 { 497 struct rockchip_gate_link_platdata gate_link_pdata = { 498 .ctx = ctx, 499 .clkbr = clkbr, 500 }; 501 502 struct platform_device_info pdevinfo = { 503 .parent = parent_dev, 504 .name = "rockchip-gate-link-clk", 505 .id = clkbr->id, 506 .fwnode = dev_fwnode(parent_dev), 507 .of_node_reused = true, 508 .data = &gate_link_pdata, 509 .size_data = sizeof(gate_link_pdata), 510 }; 511 512 return platform_device_register_full(&pdevinfo); 513 } 514 515 void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, 516 struct rockchip_clk_branch *list, 517 unsigned int nr_clk) 518 { 519 struct regmap *grf = ctx->grf; 520 struct rockchip_aux_grf *agrf; 521 struct clk *clk; 522 unsigned int idx; 523 unsigned long flags; 524 525 for (idx = 0; idx < nr_clk; idx++, list++) { 526 flags = list->flags; 527 clk = NULL; 528 529 /* for GRF-dependent branches, choose the right grf first */ 530 if (list->branch_type == branch_grf_mux || 531 list->branch_type == branch_grf_gate || 532 list->branch_type == branch_grf_mmc) { 533 hash_for_each_possible(ctx->aux_grf_table, agrf, node, list->grf_type) { 534 if (agrf->type == list->grf_type) { 535 grf = agrf->grf; 536 break; 537 } 538 } 539 } 540 541 /* catch simple muxes */ 542 switch (list->branch_type) { 543 case branch_mux: 544 if (list->mux_table) 545 clk = clk_register_mux_table(NULL, list->name, 546 list->parent_names, list->num_parents, 547 flags, 548 ctx->reg_base + list->muxdiv_offset, 549 list->mux_shift, list->mux_width, 550 list->mux_flags, list->mux_table, 551 &ctx->lock); 552 else 553 clk = clk_register_mux(NULL, list->name, 554 list->parent_names, list->num_parents, 555 flags, 556 ctx->reg_base + list->muxdiv_offset, 557 list->mux_shift, list->mux_width, 558 list->mux_flags, &ctx->lock); 559 break; 560 case branch_grf_mux: 561 clk = rockchip_clk_register_muxgrf(list->name, 562 list->parent_names, list->num_parents, 563 flags, grf, list->muxdiv_offset, 564 list->mux_shift, list->mux_width, 565 list->mux_flags); 566 break; 567 case branch_divider: 568 if (list->div_table) 569 clk = clk_register_divider_table(NULL, 570 list->name, list->parent_names[0], 571 flags, 572 ctx->reg_base + list->muxdiv_offset, 573 list->div_shift, list->div_width, 574 list->div_flags, list->div_table, 575 &ctx->lock); 576 else 577 clk = clk_register_divider(NULL, list->name, 578 list->parent_names[0], flags, 579 ctx->reg_base + list->muxdiv_offset, 580 list->div_shift, list->div_width, 581 list->div_flags, &ctx->lock); 582 break; 583 case branch_fraction_divider: 584 clk = rockchip_clk_register_frac_branch(ctx, list->name, 585 list->parent_names, list->num_parents, 586 ctx->reg_base, list->muxdiv_offset, 587 list->div_flags, 588 list->gate_offset, list->gate_shift, 589 list->gate_flags, flags, list->child, 590 &ctx->lock); 591 break; 592 case branch_half_divider: 593 clk = rockchip_clk_register_halfdiv(list->name, 594 list->parent_names, list->num_parents, 595 ctx->reg_base, list->muxdiv_offset, 596 list->mux_shift, list->mux_width, 597 list->mux_flags, list->div_shift, 598 list->div_width, list->div_flags, 599 list->gate_offset, list->gate_shift, 600 list->gate_flags, flags, &ctx->lock); 601 break; 602 case branch_gate: 603 flags |= CLK_SET_RATE_PARENT; 604 605 clk = clk_register_gate(NULL, list->name, 606 list->parent_names[0], flags, 607 ctx->reg_base + list->gate_offset, 608 list->gate_shift, list->gate_flags, &ctx->lock); 609 break; 610 case branch_grf_gate: 611 flags |= CLK_SET_RATE_PARENT; 612 clk = rockchip_clk_register_gate_grf(list->name, 613 list->parent_names[0], flags, grf, 614 list->gate_offset, list->gate_shift, 615 list->gate_flags); 616 break; 617 case branch_composite: 618 clk = rockchip_clk_register_branch(list->name, 619 list->parent_names, list->num_parents, 620 ctx->reg_base, list->muxdiv_offset, 621 list->mux_shift, 622 list->mux_width, list->mux_flags, 623 list->mux_table, list->div_offset, 624 list->div_shift, list->div_width, 625 list->div_flags, list->div_table, 626 list->gate_offset, list->gate_shift, 627 list->gate_flags, flags, &ctx->lock); 628 break; 629 case branch_mmc: 630 clk = rockchip_clk_register_mmc( 631 list->name, 632 list->parent_names, list->num_parents, 633 ctx->reg_base + list->muxdiv_offset, 634 NULL, 0, 635 list->div_shift 636 ); 637 break; 638 case branch_grf_mmc: 639 clk = rockchip_clk_register_mmc( 640 list->name, 641 list->parent_names, list->num_parents, 642 NULL, 643 grf, list->muxdiv_offset, 644 list->div_shift 645 ); 646 break; 647 case branch_inverter: 648 clk = rockchip_clk_register_inverter( 649 list->name, list->parent_names, 650 list->num_parents, 651 ctx->reg_base + list->muxdiv_offset, 652 list->div_shift, list->div_flags, &ctx->lock); 653 break; 654 case branch_factor: 655 clk = rockchip_clk_register_factor_branch( 656 list->name, list->parent_names, 657 list->num_parents, ctx->reg_base, 658 list->div_shift, list->div_width, 659 list->gate_offset, list->gate_shift, 660 list->gate_flags, flags, &ctx->lock); 661 break; 662 case branch_ddrclk: 663 clk = rockchip_clk_register_ddrclk( 664 list->name, list->flags, 665 list->parent_names, list->num_parents, 666 list->muxdiv_offset, list->mux_shift, 667 list->mux_width, list->div_shift, 668 list->div_width, list->div_flags, 669 ctx->reg_base, &ctx->lock); 670 break; 671 case branch_linked_gate: 672 /* must be registered late, fall-through for error message */ 673 break; 674 } 675 676 /* none of the cases above matched */ 677 if (!clk) { 678 pr_err("%s: unknown clock type %d\n", 679 __func__, list->branch_type); 680 continue; 681 } 682 683 if (IS_ERR(clk)) { 684 pr_err("%s: failed to register clock %s: %ld\n", 685 __func__, list->name, PTR_ERR(clk)); 686 continue; 687 } 688 689 rockchip_clk_set_lookup(ctx, clk, list->id); 690 } 691 } 692 EXPORT_SYMBOL_GPL(rockchip_clk_register_branches); 693 694 void rockchip_clk_register_late_branches(struct device *dev, 695 struct rockchip_clk_provider *ctx, 696 struct rockchip_clk_branch *list, 697 unsigned int nr_clk) 698 { 699 unsigned int idx; 700 701 for (idx = 0; idx < nr_clk; idx++, list++) { 702 struct platform_device *pdev = NULL; 703 704 switch (list->branch_type) { 705 case branch_linked_gate: 706 pdev = rockchip_clk_register_gate_link(dev, ctx, list); 707 break; 708 default: 709 dev_err(dev, "unknown clock type %d\n", list->branch_type); 710 break; 711 } 712 713 if (IS_ERR_OR_NULL(pdev)) 714 dev_err(dev, "failed to register device for clock %s\n", list->name); 715 } 716 } 717 EXPORT_SYMBOL_GPL(rockchip_clk_register_late_branches); 718 719 void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, 720 unsigned int lookup_id, 721 const char *name, const char *const *parent_names, 722 u8 num_parents, 723 const struct rockchip_cpuclk_reg_data *reg_data, 724 const struct rockchip_cpuclk_rate_table *rates, 725 int nrates) 726 { 727 struct clk *clk; 728 729 clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents, 730 reg_data, rates, nrates, 731 ctx->reg_base, &ctx->lock); 732 if (IS_ERR(clk)) { 733 pr_err("%s: failed to register clock %s: %ld\n", 734 __func__, name, PTR_ERR(clk)); 735 return; 736 } 737 738 rockchip_clk_set_lookup(ctx, clk, lookup_id); 739 } 740 EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk); 741 742 void rockchip_clk_register_armclk_multi_pll(struct rockchip_clk_provider *ctx, 743 struct rockchip_clk_branch *list, 744 const struct rockchip_cpuclk_rate_table *rates, 745 int nrates) 746 { 747 struct clk *clk; 748 749 clk = rockchip_clk_register_cpuclk_multi_pll(list->name, list->parent_names, 750 list->num_parents, ctx->reg_base, 751 list->muxdiv_offset, list->mux_shift, 752 list->mux_width, list->mux_flags, 753 list->div_offset, list->div_shift, 754 list->div_width, list->div_flags, 755 list->flags, &ctx->lock, rates, nrates); 756 if (IS_ERR(clk)) { 757 pr_err("%s: failed to register clock %s: %ld\n", 758 __func__, list->name, PTR_ERR(clk)); 759 return; 760 } 761 762 rockchip_clk_set_lookup(ctx, clk, list->id); 763 } 764 EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk_multi_pll); 765 766 void rockchip_clk_protect_critical(const char *const clocks[], 767 int nclocks) 768 { 769 int i; 770 771 /* Protect the clocks that needs to stay on */ 772 for (i = 0; i < nclocks; i++) { 773 struct clk *clk = __clk_lookup(clocks[i]); 774 775 clk_prepare_enable(clk); 776 } 777 } 778 EXPORT_SYMBOL_GPL(rockchip_clk_protect_critical); 779 780 static void __iomem *rst_base; 781 static unsigned int reg_restart; 782 static void (*cb_restart)(void); 783 static int rockchip_restart_notify(struct notifier_block *this, 784 unsigned long mode, void *cmd) 785 { 786 if (cb_restart) 787 cb_restart(); 788 789 writel(0xfdb9, rst_base + reg_restart); 790 return NOTIFY_DONE; 791 } 792 793 static struct notifier_block rockchip_restart_handler = { 794 .notifier_call = rockchip_restart_notify, 795 .priority = 128, 796 }; 797 798 void 799 rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, 800 unsigned int reg, 801 void (*cb)(void)) 802 { 803 int ret; 804 805 rst_base = ctx->reg_base; 806 reg_restart = reg; 807 cb_restart = cb; 808 ret = register_restart_handler(&rockchip_restart_handler); 809 if (ret) 810 pr_err("%s: cannot register restart handler, %d\n", 811 __func__, ret); 812 } 813 EXPORT_SYMBOL_GPL(rockchip_register_restart_notifier); 814