1 /*
2  * Copyright (c) 2019 Gerson Fernando Budke
3  * Copyright (c) 2017 Justin Watson
4  * Copyright (c) 2016 Intel Corporation.
5  * Copyright (c) 2013-2015 Wind River Systems, Inc.
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 /**
11  * @file
12  * @brief Atmel SAM4E MCU series initialization code
13  *
14  * This module provides routines to initialize and support board-level hardware
15  * for the Atmel SAM4E series processor.
16  */
17 
18 #include <device.h>
19 #include <init.h>
20 #include <soc.h>
21 #include <arch/cpu.h>
22 #include <arch/arm/aarch32/cortex_m/cmsis.h>
23 
24 /**
25  * @brief Setup various clock on SoC at boot time.
26  *
27  * Setup the SoC clocks according to section 28.12 in datasheet.
28  *
29  * Setup Slow, Main, PLLA, Processor and Master clocks during the device boot.
30  * It is assumed that the relevant registers are at their reset value.
31  */
clock_init(void)32 static ALWAYS_INLINE void clock_init(void)
33 {
34 	uint32_t reg_val;
35 
36 #ifdef CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK
37 	/* Switch slow clock to the external 32 KHz crystal oscillator. */
38 	SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL_CRYSTAL_SEL;
39 
40 	/* Wait for oscillator to be stabilized. */
41 	while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) {
42 		;
43 	}
44 
45 #endif /* CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK */
46 
47 #ifdef CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK
48 	/*
49 	 * Setup main external crystal oscillator.
50 	 */
51 
52 	/* Start the external crystal oscillator. */
53 	PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
54 			/* Fast RC oscillator frequency is at 4 MHz. */
55 			| CKGR_MOR_MOSCRCF_4_MHz
56 			/*
57 			 * We select maximum setup time. While start up time
58 			 * could be shortened this optimization is not deemed
59 			 * critical right now.
60 			 */
61 			| CKGR_MOR_MOSCXTST(0xFFu)
62 			/* RC oscillator must stay on. */
63 			| CKGR_MOR_MOSCRCEN
64 			| CKGR_MOR_MOSCXTEN;
65 
66 	/* Wait for oscillator to be stabilized. */
67 	while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) {
68 		;
69 	}
70 
71 	/* Select the external crystal oscillator as the main clock source. */
72 	PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
73 			| CKGR_MOR_MOSCRCF_4_MHz
74 			| CKGR_MOR_MOSCRCEN
75 			| CKGR_MOR_MOSCXTEN
76 			| CKGR_MOR_MOSCXTST(0xFFu)
77 			| CKGR_MOR_MOSCSEL;
78 
79 	/* Wait for external oscillator to be selected. */
80 	while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) {
81 		;
82 	}
83 
84 	/* Turn off RC oscillator, not used any longer, to save power */
85 	PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
86 			| CKGR_MOR_MOSCSEL
87 			| CKGR_MOR_MOSCXTST(0xFFu)
88 			| CKGR_MOR_MOSCXTEN;
89 
90 	/* Wait for the RC oscillator to be turned off. */
91 	while (PMC->PMC_SR & PMC_SR_MOSCRCS) {
92 		;
93 	}
94 
95 #ifdef CONFIG_SOC_ATMEL_SAM4E_WAIT_MODE
96 	/*
97 	 * Instruct CPU to enter Wait mode instead of Sleep mode to
98 	 * keep Processor Clock (HCLK) and thus be able to debug
99 	 * CPU using JTAG.
100 	 */
101 	PMC->PMC_FSMR |= PMC_FSMR_LPM;
102 #endif
103 #else
104 	/* Setup main fast RC oscillator. */
105 
106 	/*
107 	 * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR
108 	 * register, should normally be the case.
109 	 */
110 	while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) {
111 		;
112 	}
113 
114 	/* Set main fast RC oscillator to 12 MHz. */
115 	PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
116 			| CKGR_MOR_MOSCRCF_12_MHz
117 			| CKGR_MOR_MOSCRCEN;
118 
119 	/* Wait for RC oscillator to stabilize. */
120 	while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) {
121 		;
122 	}
123 #endif /* CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK */
124 
125 	/*
126 	 * Setup PLLA
127 	 */
128 
129 	/* Switch MCK (Master Clock) to the main clock first. */
130 	reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk;
131 	PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK;
132 
133 	/* Wait for clock selection to complete. */
134 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
135 		;
136 	}
137 
138 	/* Setup PLLA. */
139 	PMC->CKGR_PLLAR = CKGR_PLLAR_ONE
140 			  | CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM4E_PLLA_MULA)
141 			  | CKGR_PLLAR_PLLACOUNT(0x3Fu)
142 			  | CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM4E_PLLA_DIVA);
143 
144 	/*
145 	 * NOTE: Both MULA and DIVA must be set to a value greater than 0 or
146 	 * otherwise PLL will be disabled. In this case we would get stuck in
147 	 * the following loop.
148 	 */
149 
150 	/* Wait for PLL lock. */
151 	while (!(PMC->PMC_SR & PMC_SR_LOCKA)) {
152 		;
153 	}
154 
155 	/*
156 	 * Final setup of the Master Clock
157 	 */
158 
159 	/*
160 	 * NOTE: PMC_MCKR must not be programmed in a single write operation.
161 	 * If CSS or PRES are modified we must wait for MCKRDY bit to be
162 	 * set again.
163 	 */
164 
165 	/* Setup prescaler - PLLA Clock / Processor Clock (HCLK). */
166 	reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk;
167 	PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1;
168 
169 	/* Wait for Master Clock setup to complete */
170 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
171 		;
172 	}
173 
174 	/* Finally select PLL as Master Clock source. */
175 	reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk;
176 	PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK;
177 
178 	/* Wait for Master Clock setup to complete. */
179 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
180 		;
181 	}
182 }
183 
184 /**
185  * @brief Perform basic hardware initialization at boot.
186  *
187  * This needs to be run from the very beginning.
188  * So the init priority has to be 0 (zero).
189  *
190  * @return 0
191  */
atmel_sam4e_init(const struct device * arg)192 static int atmel_sam4e_init(const struct device *arg)
193 {
194 	uint32_t key;
195 
196 	ARG_UNUSED(arg);
197 
198 	key = irq_lock();
199 
200 	/*
201 	 * Set FWS (Flash Wait State) value before increasing Master Clock
202 	 * (MCK) frequency. Look at table 44.73 in the SAM4E datasheet.
203 	 * This is set to the highest number of read cycles because it won't
204 	 * hurt lower clock frequencies. However, a high frequency with too
205 	 * few read cycles could cause flash read problems. FWS 5 (6 cycles)
206 	 * is the safe setting for all of this SoCs usable frequencies.
207 	 */
208 	EFC->EEFC_FMR = EEFC_FMR_FWS(5);
209 
210 	/* Setup system clocks. */
211 	clock_init();
212 
213 	/*
214 	 * Install default handler that simply resets the CPU
215 	 * if configured in the kernel, NOP otherwise.
216 	 */
217 	NMI_INIT();
218 
219 	irq_unlock(key);
220 
221 	return 0;
222 }
223 
224 SYS_INIT(atmel_sam4e_init, PRE_KERNEL_1, 0);
225