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_attributes.h"
54#include "ra8_boot_entry.h"
55#include "ra8_boot_intrinsics.h"
56#include "ra8_cache.h"
57#include "trustzone_init.h"
58
59extern const uint32_t g_ra8_vector_table_start[];
60
61/* =============================================================================
62 * Core / SCB / NVIC register addresses (direct, no CMSIS dep)
63 * =============================================================================
64 */
65
66typedef enum : uintptr_t {
67 k_ra8_scb_vtor_addr = 0xE000ED08UL,
68 k_ra8_scb_ccr_addr = 0xE000ED14UL,
69 k_ra8_scb_shcsr_addr = 0xE000ED24UL,
70 k_ra8_scb_cpacr_addr = 0xE000ED88UL,
71 k_ra8_scb_nsacr_addr = 0xE000ED8CUL,
72 k_ra8_scb_iciallu = 0xE000EF50UL,
73 k_ra8_scb_dciallu = 0xE000EF58UL,
74 k_ra8_scb_csselr = 0xE000ED84UL,
75 k_ra8_scb_ccsidr = 0xE000ED80UL,
76 k_ra8_scb_dcisw = 0xE000EF60UL,
77 k_ra8_fpu_fpccr_addr = 0xE000EF34UL,
78 k_ra8_nvic_aircr = 0xE000ED0CUL,
79 k_ra8_mpu_type_addr = 0xE000ED90UL,
80 k_ra8_mpu_ctrl_addr = 0xE000ED94UL,
81 k_ra8_mpu_rnr_addr = 0xE000ED98UL,
82 k_ra8_mpu_rbar_addr = 0xE000ED9CUL,
83 k_ra8_mpu_rlar_addr = 0xE000EDA0UL,
84 k_ra8_mpu_mair0_addr = 0xE000EDC0UL,
85 k_ra8_mpu_mair1_addr = 0xE000EDC4UL,
87
88extern uint32_t g_ra8_ls_stack_top; /* from vector_table.c / linker. */
89
90/* =============================================================================
91 * Core init steps
92 * =============================================================================
93 */
94
106static void internal_set_vtor(void)
107{
108 /* Vector table sits at the start of the .vectors section, which
109 * the linker pins to the start of MRAM (`0x02000000`). The SCB
110 * VTOR register stores the absolute address. */
112}
113
125static void internal_enable_fpu(void)
126{
127 enum : uint32_t {
128 k_ra8_cpacr_cp10_cp11_full_access = 0x00F00000UL,
129 };
130 uint32_t cpacr = ra8_boot_read32(k_ra8_scb_cpacr_addr);
131 cpacr |= k_ra8_cpacr_cp10_cp11_full_access;
133 ra8_boot_dsb();
134 ra8_boot_isb();
135}
136
149{
150 enum : uint32_t {
151 k_ra8_fpccr_lspen = 1UL << 30,
152 k_ra8_fpccr_aspen = 1UL << 31,
153 };
154 uint32_t fpccr = ra8_boot_read32(k_ra8_fpu_fpccr_addr);
155 fpccr |= k_ra8_fpccr_lspen | k_ra8_fpccr_aspen;
157}
158
170static void internal_enable_icache(void)
171{
172 /* Invalidate, then set CCR.IC. */
173 ra8_boot_dsb();
175 ra8_boot_dsb();
176 ra8_boot_isb();
177
178 enum : uint32_t { k_ra8_ccr_ic = 1UL << 17 };
179 uint32_t ccr = ra8_boot_read32(k_ra8_scb_ccr_addr);
180 ccr |= k_ra8_ccr_ic;
182 ra8_boot_dsb();
183 ra8_boot_isb();
184}
185
205static void internal_enable_dcache(void)
206{
207 /* Architectural ARMv8-M set/way invalidate of the whole D-cache,
208 * driven by CCSIDR (implemented in libs/ra8_hal ra8_cache). */
210 enum : uint32_t { k_ra8_ccr_dc = 1UL << 16 };
211 uint32_t ccr = ra8_boot_read32(k_ra8_scb_ccr_addr);
212 ccr |= k_ra8_ccr_dc;
214 ra8_boot_dsb();
215 ra8_boot_isb();
216}
217
230{
231 enum : uint32_t { k_ra8_ccr_bp = 1UL << 18 };
232 uint32_t ccr = ra8_boot_read32(k_ra8_scb_ccr_addr);
233 ccr |= k_ra8_ccr_bp;
235 ra8_boot_dsb();
236 ra8_boot_isb();
237}
238
274{
275 /* ARMv8-M SCB->SHCSR: MEMFAULTENA[16], BUSFAULTENA[17], USGFAULTENA[18],
276 * SECUREFAULTENA[19] take MemManage/BusFault/UsageFault/SecureFault to
277 * their own handlers instead of escalating to HardFault, so
278 * ra8_exception_report sees the real class. SECUREFAULTENA is a
279 * Secure-bank bit (RES0 from NS); this boot executes in the Secure
280 * state, see the function contract for the scoping rationale. */
281 enum : uint32_t {
282 k_ra8_shcsr_memfaultena = 1UL << 16,
283 k_ra8_shcsr_busfaultena = 1UL << 17,
284 k_ra8_shcsr_usgfaultena = 1UL << 18,
285 k_ra8_shcsr_securefaultena = 1UL << 19,
286 };
287 uint32_t shcsr = ra8_boot_read32(k_ra8_scb_shcsr_addr);
288 shcsr |= k_ra8_shcsr_memfaultena | k_ra8_shcsr_busfaultena | k_ra8_shcsr_usgfaultena |
289 k_ra8_shcsr_securefaultena;
291 ra8_boot_dsb();
292 ra8_boot_isb();
293}
294
325{
326 /* ARMv8-M SCB->CCR: DIV_0_TRP[4] promotes SDIV/UDIV-by-zero from
327 * "quotient reads as 0" to a UsageFault with CFSR.DIVBYZERO set.
328 * UNALIGN_TRP[3] stays 0 -- see the function contract for evidence. */
329 enum : uint32_t {
330 k_ra8_ccr_div_0_trp = 1UL << 4,
331 };
332 uint32_t ccr = ra8_boot_read32(k_ra8_scb_ccr_addr);
333 ccr |= k_ra8_ccr_div_0_trp;
335 ra8_boot_dsb();
336 ra8_boot_isb();
337}
338
351{
352 enum : uint32_t {
353 k_ra8_aircr_vectkey = 0x05FA0000UL,
354 k_ra8_aircr_prigroup_4 = 0x00000300UL,
355 };
356 ra8_boot_write32(k_ra8_nvic_aircr, k_ra8_aircr_vectkey | k_ra8_aircr_prigroup_4);
357}
358
390/* RBAR attribute bits[4:0] = { SH[4:3], AP[2:1], XN[0] }. AP: 0b01<<1 = RW
391 * any-privilege, 0b11<<1 = RO any-privilege. The memory TYPE is NOT here --
392 * it is the RLAR AttrIndx (see internal_mpu_set_region). */
393enum : uint32_t {
397};
398
399/* RLAR AttrIndx (bits[3:1]) selects which MAIR byte sets the region's memory
400 * type. The old code tried to encode "device" in RBAR (k_ra8_rbar_attr_device_rw
401 * = 0x23), which both spilled bit5 into the base address and left every RLAR at
402 * AttrIndx 0 = MAIR0[0] = Normal cacheable -- so peripheral MMIO was mapped
403 * cacheable. The type must be selected here instead. */
404enum : uint32_t {
409};
410
411/* Region base and limit addresses. RLAR limits are <region-end> minus
412 * the ARMv8-M 32-byte region quantum, OR-ed with the enable bit at write time. */
413enum : uint32_t {
414 k_ra8_mpu_mram_base = 0x02000000UL,
415 k_ra8_mpu_mram_limit = 0x020FFFE0UL,
416 k_ra8_mpu_sram_base = 0x22000000UL,
417 k_ra8_mpu_sram_limit = 0x220FFFE0UL,
418 k_ra8_mpu_shram_base = 0x22100000UL,
419 k_ra8_mpu_shram_limit = 0x2219FFE0UL,
420 k_ra8_mpu_sdram_base = 0x68000000UL,
421 k_ra8_mpu_sdram_limit = 0x6BFFFFE0UL,
422 k_ra8_mpu_peri_base = 0x40000000UL,
423 k_ra8_mpu_peri_limit = 0x47FFFFE0UL,
424};
425
443static void internal_mpu_set_region(uint32_t region,
444 uint32_t base_attr,
445 uint32_t limit_enable,
446 uint32_t attr_idx)
447{
451}
452
464static void internal_mpu_init(void)
465{
466 enum : uint32_t {
467 k_ra8_mpu_ctrl_enable = 1UL << 0,
468 k_ra8_mpu_ctrl_privdefena = 1UL << 2,
469 k_ra8_mair0_default = 0x000444FFUL,
470 };
471
472 /* MAIR0: idx0 = Normal WB/WA, idx1 = Normal non-cacheable, idx2 = Device-nGnRE. */
473 ra8_boot_write32(k_ra8_mpu_mair0_addr, k_ra8_mair0_default);
475
476 /* Code = RO + executable cacheable; RAM = RW/NX cacheable; peripherals =
477 * Device-nGnRE (NOT cacheable -- the AttrIndx selects the type). */
494 /* Shared M85<->M33 SRAM bank: Normal NON-cacheable so cross-core hand-offs
495 * (mailbox at 0x22100000, CPU1 RAM) stay coherent with the M85 D-cache on. */
500
501 /* Enable MPU with PRIVDEFENA so unclassified privileged accesses
502 * still succeed through the default system memory map. */
503 ra8_boot_dsb();
505 ra8_boot_dsb();
506 ra8_boot_isb();
507}
508
509/* =============================================================================
510 * Public entry point
511 * =============================================================================
512 *
513 * Called from `Reset_Handler` before the .data copy and .bss zero.
514 * Must therefore not touch any global variables -- everything here
515 * runs on the stack and writes to CPU / SCB memory only.
516 */
517
518void SystemInit(void)
519{
520 /* Mask global IRQs so the application gets a deterministic init
521 * window. main() must call ``ra8_isr_globals_enable`` once every
522 * driver / handler is wired up before any IRQ source can fire. */
524
528 /* Always-on fault diagnostics: take MemManage/BusFault/UsageFault/
529 * SecureFault to their own decoded handlers and trap divide-by-zero
530 * as a UsageFault (independent of the cache / MPU build flag). */
533#ifdef RA8_BOOT_ENABLE_CACHE_MPU
534 /* T4-06: MPU memory-attribute map FIRST (so the D-cache sees Device-nGnRE
535 * MMIO and the non-cacheable shared SRAM, not Normal cacheable), then the
536 * caches. Each *_enable does its own architectural invalidate before setting
537 * CCR. Region 4 (non-cacheable shared SRAM) keeps M85<->M33 hand-offs
538 * coherent with no software maintenance. */
543#else
544 /* Default OFF: caches + MPU stay disabled -- no behaviour change. */
548 (void)internal_mpu_init;
549#endif
550 (void)ra8_trustzone_init; /* TrustZone has its own gate (RA8_TRUSTZONE_ENABLE). */
552}
static void internal_enable_fpu_lazy_stack(void)
Turn on FPU lazy stacking (FPCCR.LSPEN = 1, ASPEN = 1).
static void internal_enable_branch_predictor(void)
Enable branch-target prediction (CCR.BP on Cortex-M85).
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.
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_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).
static void internal_enable_div0_trap(void)
Make integer divide-by-zero trap as a decoded UsageFault.
static void internal_enable_fault_handlers(void)
Enable the configurable-fault handlers so faults decode by class.
void ra8_trustzone_init(void)
Programme + enable the SAU per the partition.
@ k_ra8_mpu_rlar_attridx_shift
RA8 MPU rlar attridx shift.
@ k_ra8_mpu_attridx_normal_wbwa
MAIR0[0] 0xFF: Normal inner/outer WB/WA.
@ k_ra8_mpu_attridx_noncacheable
MAIR0[1] 0x44: Normal non-cacheable.
@ k_ra8_mpu_attridx_device
MAIR0[2] 0x04: Device-nGnRE (MMIO).
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_shram_base
Shared SRAM2+3: M33 mailbox + CPU1 RAM.
@ k_ra8_mpu_shram_limit
Non-cacheable -> M85<->M33 stays coherent.
@ 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[]
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
static uint32_t ra8_boot_read32(uintptr_t addr)
Volatile 32-bit MMIO read.
static void ra8_boot_write32(uintptr_t addr, uint32_t value)
Volatile 32-bit MMIO write.
static void ra8_boot_isb(void)
Instruction synchronisation barrier (no-op under RA8_OFF_TARGET).
static void ra8_boot_disable_irq(void)
Mask IRQs / set PRIMASK (no-op under RA8_OFF_TARGET).
static void ra8_boot_dsb(void)
Data synchronisation barrier (no-op under RA8_OFF_TARGET).
Boot entry points shared between a vector table and its startup code.
Cortex-M85 L1 cache maintenance, enable/disable, and I-cache invalidate.
void ra8_cache_dcache_invalidate_all(void)
Invalidate the entire D-cache by set/way.
Definition ra8_cache.c:243
@ k_ra8_mpu_ctrl_enable
RA8 MPU control enable.
@ k_ra8_mpu_ctrl_privdefena
RA8 MPU control privdefena.