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
40
41#include <stdint.h>
42
43#include "ra8_boot_entry.h"
44#include "trustzone_init.h"
45
46extern const uint32_t g_ra8_vector_table_start[];
47
48/* =============================================================================
49 * Core / SCB / NVIC register addresses (direct, no CMSIS dep)
50 * =============================================================================
51 */
52
53typedef enum : uintptr_t {
54 k_ra8_scb_vtor_addr = 0xE000ED08UL,
55 k_ra8_scb_ccr_addr = 0xE000ED14UL,
56 k_ra8_scb_shcsr_addr = 0xE000ED24UL,
57 k_ra8_scb_cpacr_addr = 0xE000ED88UL,
58 k_ra8_scb_nsacr_addr = 0xE000ED8CUL,
59 k_ra8_scb_iciallu = 0xE000EF50UL,
60 k_ra8_scb_dciallu = 0xE000EF58UL,
61 k_ra8_scb_csselr = 0xE000ED84UL,
62 k_ra8_scb_ccsidr = 0xE000ED80UL,
63 k_ra8_scb_dcisw = 0xE000EF60UL,
64 k_ra8_fpu_fpccr_addr = 0xE000EF34UL,
65 k_ra8_nvic_aircr = 0xE000ED0CUL,
66 k_ra8_mpu_type_addr = 0xE000ED90UL,
67 k_ra8_mpu_ctrl_addr = 0xE000ED94UL,
68 k_ra8_mpu_rnr_addr = 0xE000ED98UL,
69 k_ra8_mpu_rbar_addr = 0xE000ED9CUL,
70 k_ra8_mpu_rlar_addr = 0xE000EDA0UL,
71 k_ra8_mpu_mair0_addr = 0xE000EDC0UL,
72 k_ra8_mpu_mair1_addr = 0xE000EDC4UL,
74
75extern uint32_t g_ra8_ls_stack_top; /* from vector_table.c / linker. */
76
77/* =============================================================================
78 * Small helpers
79 * =============================================================================
80 */
81
82static inline uint32_t internal_read32(uintptr_t addr)
83{
84 return *(volatile uint32_t*)addr;
85}
86
87static inline void internal_write32(uintptr_t addr, uint32_t value)
88{
89 *(volatile uint32_t*)addr = value;
90}
91
92static inline void internal_dsb(void)
93{
94#ifndef RA8_OFF_TARGET
95 __asm__ volatile("dsb 0xF" ::: "memory");
96#endif
97}
98
99static inline void internal_isb(void)
100{
101#ifndef RA8_OFF_TARGET
102 __asm__ volatile("isb 0xF" ::: "memory");
103#endif
104}
105
106static inline void internal_disable_irq(void)
107{
108#ifndef RA8_OFF_TARGET
109 __asm__ volatile("cpsid i" ::: "memory");
110#endif
111}
112
113/* =============================================================================
114 * Core init steps
115 * =============================================================================
116 */
117
121static void internal_set_vtor(void)
122{
123 /* Vector table sits at the start of the .vectors section, which
124 * the linker pins to the start of MRAM (`0x02000000`). The SCB
125 * VTOR register stores the absolute address. */
127}
128
132static void internal_enable_fpu(void)
133{
134 enum : uint32_t {
135 k_ra8_cpacr_cp10_cp11_full_access = 0x00F00000UL,
136 };
137 uint32_t cpacr = internal_read32(k_ra8_scb_cpacr_addr);
138 cpacr |= k_ra8_cpacr_cp10_cp11_full_access;
140 internal_dsb();
141 internal_isb();
142}
143
148{
149 enum : uint32_t {
150 k_ra8_fpccr_lspen = 1UL << 30,
151 k_ra8_fpccr_aspen = 1UL << 31,
152 };
153 uint32_t fpccr = internal_read32(k_ra8_fpu_fpccr_addr);
154 fpccr |= k_ra8_fpccr_lspen | k_ra8_fpccr_aspen;
156}
157
161static void internal_enable_icache(void)
162{
163 /* Invalidate, then set CCR.IC. */
164 internal_dsb();
166 internal_dsb();
167 internal_isb();
168
169 enum : uint32_t { k_ra8_ccr_ic = 1UL << 17 };
170 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
171 ccr |= k_ra8_ccr_ic;
173 internal_dsb();
174 internal_isb();
175}
176
186static void internal_enable_dcache(void)
187{
188 enum : uint32_t { k_ra8_ccr_dc = 1UL << 16 };
189 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
190 ccr |= k_ra8_ccr_dc;
192 internal_dsb();
193 internal_isb();
194}
195
200{
201 enum : uint32_t { k_ra8_ccr_bp = 1UL << 18 };
202 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
203 ccr |= k_ra8_ccr_bp;
205 internal_dsb();
206 internal_isb();
207}
208
213{
214 enum : uint32_t {
215 k_ra8_aircr_vectkey = 0x05FA0000UL,
216 k_ra8_aircr_prigroup_4 = 0x00000300UL,
217 };
218 internal_write32(k_ra8_nvic_aircr, k_ra8_aircr_vectkey | k_ra8_aircr_prigroup_4);
219}
220
244/* RBAR attribute-byte encodings (bottom 5 bits of RBAR). */
245enum : uint32_t {
250};
251
252/* Region base and limit addresses. RLAR limits are <region-end> minus
253 * the ARMv8-M 32-byte region quantum, OR-ed with the enable bit at write time. */
254enum : uint32_t {
255 k_ra8_mpu_mram_base = 0x02000000UL,
256 k_ra8_mpu_mram_limit = 0x020FFFE0UL,
257 k_ra8_mpu_sram_base = 0x22000000UL,
258 k_ra8_mpu_sram_limit = 0x221FFFE0UL,
259 k_ra8_mpu_sdram_base = 0x68000000UL,
260 k_ra8_mpu_sdram_limit = 0x6BFFFFE0UL,
261 k_ra8_mpu_peri_base = 0x40000000UL,
262 k_ra8_mpu_peri_limit = 0x47FFFFE0UL,
263};
264
268static void internal_mpu_set_region(uint32_t region, uint32_t base_attr, uint32_t limit_enable)
269{
273}
274
278static void internal_mpu_init(void)
279{
280 enum : uint32_t {
281 k_ra8_mpu_ctrl_enable = 1UL << 0,
282 k_ra8_mpu_ctrl_privdefena = 1UL << 2,
283 k_ra8_mair0_default = 0x000404FFUL,
284 };
285
286 /* MAIR0: idx 0 = WB/WA, idx 1 = non-cacheable, idx 2 = device-nGnRE. */
287 internal_write32(k_ra8_mpu_mair0_addr, k_ra8_mair0_default);
289
302
303 /* Enable MPU with PRIVDEFENA so unclassified privileged accesses
304 * still succeed through the default system memory map. */
305 internal_dsb();
307 internal_dsb();
308 internal_isb();
309}
310
311/* =============================================================================
312 * Public entry point
313 * =============================================================================
314 *
315 * Called from `Reset_Handler` before the .data copy and .bss zero.
316 * Must therefore not touch any global variables -- everything here
317 * runs on the stack and writes to CPU / SCB memory only.
318 */
319
320void SystemInit(void)
321{
322 /* Mask global IRQs so the application gets a deterministic init
323 * window. main() must call ``ra8_isr_globals_enable`` once every
324 * driver / handler is wired up before any IRQ source can fire. */
326
330
331 /* IPCSAR is left at reset default (0 = all channels secure).
332 *
333 * Attempt 2 on 2026-05-20: set IPCSAR = 0x000F0303 (flip
334 * channels NS) AND switch the HAL accessor to use the NS alias
335 * 0x50020000 (Secure can access NS resources via NS alias on
336 * ARMv8-M). CPU0 still HardFaulted on the first IPC register
337 * touch -- whether via S alias 0x40020100 or NS alias
338 * 0x50020100, the chip refused the access. JTAG confirmed
339 * IPCSAR did land at 0x000F0303 and PC parked in
340 * ra8_exception_halt_loop.
341 *
342 * Conclusion: the NS alias is not just a memory-map view, it
343 * requires SAU + IDAU + something else to be properly
344 * configured for accesses to succeed. The right dual-core
345 * fix needs a full TrustZone bring-up -- not feasible in a
346 * single-iteration loop. Reverted. See project memory
347 * project_cpu1_must_be_non_secure.md for the full background. */
348
349 /* Cache enable, MPU init, and TrustZone bring-up are temporarily
350 * disabled -- they HardFault on first reset because the CCSIDR-driven
351 * invalidate-by-set/way loop is not yet implemented and the MPU
352 * regions are unconfigured. Re-enable once those code paths land. */
356 (void)internal_mpu_init;
357 (void)ra8_trustzone_init;
359}
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_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.
@ k_ra8_mpu_ctrl_enable
RA8 MPU control enable.
@ k_ra8_mpu_ctrl_privdefena
RA8 MPU control privdefena.