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_cgc.h"
56#include "trustzone_init.h"
57
58extern const uint32_t g_ra8_vector_table_start[];
59
60/* =============================================================================
61 * Core / SCB / NVIC register addresses (direct, no CMSIS dep)
62 * =============================================================================
63 */
64
65typedef enum : uintptr_t {
66 k_ra8_scb_vtor_addr = 0xE000ED08UL,
67 k_ra8_scb_ccr_addr = 0xE000ED14UL,
68 k_ra8_scb_shcsr_addr = 0xE000ED24UL,
69 k_ra8_scb_cpacr_addr = 0xE000ED88UL,
70 k_ra8_scb_nsacr_addr = 0xE000ED8CUL,
71 k_ra8_scb_iciallu = 0xE000EF50UL,
72 k_ra8_scb_dciallu = 0xE000EF58UL,
73 k_ra8_scb_csselr = 0xE000ED84UL,
74 k_ra8_scb_ccsidr = 0xE000ED80UL,
75 k_ra8_scb_dcisw = 0xE000EF60UL,
76 k_ra8_fpu_fpccr_addr = 0xE000EF34UL,
77 k_ra8_nvic_aircr = 0xE000ED0CUL,
78 k_ra8_mpu_type_addr = 0xE000ED90UL,
79 k_ra8_mpu_ctrl_addr = 0xE000ED94UL,
80 k_ra8_mpu_rnr_addr = 0xE000ED98UL,
81 k_ra8_mpu_rbar_addr = 0xE000ED9CUL,
82 k_ra8_mpu_rlar_addr = 0xE000EDA0UL,
83 k_ra8_mpu_mair0_addr = 0xE000EDC0UL,
84 k_ra8_mpu_mair1_addr = 0xE000EDC4UL,
86
87extern uint32_t g_ra8_ls_stack_top; /* from vector_table.c / linker. */
88
89/* =============================================================================
90 * Small helpers
91 * =============================================================================
92 */
93
109RA8_INTERNAL static inline uint32_t internal_read32(uintptr_t addr)
110{
111 return *(volatile uint32_t*)addr;
112}
113
129RA8_INTERNAL static inline void internal_write32(uintptr_t addr, uint32_t value)
130{
131 *(volatile uint32_t*)addr = value;
132}
133
148RA8_INTERNAL static inline void internal_dsb(void)
149{
150#ifndef RA8_OFF_TARGET
151 __asm__ volatile("dsb 0xF" ::: "memory");
152#endif
153}
154
168RA8_INTERNAL static inline void internal_isb(void)
169{
170#ifndef RA8_OFF_TARGET
171 __asm__ volatile("isb 0xF" ::: "memory");
172#endif
173}
174
188RA8_INTERNAL static inline void internal_disable_irq(void)
189{
190#ifndef RA8_OFF_TARGET
191 __asm__ volatile("cpsid i" ::: "memory");
192#endif
193}
194
195/* =============================================================================
196 * Core init steps
197 * =============================================================================
198 */
199
214{
215 /* Vector table sits at the start of the .vectors section, which
216 * the linker pins to the start of MRAM (`0x02000000`). The SCB
217 * VTOR register stores the absolute address. */
219}
220
236{
237 enum : uint32_t {
238 k_ra8_cpacr_cp10_cp11_full_access = 0x00F00000UL,
239 };
240 uint32_t cpacr = internal_read32(k_ra8_scb_cpacr_addr);
241 cpacr |= k_ra8_cpacr_cp10_cp11_full_access;
243 internal_dsb();
244 internal_isb();
245}
246
262{
263 enum : uint32_t {
264 k_ra8_fpccr_lspen = 1UL << 30,
265 k_ra8_fpccr_aspen = 1UL << 31,
266 };
267 uint32_t fpccr = internal_read32(k_ra8_fpu_fpccr_addr);
268 fpccr |= k_ra8_fpccr_lspen | k_ra8_fpccr_aspen;
270}
271
284{
285 /* Invalidate, then set CCR.IC. */
286 internal_dsb();
288 internal_dsb();
289 internal_isb();
290
291 enum : uint32_t { k_ra8_ccr_ic = 1UL << 17 };
292 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
293 ccr |= k_ra8_ccr_ic;
295 internal_dsb();
296 internal_isb();
297}
298
316{
317 enum : uint32_t { k_ra8_ccr_dc = 1UL << 16 };
318 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
319 ccr |= k_ra8_ccr_dc;
321 internal_dsb();
322 internal_isb();
323}
324
337{
338 enum : uint32_t { k_ra8_ccr_bp = 1UL << 18 };
339 uint32_t ccr = internal_read32(k_ra8_scb_ccr_addr);
340 ccr |= k_ra8_ccr_bp;
342 internal_dsb();
343 internal_isb();
344}
345
361{
362 enum : uint32_t {
363 k_ra8_aircr_vectkey = 0x05FA0000UL,
364 k_ra8_aircr_prigroup_4 = 0x00000300UL,
365 };
366 internal_write32(k_ra8_nvic_aircr, k_ra8_aircr_vectkey | k_ra8_aircr_prigroup_4);
367}
368
392/* RBAR attribute-byte encodings (bottom 5 bits of RBAR). */
393enum : uint32_t {
398};
399
400/* Region base and limit addresses. RLAR limits are <region-end> minus
401 * the ARMv8-M 32-byte region quantum, OR-ed with the enable bit at write time. */
402enum : uint32_t {
403 k_ra8_mpu_mram_base = 0x02000000UL,
404 k_ra8_mpu_mram_limit = 0x020FFFE0UL,
405 k_ra8_mpu_sram_base = 0x22000000UL,
406 k_ra8_mpu_sram_limit = 0x221FFFE0UL,
407 k_ra8_mpu_sdram_base = 0x68000000UL,
408 k_ra8_mpu_sdram_limit = 0x6BFFFFE0UL,
409 k_ra8_mpu_peri_base = 0x40000000UL,
410 k_ra8_mpu_peri_limit = 0x47FFFFE0UL,
411};
412
427RA8_INTERNAL static void
428internal_mpu_set_region(uint32_t region, uint32_t base_attr, uint32_t limit_enable)
429{
433}
434
447{
448 enum : uint32_t {
449 k_ra8_mpu_ctrl_enable = 1UL << 0,
450 k_ra8_mpu_ctrl_privdefena = 1UL << 2,
451 k_ra8_mair0_default = 0x000404FFUL,
452 };
453
454 /* MAIR0: idx 0 = WB/WA, idx 1 = non-cacheable, idx 2 = device-nGnRE. */
455 internal_write32(k_ra8_mpu_mair0_addr, k_ra8_mair0_default);
457
470
471 /* Enable MPU with PRIVDEFENA so unclassified privileged accesses
472 * still succeed through the default system memory map. */
473 internal_dsb();
475 internal_dsb();
476 internal_isb();
477}
478
500RA8_INTERNAL [[noreturn, gnu::noinline]] static void internal_halt_secure_clock_fault(void)
501{
502 while (1) {
503 __asm__ volatile("wfi");
504 }
505}
506
507/* =============================================================================
508 * Public entry point
509 * =============================================================================
510 *
511 * Called from `Reset_Handler` after the C runtime is live (.data
512 * copied, .bss zeroed). It may therefore read and write globals
513 * freely; the Secure clock + TrustZone bring-up below relies on that.
514 */
515
516void SystemInit(void)
517{
518 /* Mask global IRQs so the application gets a deterministic init
519 * window. main() must call ``ra8_isr_globals_enable`` once every
520 * driver / handler is wired up before any IRQ source can fire. */
522
526 /* Cache enable, MPU init, and TrustZone bring-up are temporarily
527 * disabled -- they HardFault on first reset because the CCSIDR-driven
528 * invalidate-by-set/way loop is not yet implemented and the MPU
529 * regions are unconfigured. Re-enable once those code paths land. */
533 (void)internal_mpu_init;
535
536 /* Bring up the Secure clock tree (XTAL -> PLL1 -> CPUCLK0 = 1 GHz) BEFORE the
537 * SAU + BLXNS below. ra8_trustzone_init() does NOT return on hardware (BLXNS
538 * leaves Secure thread mode), so anything sequenced after it never runs on the
539 * Secure side. The NS-side NSC CGC veneers (ra8_nsc_cgc_pll2_enable etc.) trap
540 * back into this Secure CGC driver, which needs PLL1 already locked -- without
541 * it the first PLL2 enable fails because its PLL1 source is missing. */
542 if (ra8_cgc_init() != k_ra8_ok) {
543 /* NASA Rule 7: a failed Secure clock bring-up must not BLXNS into NS code
544 * on a dead clock tree -- park at a named symbol instead of switching. */
546 }
547
548#ifdef RA8_TRUSTZONE_ENABLE
549 /* Programme the SAU, then BLXNS into the NS image. The NSC veneers depend on
550 * the SAU being live so the cmse_nonsecure_entry traps land on the Secure
551 * side. Does not return on hardware. */
553#else
554 (void)ra8_trustzone_init;
555#endif
556}
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[]
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
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.