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