mb/google/nissa/var/pujjo: Add new supported memory part
[coreboot2.git] / src / soc / samsung / exynos5420 / clock.c
blob9809b2003edb680487b95185c1f7d751d20986a8
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <device/mmio.h>
4 #include <assert.h>
5 #include <console/console.h>
6 #include <soc/clk.h>
7 #include <soc/periph.h>
8 #include <timer.h>
10 /* input clock of PLL: SMDK5420 has 24MHz input clock */
11 #define CONF_SYS_CLK_FREQ 24000000
13 /* Epll Clock division values to achieve different frequency output */
14 static struct st_epll_con_val epll_div[] = {
15 { 192000000, 0, 48, 3, 1, 0 },
16 { 180000000, 0, 45, 3, 1, 0 },
17 { 73728000, 1, 73, 3, 3, 47710 },
18 { 67737600, 1, 90, 4, 3, 20762 },
19 { 49152000, 0, 49, 3, 3, 9961 },
20 { 45158400, 0, 45, 3, 3, 10381 },
21 { 180633600, 0, 45, 3, 1, 10381 }
24 /* exynos5: return pll clock frequency */
25 unsigned long get_pll_clk(int pllreg)
27 unsigned long r, m, p, s, k = 0, mask, fout;
28 unsigned int freq;
30 switch (pllreg) {
31 case APLL:
32 r = read32(&exynos_clock->apll_con0);
33 break;
34 case MPLL:
35 r = read32(&exynos_clock->mpll_con0);
36 break;
37 case EPLL:
38 r = read32(&exynos_clock->epll_con0);
39 k = read32(&exynos_clock->epll_con1);
40 break;
41 case VPLL:
42 r = read32(&exynos_clock->vpll_con0);
43 k = read32(&exynos_clock->vpll_con1);
44 break;
45 case BPLL:
46 r = read32(&exynos_clock->bpll_con0);
47 break;
48 case RPLL:
49 r = read32(&exynos_clock->rpll_con0);
50 k = read32(&exynos_clock->rpll_con1);
51 break;
52 case SPLL:
53 r = read32(&exynos_clock->spll_con0);
54 break;
55 case CPLL:
56 r = read32(&exynos_clock->cpll_con0);
57 break;
58 case DPLL:
59 r = read32(&exynos_clock->dpll_con0);
60 break;
61 default:
62 printk(BIOS_DEBUG, "Unsupported PLL (%d)\n", pllreg);
63 return 0;
67 * APLL_CON: MIDV [25:16]
68 * MPLL_CON: MIDV [25:16]
69 * EPLL_CON: MIDV [24:16]
70 * VPLL_CON: MIDV [24:16]
72 if (pllreg == APLL || pllreg == BPLL || pllreg == MPLL ||
73 pllreg == SPLL)
74 mask = 0x3ff;
75 else
76 mask = 0x1ff;
78 m = (r >> 16) & mask;
80 /* PDIV [13:8] */
81 p = (r >> 8) & 0x3f;
82 /* SDIV [2:0] */
83 s = r & 0x7;
85 freq = CONF_SYS_CLK_FREQ;
87 if (pllreg == EPLL || pllreg == RPLL) {
88 k = k & 0xffff;
89 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
90 fout = (m + k / 65536) * (freq / (p * (1 << s)));
91 } else if (pllreg == VPLL) {
92 k = k & 0xfff;
93 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
94 fout = (m + k / 1024) * (freq / (p * (1 << s)));
95 } else {
96 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
97 fout = m * (freq / (p * (1 << s)));
100 return fout;
103 enum peripheral_clock_select {
104 PERIPH_SRC_CPLL = 1,
105 PERIPH_SRC_DPLL = 2,
106 PERIPH_SRC_MPLL = 3,
107 PERIPH_SRC_SPLL = 4,
108 PERIPH_SRC_IPLL = 5,
109 PERIPH_SRC_EPLL = 6,
110 PERIPH_SRC_RPLL = 7,
113 static int clock_select_to_pll(enum peripheral_clock_select sel)
115 int pll;
117 switch (sel) {
118 case PERIPH_SRC_CPLL:
119 pll = CPLL;
120 break;
121 case PERIPH_SRC_DPLL:
122 pll = DPLL;
123 break;
124 case PERIPH_SRC_MPLL:
125 pll = MPLL;
126 break;
127 case PERIPH_SRC_SPLL:
128 pll = SPLL;
129 break;
130 case PERIPH_SRC_IPLL:
131 pll = IPLL;
132 break;
133 case PERIPH_SRC_EPLL:
134 pll = EPLL;
135 break;
136 case PERIPH_SRC_RPLL:
137 pll = RPLL;
138 break;
139 default:
140 pll = -1;
141 break;
144 return pll;
147 unsigned long clock_get_periph_rate(enum periph_id peripheral)
149 unsigned long sclk;
150 unsigned int div;
151 int src;
153 switch (peripheral) {
154 case PERIPH_ID_UART0:
155 src = (read32(&exynos_clock->clk_src_peric0) >> 4) & 0x7;
156 div = (read32(&exynos_clock->clk_div_peric0) >> 8) & 0xf;
157 break;
158 case PERIPH_ID_UART1:
159 src = (read32(&exynos_clock->clk_src_peric0) >> 8) & 0x7;
160 div = (read32(&exynos_clock->clk_div_peric0) >> 12) & 0xf;
161 break;
162 case PERIPH_ID_UART2:
163 src = (read32(&exynos_clock->clk_src_peric0) >> 12) & 0x7;
164 div = (read32(&exynos_clock->clk_div_peric0) >> 16) & 0xf;
165 break;
166 case PERIPH_ID_UART3:
167 src = (read32(&exynos_clock->clk_src_peric0) >> 16) & 0x7;
168 div = (read32(&exynos_clock->clk_div_peric0) >> 20) & 0xf;
169 break;
170 case PERIPH_ID_PWM0:
171 case PERIPH_ID_PWM1:
172 case PERIPH_ID_PWM2:
173 case PERIPH_ID_PWM3:
174 case PERIPH_ID_PWM4:
175 src = (read32(&exynos_clock->clk_src_peric0) >> 24) & 0x7;
176 div = (read32(&exynos_clock->clk_div_peric0) >> 28) & 0x7;
177 break;
178 case PERIPH_ID_SPI0:
179 src = (read32(&exynos_clock->clk_src_peric1) >> 20) & 0x7;
180 div = (read32(&exynos_clock->clk_div_peric1) >> 20) & 0xf;
181 break;
182 case PERIPH_ID_SPI1:
183 src = (read32(&exynos_clock->clk_src_peric1) >> 24) & 0x7;
184 div = (read32(&exynos_clock->clk_div_peric1) >> 24) & 0xf;
185 break;
186 case PERIPH_ID_SPI2:
187 src = (read32(&exynos_clock->clk_src_peric1) >> 28) & 0x7;
188 div = (read32(&exynos_clock->clk_div_peric1) >> 28) & 0xf;
189 break;
190 case PERIPH_ID_SPI3: /* aka SPI0_ISP */
191 src = (read32(&exynos_clock->clk_src_isp) >> 16) & 0x7;
192 div = (read32(&exynos_clock->clk_div_isp0) >> 0) & 0x7;
193 break;
194 case PERIPH_ID_SPI4: /* aka SPI1_ISP */
195 src = (read32(&exynos_clock->clk_src_isp) >> 12) & 0x7;
196 div = (read32(&exynos_clock->clk_div_isp1) >> 4) & 0x7;
197 break;
198 case PERIPH_ID_I2C0:
199 case PERIPH_ID_I2C1:
200 case PERIPH_ID_I2C2:
201 case PERIPH_ID_I2C3:
202 case PERIPH_ID_I2C4:
203 case PERIPH_ID_I2C5:
204 case PERIPH_ID_I2C6:
205 case PERIPH_ID_I2C7:
206 case PERIPH_ID_I2C8:
207 case PERIPH_ID_I2C9:
208 case PERIPH_ID_I2C10:
210 * I2C block parent clock selection is different from other
211 * peripherals, so we handle it all here.
212 * TODO: Add a helper function like with the peripheral clock
213 * select fields?
215 src = (read32(&exynos_clock->clk_src_top1) >> 8) & 0x3;
216 if (src == 0x0)
217 src = CPLL;
218 else if (src == 0x1)
219 src = DPLL;
220 else if (src == 0x2)
221 src = MPLL;
222 else
223 return -1;
225 sclk = get_pll_clk(src);
226 div = ((read32(&exynos_clock->clk_div_top1) >> 8) & 0x3f) + 1;
227 return sclk / div;
228 default:
229 printk(BIOS_DEBUG, "%s: invalid peripheral %d",
230 __func__, peripheral);
231 return -1;
234 src = clock_select_to_pll(src);
235 if (src < 0) {
236 printk(BIOS_DEBUG, "%s: cannot determine source PLL", __func__);
237 return -1;
240 sclk = get_pll_clk(src);
242 return sclk / (div + 1);
245 /* exynos5: return ARM clock frequency */
246 unsigned long get_arm_clk(void)
248 unsigned long div;
249 unsigned long armclk;
250 unsigned int arm_ratio;
251 unsigned int arm2_ratio;
253 div = read32(&exynos_clock->clk_div_cpu0);
255 /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
256 arm_ratio = (div >> 0) & 0x7;
257 arm2_ratio = (div >> 28) & 0x7;
259 armclk = get_pll_clk(APLL) / (arm_ratio + 1);
260 armclk /= (arm2_ratio + 1);
262 return armclk;
265 /* exynos5: get the mmc clock */
266 static unsigned long get_mmc_clk(int dev_index)
268 unsigned long uclk, sclk;
269 unsigned int sel, ratio;
270 int shift = 0;
272 sel = read32(&exynos_clock->clk_src_fsys);
273 sel = (sel >> ((dev_index * 4) + 8)) & 0x7;
275 if (sel == 0x3)
276 sclk = get_pll_clk(MPLL);
277 else if (sel == 0x6)
278 sclk = get_pll_clk(EPLL);
279 else
280 return 0;
282 ratio = read32(&exynos_clock->clk_div_fsys1);
284 shift = dev_index * 10;
286 ratio = (ratio >> shift) & 0x3ff;
287 uclk = (sclk / (ratio + 1));
288 printk(BIOS_DEBUG, "%s(%d): %lu\n", __func__, dev_index, uclk);
290 return uclk;
293 /* exynos5: set the mmc clock */
294 void set_mmc_clk(int dev_index, unsigned int div)
296 void *addr;
297 unsigned int val, shift;
299 addr = &exynos_clock->clk_div_fsys1;
300 shift = dev_index * 10;
302 val = read32(addr);
303 val &= ~(0x3ff << shift);
304 val |= (div & 0x3ff) << shift;
305 write32(addr, val);
308 /* Set DW MMC Controller clock */
309 int clock_set_dwmci(enum periph_id peripheral)
311 /* Request MMC clock value to 52MHz. */
312 const unsigned long freq = 52000000;
313 unsigned long sdclkin, cclkin;
314 int device_index = (int)peripheral - (int)PERIPH_ID_SDMMC0;
316 ASSERT(device_index >= 0 && device_index < 4);
317 sdclkin = get_mmc_clk(device_index);
318 if (!sdclkin) {
319 return -1;
322 /* The SDCLKIN is divided inside the controller by the DIVRATIO field in
323 * CLKSEL register, so we must calculate clock value as
324 * cclk_in = SDCLKIN / (DIVRATIO + 1)
325 * Currently the RIVRATIO must be 3 for MMC0 and MMC2 on Exynos5420
326 * (and must be configured in payload).
328 if (device_index == 0 || device_index == 2){
329 int divratio = 3;
330 sdclkin /= (divratio + 1);
332 printk(BIOS_DEBUG, "%s(%d): sdclkin: %ld\n", __func__, device_index, sdclkin);
334 cclkin = DIV_ROUND_UP(sdclkin, freq);
335 set_mmc_clk(device_index, cclkin);
336 return 0;
339 void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned int divisor)
341 unsigned int shift;
342 unsigned int mask = 0xff;
343 u32 *reg;
346 * For now we only handle a very small subset of peripherals here.
347 * Others will need to (and do) mangle the clock registers
348 * themselves, At some point it is hoped that this function can work
349 * from a table or calculated register offset / mask. For now this
350 * is at least better than spreading clock control code around
351 * U-Boot.
353 switch (periph_id) {
354 case PERIPH_ID_SPI0:
355 reg = &exynos_clock->clk_div_peric4;
356 shift = 8;
357 break;
358 case PERIPH_ID_SPI1:
359 reg = &exynos_clock->clk_div_peric4;
360 shift = 16;
361 break;
362 case PERIPH_ID_SPI2:
363 reg = &exynos_clock->clk_div_peric4;
364 shift = 24;
365 break;
366 case PERIPH_ID_SPI3:
367 reg = &exynos_clock->clk_div_isp1;
368 shift = 0;
369 break;
370 case PERIPH_ID_SPI4:
371 reg = &exynos_clock->clk_div_isp1;
372 shift = 8;
373 break;
374 default:
375 printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
376 periph_id);
377 return;
379 clrsetbits32(reg, mask << shift, (divisor & mask) << shift);
382 void clock_ll_set_ratio(enum periph_id periph_id, unsigned int divisor)
384 unsigned int shift;
385 unsigned int mask = 0xf;
386 u32 *reg;
388 switch (periph_id) {
389 case PERIPH_ID_SPI0:
390 reg = &exynos_clock->clk_div_peric1;
391 shift = 20;
392 break;
393 case PERIPH_ID_SPI1:
394 reg = &exynos_clock->clk_div_peric1;
395 shift = 24;
396 break;
397 case PERIPH_ID_SPI2:
398 reg = &exynos_clock->clk_div_peric1;
399 shift = 28;
400 break;
401 case PERIPH_ID_SPI3:
402 reg = &exynos_clock->clk_div_isp1;
403 shift = 16;
404 break;
405 case PERIPH_ID_SPI4:
406 reg = &exynos_clock->clk_div_isp1;
407 shift = 20;
408 break;
409 default:
410 printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
411 periph_id);
412 return;
414 clrsetbits32(reg, mask << shift, (divisor & mask) << shift);
418 * Linearly searches for the most accurate main and fine stage clock scalars
419 * (divisors) for a specified target frequency and scalar bit sizes by checking
420 * all multiples of main_scalar_bits values. Will always return scalars up to or
421 * slower than target.
423 * @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32
424 * @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32
425 * @param input_rate Clock frequency to be scaled in Hz
426 * @param target_rate Desired clock frequency in Hz
427 * @param best_fine_scalar Pointer to store the fine stage divisor
429 * @return best_main_scalar Main scalar for desired frequency or -1 if none
430 * found
432 static int clock_calc_best_scalar(unsigned int main_scaler_bits,
433 unsigned int fine_scalar_bits, unsigned int input_rate,
434 unsigned int target_rate, unsigned int *best_fine_scalar)
436 int i;
437 int best_main_scalar = -1;
438 unsigned int best_error = target_rate;
439 const unsigned int cap = (1 << fine_scalar_bits) - 1;
440 const unsigned int loops = 1 << main_scaler_bits;
442 printk(BIOS_DEBUG, "Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
443 target_rate, cap);
445 ASSERT(best_fine_scalar != NULL);
446 ASSERT(main_scaler_bits <= fine_scalar_bits);
448 *best_fine_scalar = 1;
450 if (input_rate == 0 || target_rate == 0)
451 return -1;
453 if (target_rate >= input_rate)
454 return 1;
456 for (i = 1; i <= loops; i++) {
457 const unsigned int effective_div = MAX(MIN(input_rate / i /
458 target_rate, cap), 1);
459 const unsigned int effective_rate = input_rate / i /
460 effective_div;
461 const int error = target_rate - effective_rate;
463 printk(BIOS_DEBUG, "%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
464 effective_rate, error);
466 if (error >= 0 && error <= best_error) {
467 best_error = error;
468 best_main_scalar = i;
469 *best_fine_scalar = effective_div;
473 return best_main_scalar;
476 int clock_set_rate(enum periph_id periph_id, unsigned int rate)
478 int main_scalar;
479 unsigned int fine;
481 switch (periph_id) {
482 case PERIPH_ID_SPI0:
483 case PERIPH_ID_SPI1:
484 case PERIPH_ID_SPI2:
485 case PERIPH_ID_SPI3:
486 case PERIPH_ID_SPI4:
487 main_scalar = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
488 if (main_scalar < 0) {
489 printk(BIOS_DEBUG, "%s: Cannot set clock rate for periph %d",
490 __func__, periph_id);
491 return -1;
493 clock_ll_set_ratio(periph_id, main_scalar - 1);
494 clock_ll_set_pre_ratio(periph_id, fine - 1);
495 break;
496 default:
497 printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
498 periph_id);
499 return -1;
502 return 0;
505 int clock_set_mshci(enum periph_id peripheral)
507 u32 *addr;
508 unsigned int clock;
509 unsigned int tmp;
510 unsigned int i;
512 /* get mpll clock */
513 clock = get_pll_clk(MPLL) / 1000000;
516 * CLK_DIV_FSYS1
517 * MMC0_PRE_RATIO [15:8], MMC0_RATIO [3:0]
518 * CLK_DIV_FSYS2
519 * MMC2_PRE_RATIO [15:8], MMC2_RATIO [3:0]
521 switch (peripheral) {
522 case PERIPH_ID_SDMMC0:
523 addr = &exynos_clock->clk_div_fsys1;
524 break;
525 case PERIPH_ID_SDMMC2:
526 addr = &exynos_clock->clk_div_fsys2;
527 break;
528 default:
529 printk(BIOS_DEBUG, "invalid peripheral\n");
530 return -1;
532 tmp = read32(addr) & ~0xff0f;
533 for (i = 0; i <= 0xf; i++) {
534 if ((clock / (i + 1)) <= 400) {
535 write32(addr, tmp | i << 0);
536 break;
539 return 0;
542 int clock_epll_set_rate(unsigned long rate)
544 unsigned int epll_con, epll_con_k;
545 unsigned int i;
546 unsigned int lockcnt;
547 struct stopwatch sw;
549 epll_con = read32(&exynos_clock->epll_con0);
550 epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
551 EPLL_CON0_LOCK_DET_EN_SHIFT) |
552 EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
553 EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
554 EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
556 for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
557 if (epll_div[i].freq_out == rate)
558 break;
561 if (i == ARRAY_SIZE(epll_div))
562 return -1;
564 epll_con_k = epll_div[i].k_dsm << 0;
565 epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT;
566 epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
567 epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
568 epll_con |= epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
571 * Required period (in cycles) to generate a stable clock output.
572 * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
573 * frequency input (as per spec)
575 lockcnt = 3000 * epll_div[i].p_div;
577 write32(&exynos_clock->epll_lock, lockcnt);
578 write32(&exynos_clock->epll_con0, epll_con);
579 write32(&exynos_clock->epll_con1, epll_con_k);
581 stopwatch_init_msecs_expire(&sw, TIMEOUT_EPLL_LOCK);
583 while (!(read32(&exynos_clock->epll_con0) &
584 (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
585 if (stopwatch_expired(&sw)) {
586 printk(BIOS_DEBUG, "%s: Timeout waiting for EPLL lock\n", __func__);
587 return -1;
591 return 0;
594 void clock_select_i2s_clk_source(void)
596 clrsetbits32(&exynos_clock->clk_src_peric1, AUDIO1_SEL_MASK,
597 (CLK_SRC_SCLK_EPLL));
600 int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
602 unsigned int div;
604 if ((dst_frq == 0) || (src_frq == 0)) {
605 printk(BIOS_DEBUG, "%s: Invalid frequency input for prescaler\n", __func__);
606 printk(BIOS_DEBUG, "src frq = %d des frq = %d ", src_frq, dst_frq);
607 return -1;
610 div = (src_frq / dst_frq);
611 if (div > AUDIO_1_RATIO_MASK) {
612 printk(BIOS_DEBUG, "%s: Frequency ratio is out of range\n", __func__);
613 printk(BIOS_DEBUG, "src frq = %d des frq = %d ", src_frq, dst_frq);
614 return -1;
616 clrsetbits32(&exynos_clock->clk_div_peric4, AUDIO_1_RATIO_MASK,
617 (div & AUDIO_1_RATIO_MASK));
618 return 0;