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