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