ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
system_init.c
Go to the documentation of this file.
1
50
51#include <stdint.h>
52
53#include "ra8_boot_entry.h"
54#include "ra8_cgc.h"
55#include "trustzone_init.h"
56
57extern const uint32_t g_ra8_vector_table_start[];
58
59/* =============================================================================
60 * Core / SCB / NVIC register addresses (direct, no CMSIS dep)
61 * =============================================================================
62 */
63
64typedef enum : uintptr_t {
65 k_ra8_scb_vtor_addr = 0xE000ED08UL,
66 k_ra8_scb_ccr_addr = 0xE000ED14UL,
67 k_ra8_scb_shcsr_addr = 0xE000ED24UL,
68 k_ra8_scb_cpacr_addr = 0xE000ED88UL,
69 k_ra8_scb_nsacr_addr = 0xE000ED8CUL,
70 k_ra8_scb_iciallu = 0xE000EF50UL,
71 k_ra8_scb_dciallu = 0xE000EF58UL,
72 k_ra8_scb_csselr = 0xE000ED84UL,
73 k_ra8_scb_ccsidr = 0xE000ED80UL,
74 k_ra8_scb_dcisw = 0xE000EF60UL,
75 k_ra8_fpu_fpccr_addr = 0xE000EF34UL,
76 k_ra8_nvic_aircr = 0xE000ED0CUL,
77 k_ra8_mpu_type_addr = 0xE000ED90UL,
78 k_ra8_mpu_ctrl_addr = 0xE000ED94UL,
79 k_ra8_mpu_rnr_addr = 0xE000ED98UL,
80 k_ra8_mpu_rbar_addr = 0xE000ED9CUL,
81 k_ra8_mpu_rlar_addr = 0xE000EDA0UL,
82 k_ra8_mpu_mair0_addr = 0xE000EDC0UL,
83 k_ra8_mpu_mair1_addr = 0xE000EDC4UL,
85
86extern uint32_t g_ra8_ls_stack_top; /* from vector_table.c / linker. */
87
88/* =============================================================================
89 * Small helpers
90 * =============================================================================
91 */
92
93static inline uint32_t internal_read32(uintptr_t addr)
94{
95 return *(volatile uint32_t*)addr;
96}
97
98static inline void internal_write32(uintptr_t addr, uint32_t value)
99{
100 *(volatile uint32_t*)addr = value;
101}
102
103static inline void internal_dsb(void)
104{
105#ifndef RA8_OFF_TARGET
106 __asm__ volatile("dsb 0xF" ::: "memory");
107#endif
108}
109
110static inline void internal_isb(void)
111{
112#ifndef RA8_OFF_TARGET
113 __asm__ volatile("isb 0xF" ::: "memory");
114#endif
115}
116
117static inline void internal_disable_irq(void)
118{
119#ifndef RA8_OFF_TARGET
120 __asm__ volatile("cpsid i" ::: "memory");
121#endif
122}
123
124/* =============================================================================
125 * Core init steps
126 * =============================================================================
127 */
128
132static void internal_set_vtor(void)
133{
134 /* Vector table sits at the start of the .vectors section, which
135 * the linker pins to the start of MRAM (`0x02000000`). The SCB
136 * VTOR register stores the absolute address. */
138}
139
143static void internal_enable_fpu(void)
144{
145 enum : uint32_t {
146 k_ra8_cpacr_cp10_cp11_full_access = 0x00F00000UL,
147 };
148 uint32_t cpacr = internal_read32(k_ra8_scb_cpacr_addr);
149 cpacr |= k_ra8_cpacr_cp10_cp11_full_access;
151 internal_dsb();
152 internal_isb();
153}
154
159{
160 enum : uint32_t {
161 k_ra8_fpccr_lspen = 1UL << 30,
162 k_ra8_fpccr_aspen = 1UL << 31,
163 };
164 uint32_t fpccr = internal_read32(k_ra8_fpu_fpccr_addr);
165 fpccr |= k_ra8_fpccr_lspen | k_ra8_fpccr_aspen;
167}
168
172static void internal_enable_icache(void)
173{
174 /* Invalidate, then set CCR.IC. */
175 internal_dsb();
177 internal_dsb();
178 internal_isb();
179
180 enum : uint32_t { k_ra8_ccr_ic = 1UL << 17 };
181 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
182 ccr |= k_ra8_ccr_ic;
184 internal_dsb();
185 internal_isb();
186}
187
197static void internal_enable_dcache(void)
198{
199 enum : uint32_t { k_ra8_ccr_dc = 1UL << 16 };
200 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
201 ccr |= k_ra8_ccr_dc;
203 internal_dsb();
204 internal_isb();
205}
206
211{
212 enum : uint32_t { k_ra8_ccr_bp = 1UL << 18 };
213 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
214 ccr |= k_ra8_ccr_bp;
216 internal_dsb();
217 internal_isb();
218}
219
224{
225 enum : uint32_t {
226 k_ra8_aircr_vectkey = 0x05FA0000UL,
227 k_ra8_aircr_prigroup_4 = 0x00000300UL,
228 };
229 internal_write32(k_ra8_nvic_aircr, k_ra8_aircr_vectkey | k_ra8_aircr_prigroup_4);
230}
231
255/* RBAR attribute-byte encodings (bottom 5 bits of RBAR). */
256enum : uint32_t {
261};
262
263/* Region base and limit addresses. RLAR limits are <region-end> minus
264 * the ARMv8-M 32-byte region quantum, OR-ed with the enable bit at write time. */
265enum : uint32_t {
266 k_ra8_mpu_mram_base = 0x02000000UL,
267 k_ra8_mpu_mram_limit = 0x020FFFE0UL,
268 k_ra8_mpu_sram_base = 0x22000000UL,
269 k_ra8_mpu_sram_limit = 0x221FFFE0UL,
270 k_ra8_mpu_sdram_base = 0x68000000UL,
271 k_ra8_mpu_sdram_limit = 0x6BFFFFE0UL,
272 k_ra8_mpu_peri_base = 0x40000000UL,
273 k_ra8_mpu_peri_limit = 0x47FFFFE0UL,
274};
275
279static void internal_mpu_set_region(uint32_t region, uint32_t base_attr, uint32_t limit_enable)
280{
284}
285
289static void internal_mpu_init(void)
290{
291 enum : uint32_t {
292 k_ra8_mpu_ctrl_enable = 1UL << 0,
293 k_ra8_mpu_ctrl_privdefena = 1UL << 2,
294 k_ra8_mair0_default = 0x000404FFUL,
295 };
296
297 /* MAIR0: idx 0 = WB/WA, idx 1 = non-cacheable, idx 2 = device-nGnRE. */
298 internal_write32(k_ra8_mpu_mair0_addr, k_ra8_mair0_default);
300
313
314 /* Enable MPU with PRIVDEFENA so unclassified privileged accesses
315 * still succeed through the default system memory map. */
316 internal_dsb();
318 internal_dsb();
319 internal_isb();
320}
321
343[[noreturn, gnu::noinline]] static void internal_halt_secure_clock_fault(void)
344{
345 while (1) {
346 __asm__ volatile("wfi");
347 }
348}
349
350/* =============================================================================
351 * Public entry point
352 * =============================================================================
353 *
354 * Called from `Reset_Handler` after the C runtime is live (.data
355 * copied, .bss zeroed). It may therefore read and write globals
356 * freely; the Secure clock + TrustZone bring-up below relies on that.
357 */
358
359void SystemInit(void)
360{
361 /* Mask global IRQs so the application gets a deterministic init
362 * window. main() must call ``ra8_isr_globals_enable`` once every
363 * driver / handler is wired up before any IRQ source can fire. */
365
369 /* Cache enable, MPU init, and TrustZone bring-up are temporarily
370 * disabled -- they HardFault on first reset because the CCSIDR-driven
371 * invalidate-by-set/way loop is not yet implemented and the MPU
372 * regions are unconfigured. Re-enable once those code paths land. */
376 (void)internal_mpu_init;
378
379 /* Bring up the Secure clock tree (XTAL -> PLL1 -> CPUCLK0 = 1 GHz) BEFORE the
380 * SAU + BLXNS below. ra8_trustzone_init() does NOT return on hardware (BLXNS
381 * leaves Secure thread mode), so anything sequenced after it never runs on the
382 * Secure side. The NS-side NSC CGC veneers (ra8_nsc_cgc_pll2_enable etc.) trap
383 * back into this Secure CGC driver, which needs PLL1 already locked -- without
384 * it the first PLL2 enable fails because its PLL1 source is missing. */
385 if (ra8_cgc_init() != k_ra8_ok) {
386 /* NASA Rule 7: a failed Secure clock bring-up must not BLXNS into NS code
387 * on a dead clock tree -- park at a named symbol instead of switching. */
389 }
390
391#ifdef RA8_TRUSTZONE_ENABLE
392 /* Programme the SAU, then BLXNS into the NS image. The NSC veneers depend on
393 * the SAU being live so the cmse_nonsecure_entry traps land on the Secure
394 * side. Does not return on hardware. */
396#else
397 (void)ra8_trustzone_init;
398#endif
399}
static void internal_enable_fpu_lazy_stack(void)
Turn on FPU lazy stacking (FPCCR.LSPEN = 1, ASPEN = 1).
static void internal_dsb(void)
Data Synchronization Barrier (DSB).
static void internal_enable_branch_predictor(void)
Enable branch-target prediction (CCR.BP on Cortex-M85).
static void internal_write32(uintptr_t addr, uint32_t value)
Write a 32-bit value to a core/system register via a volatile store.
static void internal_disable_irq(void)
Mask all maskable IRQs at the core (PRIMASK = 1, cpsid i).
static void internal_set_vtor(void)
Point VTOR at the physical vector table base.
static void internal_enable_dcache(void)
Invalidate and enable the Cortex-M85 D-cache.
static void internal_enable_icache(void)
Invalidate and enable the Cortex-M85 I-cache.
static void internal_mpu_init(void)
Programme and enable the Cortex-M85 core MPU.
static uint32_t internal_read32(uintptr_t addr)
Read a 32-bit core/system register via a volatile load.
void SystemInit(void)
Earliest C code the image runs: bring the core up before RAM init.
static void internal_mpu_set_region(uint32_t region, uint32_t base_attr, uint32_t limit_enable)
Program a single MPU region via RNR/RBAR/RLAR.
static void internal_halt_secure_clock_fault(void)
Park forever after a Secure clock-tree bring-up failure.
static void internal_isb(void)
Instruction Synchronization Barrier (ISB).
static void internal_set_priority_grouping(void)
Set NVIC priority grouping to 4 preempt bits / 0 sub-priority.
static void internal_enable_fpu(void)
Grant full access to CP10 / CP11 (the FPU coprocessors).
@ k_ra8_rbar_attr_device_rw
AP=RW, SH=outer sh, XN=1, MAIR idx = device.
void ra8_trustzone_init(void)
Programme + enable the SAU per the partition.
static void internal_enable_branch_predictor(void)
Enable branch-target prediction (CCR.BP on Cortex-M85).
static void internal_enable_dcache(void)
Invalidate and enable the Cortex-M85 D-cache.
uint32_t g_ra8_ls_stack_top
static void internal_enable_icache(void)
Invalidate and enable the Cortex-M85 I-cache.
@ k_ra8_mpu_sdram_limit
RA8 MPU SDRAM limit.
@ k_ra8_mpu_mram_base
1 MiB MRAM code region.
@ k_ra8_mpu_sram_limit
RA8 MPU SRAM limit.
@ k_ra8_mpu_sram_base
M85 private SRAM0+1, 1 MiB, cacheable.
@ k_ra8_mpu_peri_base
Peripheral bus window base.
@ k_ra8_mpu_mram_limit
RA8 MPU MRAM limit.
@ k_ra8_mpu_peri_limit
RA8 MPU peri limit.
@ k_ra8_mpu_sdram_base
64 MiB external SDRAM.
static void internal_mpu_init(void)
Programme and enable the Cortex-M85 core MPU.
@ k_ra8_rbar_attr_ro_x
AP=RO any-priv, SH=none, XN=0 (executable).
@ k_ra8_mpu_rlar_enable
RA8 MPU rlar enable.
@ k_ra8_rbar_attr_rw_xn
AP=RW any-priv, SH=none, XN=1 (no execute).
ra8_core_addr_t
Definition system_init.c:60
@ k_ra8_scb_iciallu
ICIALLU – invalidate I-cache.
Definition system_init.c:66
@ k_ra8_scb_dcisw
D-cache Invalidate by Set/Way.
Definition system_init.c:70
@ k_ra8_scb_csselr
Cache Size Selection Register.
Definition system_init.c:68
@ k_ra8_scb_dciallu
DCIALLU – invalidate D-cache (sets only).
Definition system_init.c:67
@ k_ra8_mpu_mair0_addr
MPU Attribute Indirection 0.
Definition system_init.c:78
@ k_ra8_scb_ccsidr
Cache Size ID Register.
Definition system_init.c:69
@ k_ra8_scb_cpacr_addr
Coprocessor Access Control.
Definition system_init.c:64
@ k_ra8_scb_shcsr_addr
System Handler Control and State.
Definition system_init.c:63
@ k_ra8_fpu_fpccr_addr
FPU Context Control Register.
Definition system_init.c:71
@ k_ra8_scb_ccr_addr
Configuration and Control Register.
Definition system_init.c:62
@ k_ra8_mpu_type_addr
MPU Type Register.
Definition system_init.c:73
@ k_ra8_mpu_rnr_addr
MPU Region Number.
Definition system_init.c:75
@ k_ra8_mpu_rbar_addr
MPU Region Base Address.
Definition system_init.c:76
@ k_ra8_mpu_mair1_addr
MPU Attribute Indirection 1.
Definition system_init.c:79
@ k_ra8_mpu_ctrl_addr
MPU Control Register.
Definition system_init.c:74
@ k_ra8_scb_vtor_addr
Vector Table Offset Register.
Definition system_init.c:61
@ k_ra8_scb_nsacr_addr
Non-secure Access Control.
Definition system_init.c:65
@ k_ra8_mpu_rlar_addr
MPU Region Limit Address.
Definition system_init.c:77
@ k_ra8_nvic_aircr
Application Interrupt and Reset Ctrl.
Definition system_init.c:72
const uint32_t g_ra8_vector_table_start[]
Boot entry points shared between a vector table and its startup code.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_mpu_ctrl_enable
RA8 MPU control enable.
@ k_ra8_mpu_ctrl_privdefena
RA8 MPU control privdefena.