1 /* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
2 *
3 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
4 *the the People's Republic of China and other countries.
5 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
6 *
7 * DISCLAIMER
8 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
9 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
10 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
11 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
12 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
13 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
14 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
15 *
16 *
17 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
18 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
19 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
20 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
21 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include "ccu.h"
32 #include <stdlib.h>
33 #include <hal_clk.h>
34 #include <sunxi_hal_common.h>
35
36 static LIST_HEAD(clk_root_list);
37
clk_hw_get_name(const struct clk_hw * hw)38 const char *clk_hw_get_name(const struct clk_hw *hw)
39 {
40 if (!hw || !hw->core)
41 return NULL;
42
43 return hw->core->name;
44 }
45
clk_hw_get_flags(const struct clk_hw * hw)46 unsigned long clk_hw_get_flags(const struct clk_hw *hw)
47 {
48 if (!hw || !hw->core)
49 return 0;
50
51 return hw->core->flags;
52 }
53
clk_hw_get_core(const struct clk_hw * hw)54 struct clk_core *clk_hw_get_core(const struct clk_hw *hw)
55 {
56 if (!hw || !hw->core)
57 return NULL;
58
59 return hw->core;
60 }
61
clk_core_get_by_name(const char * name)62 struct clk_core *clk_core_get_by_name(const char *name)
63 {
64 struct clk_core *core = NULL;
65
66 list_for_each_entry(core, &clk_root_list, node)
67 {
68 if (strcmp(name, core->name))
69 {
70 continue;
71 }
72 return core;
73 }
74
75 return NULL;
76 }
77
clk_core_get_by_pindex(struct clk_core * core,u8 p_index)78 static struct clk_core *clk_core_get_by_pindex(struct clk_core *core, u8 p_index)
79 {
80 if (p_index > core->num_parents)
81 {
82 return NULL;
83 }
84
85 return clk_core_get_by_name(core->parents[p_index].name);
86 }
87
clk_core_fill_parent_index(struct clk_core * core,u8 index)88 static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
89 {
90 struct clk_parent_map *entry = &core->parents[index];
91 struct clk_core *parent = NULL;
92
93 if (entry->hw)
94 {
95 parent = entry->hw->core;
96 /*
97 * We have a direct reference but it isn't registered yet?
98 * Orphan it and let clk_reparent() update the orphan status
99 * when the parent is registered.
100 */
101 }
102 else
103 {
104 parent = clk_core_get_by_pindex(core, index);
105 }
106
107 /* Only cache it if it's not an error */
108 if (parent)
109 {
110 entry->core = parent;
111 }
112 }
113
clk_core_get_parent_by_index(struct clk_core * core,u8 index)114 static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
115 u8 index)
116 {
117 if (!core || index >= core->num_parents || !core->parents)
118 {
119 return NULL;
120 }
121
122 if (!core->parents[index].core)
123 {
124 clk_core_fill_parent_index(core, index);
125 }
126 return core->parents[index].core;
127 }
128
129 struct clk_hw *
clk_hw_get_parent_by_index(const struct clk_hw * hw,unsigned int index)130 clk_hw_get_parent_by_index(const struct clk_hw *hw, unsigned int index)
131 {
132 struct clk_core *parent;
133
134 parent = clk_core_get_parent_by_index(hw->core, index);
135
136 return !parent ? NULL : parent->hw;
137 }
138
clk_hw_get_num_parents(const struct clk_hw * hw)139 unsigned int clk_hw_get_num_parents(const struct clk_hw *hw)
140 {
141 return hw->core->num_parents;
142 }
143
clk_hw_get_parent(const struct clk_hw * hw)144 struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw)
145 {
146 return hw->core->parent ? hw->core->parent->hw : NULL;
147 }
148
__clk_get_accuracy(struct clk_core * core)149 static u32 __clk_get_accuracy(struct clk_core *core)
150 {
151 if (!core)
152 {
153 return 0;
154 }
155 return core->accuracy;
156 }
157
clk_core_get_rate_nolock(struct clk_core * core)158 static unsigned long clk_core_get_rate_nolock(struct clk_core *core)
159 {
160 if (!core)
161 {
162 return 0;
163 }
164
165 if (!core->num_parents || core->parent)
166 {
167 return core->rate;
168 }
169
170 /*
171 * Clk must have a parent because num_parents > 0 but the parent isn't
172 * known yet. Best to return 0 as the rate of this clk until we can
173 * properly recalc the rate based on the parent's rate.
174 */
175 return 0;
176 }
177
clk_core_determine_round_nolock(struct clk_core * core,struct clk_rate_request * req)178 static int clk_core_determine_round_nolock(struct clk_core *core,
179 struct clk_rate_request *req)
180 {
181 long rate;
182
183 if (!core)
184 {
185 return 0;
186 }
187
188 /*
189 * At this point, core protection will be disabled if
190 * - if the provider is not protected at all
191 * - if the calling consumer is the only one which has exclusivity
192 * over the provider
193 */
194 if (core->ops->determine_rate)
195 {
196 return core->ops->determine_rate(core->hw, req);
197 }
198 else if (core->ops->round_rate)
199 {
200 rate = core->ops->round_rate(core->hw, req->rate,
201 &req->best_parent_rate);
202 if (rate < 0)
203 {
204 return rate;
205 }
206
207 req->rate = rate;
208 }
209 else
210 {
211 return -1;
212 }
213
214 return 0;
215 }
216
clk_core_init_rate_req(struct clk_core * const core,struct clk_rate_request * req)217 static void clk_core_init_rate_req(struct clk_core *const core,
218 struct clk_rate_request *req)
219 {
220 struct clk_core *parent;
221
222 if (!core || !req)
223 {
224 return;
225 }
226
227 parent = core->parent;
228 if (parent)
229 {
230 req->best_parent_hw = parent->hw;
231 req->best_parent_rate = parent->rate;
232 }
233 else
234 {
235 req->best_parent_hw = NULL;
236 req->best_parent_rate = 0;
237 }
238 }
239
clk_core_can_round(struct clk_core * const core)240 static u8 clk_core_can_round(struct clk_core *const core)
241 {
242 return core->ops->determine_rate || core->ops->round_rate;
243 }
244
clk_core_round_rate_nolock(struct clk_core * core,struct clk_rate_request * req)245 static int clk_core_round_rate_nolock(struct clk_core *core,
246 struct clk_rate_request *req)
247 {
248 if (!core)
249 {
250 req->rate = 0;
251 return 0;
252 }
253
254 clk_core_init_rate_req(core, req);
255
256 if (clk_core_can_round(core))
257 {
258 return clk_core_determine_round_nolock(core, req);
259 }
260 else if (core->flags & CLK_SET_RATE_PARENT)
261 {
262 return clk_core_round_rate_nolock(core->parent, req);
263 }
264
265 req->rate = core->rate;
266 return 0;
267 }
268
269 /**
270 * __clk_determine_rate - get the closest rate actually supported by a clock
271 * @hw: determine the rate of this clock
272 * @req: target rate request
273 *
274 * Useful for clk_ops such as .set_rate and .determine_rate.
275 */
__clk_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)276 int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
277 {
278 if (!hw)
279 {
280 req->rate = 0;
281 return 0;
282 }
283
284 return clk_core_round_rate_nolock(hw->core, req);
285 }
286
mux_is_better_rate(unsigned long rate,unsigned long now,unsigned long best,unsigned long flags)287 static u8 mux_is_better_rate(unsigned long rate, unsigned long now,
288 unsigned long best, unsigned long flags)
289 {
290 if (flags & CLK_MUX_ROUND_CLOSEST)
291 {
292 return abs(now - rate) < abs(best - rate);
293 }
294
295 return now <= rate && now > best;
296 }
297
clk_mux_determine_rate_flags(struct clk_hw * hw,struct clk_rate_request * req,unsigned long flags)298 int clk_mux_determine_rate_flags(struct clk_hw *hw,
299 struct clk_rate_request *req,
300 unsigned long flags)
301 {
302 struct clk_core *core = hw->core, *parent, *best_parent = NULL;
303 int i, num_parents, ret;
304 unsigned long best = 0;
305 struct clk_rate_request parent_req = *req;
306
307 /* if NO_REPARENT flag set, pass through to current parent */
308 if (core->flags & CLK_SET_RATE_NO_REPARENT)
309 {
310 parent = core->parent;
311 if (core->flags & CLK_SET_RATE_PARENT)
312 {
313 ret = __clk_determine_rate(parent ? parent->hw : NULL,
314 &parent_req);
315 if (ret)
316 {
317 return ret;
318 }
319
320 best = parent_req.rate;
321 }
322 else if (parent)
323 {
324 best = clk_core_get_rate_nolock(parent);
325 }
326 else
327 {
328 best = clk_core_get_rate_nolock(core);
329 }
330
331 goto out;
332 }
333
334 /* find the parent that can provide the fastest rate <= rate */
335 num_parents = core->num_parents;
336 for (i = 0; i < num_parents; i++)
337 {
338 parent = clk_core_get_parent_by_index(core, i);
339 if (!parent)
340 {
341 continue;
342 }
343
344 if (core->flags & CLK_SET_RATE_PARENT)
345 {
346 parent_req = *req;
347 ret = __clk_determine_rate(parent->hw, &parent_req);
348 if (ret)
349 {
350 continue;
351 }
352 }
353 else
354 {
355 parent_req.rate = clk_core_get_rate_nolock(parent);
356 }
357
358 if (mux_is_better_rate(req->rate, parent_req.rate,
359 best, flags))
360 {
361 best_parent = parent;
362 best = parent_req.rate;
363 }
364 }
365
366 if (!best_parent)
367 {
368 return -1;
369 }
370
371 out:
372 if (best_parent)
373 {
374 req->best_parent_hw = best_parent->hw;
375 }
376 req->best_parent_rate = best;
377 req->rate = best;
378
379 return 0;
380 }
381
382 /*
383 * __clk_mux_determine_rate - clk_ops::determine_rate implementation for a mux type clk
384 * @hw: mux type clk to determine rate on
385 * @req: rate request, also used to return preferred parent and frequencies
386 *
387 * Helper for finding best parent to provide a given frequency. This can be used
388 * directly as a determine_rate callback (e.g. for a mux), or from a more
389 * complex clock that may combine a mux with other operations.
390 *
391 * Returns: 0 on success, -EERROR value on error
392 */
__clk_mux_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)393 int __clk_mux_determine_rate(struct clk_hw *hw,
394 struct clk_rate_request *req)
395 {
396 return clk_mux_determine_rate_flags(hw, req, 0);
397 }
398
clk_core_get_boundaries(struct clk_core * core,unsigned long * min_rate,unsigned long * max_rate)399 static void clk_core_get_boundaries(struct clk_core *core,
400 unsigned long *min_rate,
401 unsigned long *max_rate)
402 {
403 *min_rate = core->min_rate;
404 *max_rate = core->max_rate;
405 }
406
clk_hw_round_rate(struct clk_hw * hw,unsigned long rate)407 unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
408 {
409 int ret;
410 struct clk_rate_request req;
411
412 if (!hw)
413 {
414 return 0;
415 }
416
417 clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate);
418 req.rate = rate;
419
420 ret = clk_core_round_rate_nolock(hw->core, &req);
421 if (ret)
422 {
423 return 0;
424 }
425
426 return req.rate;
427 }
428
__clk_init_parent(struct clk_core * core)429 static struct clk_core *__clk_init_parent(struct clk_core *core)
430 {
431 u8 index = 0;
432
433 if (!core->num_parents)
434 {
435 return NULL;
436 }
437
438 if (core->num_parents > 1 && core->ops->get_parent)
439 {
440 index = core->ops->get_parent(core->hw);
441 }
442
443 return clk_core_get_parent_by_index(core, index);
444 }
445
__clk_core_init(struct clk_core * core)446 static int __clk_core_init(struct clk_core *core)
447 {
448 u32 rate;
449 int ret = -1;
450
451 if (!core)
452 {
453 return ret;
454 }
455
456 if (core->ops->init)
457 {
458 core->ops->init(core->hw);
459 }
460
461 core->parent = __clk_init_parent(core);
462
463 if (core->ops->recalc_accuracy)
464 {
465 core->accuracy = core->ops->recalc_accuracy(core->hw,
466 __clk_get_accuracy(core->parent));
467 }
468 else if (core->parent)
469 {
470 core->accuracy = core->parent->accuracy;
471 }
472 else
473 {
474 core->accuracy = 0;
475 }
476
477 if (core->ops->recalc_rate)
478 {
479 rate = core->ops->recalc_rate(core->hw, clk_core_get_rate(core->parent));
480 }
481 else if (core->parent)
482 {
483 rate = core->parent->rate;
484 }
485 else
486 {
487 rate = 0;
488 }
489
490 if (core->parent)
491 {
492 core->p_rate = core->parent->rate;
493 }
494 else
495 {
496 core->p_rate = 0;
497 }
498
499 core->rate = rate;
500
501 if (core->flags & CLK_IS_CRITICAL)
502 {
503 ret = clk_core_enable(core);
504 if (ret)
505 {
506 return ret;
507 }
508 }
509
510 return 0;
511 }
512
clk_core_populate_parent_map(struct clk_core * core,const struct clk_init_data * init)513 static int clk_core_populate_parent_map(struct clk_core *core,
514 const struct clk_init_data *init)
515 {
516 u8 num_parents = init->num_parents;
517 const char *const *parent_names = init->parent_names;
518 const struct clk_hw **parent_hws = init->parent_hws;
519 const struct clk_parent_data *parent_data = init->parent_data;
520 int i, ret = 0;
521 struct clk_parent_map *parents, *parent;
522
523 if (!num_parents)
524 {
525 return 0;
526 }
527
528 /*
529 * Avoid unnecessary string look-ups of clk_core's possible parents by
530 * having a cache of names/clk_hw pointers to clk_core pointers.
531 */
532 parents = (struct clk_parent_map *)malloc(num_parents * sizeof(*parents));
533 core->parents = parents;
534 if (!parents)
535 {
536 return -1;
537 }
538
539 /* Copy everything over because it might be __initdata */
540 for (i = 0, parent = parents; i < num_parents; i++, parent++)
541 {
542 parent->index = -1;
543 parent->core = NULL;
544 parent->hw = NULL;
545 parent->name = NULL;
546 parent->fw_name = NULL;
547 if (parent_names)
548 {
549 if (!parent_names[i])
550 {
551 hal_log_err("invalid NULL in %s's .parent_names\n", core->name);
552 }
553 else
554 {
555 parent->name = parent_names[i];
556 }
557 }
558 else if (parent_data)
559 {
560 parent->hw = parent_data[i].hw;
561 parent->index = parent_data[i].index;
562 if (parent_data[i].name)
563 {
564 parent->name = parent_data[i].name;
565 }
566 else
567 {
568 parent->name = parent_data[i].fw_name;
569 }
570
571 }
572 else if (parent_hws)
573 {
574 parent->hw = parent_hws[i];
575 }
576 else
577 {
578 ret = -1;
579 hal_log_err("Must specify parents if num_parents > 0\n");
580 }
581
582 if (ret)
583 {
584 core->parents = NULL;
585 free(parents);
586 return ret;
587 }
588 }
589
590 return 0;
591 }
592
593 #if 0
594 static void clk_core_free_parent_map(struct clk_core *core)
595 {
596 if (!core->num_parents)
597 {
598 return;
599 }
600
601 free(core->parents);
602 }
603 #endif
604
clk_hw_register(struct clk_hw * hw)605 int clk_hw_register(struct clk_hw *hw)
606 {
607 int ret = -1;
608 struct clk_core *core;
609 struct clk_init_data *init;
610
611 if (!hw)
612 {
613 return 0;
614 }
615
616 init = hw->init;
617
618 core = (struct clk_core *)malloc(sizeof(*core));
619 if (!core)
620 {
621 hal_log_err("out of memory\n");
622 return -1;
623 }
624
625 core->name = init->name;
626 core->num_parents = init->num_parents;
627 core->flags = init->flags;
628 core->hw = hw;
629 core->ops = hw->init->ops;
630 core->min_rate = 0;
631 core->max_rate = ULONG_MAX;
632 core->enable_count = 0;
633
634 core->clk = (struct clk *)malloc(sizeof(struct clk));
635 if (!core->clk)
636 {
637 hal_log_err("out of memory\n");
638 goto fail_clk;
639 }
640 core->clk->core = core;
641 core->clk->name = core->name;
642 core->clk->count = 0;
643
644 ret = clk_core_populate_parent_map(core, init);
645 if (ret)
646 {
647 goto fail_parents;
648 }
649
650 ret = __clk_core_init(core);
651
652 if (ret)
653 {
654 free(core);
655 return -1;
656 }
657 hw->core = core;
658
659 list_add_tail(&core->node, &clk_root_list);
660
661 return ret;
662
663 fail_parents:
664 free(core->clk);
665 core->clk = NULL;
666
667 fail_clk:
668 free(core);
669 core = NULL;
670
671 return ret;
672 }
673
clk_hw_unregister(struct clk_hw * hw)674 int clk_hw_unregister(struct clk_hw *hw)
675 {
676 struct clk_core *core;
677
678 if (!hw || !hw->core)
679 {
680 return 0;
681 }
682
683 list_for_each_entry(core, &clk_root_list, node)
684 {
685 if (core->hw->type != hw->type)
686 {
687 continue;
688 }
689 if (core->hw->id != hw->id)
690 {
691 continue;
692 }
693 list_del(&core->node);
694 free(core->clk);
695 free(core);
696 return 0;
697 }
698
699 return 0;
700 }
701
clk_core_get(hal_clk_type_t type,hal_clk_id_t id)702 struct clk_core *clk_core_get(hal_clk_type_t type, hal_clk_id_t id)
703 {
704 struct clk_core *core = NULL;
705
706 list_for_each_entry(core, &clk_root_list, node)
707 {
708 if (core->hw->type != type)
709 {
710 continue;
711 }
712 if (core->hw->id != id)
713 {
714 continue;
715 }
716
717 return core;
718 }
719
720 return NULL;
721 }
722
clk_core_is_enabled(struct clk_core * core)723 hal_clk_status_t clk_core_is_enabled(struct clk_core *core)
724 {
725 /*
726 * .is_enabled is only mandatory for clocks that gate
727 * fall back to software usage counter if .is_enabled is missing
728 */
729 if (!core->ops->is_enabled)
730 {
731 return !!core->enable_count;
732 }
733
734 return core->ops->is_enabled(core->hw);
735 }
736
clk_core_enable(struct clk_core * core)737 hal_clk_status_t clk_core_enable(struct clk_core *core)
738 {
739 int ret = 0;
740
741 if (!core)
742 {
743 return 0;
744 }
745
746 if (core->enable_count == 0)
747 {
748 ret = clk_core_enable(core->parent);
749
750 if (ret)
751 {
752 return ret;
753 }
754
755 if (core->ops->enable)
756 {
757 ret = core->ops->enable(core->hw);
758 }
759
760 if (ret)
761 {
762 clk_core_disable(core->parent);
763 return ret;
764 }
765 }
766
767 core->enable_count++;
768 return 0;
769 }
770
clk_core_disable(struct clk_core * core)771 hal_clk_status_t clk_core_disable(struct clk_core *core)
772 {
773 if (!core)
774 {
775 return 0;
776 }
777
778 if (core->enable_count == 0)
779 {
780 return 0;
781 }
782
783 if (--core->enable_count > 0)
784 {
785 return 0;
786 }
787
788 if (core->ops->disable)
789 {
790 core->ops->disable(core->hw);
791 }
792
793 clk_core_disable(core->parent);
794
795 return 0;
796 }
797
clk_core_round_rate(struct clk_core * core,u32 rate)798 u32 clk_core_round_rate(struct clk_core *core, u32 rate)
799 {
800 struct clk_rate_request req;
801 int ret;
802
803 if (!core)
804 {
805 return 0;
806 }
807
808 clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
809 req.rate = rate;
810
811 ret = clk_core_round_rate_nolock(core, &req);
812
813 if (ret)
814 {
815 return ret;
816 }
817
818 return req.rate;
819 }
820
clk_core_recalc_rate(struct clk_core * core,struct clk_core * p_core)821 u32 clk_core_recalc_rate(struct clk_core *core, struct clk_core *p_core)
822 {
823 u32 p_rate = 0;
824
825 if (!core)
826 {
827 return 0;
828 }
829
830 if (!p_core)
831 {
832 return core->rate;
833 }
834
835 clk_core_recalc_rate(p_core, p_core->parent);
836
837 p_rate = p_core->rate;
838 if (core->ops->recalc_rate)
839 {
840 return core->ops->recalc_rate(core->hw, p_rate);
841 }
842
843 return core->rate;
844 }
845
clk_core_get_rate(struct clk_core * core)846 u32 clk_core_get_rate(struct clk_core *core)
847 {
848 if (!core)
849 {
850 return 0;
851 }
852
853 core->parent = __clk_init_parent(core);
854
855 return clk_core_recalc_rate(core, core->parent);
856 }
857
clk_hw_get_rate(const struct clk_hw * hw)858 u32 clk_hw_get_rate(const struct clk_hw *hw)
859 {
860 return clk_core_get_rate(hw->core);
861 }
862
clk_core_set_rate(struct clk_core * core,struct clk_core * p_core,unsigned long rate)863 hal_clk_status_t clk_core_set_rate(struct clk_core *core, struct clk_core *p_core, unsigned long rate)
864 {
865 u8 ret = -1;
866
867 if (!core || !p_core)
868 {
869 hal_log_err("core or p_core is NULL\n");
870 return ret;
871 }
872
873 if (core->ops->set_rate)
874 {
875 ret = core->ops->set_rate(core->hw, rate, p_core->rate);
876 }
877
878 if (ret)
879 {
880 return ret;
881 }
882
883 core->rate = rate;
884 return ret;
885 }
886
clk_hw_set_rate(struct clk_hw * hw,unsigned long rate)887 hal_clk_status_t clk_hw_set_rate(struct clk_hw *hw, unsigned long rate)
888 {
889 struct clk_core *core, *p_core;
890 core = clk_hw_get_core(hw);
891 p_core = clk_core_get_parent(core);
892
893 return clk_core_set_rate(core, p_core, rate);
894 }
895
896
__clk_set_parent(struct clk_core * core,struct clk_core * parent,u8 p_index)897 static int __clk_set_parent(struct clk_core *core, struct clk_core *parent,
898 u8 p_index)
899 {
900 int ret = 0;
901
902 /* change clock input source */
903 if (parent && core->ops->set_parent)
904 {
905 ret = core->ops->set_parent(core->hw, p_index);
906 }
907
908 return ret;
909 }
910
clk_fetch_parent_index(struct clk_core * core,struct clk_core * parent)911 static int clk_fetch_parent_index(struct clk_core *core,
912 struct clk_core *parent)
913 {
914 int i;
915
916 if (!parent)
917 {
918 return -1;
919 }
920
921 for (i = 0; i < core->num_parents; i++)
922 {
923 /* Found it first try! */
924 if (core->parents[i].core)
925 {
926 if (core->parents[i].core == parent)
927 {
928 return i;
929 }
930 }
931
932 /* Something else is here, so keep looking */
933 if (core->parents[i].core)
934 {
935 continue;
936 }
937
938 /* Maybe core hasn't been cached but the hw is all we know? */
939 if (core->parents[i].hw)
940 {
941 if (core->parents[i].hw == parent->hw)
942 {
943 break;
944 }
945
946 /* Didn't match, but we're expecting a clk_hw */
947 continue;
948 }
949
950 /* Fallback to comparing globally unique names */
951 if (core->parents[i].name &&
952 !strcmp(parent->name, core->parents[i].name))
953 {
954 break;
955 }
956 }
957
958 if (i == core->num_parents)
959 {
960 return -1;
961 }
962
963 core->parents[i].core = parent;
964 return i;
965 }
966
clk_core_get_parent(struct clk_core * core)967 struct clk_core *clk_core_get_parent(struct clk_core *core)
968 {
969 if (!core)
970 {
971 return NULL;
972 }
973
974 if (!core->parent)
975 core->parent = __clk_init_parent(core);
976
977 return core->parent;
978 }
979
clk_core_set_parent(struct clk_core * core,struct clk_core * parent)980 hal_clk_status_t clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
981 {
982 int ret = 0;
983 int p_index = 0;
984 uint32_t p_rate = 0;
985
986 if (!core)
987 {
988 return 0;
989 }
990
991 if (core->parent == parent)
992 {
993 return 0;
994 }
995
996 /* verify ops for for multi-parent clks */
997 if ((core->num_parents > 1) && (!core->ops->set_parent))
998 {
999 ret = -1;
1000 goto out;
1001 }
1002
1003 /* try finding the new parent index */
1004 if (parent)
1005 {
1006 p_index = clk_fetch_parent_index(core, parent);
1007 if (p_index < 0)
1008 {
1009 printf("%s: clk %s can not be parent of clk %s\n",
1010 __func__, parent->name, core->name);
1011 ret = p_index;
1012 goto out;
1013 }
1014 p_rate = parent->rate;
1015 }
1016
1017 /* do the re-parent */
1018 ret = __clk_set_parent(core, parent, p_index);
1019
1020 /* propagate rate an accuracy recalculation accordingly */
1021 if (!ret)
1022 {
1023 core->parent = parent;
1024 core->p_rate = p_rate;
1025 core->rate = clk_core_recalc_rate(core, parent);
1026 }
1027
1028 out:
1029 return ret;
1030 }
1031
1032