Skip to content

Commit 826eaa8

Browse files
Elaine Zhangmmind
authored andcommitted
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>
1 parent ca38f0f commit 826eaa8

3 files changed

Lines changed: 204 additions & 0 deletions

File tree

drivers/clk/rockchip/clk-cpu.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,168 @@ struct clk *rockchip_clk_register_cpuclk(const char *name,
396396
kfree(cpuclk);
397397
return ERR_PTR(ret);
398398
}
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+
}

drivers/clk/rockchip/clk.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,30 @@ void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
722722
}
723723
EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk);
724724

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+
725749
void rockchip_clk_protect_critical(const char *const clocks[],
726750
int nclocks)
727751
{

drivers/clk/rockchip/clk.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,17 @@ struct clk *rockchip_clk_register_cpuclk(const char *name,
622622
const struct rockchip_cpuclk_rate_table *rates,
623623
int nrates, void __iomem *reg_base, spinlock_t *lock);
624624

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+
625636
struct clk *rockchip_clk_register_mmc(const char *name,
626637
const char *const *parent_names, u8 num_parents,
627638
void __iomem *reg,
@@ -1208,6 +1219,10 @@ void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
12081219
const struct rockchip_cpuclk_reg_data *reg_data,
12091220
const struct rockchip_cpuclk_rate_table *rates,
12101221
int nrates);
1222+
void rockchip_clk_register_armclk_multi_pll(struct rockchip_clk_provider *ctx,
1223+
struct rockchip_clk_branch *list,
1224+
const struct rockchip_cpuclk_rate_table *rates,
1225+
int nrates);
12111226
void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
12121227
void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
12131228
unsigned int reg, void (*cb)(void));

0 commit comments

Comments
 (0)