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