1 /*
2  * Copyright (c) 2013-2015 Wind River Systems, Inc.
3  * Copyright (c) 2016 Intel Corporation.
4  * Copyright (c) 2023 Gerson Fernando Budke <nandojve@gmail.com>
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /**
10  * @file
11  * @brief Atmel SAM3X MCU series initialization code
12  *
13  * This module provides routines to initialize and support board-level hardware
14  * for the Atmel SAM3X series processor.
15  */
16 
17 #include <zephyr/kernel.h>
18 #include <zephyr/device.h>
19 #include <zephyr/init.h>
20 #include <soc.h>
21 
22 /*
23  * PLL clock = Main * (MULA + 1) / DIVA
24  *
25  * By default, MULA == 6, DIVA == 1.
26  * With main crystal running at 12 MHz,
27  * PLL = 12 * (6 + 1) / 1 = 84 MHz
28  *
29  * With Processor Clock prescaler at 1
30  * Processor Clock (HCLK) = 84 MHz.
31  */
32 #define PMC_CKGR_PLLAR_MULA	\
33 	(CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM3X_PLLA_MULA))
34 #define PMC_CKGR_PLLAR_DIVA	\
35 	(CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM3X_PLLA_DIVA))
36 
37 /**
38  * @brief Setup various clocks on SoC at boot time.
39  *
40  * Setup Slow, Main, PLLA, Processor and Master clocks during the device boot.
41  * It is assumed that the relevant registers are at their reset value.
42  */
clock_init(void)43 static ALWAYS_INLINE void clock_init(void)
44 {
45 	uint32_t reg_val;
46 
47 #ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK
48 	/* Switch slow clock to the external 32 kHz crystal oscillator */
49 	SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL;
50 
51 	/* Wait for oscillator to be stabilized */
52 	while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) {
53 		;
54 	}
55 #endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK */
56 
57 #ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK
58 	/*
59 	 * Setup main external crystal oscillator
60 	 */
61 
62 	/* Start the external crystal oscillator */
63 	PMC->CKGR_MOR =   CKGR_MOR_KEY_PASSWD
64 			/* Fast RC Oscillator Frequency is at 4 MHz (default) */
65 			| CKGR_MOR_MOSCRCF_4_MHz
66 			/* We select maximum setup time. While start up time
67 			 * could be shortened this optimization is not deemed
68 			 * critical now.
69 			 */
70 			| CKGR_MOR_MOSCXTST(0xFFu)
71 			/* RC OSC must stay on */
72 			| CKGR_MOR_MOSCRCEN
73 			| CKGR_MOR_MOSCXTEN;
74 
75 	/* Wait for oscillator to be stabilized */
76 	while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) {
77 		;
78 	}
79 
80 	/* Select the external crystal oscillator as the main clock source */
81 	PMC->CKGR_MOR =   CKGR_MOR_KEY_PASSWD
82 			| CKGR_MOR_MOSCRCF_4_MHz
83 			| CKGR_MOR_MOSCSEL
84 			| CKGR_MOR_MOSCXTST(0xFFu)
85 			| CKGR_MOR_MOSCRCEN
86 			| CKGR_MOR_MOSCXTEN;
87 
88 	/* Wait for external oscillator to be selected */
89 	while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) {
90 		;
91 	}
92 
93 	/* Turn off RC OSC, not used any longer, to save power */
94 	PMC->CKGR_MOR =   CKGR_MOR_KEY_PASSWD
95 			| CKGR_MOR_MOSCSEL
96 			| CKGR_MOR_MOSCXTST(0xFFu)
97 			| CKGR_MOR_MOSCXTEN;
98 
99 	/* Wait for RC OSC to be turned off */
100 	while (PMC->PMC_SR & PMC_SR_MOSCRCS) {
101 		;
102 	}
103 
104 #ifdef CONFIG_SOC_ATMEL_SAM3X_WAIT_MODE
105 	/*
106 	 * Instruct CPU to enter Wait mode instead of Sleep mode to
107 	 * keep Processor Clock (HCLK) and thus be able to debug
108 	 * CPU using JTAG
109 	 */
110 	PMC->PMC_FSMR |= PMC_FSMR_LPM;
111 #endif
112 #else
113 	/*
114 	 * Setup main fast RC oscillator
115 	 */
116 
117 	/*
118 	 * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR
119 	 * register, should normally be the case here
120 	 */
121 	while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) {
122 		;
123 	}
124 
125 	/* Set main fast RC oscillator to 12 MHz */
126 	PMC->CKGR_MOR =   CKGR_MOR_KEY_PASSWD
127 			| CKGR_MOR_MOSCRCF_12_MHz
128 			| CKGR_MOR_MOSCRCEN;
129 
130 	/* Wait for oscillator to be stabilized */
131 	while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) {
132 		;
133 	}
134 #endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK */
135 
136 	/*
137 	 * Setup PLLA
138 	 */
139 
140 	/* Switch MCK (Master Clock) to the main clock first */
141 	reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk;
142 	PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK;
143 
144 	/* Wait for clock selection to complete */
145 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
146 		;
147 	}
148 
149 	/* Setup PLLA */
150 	PMC->CKGR_PLLAR =   CKGR_PLLAR_ONE
151 			  | PMC_CKGR_PLLAR_MULA
152 			  | CKGR_PLLAR_PLLACOUNT(0x3Fu)
153 			  | PMC_CKGR_PLLAR_DIVA;
154 
155 	/*
156 	 * NOTE: Both MULA and DIVA must be set to a value greater than 0 or
157 	 * otherwise PLL will be disabled. In this case we would get stuck in
158 	 * the following loop.
159 	 */
160 
161 	/* Wait for PLL lock */
162 	while (!(PMC->PMC_SR & PMC_SR_LOCKA)) {
163 		;
164 	}
165 
166 	/*
167 	 * Final setup of the Master Clock
168 	 */
169 
170 	/*
171 	 * NOTE: PMC_MCKR must not be programmed in a single write operation.
172 	 * If CSS or PRES are modified we must wait for MCKRDY bit to be
173 	 * set again.
174 	 */
175 
176 	/* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */
177 	reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk;
178 	PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1;
179 
180 	/* Wait for Master Clock setup to complete */
181 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
182 		;
183 	}
184 
185 	/* Finally select PLL as Master Clock source */
186 	reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk;
187 	PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK;
188 
189 	/* Wait for Master Clock setup to complete */
190 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
191 		;
192 	}
193 }
194 
z_arm_platform_init(void)195 void z_arm_platform_init(void)
196 {
197 	/*
198 	 * Set FWS (Flash Wait State) value before increasing Master Clock
199 	 * (MCK) frequency.
200 	 * TODO: set FWS based on the actual MCK frequency and VDDCORE value
201 	 * rather than maximum supported 84 MHz at standard VDDCORE=1.8V
202 	 */
203 	EFC0->EEFC_FMR = EEFC_FMR_FWS(4);
204 	EFC1->EEFC_FMR = EEFC_FMR_FWS(4);
205 
206 	/* Setup system clocks */
207 	clock_init();
208 }
209