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