1 /*
2 
3 Copyright (c) 2009-2024 ARM Limited. All rights reserved.
4 
5     SPDX-License-Identifier: Apache-2.0
6 
7 Licensed under the Apache License, Version 2.0 (the License); you may
8 not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10 
11     www.apache.org/licenses/LICENSE-2.0
12 
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an AS IS BASIS, WITHOUT
15 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 
19 NOTICE: This file has been modified by Nordic Semiconductor ASA.
20 
21 */
22 
23 /* NOTE: Template files (including this one) are application specific and therefore expected to
24    be copied into the application project folder prior to its use! */
25 
26 #include <stdint.h>
27 #include <stdbool.h>
28 #include "nrf.h"
29 #include "nrf_peripherals.h"
30 #include "nrf91_erratas.h"
31 #include "system_nrf91.h"
32 #include "system_nrf91_approtect.h"
33 
34 /*lint ++flb "Enter library region" */
35 
36 void SystemStoreFICRNS(void);
37 void SystemLockFICRNS(void);
38 
39 #define __SYSTEM_CLOCK_DEFAULT      (64000000UL)     /*!< nRF91 Application core uses a fixed System Clock Frequency of 64MHz */
40 
41 #define TRACE_PIN_CNF_VALUE (   (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | \
42                                 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | \
43                                 (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | \
44                                 (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | \
45                                 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) )
46 #define TRACE_TRACECLK_PIN   (21ul)
47 #define TRACE_TRACEDATA0_PIN (22ul)
48 #define TRACE_TRACEDATA1_PIN (23ul)
49 #define TRACE_TRACEDATA2_PIN (24ul)
50 #define TRACE_TRACEDATA3_PIN (25ul)
51 
52 #if defined ( __CC_ARM )
53     uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_DEFAULT;
54 #elif defined ( __ICCARM__ )
55     __root uint32_t SystemCoreClock = __SYSTEM_CLOCK_DEFAULT;
56 #elif defined ( __GNUC__ )
57     uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_DEFAULT;
58 #endif
59 
60 /* Errata are only handled in secure mode since they usually need access to FICR. */
61 #if !defined(NRF_TRUSTZONE_NONSECURE)
62     #if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)
63         static bool uicr_HFXOSRC_erased(void);
64         static bool uicr_HFXOCNT_erased(void);
65     #endif
66     static bool is_empty_word(uint32_t const volatile * word);
67 #endif
68 
SystemCoreClockUpdate(void)69 void SystemCoreClockUpdate(void)
70 {
71     SystemCoreClock = __SYSTEM_CLOCK_DEFAULT;
72 }
73 
SystemInit(void)74 void SystemInit(void)
75 {
76     #if !defined(NRF_TRUSTZONE_NONSECURE)
77         /* Perform Secure-mode initialization routines. */
78 
79         /* Set all ARM SAU regions to NonSecure if TrustZone extensions are enabled.
80         * Nordic SPU should handle Secure Attribution tasks */
81         #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
82           SAU->CTRL |= (1ul << SAU_CTRL_ALLNS_Pos);
83         #endif
84 
85         /* Workaround for Errata 6 "POWER: SLEEPENTER and SLEEPEXIT events asserted after pin reset" found at the Errata document
86             for your device located at https://infocenter.nordicsemi.com/index.jsp  */
87         if (nrf91_errata_6()){
88             NRF_POWER_S->EVENTS_SLEEPENTER = (POWER_EVENTS_SLEEPENTER_EVENTS_SLEEPENTER_NotGenerated << POWER_EVENTS_SLEEPENTER_EVENTS_SLEEPENTER_Pos);
89             NRF_POWER_S->EVENTS_SLEEPEXIT = (POWER_EVENTS_SLEEPEXIT_EVENTS_SLEEPEXIT_NotGenerated << POWER_EVENTS_SLEEPEXIT_EVENTS_SLEEPEXIT_Pos);
90         }
91 
92         /* Workaround for Errata 14 "REGULATORS: LDO mode at startup" found at the Errata document
93             for your device located at https://infocenter.nordicsemi.com/index.jsp  */
94         if (nrf91_errata_14()){
95             *((volatile uint32_t *)0x50004A38ul) = 0x01ul;
96             NRF_REGULATORS_S->DCDCEN = REGULATORS_DCDCEN_DCDCEN_Enabled << REGULATORS_DCDCEN_DCDCEN_Pos;
97         }
98 
99         /* Workaround for Errata 15 "REGULATORS: LDO mode at startup" found at the Errata document
100             for your device located at https://infocenter.nordicsemi.com/index.jsp  */
101         if (nrf91_errata_15()){
102             NRF_REGULATORS_S->DCDCEN = REGULATORS_DCDCEN_DCDCEN_Enabled << REGULATORS_DCDCEN_DCDCEN_Pos;
103         }
104 
105         /* Workaround for Errata 20 "RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
106             for your device located at https://infocenter.nordicsemi.com/index.jsp  */
107         if (nrf91_errata_20()){
108             *((volatile uint32_t *)0x5003AEE4ul) = 0xEul;
109         }
110 
111         /* Workaround for Errata 31 "XOSC32k Startup Failure" found at the Errata document
112             for your device located at https://infocenter.nordicsemi.com/index.jsp  */
113         if (nrf91_errata_31()){
114             *((volatile uint32_t *)0x5000470Cul) = 0x0ul;
115             *((volatile uint32_t *)0x50004710ul) = 0x1ul;
116         }
117 
118         #if !defined(NRF_SKIP_FICR_NS_COPY_TO_RAM)
119             SystemStoreFICRNS();
120         #endif
121 
122         /* Trimming of the device. Copy all the trimming values from FICR into the target addresses. Trim
123          until one ADDR is not initialized. */
124 
125         for (uint32_t index = 0ul; index < 256ul && !is_empty_word(&NRF_FICR_S->TRIMCNF[index].ADDR); index++){
126           #if defined ( __ICCARM__ )
127               #pragma diag_suppress=Pa082
128           #endif
129           *(volatile uint32_t *)NRF_FICR_S->TRIMCNF[index].ADDR = NRF_FICR_S->TRIMCNF[index].DATA;
130           #if defined ( __ICCARM__ )
131               #pragma diag_default=Pa082
132           #endif
133         }
134 
135         #if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)
136             bool irq_disabled = __get_PRIMASK() == 1;
137             uint32_t uicr_erased_value;
138             uint32_t uicr_new_value;
139             /* Set UICR->HFXOSRC and UICR->HFXOCNT to working defaults if UICR was erased */
140             if (uicr_HFXOSRC_erased() || uicr_HFXOCNT_erased()) {
141                 __DSB();
142                 /* Wait for pending NVMC operations to finish */
143                 while (NRF_NVMC_S->READY != NVMC_READY_READY_Ready);
144 
145                 /* Enable write mode in NVMC */
146                 NRF_NVMC_S->CONFIG = NVMC_CONFIG_WEN_Wen;
147                 while (NRF_NVMC_S->READY != NVMC_READY_READY_Ready);
148 
149                 if (!irq_disabled && nrf91_errata_7()){
150                     __disable_irq();
151                 }
152 
153                 if (uicr_HFXOSRC_erased()){
154                     /* Write default value to UICR->HFXOSRC */
155                     uicr_erased_value = NRF_UICR_S->HFXOSRC;
156                     uicr_new_value = (uicr_erased_value & ~UICR_HFXOSRC_HFXOSRC_Msk) | UICR_HFXOSRC_HFXOSRC_TCXO;
157                     NRF_UICR_S->HFXOSRC = uicr_new_value;
158                     __DSB();
159                     while (NRF_NVMC_S->READY != NVMC_READY_READY_Ready);
160                 }
161 
162                 if (uicr_HFXOCNT_erased()){
163                     /* Write default value to UICR->HFXOCNT */
164                     uicr_erased_value = NRF_UICR_S->HFXOCNT;
165                     uicr_new_value = (uicr_erased_value & ~UICR_HFXOCNT_HFXOCNT_Msk) | 0x20;
166                     NRF_UICR_S->HFXOCNT = uicr_new_value;
167                     __DSB();
168                     while (NRF_NVMC_S->READY != NVMC_READY_READY_Ready);
169                 }
170 
171                 if(!irq_disabled && nrf91_errata_7()){
172                     __enable_irq();
173                 }
174 
175                 /* Enable read mode in NVMC */
176                 NRF_NVMC_S->CONFIG = NVMC_CONFIG_WEN_Ren;
177                 while (NRF_NVMC_S->READY != NVMC_READY_READY_Ready);
178 
179                 /* Reset to apply clock select update */
180                 NVIC_SystemReset();
181             }
182         #endif
183 
184         /* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product
185            Specification to see which ones). */
186         #if defined (ENABLE_TRACE)
187             // Enable Trace And Debug peripheral
188             NRF_TAD_S->ENABLE = TAD_ENABLE_ENABLE_Msk;
189             NRF_TAD_S->TASKS_CLOCKSTART = TAD_TASKS_CLOCKSTART_TASKS_CLOCKSTART_Msk;
190 
191             // Set up Trace pads SPU firewall
192             NRF_SPU_S->GPIOPORT[0].PERM &= ~(1ul << TRACE_TRACECLK_PIN);
193             NRF_SPU_S->GPIOPORT[0].PERM &= ~(1ul << TRACE_TRACEDATA0_PIN);
194             NRF_SPU_S->GPIOPORT[0].PERM &= ~(1ul << TRACE_TRACEDATA1_PIN);
195             NRF_SPU_S->GPIOPORT[0].PERM &= ~(1ul << TRACE_TRACEDATA2_PIN);
196             NRF_SPU_S->GPIOPORT[0].PERM &= ~(1ul << TRACE_TRACEDATA3_PIN);
197 
198             // Configure trace port pads
199             NRF_P0_S->PIN_CNF[TRACE_TRACECLK_PIN] =   TRACE_PIN_CNF_VALUE;
200             NRF_P0_S->PIN_CNF[TRACE_TRACEDATA0_PIN] = TRACE_PIN_CNF_VALUE;
201             NRF_P0_S->PIN_CNF[TRACE_TRACEDATA1_PIN] = TRACE_PIN_CNF_VALUE;
202             NRF_P0_S->PIN_CNF[TRACE_TRACEDATA2_PIN] = TRACE_PIN_CNF_VALUE;
203             NRF_P0_S->PIN_CNF[TRACE_TRACEDATA3_PIN] = TRACE_PIN_CNF_VALUE;
204 
205             // Select trace pins
206             NRF_TAD_S->PSEL.TRACECLK   = TRACE_TRACECLK_PIN;
207             NRF_TAD_S->PSEL.TRACEDATA0 = TRACE_TRACEDATA0_PIN;
208             NRF_TAD_S->PSEL.TRACEDATA1 = TRACE_TRACEDATA1_PIN;
209             NRF_TAD_S->PSEL.TRACEDATA2 = TRACE_TRACEDATA2_PIN;
210             NRF_TAD_S->PSEL.TRACEDATA3 = TRACE_TRACEDATA3_PIN;
211 
212             // Set trace port speed to 32 MHz
213             NRF_TAD_S->TRACEPORTSPEED = TAD_TRACEPORTSPEED_TRACEPORTSPEED_32MHz;
214 
215             *((volatile uint32_t *)(0xE0053000ul)) = 0x00000001ul;
216 
217             *((volatile uint32_t *)(0xE005AFB0ul))  = 0xC5ACCE55ul;
218             *((volatile uint32_t *)(0xE005A000ul)) &= 0xFFFFFF00ul;
219             *((volatile uint32_t *)(0xE005A004ul))  = 0x00000009ul;
220             *((volatile uint32_t *)(0xE005A000ul))  = 0x00000303ul;
221             *((volatile uint32_t *)(0xE005AFB0ul))  = 0x00000000ul;
222 
223             *((volatile uint32_t *)(0xE005BFB0ul))  = 0xC5ACCE55ul;
224             *((volatile uint32_t *)(0xE005B000ul)) &= 0xFFFFFF00ul;
225             *((volatile uint32_t *)(0xE005B004ul))  = 0x00003000ul;
226             *((volatile uint32_t *)(0xE005B000ul))  = 0x00000308ul;
227             *((volatile uint32_t *)(0xE005BFB0ul))  = 0x00000000ul;
228 
229             *((volatile uint32_t *)(0xE0058FB0ul)) = 0xC5ACCE55ul;
230             *((volatile uint32_t *)(0xE0058000ul)) = 0x00000000ul;
231             *((volatile uint32_t *)(0xE0058004ul)) = 0x00000000ul;
232             *((volatile uint32_t *)(0xE0058FB0ul)) = 0x00000000ul;
233 
234             /* Rom table does not list ETB, or TPIU base addresses.
235              * Some debug probes may require manual configuration of these peripherals to enable tracing.
236              * ETB_BASE = 0xE0051000
237              * TPIU_BASE = 0xE0054000
238              */
239         #endif
240 
241         /* Allow Non-Secure code to run FPU instructions.
242          * If only the secure code should control FPU power state these registers should be configured accordingly in the secure application code. */
243         SCB->NSACR |= (3UL << 10ul);
244 
245         nrf91_handle_approtect();
246     #endif
247 
248     /* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
249     * compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
250     * operations are not used in your code. */
251     #if (__FPU_USED == 1)
252         SCB->CPACR |= (3UL << 20ul) | (3UL << 22ul);
253         __DSB();
254         __ISB();
255     #endif
256 }
257 
258 
259 #if !defined(NRF_TRUSTZONE_NONSECURE)
260 
261     #if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)
uicr_HFXOCNT_erased()262         bool uicr_HFXOCNT_erased()
263         {
264             bool irq_disabled = __get_PRIMASK() == 1;
265             if (!irq_disabled && nrf91_errata_7()){
266                 __disable_irq();
267             }
268             bool is_empty = is_empty_word(&NRF_UICR_S->HFXOCNT);
269             if (!irq_disabled && nrf91_errata_7()){
270                 __enable_irq();
271             }
272             return is_empty;
273         }
274 
275 
uicr_HFXOSRC_erased()276         bool uicr_HFXOSRC_erased()
277         {
278             bool irq_disabled = __get_PRIMASK() == 1;
279             if (!irq_disabled && nrf91_errata_7()){
280                 __disable_irq();
281             }
282             uint32_t HFXOSRC_readout = NRF_UICR_S->HFXOSRC;
283             __DSB();
284             bool erased = (HFXOSRC_readout & UICR_HFXOSRC_HFXOSRC_Msk) != UICR_HFXOSRC_HFXOSRC_TCXO;
285             if (!irq_disabled && nrf91_errata_7()){
286                 __enable_irq();
287             }
288             return erased;
289         }
290     #endif
291 
is_empty_word(uint32_t const volatile * word)292     bool is_empty_word(uint32_t const volatile * word)
293     {
294         uint32_t val = *word;
295         __DSB();
296         return val == 0xFFFFFFFFul;
297     }
298 #endif
299 
300 
301 /* Workaround to allow NS code to access FICR. Override NRF_FICR_NS to move FICR_NS buffer. */
302 #define FICR_SIZE 0x1000ul
303 #define RAM_BASE 0x20000000ul
304 #define RAM_END  0x2FFFFFFFul
305 
306 /* Copy FICR_S to FICR_NS RAM region */
SystemStoreFICRNS()307 void SystemStoreFICRNS()
308 {
309     if ((uint32_t)NRF_FICR_NS < RAM_BASE || (uint32_t)NRF_FICR_NS + FICR_SIZE > RAM_END)
310     {
311         /* FICR_NS is not in RAM. */
312         return;
313     }
314     /* Copy FICR to NS-accessible RAM block. */
315     volatile uint32_t * from            = (volatile uint32_t *)((uint32_t)NRF_FICR_S + (FICR_SIZE - sizeof(uint32_t)));
316     volatile uint32_t * to              = (volatile uint32_t *)((uint32_t)NRF_FICR_NS + (FICR_SIZE - sizeof(uint32_t)));
317     volatile uint32_t * copy_from_end   = (volatile uint32_t *)NRF_FICR_S;
318     while (from >= copy_from_end)
319     {
320         *(to--) = *(from--);
321     }
322 
323     /* Make RAM region NS. */
324     uint32_t ram_region = ((uint32_t)NRF_FICR_NS - (uint32_t)RAM_BASE) / SPU_RAMREGION_SIZE;
325     __DSB();
326     NRF_SPU_S->RAMREGION[ram_region].PERM &= ~(1ul << SPU_RAMREGION_PERM_SECATTR_Pos);
327 }
328 
329 /* Block write and execute access to FICR RAM region */
SystemLockFICRNS()330 void SystemLockFICRNS()
331 {
332     if ((uint32_t)NRF_FICR_NS < RAM_BASE || (uint32_t)NRF_FICR_NS + FICR_SIZE > RAM_END)
333     {
334         /* FICR_NS is not in RAM. */
335         return;
336     }
337 
338     uint32_t ram_region = ((uint32_t)NRF_FICR_NS - (uint32_t)RAM_BASE) / SPU_RAMREGION_SIZE;
339     __DSB();
340     NRF_SPU_S->RAMREGION[ram_region].PERM &=
341         ~(
342             (1ul << SPU_RAMREGION_PERM_WRITE_Pos) |
343             (1ul << SPU_RAMREGION_PERM_EXECUTE_Pos)
344         );
345     NRF_SPU_S->RAMREGION[ram_region].PERM |= 1ul << SPU_RAMREGION_PERM_LOCK_Pos;
346 }
347 
348 /*lint --flb "Leave library region" */
349