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 
32 #include "sunxi_hal_common.h"
33 #include "clk_factors.h"
34 #include "clk.h"
35 
sunxi_clk_disable_plllock(struct factor_init_data * factor)36 static int sunxi_clk_disable_plllock(struct factor_init_data *factor)
37 {
38     volatile u32 reg;
39 
40     switch (factor->lock_mode)
41     {
42         case PLL_LOCK_NEW_MODE:
43         case PLL_LOCK_OLD_MODE:
44             /* make sure pll new mode is disable */
45             reg = readl(factor->pll_lock_ctrl_reg);
46             reg = SET_BITS(factor->lock_en_bit, 1, reg, 0);
47             writel(reg, factor->pll_lock_ctrl_reg);
48 
49             reg = readl(factor->pll_lock_ctrl_reg);
50             reg = SET_BITS(28, 1, reg, 0);
51             writel(reg, factor->pll_lock_ctrl_reg);
52             break;
53         case PLL_LOCK_NONE_MODE:
54             break;
55         default:
56             //WARN(1, "invaild pll lock mode:%u\n", factor->lock_mode);
57             return -1;
58     }
59 
60     return 0;
61 }
62 
sunxi_clk_is_lock(struct factor_init_data * factor)63 static int sunxi_clk_is_lock(struct factor_init_data *factor)
64 {
65     volatile u32 reg;
66     u32 loop = 5000;
67 
68     if (factor->lock_mode >= PLL_LOCK_MODE_MAX)
69     {
70         //WARN(1, "invaild pll lock mode:%u\n", factor->lock_mode);
71         return -1;
72     }
73 
74     if (factor->lock_mode == PLL_LOCK_NEW_MODE)
75     {
76         /* enable pll new mode */
77         reg = readl(factor->pll_lock_ctrl_reg);
78         reg = SET_BITS(28, 1, reg, 1);
79         writel(reg, factor->pll_lock_ctrl_reg);
80 
81         reg = readl(factor->pll_lock_ctrl_reg);
82         reg = SET_BITS(factor->lock_en_bit, 1, reg, 1);
83         writel(reg, factor->pll_lock_ctrl_reg);
84     }
85 
86     while (--loop)
87     {
88         reg = readl(factor->lock_reg);
89         if (GET_BITS(factor->lock_bit, 1, reg))
90         {
91             clk_udelay(20);
92             break;
93         }
94 
95         clk_udelay(1);
96     }
97 
98     if (factor->lock_mode == PLL_LOCK_NEW_MODE)
99     {
100         /* disable pll new mode */
101         reg = readl(factor->pll_lock_ctrl_reg);
102         reg = SET_BITS(factor->lock_en_bit, 1, reg, 0);
103         writel(reg, factor->pll_lock_ctrl_reg);
104 
105         reg = readl(factor->pll_lock_ctrl_reg);
106         reg = SET_BITS(28, 1, reg, 0);
107         writel(reg, factor->pll_lock_ctrl_reg);
108     }
109 
110     if (!loop)
111     {
112         //#if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM)
113         //      pr_err("clk %s wait lock timeout\n",
114         //             clk_hw_get_name(&factor->hw));
115         return 0;
116         //#else
117         //      return -1;
118         //#endif
119     }
120 
121     return 0;
122 }
123 
sunxi_clk_fators_enable(clk_factor_pt clk)124 hal_clk_status_t sunxi_clk_fators_enable(clk_factor_pt clk)
125 {
126     u32 reg = 0;
127     hal_clk_status_t ret = HAL_CLK_STATUS_ENABLED;
128     struct factor_init_data *factor = NULL;
129     struct sunxi_clk_factors_config *config = NULL;
130 
131     factor = clk->factor_data;
132     config = factor->config;
133 
134     /* check if the pll enabled already */
135     reg = readl(factor->reg);
136     if (GET_BITS(config->enshift, 1, reg))
137     {
138         sunxi_clk_disable_plllock(factor);
139         /* get factor register value */
140         reg = readl(factor->reg);
141         goto enable_sdm;
142     }
143 
144     //  if (factor->lock)
145     //      spin_lock_irqsave(factor->lock, flags);
146 
147     sunxi_clk_disable_plllock(factor);
148 
149     /* get factor register value */
150     reg = readl(factor->reg);
151 
152     /* enable the register */
153     reg = SET_BITS(config->enshift, 1, reg, 1);
154 
155     /* update for pll_ddr register */
156     if (config->updshift)
157     {
158         reg = SET_BITS(config->updshift, 1, reg, 1);
159     }
160 
161     if (config->out_enshift)
162     {
163         reg = SET_BITS(config->out_enshift, 1, reg, 1);
164     }
165 
166     if (config->mux_inshift)
167     {
168         reg = SET_BITS(config->mux_inshift, 1, reg, 1);
169     }
170 
171 enable_sdm:
172     if (config->sdmwidth)
173     {
174         writel(config->sdmval,
175                (volatile uint32_t *)config->sdmpat);
176         reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1);
177     }
178 
179     writel(reg, factor->reg);
180 
181     if (sunxi_clk_is_lock(factor))
182     {
183         //  if (factor->lock)
184         //      spin_unlock_irqrestore(factor->lock, flags);
185         //  WARN(1, "clk %s wait lock timeout\n", clk_hw_get_name(&factor->hw));
186         ret = HAL_CLK_STATUS_DISABLED;
187     }
188 
189     //if (factor->lock)
190     //  spin_unlock_irqrestore(factor->lock, flags);
191 
192     return ret;
193 }
194 
sunxi_clk_fators_disable(clk_factor_pt clk)195 hal_clk_status_t sunxi_clk_fators_disable(clk_factor_pt clk)
196 {
197     u32 reg = 0;
198     hal_clk_status_t ret = HAL_CLK_STATUS_DISABLED;
199     struct factor_init_data *factor = NULL;
200     struct sunxi_clk_factors_config *config = NULL;
201 
202     factor = clk->factor_data;
203     config = factor->config;;
204 
205     //if (factor->flags & CLK_NO_DISABLE)
206     //  return;
207 
208     /* check if the pll disabled already */
209     reg = readl(factor->reg);
210     if (!GET_BITS(config->enshift, 1, reg))
211     {
212         return ret;
213     }
214 
215     /* When the pll is not in use, just set it to the minimum frequency */
216     /* if (factor->flags & CLK_IGNORE_DISABLE) {
217         //clk_set_rate(hw->clk, 0);
218         return;
219     }
220     */
221 
222     //if (factor->lock)
223     //  spin_lock_irqsave(factor->lock, flags);
224 
225     reg = readl(factor->reg);
226     if (config->sdmwidth)
227     {
228         reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 0);
229     }
230 
231     /* update for pll_ddr register */
232     if (config->updshift)
233     {
234         reg = SET_BITS(config->updshift, 1, reg, 1);
235     }
236 
237     /* disable Pll-enable-bit*/
238     reg = SET_BITS(config->enshift, 1, reg, 0);
239     writel(reg, factor->reg);
240 
241     /* disable Pll-lock-bit if needed */
242     sunxi_clk_disable_plllock(factor);
243 
244     //if (factor->lock)
245     //  spin_unlock_irqrestore(factor->lock, flags);
246     return ret;
247 }
248 
sunxi_clk_fators_is_enabled(clk_factor_pt clk)249 hal_clk_status_t sunxi_clk_fators_is_enabled(clk_factor_pt clk)
250 {
251     u32 reg = 0, val = 0;
252     hal_clk_status_t ret;
253     struct factor_init_data *factor = NULL;
254     struct sunxi_clk_factors_config *config = NULL;
255     CCMU_TRACE();
256 
257     //  unsigned long flags = 0;
258     factor = clk->factor_data;
259     config = factor->config;
260     //  if (factor->flags & CLK_NO_DISABLE)
261     //      return __clk_get_enable_count(hw->clk);
262 
263     //if (factor->lock)
264     //  spin_lock_irqsave(factor->lock, flags);
265 
266     reg = readl(factor->reg);
267     val = GET_BITS(config->enshift, 1, reg);
268 
269     //if (factor->lock)
270     //  spin_unlock_irqrestore(factor->lock, flags);
271 
272     return val ? HAL_CLK_STATUS_ENABLED : HAL_CLK_STATUS_DISABLED;
273 }
274 
sunxi_clk_factors_recalc_rate(clk_factor_pt clk,u32 * rate)275 hal_clk_status_t sunxi_clk_factors_recalc_rate(clk_factor_pt clk, u32 *rate)
276 {
277     u32 reg = 0,  flags = 0,  parent_rate = 0;
278     struct clk_factors_value factor_val;
279     hal_clk_status_t ret = HAL_CLK_STATUS_OK;
280     struct factor_init_data *factor = NULL;
281     struct sunxi_clk_factors_config *config = NULL;
282 
283     CCMU_TRACE();
284 
285     factor = clk->factor_data;
286     if (!factor->calc_rate)
287     {
288         return HAL_CLK_STATUS_UNINITIALIZED;
289     }
290 
291     config = factor->config;
292     parent_rate = clk->clk_core.parent_rate;
293 
294     //if (factor->lock)
295     //  spin_lock_irqsave(factor->lock, flags);
296 
297     reg = readl(factor->reg);
298 
299     //if (factor->lock)
300     //  spin_unlock_irqrestore(factor->lock, flags);
301 
302     if (config->nwidth)
303     {
304         factor_val.factorn = GET_BITS(config->nshift, config->nwidth, reg);
305     }
306     else
307     {
308         factor_val.factorn = 0xffff;
309     }
310 
311     if (config->kwidth)
312     {
313         factor_val.factork = GET_BITS(config->kshift, config->kwidth, reg);
314     }
315     else
316     {
317         factor_val.factork = 0xffff;
318     }
319 
320     if (config->mwidth)
321     {
322         factor_val.factorm = GET_BITS(config->mshift, config->mwidth, reg);
323     }
324     else
325     {
326         factor_val.factorm = 0xffff;
327     }
328 
329     if (config->pwidth)
330     {
331         factor_val.factorp = GET_BITS(config->pshift, config->pwidth, reg);
332     }
333     else
334     {
335         factor_val.factorp = 0xffff;
336     }
337 
338     if (config->d1width)
339     {
340         factor_val.factord1 = GET_BITS(config->d1shift, config->d1width, reg);
341     }
342     else
343     {
344         factor_val.factord1 = 0xffff;
345     }
346 
347     if (config->d2width)
348     {
349         factor_val.factord2 = GET_BITS(config->d2shift, config->d2width, reg);
350     }
351     else
352     {
353         factor_val.factord2 = 0xffff;
354     }
355 
356     if (config->frac)
357     {
358         factor_val.frac_mode = GET_BITS(config->modeshift, 1, reg);
359         factor_val.frac_freq = GET_BITS(config->outshift, 1, reg);
360     }
361     else
362     {
363         factor_val.frac_mode = 0xffff;
364         factor_val.frac_freq = 0xffff;
365     }
366     if (factor->calc_rate)
367     {
368         (*rate)  = factor->calc_rate(parent_rate, &factor_val);
369     }
370 
371     return ret;
372 }
373 
sunxi_clk_factors_set_rate(clk_factor_pt clk,u32 rate)374 hal_clk_status_t sunxi_clk_factors_set_rate(clk_factor_pt clk, u32 rate)
375 {
376     u32 reg = 0, parent_rate = 0;
377     hal_clk_status_t ret = HAL_CLK_STATUS_OK;
378     struct clk_factors_value factor_val;
379     struct factor_init_data *factor = NULL;
380     struct sunxi_clk_factors_config *config = NULL;
381 
382     factor = clk->factor_data;
383     config = factor->config;
384     parent_rate = clk->clk_core.parent_rate;
385     CCMU_TRACE();
386     if (!factor->get_factors)
387     {
388         return HAL_CLK_STATUS_UNINITIALIZED;
389     }
390 
391     /* factor_val is initialized with its original value,
392      * it's factors(such as:M,N,K,P,d1,d2...) are Random Value.
393      * if donot judge the return value of "factor->get_factors",
394      * it may change the original register value.
395      */
396     if (factor->get_factors(rate, parent_rate, &factor_val) < 0)
397     {
398         /* cannot get right factors for clk,just break */
399         CCMU_ERR("clk %d set rate failed! Because cannot get right factors for clk\n", clk->clk_core.clk);
400         return HAL_CLK_STATUS_UNINITIALIZED;
401     }
402 #if 0
403     if (factor->flags & CLK_RATE_FLAT_FACTORS)
404     {
405         return sunxi_clk_factors_set_flat_facotrs(factor, &factor_val);
406     }
407 #endif
408     //if (factor->lock)
409     //  spin_lock_irqsave(factor->lock, flags);
410 
411     sunxi_clk_disable_plllock(factor);
412 
413     reg = readl(factor->reg);
414     if (config->sdmwidth)
415     {
416         writel(config->sdmval, (volatile uint32_t *)config->sdmpat);
417         reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1);
418     }
419     if (config->nwidth)
420     {
421         reg = SET_BITS(config->nshift, config->nwidth, reg, factor_val.factorn);
422     }
423     if (config->kwidth)
424     {
425         reg = SET_BITS(config->kshift, config->kwidth, reg, factor_val.factork);
426     }
427     if (config->mwidth)
428     {
429         reg = SET_BITS(config->mshift, config->mwidth, reg, factor_val.factorm);
430     }
431     if (config->pwidth)
432     {
433         reg = SET_BITS(config->pshift, config->pwidth, reg, factor_val.factorp);
434     }
435     if (config->d1width)
436     {
437         reg = SET_BITS(config->d1shift, config->d1width, reg, factor_val.factord1);
438     }
439     if (config->d2width)
440     {
441         reg = SET_BITS(config->d2shift, config->d2width, reg, factor_val.factord2);
442     }
443     if (config->frac)
444     {
445         reg = SET_BITS(config->modeshift, 1, reg, factor_val.frac_mode);
446         reg = SET_BITS(config->outshift, 1, reg, factor_val.frac_freq);
447     }
448     if (config->updshift)
449     {
450         reg = SET_BITS(config->updshift, 1, reg, 1);
451     }
452     writel(reg, factor->reg);
453 
454     if (GET_BITS(config->enshift, 1, reg))
455     {
456         if (sunxi_clk_is_lock(factor))
457         {
458             //if (factor->lock)
459             //spin_unlock_irqrestore(factor->lock, flags);
460             CCMU_ERR("clk %d wait lock timeout\n", clk->clk_core.clk);
461             return -1;
462         }
463     }
464 
465     //if (factor->lock)
466     //  spin_unlock_irqrestore(factor->lock, flags);
467 
468     return ret;
469 }
470 
471 
472 /*
473  * sunxi_clk_set_factor_lock_mode() - Set factor lock mode
474  */
sunxi_clk_set_factor_lock_mode(struct factor_init_data * factor,const char * lock_mode)475 void sunxi_clk_set_factor_lock_mode(struct factor_init_data *factor,
476                                     const char *lock_mode)
477 {
478     if (!strcmp(lock_mode, "new"))
479     {
480         factor->lock_mode = PLL_LOCK_NEW_MODE;
481     }
482     else if (!strcmp(lock_mode, "old"))
483     {
484         factor->lock_mode = PLL_LOCK_OLD_MODE;
485     }
486     else
487     {
488         factor->lock_mode = PLL_LOCK_NONE_MODE;
489     }
490 }
491 
492 
sunxi_clk_factors_round_rate(clk_factor_pt clk,u32 rate)493 u32 sunxi_clk_factors_round_rate(clk_factor_pt clk, u32 rate)
494 {
495     u32 parent_rate = 0;
496     struct clk_factors_value factor_val;
497     struct factor_init_data *factor = clk->factor_data;
498 
499     if (!factor->get_factors || !factor->calc_rate)
500     {
501         return rate;
502     }
503 
504     parent_rate = clk->clk_core.parent_rate;
505     factor->get_factors(rate, parent_rate, &factor_val);
506     return factor->calc_rate(parent_rate, &factor_val);
507 }
508 
509 
sunxi_clk_get_common_factors(struct sunxi_clk_factors_config * f_config,struct clk_factors_value * factor,struct sunxi_clk_factor_freq table[],unsigned long index,unsigned long tbl_size)510 int sunxi_clk_get_common_factors(struct sunxi_clk_factors_config *f_config, struct clk_factors_value *factor,
511                                  struct sunxi_clk_factor_freq table[], unsigned long index, unsigned long tbl_size)
512 {
513     if (index >= tbl_size / sizeof(struct sunxi_clk_factor_freq))
514     {
515         return -1;
516     }
517 
518     factor->factorn = (table[index].factor >> f_config->nshift) & ((1 << (f_config->nwidth)) - 1);
519     factor->factork = (table[index].factor >> f_config->kshift) & ((1 << (f_config->kwidth)) - 1);
520     factor->factorm = (table[index].factor >> f_config->mshift) & ((1 << (f_config->mwidth)) - 1);
521     factor->factorp = (table[index].factor >> f_config->pshift) & ((1 << (f_config->pwidth)) - 1);
522     factor->factord1 = (table[index].factor >> f_config->d1shift) & ((1 << (f_config->d1width)) - 1);
523     factor->factord2 = (table[index].factor >> f_config->d2shift) & ((1 << (f_config->d2width)) - 1);
524 
525     if (f_config->frac)
526     {
527         factor->frac_mode = (table[index].factor >> f_config->modeshift) & 1;
528         factor->frac_freq = (table[index].factor >> f_config->outshift) & 1;
529     }
530 
531     return 0;
532 }
533 
sunxi_clk_freq_search(struct sunxi_clk_factor_freq tbl[],unsigned long freq,int low,int high)534 int sunxi_clk_freq_search(struct sunxi_clk_factor_freq tbl[],
535                           unsigned long freq, int low, int high)
536 {
537     int mid;
538     unsigned long checkfreq;
539 
540     if (low > high)
541     {
542         return (high == -1) ? 0 : high;
543     }
544 
545     mid = (low + high) / 2;
546     checkfreq = tbl[mid].freq / 1000000;
547 
548     if (checkfreq == freq)
549     {
550         return mid;
551     }
552     else if (checkfreq > freq)
553     {
554         return sunxi_clk_freq_search(tbl, freq, low, mid - 1);
555     }
556     else
557     {
558         return sunxi_clk_freq_search(tbl, freq, mid + 1, high);
559     }
560 }
561 
sunxi_clk_freq_find(struct sunxi_clk_factor_freq tbl[],unsigned long n,unsigned long freq)562 int sunxi_clk_freq_find(struct sunxi_clk_factor_freq tbl[],
563                         unsigned long n, unsigned long freq)
564 {
565     int delta1, delta2;
566     int i = sunxi_clk_freq_search(tbl, freq, 0, n - 1);
567 
568     if (i != n - 1)
569     {
570 
571         delta1 = (freq > tbl[i].freq / 1000000)
572                  ? (freq - tbl[i].freq / 1000000)
573                  : (tbl[i].freq / 1000000 - freq);
574 
575         delta2 = (freq > tbl[i + 1].freq / 1000000)
576                  ? (freq - tbl[i + 1].freq / 1000000)
577                  : (tbl[i + 1].freq / 1000000 - freq);
578 
579         if (delta2 < delta1)
580         {
581             i++;
582         }
583     }
584 
585     return i;
586 }
587 
588 
sunxi_clk_com_ftr_sr(struct sunxi_clk_factors_config * f_config,struct clk_factors_value * factor,struct sunxi_clk_factor_freq table[],unsigned long index,unsigned long tbl_count)589 int sunxi_clk_com_ftr_sr(struct sunxi_clk_factors_config *f_config,
590                          struct clk_factors_value *factor,
591                          struct sunxi_clk_factor_freq table[],
592                          unsigned long index, unsigned long tbl_count)
593 {
594     int i = sunxi_clk_freq_find(table, tbl_count, index);
595 
596     if (i >= tbl_count)
597     {
598         return -1;
599     }
600 
601     factor->factorn = (table[i].factor >> f_config->nshift) & ((1 << (f_config->nwidth)) - 1);
602     factor->factork = (table[i].factor >> f_config->kshift) & ((1 << (f_config->kwidth)) - 1);
603     factor->factorm = (table[i].factor >> f_config->mshift) & ((1 << (f_config->mwidth)) - 1);
604     factor->factorp = (table[i].factor >> f_config->pshift) & ((1 << (f_config->pwidth)) - 1);
605     factor->factord1 = (table[i].factor >> f_config->d1shift) & ((1 << (f_config->d1width)) - 1);
606     factor->factord2 = (table[i].factor >> f_config->d2shift) & ((1 << (f_config->d2width)) - 1);
607 
608     if (f_config->frac)
609     {
610         factor->frac_mode = (table[i].factor >> f_config->modeshift) & 1;
611         factor->frac_freq = (table[i].factor >> f_config->outshift) & 1;
612     }
613 
614     return 0;
615 }
616 
617 
618