1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018-02-08     RT-Thread    the first version
9  */
10 #include <rtthread.h>
11 #include <rthw.h>
12 
13 #include "drv_clock.h"
14 
cpu_get_pll_clk(void)15 int cpu_get_pll_clk(void)
16 {
17     rt_uint32_t reg;
18     int n, k, m, p;
19 
20     reg = CCU->pll_cpu_ctrl;
21     if (!(reg & (0x01 << 31)))
22         return 0;
23 
24     p = PLL_CPU_DIV_P(reg) + 1;
25     n = PLL_CPU_FACTOR_N(reg) + 1;
26     k = PLL_CPU_FACTOR_K(reg) + 1;
27     m = PLL_CPU_FACTOR_M(reg) + 1;
28     //(24MHz*n*k)/(m*p)
29     return (_24MHZ_ * n * k) / (m * p);
30 }
31 
audio_get_pll_clk(void)32 int audio_get_pll_clk(void)
33 {
34     rt_uint32_t reg;
35     unsigned char n, m;
36 
37     reg = CCU->pll_audio_ctrl;
38     if (!(reg & (0x01 << 31)))
39         return 0;
40 
41     n = PLL_AUDIO_FACTOR_N(reg) + 1;
42     m = PLL_AUDIO_PREDIV_M(reg) + 1;
43 
44     //24MHz*n*2/m
45     return _24MHZ_ * 2 * n / m;
46 }
47 
video_get_pll_clk(void)48 int video_get_pll_clk(void)
49 {
50     rt_uint32_t reg;
51     int n, m;
52 
53     reg = CCU->pll_video_ctrl;
54     if (!(reg & (0x01 << 31)))
55         return 0;
56 
57     if (reg & PLL_VIDEO_MODE_SEL)
58     {
59         //(24MHz*n)/m
60         n = PLL_VIDEO_FACTOR_N(reg) + 1;
61         m = PLL_VIDEO_PREDIV_M(reg) + 1;
62         return (_24MHZ_ * n) / m;
63     }
64 
65     if (reg & PLL_VIDEO_FRAC_CLK_OUT)
66         return 270000000;
67     else
68         return 297000000;
69 
70     return 0;
71 }
72 
ve_get_pll_clk(void)73 int ve_get_pll_clk(void)
74 {
75     rt_uint32_t reg;
76     int n, m;
77 
78     reg = CCU->pll_ve_ctrl;
79     if (!(reg & (0x01 << 31)))
80         return 0;
81 
82     if (reg & PLL_VE_MODE_SEL)
83     {
84         //(24MHz*n)/m
85         n = PLL_VE_FACTOR_N(reg) + 1;
86         m = PLL_VE_PREDIV_M(reg) + 1;
87 
88         return (_24MHZ_ * n) / m;
89     }
90 
91     if (reg & PLL_VE_FRAC_CLK_OUT)
92         return 297000000;
93     else
94         return 270000000;
95 
96     return 0;
97 }
98 
ddr_get_pll_clk(void)99 int ddr_get_pll_clk(void)
100 {
101     rt_uint32_t reg;
102     int n, k, m;
103 
104     reg = CCU->pll_ddr_ctrl;
105     if (!(reg & (0x01 << 31)))
106         return 0;
107 
108     n = PLL_DDR_FACTOR_N(reg) + 1;
109     k = PLL_DDR_FACTOR_K(reg) + 1;
110     m = PLL_DDR_FACTOR_M(reg) + 1;
111 
112     //(24MHz*n*k)/m
113     return (_24MHZ_ * n * k) / m;
114 }
115 
periph_get_pll_clk(void)116 int periph_get_pll_clk(void)
117 {
118     rt_uint32_t reg;
119     int n, k;
120 
121     reg = CCU->pll_periph_ctrl;
122     if (!(reg & (0x01 << 31)))
123         return 0;
124 
125     n = PLL_PERIPH_FACTOR_N(reg) + 1;
126     k = PLL_PERIPH_FACTOR_K(reg) + 1;
127 
128     return _24MHZ_ * n * k;
129 }
130 
cpu_get_clk_src(void)131 static int cpu_get_clk_src(void)
132 {
133     return (CCU->cpu_clk_src >> 16) & 0x3;
134 }
135 
cpu_get_clk(void)136 int cpu_get_clk(void)
137 {
138     rt_uint32_t reg;
139     int cpusrc;
140 
141     reg = CCU->ahb_apb_hclkc_cfg;
142     cpusrc = cpu_get_clk_src();
143 
144     if (cpusrc == CLK_PLL_SRC)
145         return (cpu_get_pll_clk() / (HCLKC_DIV(reg) + 1));
146     else if (cpusrc == CLK_OSC24M_SRC)
147         return _24MHZ_ / (HCLKC_DIV(reg) + 1);
148     else
149         return _32KHZ_ / (HCLKC_DIV(reg) + 1);  //猜测 内部32KHz时钟
150 
151     return 0;
152 }
153 
ahb_get_clk(void)154 int ahb_get_clk(void)
155 {
156     rt_uint32_t reg;
157     int sel, spd;
158 
159     reg = CCU->ahb_apb_hclkc_cfg;
160     sel = AHB_SRC_SEL(reg);
161 
162     if (sel == CLK_PLL_SRC)
163     {
164         spd = cpu_get_clk();
165         return spd / (1 << AHB_CLK_DIV(reg));
166     }
167     else if (sel == PRE_DIV_SRC)
168     {
169         spd = periph_get_pll_clk();
170         return spd / (AHB_PRE_DIV(reg) + 1) / (1 << AHB_CLK_DIV(reg));
171     }
172     else if (sel == CLK_OSC24M_SRC)
173         return _24MHZ_ / (1 << AHB_CLK_DIV(reg));
174     else
175         return _32KHZ_ / (1 << AHB_CLK_DIV(reg));
176 }
177 
apb_get_clk(void)178 int apb_get_clk(void)
179 {
180     rt_uint32_t reg;
181     int spd;
182 
183     reg = CCU->ahb_apb_hclkc_cfg;
184     spd = ahb_get_clk();
185     // 0x:/2 10:/4 11:/8
186     if (!(APH_CLK_PATIO(reg) & 0x1))
187         return spd / 2;
188     else
189         return spd / (1 << APH_CLK_PATIO(reg));
190 }
191 
192 
wait_pll_stable(rt_uint32_t base)193 static rt_err_t wait_pll_stable(rt_uint32_t base)
194 {
195     rt_uint32_t rval = 0;
196     volatile int time = 0xfff;
197 
198     do
199     {
200         rval = *((volatile rt_uint32_t *)base);
201         time--;
202     }
203     while (time && !(rval & (1 << 28)));
204 
205     return !time;
206 }
207 
cpu_set_pll_clk(int clk)208 rt_err_t cpu_set_pll_clk(int clk)
209 {
210     rt_uint32_t cpu_src;
211     int p = 0, k = 1, m = 1, n = 0;
212 
213     if (clk == 0)
214         return -RT_EINVAL;
215 
216     if (clk > 1152000000)
217     {
218         k = 2;
219     }
220     else if (clk > 768000000)
221     {
222         k = 3;
223         m = 2;
224     }
225 
226     n = clk / (_24MHZ_ * k / m) - 1;
227     cpu_src = (CCU->cpu_clk_src >> 16) & 0x3;
228     CCU->cpu_clk_src = CLK_OSC24M_SRC << 16;
229     CCU->pll_cpu_ctrl &= ~(0x1 << 31);
230     //PLL1 rate = ((24000000 * n * k) >> 0) / m   (p is ignored)
231     CCU->pll_cpu_ctrl = (0x1 << 31) | (m << 0) | (k << 4) | (n << 8) | (p << 16);
232     if (wait_pll_stable((rt_uint32_t)(&CCU->pll_cpu_ctrl)))
233         return -RT_ERROR;
234 
235     CCU->cpu_clk_src = cpu_src << 16;
236 
237     return RT_EOK;
238 }
239 
audio_set_pll_clk(int clk)240 rt_err_t audio_set_pll_clk(int clk)
241 {
242     int n = 0, m = 0;
243     int n_temp = clk;
244     int m_temp = _24MHZ_ * 2;
245 
246     if ((clk > 200000000) || (clk < 20000000))
247         return -RT_EINVAL;
248 
249     if (clk == 0)
250     {
251         CCU->pll_audio_ctrl &= ~(0x1 << 31);
252         return RT_EOK;
253     }
254 
255     while (n_temp != m_temp)
256     {
257         if (n_temp > m_temp)
258         {
259             n_temp = n_temp - m_temp;
260         }
261         else if (m_temp > n_temp)
262         {
263             m_temp = m_temp - n_temp;
264         }
265     }
266 
267     n = clk / n_temp;
268     m = _24MHZ_ * 2 / m_temp;
269     if ((n > 128) || (m > 32) || (clk != (_24MHZ_ * n * 2) / m))
270         return -RT_ERROR;
271 
272     CCU->pll_audio_ctrl &= ~(0x1 << 31);
273     n = (n - 1) & 0x7f;
274     m = (m - 1) & 0x1f;
275     //clk = (24 * n * 2) / m
276     CCU->pll_audio_ctrl = (0x1 << 31) | (0x0 << 24) | (n << 8) | m;
277 
278     if (wait_pll_stable((rt_uint32_t)(&CCU->pll_audio_ctrl)))
279         return -RT_ERROR;
280     else
281         return RT_EOK;
282 }
283 
video_set_pll_clk(int clk)284 rt_err_t video_set_pll_clk(int clk)
285 {
286     int n = 0, m = 0;
287     int n_temp = clk;
288     int m_temp = _24MHZ_;
289 
290     if ((clk > 600000000) || (clk < 30000000))
291         return -RT_EINVAL;
292 
293     if (clk == 0)
294     {
295         CCU->pll_video_ctrl &= ~(0x1 << 31);
296         return RT_EOK;
297     }
298 
299     while (n_temp != m_temp)
300     {
301         if (n_temp > m_temp)
302         {
303             n_temp = n_temp - m_temp;
304         }
305         else if (m_temp > n_temp)
306         {
307             m_temp = m_temp - n_temp;
308         }
309     }
310 
311     n = clk / n_temp;
312     m = _24MHZ_ / m_temp;
313 
314     if ((n > 128) || (m > 16) || (clk != (_24MHZ_ * n) / m))
315         return -RT_ERROR;
316 
317     CCU->pll_video_ctrl &= ~(0x1 << 31);
318     n = (n - 1) & 0x7f;
319     m = (m - 1) & 0xf;
320     //speed = (24*n)/m
321     CCU->pll_video_ctrl = (0x1 << 31) | (0x0 << 30) | (0x1 << 24) | (n << 8) | m;
322 
323     if (wait_pll_stable((rt_uint32_t)(&CCU->pll_video_ctrl)))
324         return -RT_ERROR;
325     else
326         return RT_EOK;
327 }
328 
ve_set_pll_clk(int clk)329 rt_err_t ve_set_pll_clk(int clk)
330 {
331     int n = 0, m = 0;
332     int n_temp = clk;
333     int m_temp = _24MHZ_;
334 
335     if ((clk > 600000000) || (clk < 30000000))
336         return -RT_EINVAL;
337 
338     if (clk == 0)
339     {
340         CCU->pll_ve_ctrl &= ~(0x1 << 31);
341         return RT_EOK;
342     }
343 
344     while (n_temp != m_temp)
345     {
346         if (n_temp > m_temp)
347         {
348             n_temp = n_temp - m_temp;
349         }
350         else if (m_temp > n_temp)
351         {
352             m_temp = m_temp - n_temp;
353         }
354     }
355 
356     n = clk / n_temp;
357     m = _24MHZ_ / m_temp;
358 
359     if ((n > 128) || (m > 16) || (clk != (_24MHZ_ * n) / m))
360         return -RT_ERROR;
361 
362     CCU->pll_ve_ctrl &= ~(0x1 << 31);
363     n = (n - 1) & 0x7f;
364     m = (m - 1) & 0xf;
365     //clk = (24 * n) / m
366     CCU->pll_ve_ctrl = (0x1 << 31) | (0x1 << 24) | (n << 8) | m;
367     if (wait_pll_stable((rt_uint32_t)(&CCU->pll_ve_ctrl)))
368         return -RT_ERROR;
369     else
370         return RT_EOK;
371 }
372 
periph_set_pll_clk(int clk)373 rt_err_t periph_set_pll_clk(int clk)
374 {
375     rt_uint32_t clk_src;
376     rt_uint32_t temp_data;
377     int n = 0, k = 0;
378 
379     if ((clk > 1800000000) || (clk < 200000000) || (clk == 0) || (clk % _24MHZ_ != 0))
380         return -RT_EINVAL;
381 
382     n = clk / _24MHZ_;
383 
384     for (k = 2; ((n > 32) || (k < 5)); k++)
385     {
386         if ((n % k) != 0)
387             n /= k;
388     }
389 
390     if ((n > 32) || (k > 4) || (clk != (_24MHZ_ * n * k)))
391         return -RT_ERROR;
392     temp_data = CCU->ahb_apb_hclkc_cfg;
393     clk_src = (temp_data >> 12) & 0x3;
394     temp_data &= ~(0x3 << 12);
395     temp_data |= (CLK_PLL_SRC << 12);
396     CCU->ahb_apb_hclkc_cfg = temp_data;
397     CCU->pll_periph_ctrl &= ~(0x1 << 31);
398     n = (n - 1) & 0x1f;
399     k = (k - 1) & 0x3;
400     //clk = 24 * n *k
401     CCU->pll_periph_ctrl = (0x1 << 31) | (0x1 << 18) | (n << 8) | (k << 4) || (0x1);
402     if (wait_pll_stable((rt_uint32_t)(&CCU->pll_periph_ctrl)))
403         return -RT_ERROR;
404 
405     temp_data = CCU->ahb_apb_hclkc_cfg;
406     temp_data &= ~(0x3 << 12);
407     temp_data |= (clk_src << 12);
408     CCU->ahb_apb_hclkc_cfg = temp_data;
409 
410     return RT_EOK;
411 }
412 
cpu_set_clk(int clk)413 rt_err_t cpu_set_clk(int clk)
414 {
415     if (clk < _24MHZ_)
416         return -RT_EINVAL;
417 
418     if (clk == cpu_get_clk())
419         return RT_EOK;
420 
421     CCU->cpu_clk_src = CLK_OSC24M_SRC << 16;
422     if (clk == _24MHZ_)
423         return RT_EOK;
424 
425     if (cpu_set_pll_clk(clk))
426         return -RT_ERROR;
427 
428     CCU->ahb_apb_hclkc_cfg &= ~(0x3 << 16);
429     CCU->cpu_clk_src = CLK_PLL_SRC << 16;
430 
431     return RT_EOK;
432 }
433 
bus_gate_clk_enalbe(enum bus_gate bus)434 rt_err_t bus_gate_clk_enalbe(enum bus_gate bus)
435 {
436     rt_uint32_t offset;
437     rt_uint32_t gate_reg;
438 
439     offset = bus & 0xfff;
440     gate_reg = bus >> BUS_GATE_OFFSET_BIT;
441 
442     if (gate_reg == 0x00)
443         CCU->bus_clk_gating0 |= (0x1 << offset);
444     else if (gate_reg == 0x01)
445         CCU->bus_clk_gating1 |= (0x1 << offset);
446     else if (gate_reg == 0x02)
447         CCU->bus_clk_gating2 |= (0x1 << offset);
448     else
449         return -RT_EINVAL;
450 
451     return RT_EOK;
452 }
453 
bus_gate_clk_disalbe(enum bus_gate bus)454 rt_err_t bus_gate_clk_disalbe(enum bus_gate bus)
455 {
456     rt_uint32_t offset;
457     rt_uint32_t gate_reg;
458 
459     offset = bus & 0xfff;
460     gate_reg = bus >> BUS_GATE_OFFSET_BIT;
461 
462     if (gate_reg == 0x00)
463         CCU->bus_clk_gating0 &= ~(0x1 << offset);
464     else if (gate_reg == 0x01)
465         CCU->bus_clk_gating1 &= ~(0x1 << offset);
466     else if (gate_reg == 0x02)
467         CCU->bus_clk_gating2 &= ~(0x1 << offset);
468     else
469         return -RT_EINVAL;
470 
471     return RT_EOK;
472 }
473 
bus_software_reset_disalbe(enum bus_gate bus)474 rt_err_t bus_software_reset_disalbe(enum bus_gate bus)
475 {
476     rt_uint32_t offset;
477     rt_uint32_t gate_reg;
478 
479     offset = bus & 0xfff;
480     gate_reg = bus >> BUS_GATE_OFFSET_BIT;
481 
482     if (gate_reg == 0x00)
483         CCU->bus_soft_rst0 |= (0x1 << offset);
484     else if (gate_reg == 0x01)
485         CCU->bus_soft_rst1 |= (0x1 << offset);
486     else if (gate_reg == 0x02)
487         CCU->bus_soft_rst2 |= (0x1 << offset);
488     else
489         return -RT_EINVAL;
490 
491     return RT_EOK;
492 }
493 
bus_software_reset_enalbe(enum bus_gate bus)494 rt_err_t bus_software_reset_enalbe(enum bus_gate bus)
495 {
496     rt_uint32_t offset;
497     rt_uint32_t gate_reg;
498 
499     offset = bus & 0xfff;
500     gate_reg = bus >> BUS_GATE_OFFSET_BIT;
501 
502     if (gate_reg == 0x00)
503         CCU->bus_soft_rst0 &= ~(0x1 << offset);
504     else if (gate_reg == 0x01)
505         CCU->bus_soft_rst1 &= ~(0x1 << offset);
506     else if (gate_reg == 0x02)
507         CCU->bus_soft_rst2 &= ~(0x1 << offset);
508     else
509         return -RT_EINVAL;
510 
511     return RT_EOK;
512 }
513 
mmc_set_clk(enum mmc_clk_id clk_id,int hz)514 rt_err_t mmc_set_clk(enum mmc_clk_id clk_id, int hz)
515 {
516     unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
517     volatile rt_uint32_t *mmc_clk = (clk_id == SDMMC0) ? \
518         (&CCU->sdmmc0_clk) : (&CCU->sdmmc1_clk);
519 
520     if (hz < 0)
521     {
522         return -RT_EINVAL;
523     }
524 
525     if (hz == 0)
526     {
527         *mmc_clk &= ~(0x1 << 31);
528         return RT_EOK;
529     }
530 
531     if (hz <= 24000000)
532     {
533         pll = (0x0 << 24);
534         pll_hz = 24000000;
535     }
536     else
537     {
538         pll = (0x1 << 24);
539         pll_hz = periph_get_pll_clk();
540     }
541 
542     div = pll_hz / hz;
543     if (pll_hz % hz)
544     {
545         div++;
546     }
547 
548     n = 0;
549     while (div > 16)
550     {
551         n++;
552         div = (div + 1) / 2;
553     }
554 
555     if (n > 3)
556     {
557         return -1;
558     }
559 
560     /* determine delays */
561     if (hz <= 400000)
562     {
563         oclk_dly = 0;
564         sclk_dly = 0;
565     }
566     else if (hz <= 25000000)
567     {
568         oclk_dly = 0;
569         sclk_dly = 5;
570     }
571     else if (hz <= 50000000)
572     {
573         oclk_dly = 3;
574         sclk_dly = 4;
575     }
576     else
577     {
578         /* hz > 50000000 */
579         oclk_dly = 1;
580         sclk_dly = 4;
581     }
582 
583     *mmc_clk = (0x1 << 31) | pll | (sclk_dly << 20) | \
584            (n << 16) | (oclk_dly << 8) | (div - 1);
585 
586     return RT_EOK;
587 }
588 
dram_gate_clk_enable(enum dram_gate dram_gate)589 rt_err_t dram_gate_clk_enable(enum dram_gate dram_gate)
590 {
591     CCU->dram_gating |= (0x01 << dram_gate);
592     return RT_EOK;
593 }
594 
dram_gate_clk_disable(enum dram_gate dram_gate)595 rt_err_t dram_gate_clk_disable(enum dram_gate dram_gate)
596 {
597     CCU->dram_gating &= ~(0x01 << dram_gate);
598     return RT_EOK;
599 }
600