1 /*
2  * Copyright (c) 2021 Katsuhiro Suzuki
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/init.h>
8 #include <zephyr/devicetree.h>
9 #include <zephyr/sys/util.h>
10 
11 #include "prci.h"
12 
13 BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency),
14 	"Unsupported CORECLK frequency");
15 BUILD_ASSERT(KHZ(125125) == DT_PROP(DT_NODELABEL(pclk), clock_frequency),
16 	"Unsupported PCLK frequency");
17 
wait_controller_cycle(void)18 static inline void wait_controller_cycle(void)
19 {
20 	/* HACK to get the '1 full controller clock cycle'. */
21 	__asm__ volatile ("fence");
22 }
23 
24 /*
25  * Switch the clock source
26  *   - core: to 1GHz PLL (CORE_PLL) from 26MHz oscillator (HFCLK)
27  *   - peri: to 250MHz PLL (HFPCLKPLL) from HFCLK
28  *   - ddr:  to 923MHz PLL (DDRPLL) from HFCLK (half of the data rate)
29  * on the HiFive Unmatched board.
30  *
31  * Note: Valid PLL VCO range is 2400MHz to 4800MHz
32  */
soc_early_init_hook(void)33 void soc_early_init_hook(void)
34 {
35 
36 	PRCI_REG(PRCI_COREPLLCFG) =
37 		PLL_R(0) |   /* input divider: Fin / (0 + 1) = 26MHz */
38 		PLL_F(76) |  /* VCO: 2 x (76 + 1) = 154 = 4004MHz */
39 		PLL_Q(2) |   /* output divider: VCO / 2^2 = 1001MHz */
40 		PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */
41 		PLL_BYPASS(PLL_BYPASS_DISABLE) |
42 		PLL_FSE(PLL_FSE_INTERNAL);
43 	while ((PRCI_REG(PRCI_COREPLLCFG) & PLL_LOCK(1)) == 0) {
44 		;
45 	}
46 
47 	/* Switch CORE_CLK to CORE_PLL from HFCLK */
48 	PRCI_REG(PRCI_COREPLLSEL) = COREPLLSEL_SEL(COREPLLSEL_COREPLL);
49 	PRCI_REG(PRCI_CORECLKSEL) = CLKSEL_SEL(CLKSEL_PLL);
50 
51 	PRCI_REG(PRCI_HFPCLKPLLCFG) =
52 		PLL_R(0) |   /* input divider: Fin / (0 + 1) = 26MHz */
53 		PLL_F(76) |  /* VCO: 2 x (76 + 1) = 154 = 4004MHz */
54 		PLL_Q(4) |   /* output divider: VCO / 2^4 = 250.25MHz */
55 		PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */
56 		PLL_BYPASS(PLL_BYPASS_DISABLE) |
57 		PLL_FSE(PLL_FSE_INTERNAL);
58 	while ((PRCI_REG(PRCI_HFPCLKPLLCFG) & PLL_LOCK(1)) == 0) {
59 		;
60 	}
61 
62 	/* Switch PCLK to HFPCLKPLL/2 from HFCLK/2 */
63 	PRCI_REG(PRCI_HFPCLKPLLOUTDIV) = OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA);
64 	PRCI_REG(PRCI_HFPCLKPLLSEL) = CLKSEL_SEL(CLKSEL_PLL);
65 
66 	PRCI_REG(PRCI_DDRPLLCFG) =
67 		PLL_R(0) |   /* input divider: Fin / (0 + 1) = 26MHz */
68 		PLL_F(70) |  /* VCO: 2 x (70 + 1) = 154 = 1872MHz */
69 		PLL_Q(2) |   /* output divider: VCO / 2^2 = 936MHz */
70 		PLL_RANGE(PLL_RANGE_18MHZ) |
71 		PLL_BYPASS(PLL_BYPASS_DISABLE) |
72 		PLL_FSE(PLL_FSE_INTERNAL);
73 	while ((PRCI_REG(PRCI_DDRPLLCFG) & PLL_LOCK(1)) == 0) {
74 		;
75 	}
76 
77 	PRCI_REG(PRCI_DDRPLLOUTDIV) |= OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA);
78 
79 	PRCI_REG(PRCI_DEVICESRESETN) |= DEVICERESETN_DDRCTRL;
80 	wait_controller_cycle();
81 
82 	/* Release DDR reset */
83 	PRCI_REG(PRCI_DEVICESRESETN) |= DEVICERESETN_DDRAXI |
84 					DEVICERESETN_DDRAHB |
85 					DEVICERESETN_DDRPHY;
86 	wait_controller_cycle();
87 
88 	/*
89 	 * These take like 16 cycles to actually propagate. We can't go sending stuff before they
90 	 * come out of reset. So wait.
91 	 */
92 	for (int i = 0; i < 256; i++) {
93 		__asm__ volatile ("nop");
94 	}
95 }
96