1 /*
2  * Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
3  * Copyright (c) 2017 Palmer Dabbelt <palmer@dabbelt.com>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/init.h>
9 #include <zephyr/devicetree.h>
10 #include "prci.h"
11 
12 #define CORECLK_HZ (DT_PROP(DT_NODELABEL(coreclk), clock_frequency))
13 BUILD_ASSERT(DT_PROP(DT_NODELABEL(tlclk), clock_div) == 1,
14 	"Unsupported TLCLK divider");
15 
soc_early_init_hook(void)16 void soc_early_init_hook(void)
17 {
18 
19 	/*
20 	 * HFXOSC (16 MHz) is used to produce coreclk (and therefore tlclk /
21 	 * peripheral clock). This code supports the following frequencies:
22 	 * - 16 MHz (bypass HFPLL).
23 	 * - 48 MHz - 320 MHz, in 8 MHz steps (use HFPLL).
24 	 */
25 	BUILD_ASSERT(MHZ(16) == CORECLK_HZ ||
26 		(MHZ(48) <= CORECLK_HZ && MHZ(320) >= CORECLK_HZ &&
27 		(CORECLK_HZ % MHZ(8)) == 0),
28 		"Unsupported CORECLK frequency");
29 
30 	uint32_t prci;
31 
32 	if (MHZ(16) == CORECLK_HZ) {
33 		/* Bypass HFPLL. */
34 		prci = PLL_REFSEL(1) | PLL_BYPASS(1);
35 	} else {
36 		/* refr = 8 MHz. */
37 		const int pll_r = 0x1;
38 		int pll_q;
39 
40 		/* Select Q divisor to produce vco on [384 MHz, 768 MHz]. */
41 		if (MHZ(768) / 8 >= CORECLK_HZ) {
42 			pll_q = 0x3;
43 		} else if (MHZ(768) / 4 >= CORECLK_HZ) {
44 			pll_q = 0x2;
45 		} else {
46 			pll_q = 0x1;
47 		}
48 		/* Select F multiplier to produce vco target. */
49 		const int pll_f = ((CORECLK_HZ / MHZ(1)) >> (4 - pll_q)) - 1;
50 
51 		prci = PLL_REFSEL(1) | PLL_R(pll_r) | PLL_F(pll_f) | PLL_Q(pll_q);
52 	}
53 
54 	PRCI_REG(PRCI_PLLCFG) = prci;
55 	PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
56 	PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
57 	PRCI_REG(PRCI_HFROSCCFG) &= ~ROSC_EN(1);
58 }
59