hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/clk/rockchip/clk.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (c) 2014 MundoReader S.L.
34 * Author: Heiko Stuebner <heiko@sntech.de>
....@@ -11,26 +12,21 @@
1112 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
1213 * Copyright (c) 2013 Linaro Ltd.
1314 * Author: Thomas Abraham <thomas.ab@samsung.com>
14
- *
15
- * This program is free software; you can redistribute it and/or modify
16
- * it under the terms of the GNU General Public License as published by
17
- * the Free Software Foundation; either version 2 of the License, or
18
- * (at your option) any later version.
19
- *
20
- * This program is distributed in the hope that it will be useful,
21
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
- * GNU General Public License for more details.
2415 */
2516
2617 #include <linux/slab.h>
2718 #include <linux/clk.h>
2819 #include <linux/clk-provider.h>
20
+#include <linux/io.h>
2921 #include <linux/mfd/syscon.h>
3022 #include <linux/regmap.h>
3123 #include <linux/reboot.h>
3224 #include <linux/rational.h>
3325 #include "clk.h"
26
+
27
+#ifdef MODULE
28
+static HLIST_HEAD(clk_ctx_list);
29
+#endif
3430
3531 /**
3632 * Register a clock branch.
....@@ -52,7 +48,7 @@
5248 u8 gate_shift, u8 gate_flags, unsigned long flags,
5349 spinlock_t *lock)
5450 {
55
- struct clk *clk;
51
+ struct clk_hw *hw;
5652 struct clk_mux *mux = NULL;
5753 struct clk_gate *gate = NULL;
5854 struct clk_divider *div = NULL;
....@@ -110,20 +106,18 @@
110106 : &clk_divider_ops;
111107 }
112108
113
- clk = clk_register_composite(NULL, name, parent_names, num_parents,
114
- mux ? &mux->hw : NULL, mux_ops,
115
- div ? &div->hw : NULL, div_ops,
116
- gate ? &gate->hw : NULL, gate_ops,
117
- flags);
118
-
119
- if (IS_ERR(clk)) {
120
- ret = PTR_ERR(clk);
121
- goto err_composite;
109
+ hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
110
+ mux ? &mux->hw : NULL, mux_ops,
111
+ div ? &div->hw : NULL, div_ops,
112
+ gate ? &gate->hw : NULL, gate_ops,
113
+ flags);
114
+ if (IS_ERR(hw)) {
115
+ kfree(div);
116
+ kfree(gate);
117
+ return ERR_CAST(hw);
122118 }
123119
124
- return clk;
125
-err_composite:
126
- kfree(div);
120
+ return hw->clk;
127121 err_div:
128122 kfree(gate);
129123 err_gate:
....@@ -194,22 +188,23 @@
194188 unsigned long p_rate, p_parent_rate;
195189 struct clk_hw *p_parent;
196190 unsigned long scale;
197
- u32 div;
191
+
192
+ if (rate == 0) {
193
+ pr_warn("%s p_rate(%ld), rate(%ld), maybe invalid frequency setting!\n",
194
+ clk_hw_get_name(hw), *parent_rate, rate);
195
+ *m = 0;
196
+ *n = 1;
197
+ return;
198
+ }
198199
199200 p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
200
- if (((rate * 20 > p_rate) && (p_rate % rate != 0)) ||
201
- (fd->max_prate && fd->max_prate < p_rate)) {
201
+ if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
202202 p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
203203 if (!p_parent) {
204204 *parent_rate = p_rate;
205205 } else {
206206 p_parent_rate = clk_hw_get_rate(p_parent);
207207 *parent_rate = p_parent_rate;
208
- if (fd->max_prate && p_parent_rate > fd->max_prate) {
209
- div = DIV_ROUND_UP(p_parent_rate,
210
- fd->max_prate);
211
- *parent_rate = p_parent_rate / div;
212
- }
213208 }
214209
215210 if (*parent_rate < rate * 20) {
....@@ -238,6 +233,13 @@
238233 * for m and n. In the result it will be the nearest rate left shifted
239234 * by (scale - fd->nwidth) bits.
240235 */
236
+ if (*parent_rate == 0) {
237
+ pr_warn("%s p_rate(%ld), rate(%ld), maybe invalid frequency setting!\n",
238
+ clk_hw_get_name(hw), *parent_rate, rate);
239
+ *m = 0;
240
+ *n = 1;
241
+ return;
242
+ }
241243 scale = fls_long(*parent_rate / rate - 1);
242244 if (scale > fd->nwidth)
243245 rate <<= scale - fd->nwidth;
....@@ -253,10 +255,10 @@
253255 void __iomem *base, int muxdiv_offset, u8 div_flags,
254256 int gate_offset, u8 gate_shift, u8 gate_flags,
255257 unsigned long flags, struct rockchip_clk_branch *child,
256
- unsigned long max_prate, spinlock_t *lock)
258
+ spinlock_t *lock)
257259 {
260
+ struct clk_hw *hw;
258261 struct rockchip_clk_frac *frac;
259
- struct clk *clk;
260262 struct clk_gate *gate = NULL;
261263 struct clk_fractional_divider *div = NULL;
262264 const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
....@@ -294,22 +296,21 @@
294296 div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift;
295297 div->lock = lock;
296298 div->approximation = rockchip_fractional_approximation;
297
- div->max_prate = max_prate;
298299 div_ops = &clk_fractional_divider_ops;
299300
300
- clk = clk_register_composite(NULL, name, parent_names, num_parents,
301
- NULL, NULL,
302
- &div->hw, div_ops,
303
- gate ? &gate->hw : NULL, gate_ops,
304
- flags | CLK_SET_RATE_UNGATE);
305
- if (IS_ERR(clk)) {
301
+ hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
302
+ NULL, NULL,
303
+ &div->hw, div_ops,
304
+ gate ? &gate->hw : NULL, gate_ops,
305
+ flags | CLK_SET_RATE_UNGATE);
306
+ if (IS_ERR(hw)) {
306307 kfree(frac);
307
- return clk;
308
+ return ERR_CAST(hw);
308309 }
309310
310311 if (child) {
311312 struct clk_mux *frac_mux = &frac->mux;
312
- struct clk_init_data init = {};
313
+ struct clk_init_data init;
313314 struct clk *mux_clk;
314315 int ret;
315316
....@@ -336,7 +337,7 @@
336337 mux_clk = clk_register(NULL, &frac_mux->hw);
337338 if (IS_ERR(mux_clk)) {
338339 kfree(frac);
339
- return clk;
340
+ return mux_clk;
340341 }
341342
342343 rockchip_clk_add_lookup(ctx, mux_clk, child->id);
....@@ -345,7 +346,7 @@
345346 if (frac->mux_frac_idx >= 0) {
346347 pr_debug("%s: found fractional parent in mux at pos %d\n",
347348 __func__, frac->mux_frac_idx);
348
- ret = clk_notifier_register(clk, &frac->clk_nb);
349
+ ret = clk_notifier_register(hw->clk, &frac->clk_nb);
349350 if (ret)
350351 pr_err("%s: failed to register clock notifier for %s\n",
351352 __func__, name);
....@@ -355,7 +356,7 @@
355356 }
356357 }
357358
358
- return clk;
359
+ return hw->clk;
359360 }
360361
361362 static struct clk *rockchip_clk_register_factor_branch(const char *name,
....@@ -364,7 +365,7 @@
364365 int gate_offset, u8 gate_shift, u8 gate_flags,
365366 unsigned long flags, spinlock_t *lock)
366367 {
367
- struct clk *clk;
368
+ struct clk_hw *hw;
368369 struct clk_gate *gate = NULL;
369370 struct clk_fixed_factor *fix = NULL;
370371
....@@ -393,75 +394,22 @@
393394 fix->mult = mult;
394395 fix->div = div;
395396
396
- clk = clk_register_composite(NULL, name, parent_names, num_parents,
397
- NULL, NULL,
398
- &fix->hw, &clk_fixed_factor_ops,
399
- &gate->hw, &clk_gate_ops, flags);
400
- if (IS_ERR(clk)) {
397
+ hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
398
+ NULL, NULL,
399
+ &fix->hw, &clk_fixed_factor_ops,
400
+ &gate->hw, &clk_gate_ops, flags);
401
+ if (IS_ERR(hw)) {
401402 kfree(fix);
402403 kfree(gate);
404
+ return ERR_CAST(hw);
403405 }
404406
405
- return clk;
407
+ return hw->clk;
406408 }
407409
408
-static struct clk *rockchip_clk_register_composite_brother_branch(
409
- struct rockchip_clk_provider *ctx, const char *name,
410
- const char *const *parent_names, u8 num_parents,
411
- void __iomem *base, int muxdiv_offset, u8 mux_shift,
412
- u8 mux_width, u8 mux_flags, u32 *mux_table,
413
- int div_offset, u8 div_shift, u8 div_width, u8 div_flags,
414
- struct clk_div_table *div_table, int gate_offset,
415
- u8 gate_shift, u8 gate_flags, unsigned long flags,
416
- struct rockchip_clk_branch *brother, spinlock_t *lock)
417
-{
418
- struct clk *clk, *brother_clk;
419
- struct clk_composite *composite, *brother_composite;
420
- struct clk_hw *hw, *brother_hw;
421
-
422
- if (brother && brother->branch_type != branch_half_divider) {
423
- pr_err("%s: composite brother for %s can only be a halfdiv\n",
424
- __func__, name);
425
- return ERR_PTR(-EINVAL);
426
- }
427
-
428
- clk = rockchip_clk_register_branch(name, parent_names, num_parents,
429
- base, muxdiv_offset, mux_shift,
430
- mux_width, mux_flags, mux_table,
431
- div_offset, div_shift, div_width,
432
- div_flags, div_table,
433
- gate_offset, gate_shift, gate_flags,
434
- flags, lock);
435
- if (IS_ERR(clk))
436
- return clk;
437
-
438
- brother_clk = rockchip_clk_register_halfdiv(brother->name,
439
- brother->parent_names, brother->num_parents,
440
- base, brother->muxdiv_offset,
441
- brother->mux_shift, brother->mux_width,
442
- brother->mux_flags, brother->div_offset,
443
- brother->div_shift, brother->div_width,
444
- brother->div_flags, brother->gate_offset,
445
- brother->gate_shift, brother->gate_flags,
446
- flags, lock);
447
- if (IS_ERR(brother_clk))
448
- return brother_clk;
449
- rockchip_clk_add_lookup(ctx, brother_clk, brother->id);
450
-
451
- hw = __clk_get_hw(clk);
452
- brother_hw = __clk_get_hw(brother_clk);
453
- if (hw && brother_hw) {
454
- composite = to_clk_composite(hw);
455
- brother_composite = to_clk_composite(brother_hw);
456
- composite->brother_hw = brother_hw;
457
- brother_composite->brother_hw = hw;
458
- }
459
-
460
- return clk;
461
-}
462
-
463
-struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np,
464
- void __iomem *base, unsigned long nr_clks)
410
+struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
411
+ void __iomem *base,
412
+ unsigned long nr_clks)
465413 {
466414 struct rockchip_clk_provider *ctx;
467415 struct clk **clk_table;
....@@ -489,20 +437,26 @@
489437 ctx->pmugrf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
490438 "rockchip,pmugrf");
491439
440
+#ifdef MODULE
441
+ hlist_add_head(&ctx->list_node, &clk_ctx_list);
442
+#endif
443
+
492444 return ctx;
493445
494446 err_free:
495447 kfree(ctx);
496448 return ERR_PTR(-ENOMEM);
497449 }
450
+EXPORT_SYMBOL_GPL(rockchip_clk_init);
498451
499
-void __init rockchip_clk_of_add_provider(struct device_node *np,
500
- struct rockchip_clk_provider *ctx)
452
+void rockchip_clk_of_add_provider(struct device_node *np,
453
+ struct rockchip_clk_provider *ctx)
501454 {
502455 if (of_clk_add_provider(np, of_clk_src_onecell_get,
503456 &ctx->clk_data))
504457 pr_err("%s: could not register clk provider\n", __func__);
505458 }
459
+EXPORT_SYMBOL_GPL(rockchip_clk_of_add_provider);
506460
507461 void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
508462 struct clk *clk, unsigned int id)
....@@ -510,8 +464,9 @@
510464 if (ctx->clk_data.clks && id)
511465 ctx->clk_data.clks[id] = clk;
512466 }
467
+EXPORT_SYMBOL_GPL(rockchip_clk_add_lookup);
513468
514
-void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
469
+void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
515470 struct rockchip_pll_clock *list,
516471 unsigned int nr_pll, int grf_lock_offset)
517472 {
....@@ -534,11 +489,11 @@
534489 rockchip_clk_add_lookup(ctx, clk, list->id);
535490 }
536491 }
492
+EXPORT_SYMBOL_GPL(rockchip_clk_register_plls);
537493
538
-void __init rockchip_clk_register_branches(
539
- struct rockchip_clk_provider *ctx,
540
- struct rockchip_clk_branch *list,
541
- unsigned int nr_clk)
494
+void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
495
+ struct rockchip_clk_branch *list,
496
+ unsigned int nr_clk)
542497 {
543498 struct clk *clk = NULL;
544499 unsigned int idx;
....@@ -604,7 +559,7 @@
604559 list->div_flags,
605560 list->gate_offset, list->gate_shift,
606561 list->gate_flags, flags, list->child,
607
- list->max_prate, &ctx->lock);
562
+ &ctx->lock);
608563 break;
609564 case branch_half_divider:
610565 clk = rockchip_clk_register_halfdiv(list->name,
....@@ -618,8 +573,15 @@
618573 flags, &ctx->lock);
619574 break;
620575 case branch_gate:
621
- if (!(list->gate_flags & CLK_GATE_NO_SET_RATE))
622
- flags |= CLK_SET_RATE_PARENT;
576
+ flags |= CLK_SET_RATE_PARENT;
577
+
578
+ clk = clk_register_gate(NULL, list->name,
579
+ list->parent_names[0], flags,
580
+ ctx->reg_base + list->gate_offset,
581
+ list->gate_shift, list->gate_flags, &ctx->lock);
582
+ break;
583
+ case branch_gate_no_set_rate:
584
+ flags &= ~CLK_SET_RATE_PARENT;
623585
624586 clk = clk_register_gate(NULL, list->name,
625587 list->parent_names[0], flags,
....@@ -637,19 +599,6 @@
637599 list->div_flags, list->div_table,
638600 list->gate_offset, list->gate_shift,
639601 list->gate_flags, flags, &ctx->lock);
640
- break;
641
- case branch_composite_brother:
642
- clk = rockchip_clk_register_composite_brother_branch(
643
- ctx, list->name, list->parent_names,
644
- list->num_parents, ctx->reg_base,
645
- list->muxdiv_offset, list->mux_shift,
646
- list->mux_width, list->mux_flags,
647
- list->mux_table, list->div_offset,
648
- list->div_shift, list->div_width,
649
- list->div_flags, list->div_table,
650
- list->gate_offset, list->gate_shift,
651
- list->gate_flags, flags, list->child,
652
- &ctx->lock);
653602 break;
654603 case branch_mmc:
655604 clk = rockchip_clk_register_mmc(
....@@ -685,18 +634,6 @@
685634 list->div_width, list->div_flags,
686635 ctx->reg_base);
687636 break;
688
- case branch_dclk_divider:
689
-#ifdef CONFIG_ROCKCHIP_DCLK_DIV
690
- clk = rockchip_clk_register_dclk_branch(list->name,
691
- list->parent_names, list->num_parents,
692
- ctx->reg_base, list->muxdiv_offset, list->mux_shift,
693
- list->mux_width, list->mux_flags,
694
- list->div_offset, list->div_shift, list->div_width,
695
- list->div_flags, list->div_table,
696
- list->gate_offset, list->gate_shift,
697
- list->gate_flags, flags, list->max_prate, &ctx->lock);
698
-#endif
699
- break;
700637 }
701638
702639 /* none of the cases above matched */
....@@ -715,18 +652,21 @@
715652 rockchip_clk_add_lookup(ctx, clk, list->id);
716653 }
717654 }
655
+EXPORT_SYMBOL_GPL(rockchip_clk_register_branches);
718656
719
-void __init 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)
657
+void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
658
+ unsigned int lookup_id,
659
+ const char *name,
660
+ u8 num_parents,
661
+ struct clk *parent, struct clk *alt_parent,
662
+ const struct rockchip_cpuclk_reg_data *reg_data,
663
+ const struct rockchip_cpuclk_rate_table *rates,
664
+ int nrates)
726665 {
727666 struct clk *clk;
728667
729
- clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents,
668
+ clk = rockchip_clk_register_cpuclk(name, num_parents,
669
+ parent, alt_parent,
730670 reg_data, rates, nrates,
731671 ctx->reg_base, &ctx->lock);
732672 if (IS_ERR(clk)) {
....@@ -737,20 +677,31 @@
737677
738678 rockchip_clk_add_lookup(ctx, clk, lookup_id);
739679 }
680
+EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk);
740681
741
-void __init rockchip_clk_protect_critical(const char *const clocks[],
742
- int nclocks)
682
+void rockchip_clk_register_armclk_v2(struct rockchip_clk_provider *ctx,
683
+ struct rockchip_clk_branch *list,
684
+ const struct rockchip_cpuclk_rate_table *rates,
685
+ int nrates)
743686 {
744
- int i;
687
+ struct clk *clk;
745688
746
- /* Protect the clocks that needs to stay on */
747
- for (i = 0; i < nclocks; i++) {
748
- struct clk *clk = __clk_lookup(clocks[i]);
749
-
750
- if (clk)
751
- clk_prepare_enable(clk);
689
+ clk = rockchip_clk_register_cpuclk_v2(list->name, list->parent_names,
690
+ list->num_parents, ctx->reg_base,
691
+ list->muxdiv_offset, list->mux_shift,
692
+ list->mux_width, list->mux_flags,
693
+ list->div_offset, list->div_shift,
694
+ list->div_width, list->div_flags,
695
+ list->flags, &ctx->lock, rates, nrates);
696
+ if (IS_ERR(clk)) {
697
+ pr_err("%s: failed to register clock %s: %ld\n",
698
+ __func__, list->name, PTR_ERR(clk));
699
+ return;
752700 }
701
+
702
+ rockchip_clk_add_lookup(ctx, clk, list->id);
753703 }
704
+EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk_v2);
754705
755706 void (*rk_dump_cru)(void);
756707 EXPORT_SYMBOL(rk_dump_cru);
....@@ -785,10 +736,10 @@
785736 .priority = 128,
786737 };
787738
788
-void __init
739
+void
789740 rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
790
- unsigned int reg,
791
- void (*cb)(void))
741
+ unsigned int reg,
742
+ void (*cb)(void))
792743 {
793744 int ret;
794745
....@@ -802,3 +753,83 @@
802753 atomic_notifier_chain_register(&panic_notifier_list,
803754 &rk_clk_panic_block);
804755 }
756
+EXPORT_SYMBOL_GPL(rockchip_register_restart_notifier);
757
+
758
+#ifdef MODULE
759
+static struct clk **protect_clocks;
760
+static unsigned int protect_nclocks;
761
+
762
+int rockchip_clk_protect(struct rockchip_clk_provider *ctx,
763
+ unsigned int *clocks, unsigned int nclocks)
764
+{
765
+ struct clk *clk = NULL;
766
+ int i = 0;
767
+
768
+ if (protect_clocks || !ctx || !clocks || !ctx->clk_data.clks)
769
+ return 0;
770
+
771
+ protect_clocks = kcalloc(nclocks, sizeof(void *), GFP_KERNEL);
772
+ if (!protect_clocks)
773
+ return -ENOMEM;
774
+
775
+ for (i = 0; i < nclocks; i++) {
776
+ if (clocks[i] >= ctx->clk_data.clk_num) {
777
+ pr_err("%s: invalid clock id %u\n", __func__, clocks[i]);
778
+ continue;
779
+ }
780
+ clk = ctx->clk_data.clks[clocks[i]];
781
+ if (clk) {
782
+ clk_prepare_enable(clk);
783
+ protect_clocks[i] = clk;
784
+ }
785
+ }
786
+ protect_nclocks = nclocks;
787
+
788
+ return 0;
789
+}
790
+EXPORT_SYMBOL_GPL(rockchip_clk_protect);
791
+
792
+void rockchip_clk_unprotect(void)
793
+{
794
+ int i = 0;
795
+
796
+ if (!protect_clocks || !protect_nclocks)
797
+ return;
798
+
799
+ for (i = 0; i < protect_nclocks; i++) {
800
+ if (protect_clocks[i])
801
+ clk_disable_unprepare(protect_clocks[i]);
802
+ }
803
+ protect_nclocks = 0;
804
+ kfree(protect_clocks);
805
+ protect_clocks = NULL;
806
+
807
+}
808
+EXPORT_SYMBOL_GPL(rockchip_clk_unprotect);
809
+
810
+void rockchip_clk_disable_unused(void)
811
+{
812
+ struct rockchip_clk_provider *ctx;
813
+ struct clk *clk;
814
+ struct clk_hw *hw;
815
+ int i = 0, flag = 0;
816
+
817
+ hlist_for_each_entry(ctx, &clk_ctx_list, list_node) {
818
+ for (i = 0; i < ctx->clk_data.clk_num; i++) {
819
+ clk = ctx->clk_data.clks[i];
820
+ if (clk && !IS_ERR(clk)) {
821
+ hw = __clk_get_hw(clk);
822
+ if (hw)
823
+ flag = clk_hw_get_flags(hw);
824
+ if (flag & CLK_IGNORE_UNUSED)
825
+ continue;
826
+ if (flag & CLK_IS_CRITICAL)
827
+ continue;
828
+ clk_prepare_enable(clk);
829
+ clk_disable_unprepare(clk);
830
+ }
831
+ }
832
+ }
833
+}
834
+EXPORT_SYMBOL_GPL(rockchip_clk_disable_unused);
835
+#endif /* MODULE */