1 /*
2 * Copyright (c) 2016 Piotr Mienkowski
3 * Copyright (c) 2023-2024 Gerson Fernando Budke <nandojve@gmail.com>
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /** @file
8 * @brief Atmel SAM E70 MCU initialization code
9 *
10 * This file provides routines to initialize and support board-level hardware
11 * for the Atmel SAM E70 MCU.
12 */
13
14 #include <zephyr/kernel.h>
15 #include <zephyr/device.h>
16 #include <zephyr/init.h>
17 #include <zephyr/cache.h>
18 #include <zephyr/arch/cache.h>
19 #include <soc.h>
20 #include <soc_pmc.h>
21 #include <soc_supc.h>
22 #include <cmsis_core.h>
23 #include <zephyr/logging/log.h>
24
25 #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL
26 LOG_MODULE_REGISTER(soc);
27
28 /**
29 * @brief Setup various clocks on SoC at boot time.
30 *
31 * Setup Slow, Main, PLLA, Processor and Master clocks during the device boot.
32 * It is assumed that the relevant registers are at their reset value.
33 */
clock_init(void)34 static ALWAYS_INLINE void clock_init(void)
35 {
36 /* Switch the main clock to the internal OSC with 12MHz */
37 soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ);
38
39 /* Switch MCK (Master Clock) to the main clock */
40 soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK);
41
42 EFC->EEFC_FMR = EEFC_FMR_FWS(0) | EEFC_FMR_CLOE;
43
44 soc_pmc_enable_clock_failure_detector();
45
46 if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM_EXT_SLCK)) {
47 soc_supc_slow_clock_select_crystal_osc();
48 }
49
50
51 if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM_EXT_MAINCK)) {
52 /*
53 * Setup main external crystal oscillator.
54 */
55
56 /* We select maximum setup time.
57 * While start up time could be shortened
58 * this optimization is not deemed
59 * critical now.
60 */
61 soc_pmc_switch_mainck_to_xtal(false, 0xff);
62 }
63
64 /*
65 * Set FWS (Flash Wait State) value before increasing Master Clock
66 * (MCK) frequency.
67 * TODO: set FWS based on the actual MCK frequency and VDDIO value
68 * rather than maximum supported 150 MHz at standard VDDIO=2.7V
69 */
70 EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE;
71
72 /*
73 * Setup PLLA
74 */
75
76 /*
77 * PLL clock = Main * (MULA + 1) / DIVA
78 *
79 * By default, MULA == 24, DIVA == 1.
80 * With main crystal running at 12 MHz,
81 * PLL = 12 * (24 + 1) / 1 = 300 MHz
82 *
83 * With Processor Clock prescaler at 1
84 * Processor Clock (HCLK)=300 MHz.
85 */
86 soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAM_PLLA_MULA, 0x3Fu,
87 CONFIG_SOC_ATMEL_SAM_PLLA_DIVA);
88
89
90 soc_pmc_enable_upllck(0x3Fu);
91
92 /*
93 * Final setup of the Master Clock
94 */
95
96 /* Setting PLLA as MCK, first prescaler, then divider and source last */
97 soc_pmc_mck_set_prescaler(1);
98 soc_pmc_mck_set_divider(CONFIG_SOC_ATMEL_SAM_MDIV);
99 soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK);
100
101
102 /* Disable internal fast RC if we have an external crystal oscillator */
103 if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM_EXT_MAINCK)) {
104 soc_pmc_osc_disable_fastrc();
105 }
106 }
107
z_arm_platform_init(void)108 void z_arm_platform_init(void)
109 {
110 if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM_WAIT_MODE)) {
111 /*
112 * Instruct CPU to enter Wait mode instead of Sleep mode to
113 * keep Processor Clock (HCLK) and thus be able to debug
114 * CPU using JTAG.
115 */
116 soc_pmc_enable_waitmode();
117 }
118
119 /*
120 * DTCM is enabled by default at reset, therefore we have to disable
121 * it first to get the caches into a state where then the
122 * sys_cache*-functions can enable them, if requested by the
123 * configuration.
124 */
125 SCB_InvalidateDCache();
126 SCB_DisableDCache();
127
128 /*
129 * Enable the caches only if configured to do so.
130 */
131 sys_cache_instr_enable();
132 sys_cache_data_enable();
133
134 /* Setup system clocks */
135 clock_init();
136 }
137
138 /**
139 * @brief Perform basic hardware initialization at boot.
140 *
141 * This needs to be run at the very beginning.
142 * So the init priority has to be 0 (zero).
143 *
144 * @return 0
145 */
atmel_same70_init(void)146 static int atmel_same70_init(void)
147 {
148 /* Check that the CHIP CIDR matches the HAL one */
149 if (CHIPID->CHIPID_CIDR != CHIP_CIDR) {
150 LOG_WRN("CIDR mismatch: chip = 0x%08x vs HAL = 0x%08x",
151 (uint32_t)CHIPID->CHIPID_CIDR, (uint32_t)CHIP_CIDR);
152 }
153
154 return 0;
155 }
156
157 SYS_INIT(atmel_same70_init, PRE_KERNEL_1, 0);
158