Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

clk: rockchip: Implement rockchip_clk_register_armclk_multi_pll()

The current path will have an independent PLL(LPLL\BPLL)
exclusively for the CPU to use.
As follows:

|-\
--lpll--| \
|mux|--[gate]--[div]--clk_core--
--gpll--| /
|-/

The new chip does not have a dedicated PLL for the cpu;
it is distributed nearby from the common PLL.
If there are special frequency requirements that require the
use of pvtpll, explanations will be submitted later.

The clock path of new soc CPU simplified as follows:

--gpll--|--\
| \
| \
| \
--v0pll--| mux |--[gate]--[div]--clk_core--
| /
| /
--v1pll--| /
|--/

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Link: https://patch.msgid.link/20251111025738.869847-2-zhangqing@rock-chips.com
Signed-off-by: Heiko Stuebner <heiko@sntech.de>

authored by

Elaine Zhang and committed by
Heiko Stuebner
826eaa8f ca38f0f6

+204
+165
drivers/clk/rockchip/clk-cpu.c
··· 396 396 kfree(cpuclk); 397 397 return ERR_PTR(ret); 398 398 } 399 + 400 + static int rockchip_cpuclk_multi_pll_pre_rate_change(struct rockchip_cpuclk *cpuclk, 401 + struct clk_notifier_data *ndata) 402 + { 403 + unsigned long new_rate = roundup(ndata->new_rate, 1000); 404 + const struct rockchip_cpuclk_rate_table *rate; 405 + unsigned long flags; 406 + 407 + rate = rockchip_get_cpuclk_settings(cpuclk, new_rate); 408 + if (!rate) { 409 + pr_err("%s: Invalid rate : %lu for cpuclk\n", 410 + __func__, new_rate); 411 + return -EINVAL; 412 + } 413 + 414 + if (new_rate > ndata->old_rate) { 415 + spin_lock_irqsave(cpuclk->lock, flags); 416 + rockchip_cpuclk_set_dividers(cpuclk, rate); 417 + spin_unlock_irqrestore(cpuclk->lock, flags); 418 + } 419 + 420 + return 0; 421 + } 422 + 423 + static int rockchip_cpuclk_multi_pll_post_rate_change(struct rockchip_cpuclk *cpuclk, 424 + struct clk_notifier_data *ndata) 425 + { 426 + unsigned long new_rate = roundup(ndata->new_rate, 1000); 427 + const struct rockchip_cpuclk_rate_table *rate; 428 + unsigned long flags; 429 + 430 + rate = rockchip_get_cpuclk_settings(cpuclk, new_rate); 431 + if (!rate) { 432 + pr_err("%s: Invalid rate : %lu for cpuclk\n", 433 + __func__, new_rate); 434 + return -EINVAL; 435 + } 436 + 437 + if (new_rate < ndata->old_rate) { 438 + spin_lock_irqsave(cpuclk->lock, flags); 439 + rockchip_cpuclk_set_dividers(cpuclk, rate); 440 + spin_unlock_irqrestore(cpuclk->lock, flags); 441 + } 442 + 443 + return 0; 444 + } 445 + 446 + static int rockchip_cpuclk_multi_pll_notifier_cb(struct notifier_block *nb, 447 + unsigned long event, void *data) 448 + { 449 + struct clk_notifier_data *ndata = data; 450 + struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_nb(nb); 451 + int ret = 0; 452 + 453 + pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n", 454 + __func__, event, ndata->old_rate, ndata->new_rate); 455 + if (event == PRE_RATE_CHANGE) 456 + ret = rockchip_cpuclk_multi_pll_pre_rate_change(cpuclk, ndata); 457 + else if (event == POST_RATE_CHANGE) 458 + ret = rockchip_cpuclk_multi_pll_post_rate_change(cpuclk, ndata); 459 + 460 + return notifier_from_errno(ret); 461 + } 462 + 463 + struct clk *rockchip_clk_register_cpuclk_multi_pll(const char *name, 464 + const char *const *parent_names, 465 + u8 num_parents, void __iomem *base, 466 + int muxdiv_offset, u8 mux_shift, 467 + u8 mux_width, u8 mux_flags, 468 + int div_offset, u8 div_shift, 469 + u8 div_width, u8 div_flags, 470 + unsigned long flags, spinlock_t *lock, 471 + const struct rockchip_cpuclk_rate_table *rates, 472 + int nrates) 473 + { 474 + struct rockchip_cpuclk *cpuclk; 475 + struct clk_hw *hw; 476 + struct clk_mux *mux = NULL; 477 + struct clk_divider *div = NULL; 478 + const struct clk_ops *mux_ops = NULL, *div_ops = NULL; 479 + int ret; 480 + 481 + if (num_parents > 1) { 482 + mux = kzalloc(sizeof(*mux), GFP_KERNEL); 483 + if (!mux) 484 + return ERR_PTR(-ENOMEM); 485 + 486 + mux->reg = base + muxdiv_offset; 487 + mux->shift = mux_shift; 488 + mux->mask = BIT(mux_width) - 1; 489 + mux->flags = mux_flags; 490 + mux->lock = lock; 491 + mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops 492 + : &clk_mux_ops; 493 + } 494 + 495 + if (div_width > 0) { 496 + div = kzalloc(sizeof(*div), GFP_KERNEL); 497 + if (!div) { 498 + ret = -ENOMEM; 499 + goto free_mux; 500 + } 501 + 502 + div->flags = div_flags; 503 + if (div_offset) 504 + div->reg = base + div_offset; 505 + else 506 + div->reg = base + muxdiv_offset; 507 + div->shift = div_shift; 508 + div->width = div_width; 509 + div->lock = lock; 510 + div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) 511 + ? &clk_divider_ro_ops 512 + : &clk_divider_ops; 513 + } 514 + 515 + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, 516 + mux ? &mux->hw : NULL, mux_ops, 517 + div ? &div->hw : NULL, div_ops, 518 + NULL, NULL, flags); 519 + if (IS_ERR(hw)) { 520 + ret = PTR_ERR(hw); 521 + goto free_div; 522 + } 523 + 524 + cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL); 525 + if (!cpuclk) { 526 + ret = -ENOMEM; 527 + goto unregister_clk; 528 + } 529 + 530 + cpuclk->reg_base = base; 531 + cpuclk->lock = lock; 532 + cpuclk->clk_nb.notifier_call = rockchip_cpuclk_multi_pll_notifier_cb; 533 + ret = clk_notifier_register(hw->clk, &cpuclk->clk_nb); 534 + if (ret) { 535 + pr_err("%s: failed to register clock notifier for %s\n", 536 + __func__, name); 537 + goto free_cpuclk; 538 + } 539 + 540 + if (nrates > 0) { 541 + cpuclk->rate_count = nrates; 542 + cpuclk->rate_table = kmemdup(rates, 543 + sizeof(*rates) * nrates, 544 + GFP_KERNEL); 545 + if (!cpuclk->rate_table) { 546 + ret = -ENOMEM; 547 + goto free_cpuclk; 548 + } 549 + } 550 + 551 + return hw->clk; 552 + 553 + free_cpuclk: 554 + kfree(cpuclk); 555 + unregister_clk: 556 + clk_hw_unregister_composite(hw); 557 + free_div: 558 + kfree(div); 559 + free_mux: 560 + kfree(mux); 561 + 562 + return ERR_PTR(ret); 563 + }
+24
drivers/clk/rockchip/clk.c
··· 722 722 } 723 723 EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk); 724 724 725 + void rockchip_clk_register_armclk_multi_pll(struct rockchip_clk_provider *ctx, 726 + struct rockchip_clk_branch *list, 727 + const struct rockchip_cpuclk_rate_table *rates, 728 + int nrates) 729 + { 730 + struct clk *clk; 731 + 732 + clk = rockchip_clk_register_cpuclk_multi_pll(list->name, list->parent_names, 733 + list->num_parents, ctx->reg_base, 734 + list->muxdiv_offset, list->mux_shift, 735 + list->mux_width, list->mux_flags, 736 + list->div_offset, list->div_shift, 737 + list->div_width, list->div_flags, 738 + list->flags, &ctx->lock, rates, nrates); 739 + if (IS_ERR(clk)) { 740 + pr_err("%s: failed to register clock %s: %ld\n", 741 + __func__, list->name, PTR_ERR(clk)); 742 + return; 743 + } 744 + 745 + rockchip_clk_set_lookup(ctx, clk, list->id); 746 + } 747 + EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk_multi_pll); 748 + 725 749 void rockchip_clk_protect_critical(const char *const clocks[], 726 750 int nclocks) 727 751 {
+15
drivers/clk/rockchip/clk.h
··· 622 622 const struct rockchip_cpuclk_rate_table *rates, 623 623 int nrates, void __iomem *reg_base, spinlock_t *lock); 624 624 625 + struct clk *rockchip_clk_register_cpuclk_multi_pll(const char *name, 626 + const char *const *parent_names, 627 + u8 num_parents, void __iomem *base, 628 + int muxdiv_offset, u8 mux_shift, 629 + u8 mux_width, u8 mux_flags, 630 + int div_offset, u8 div_shift, 631 + u8 div_width, u8 div_flags, 632 + unsigned long flags, spinlock_t *lock, 633 + const struct rockchip_cpuclk_rate_table *rates, 634 + int nrates); 635 + 625 636 struct clk *rockchip_clk_register_mmc(const char *name, 626 637 const char *const *parent_names, u8 num_parents, 627 638 void __iomem *reg, ··· 1219 1208 const struct rockchip_cpuclk_reg_data *reg_data, 1220 1209 const struct rockchip_cpuclk_rate_table *rates, 1221 1210 int nrates); 1211 + void rockchip_clk_register_armclk_multi_pll(struct rockchip_clk_provider *ctx, 1212 + struct rockchip_clk_branch *list, 1213 + const struct rockchip_cpuclk_rate_table *rates, 1214 + int nrates); 1222 1215 void rockchip_clk_protect_critical(const char *const clocks[], int nclocks); 1223 1216 void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, 1224 1217 unsigned int reg, void (*cb)(void));