ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_dual_core.h File Reference

Dual-core (CPU0 / CPU1) lifecycle helper – public API. More...

#include <stdint.h>
#include "ra8_err.h"
Include dependency graph for ra8_dual_core.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  ra8_dual_core_addr_t : uintptr_t { k_ra8_dual_core_ctrl_base_addr = 0x4000F000UL }
 Base address of the CPU control register window used for secondary-core lifecycle management. More...
enum  ra8_dual_core_off_t : uint16_t {
  k_ra8_dual_core_off_cpu1_initvtor = 0x044U ,
  k_ra8_dual_core_off_cpu1_waitcr = 0x054U ,
  k_ra8_dual_core_off_cpu1_actcsr = 0x064U
}
 Offsets within the CPU_CTRL window for the CPU1 lifecycle registers (HUM Ch 2.9.1 p 128-130, section indices 2.9.1.7 / 2.9.1.8 / 2.9.1.9). More...
enum  ra8_dual_core_field_t : uint16_t {
  k_ra8_dual_core_waitcr_cpuwait_mask = (1U << 0) ,
  k_ra8_dual_core_actcsr_actreq_mask = (1U << 0) ,
  k_ra8_dual_core_actcsr_act_mask = (1U << 7) ,
  k_ra8_dual_core_actcsr_key_shift = 8U ,
  k_ra8_dual_core_actcsr_key_value = 0xA5U
}
 Bit positions inside CPU1WAITCR / CPU1ACTCSR. More...
enum  ra8_dual_core_const_t : uint32_t { k_ra8_dual_core_release_poll_max = 1000000U }
 Tunable constants for the bounded poll loops. More...

Functions

ra8_err_t ra8_cpu1_release (void *entry, void *sp)
 Release CPU1 (Cortex-M33) from reset and start it executing.
ra8_err_t ra8_cpu1_halt (void)
 Park CPU1 by asserting CPU1WAITCR.CPUWAIT.
bool ra8_cpu1_is_running (void)
 Return whether CPU1 is currently fetching instructions.

Detailed Description

Dual-core (CPU0 / CPU1) lifecycle helper – public API.

Tag
[Ring 3 / HAL] {World: NS}

The Renesas RA8D2 ships two Arm cores – a Cortex-M85 primary (CPU0) at 1 GHz and a Cortex-M33 secondary (CPU1) at 250 MHz. The secondary core boots held in a power-gated reset/wait state. CPU0 firmware is responsible for installing the CPU1 reset vector address and then issuing an activation request that takes CPU1 out of reset.

Register map (HUM Ch 2.9.1 "CPU control registers" p 128-130 and Ch 2.6.1.1 "Boot CPU Selection" p 117):

  • CPU_CTRL base = 0x4000_F000 (Secure alias).
  • CPU1INITVTOR @ 0x044 – CPU1 initial vector table base; the M33 latches this into VTOR on the next reset-release edge. The first word of that vector table is the initial MSP (Armv8-M reset behaviour) so a separate stack-pointer register is NOT needed.
  • CPU1WAITCR @ 0x054 – bit 0 CPUWAIT: 0 = run on release, 1 = stall after reset release. Reset value = 0.
  • CPU1ACTCSR @ 0x064 – 16-bit register, bit 0 ACTREQ (W, activation request), bit 7 ACT (R, active state). Writes require KEY=0xA5 in the upper byte.

The earlier draft of this driver used Renesas-FSP-style names (LPCSR / VTORC1 / MSPC1 at SYSC base 0x4001_E000); those registers do not exist in the RA8D2 HUM and the hardware silently dropped every write, so CPU1 never came out of reset. The cpu1_pingpong HIL gate caught this when g_cpu1_pingpong_match stayed at zero for the entire 5 s probe window.

Since
0.1.0

Definition in file ra8_dual_core.h.

Enumeration Type Documentation

◆ ra8_dual_core_addr_t

enum ra8_dual_core_addr_t : uintptr_t

Base address of the CPU control register window used for secondary-core lifecycle management.

The HUM lists both a Secure (0x4000_F000) and Non-Secure (0x5000_F000) alias for this window; this driver uses the Secure alias because CPU1 lifecycle is owned by Secure firmware on this project (CPUSAR.CPUSA1 defaults Secure).

Enumerator
k_ra8_dual_core_ctrl_base_addr 

CPU_CTRL Secure base.

Definition at line 62 of file ra8_dual_core.h.

◆ ra8_dual_core_const_t

enum ra8_dual_core_const_t : uint32_t

Tunable constants for the bounded poll loops.

Enumerator
k_ra8_dual_core_release_poll_max 

Bounded poll iterations.

Definition at line 99 of file ra8_dual_core.h.

◆ ra8_dual_core_field_t

enum ra8_dual_core_field_t : uint16_t

Bit positions inside CPU1WAITCR / CPU1ACTCSR.

HUM Ch 2.9.1.8 p 129 – CPU1WAITCR.CPUWAIT @ bit 0. HUM Ch 2.9.1.9 p 129-130 – CPU1ACTCSR.ACTREQ @ bit 0 (W), ACT @ bit 7 (R). Writes to CPU1ACTCSR require KEY=0xA5 in bits 15:8.

Enumerator
k_ra8_dual_core_waitcr_cpuwait_mask 

CPU1WAITCR.CPUWAIT.

k_ra8_dual_core_actcsr_actreq_mask 

CPU1ACTCSR.ACTREQ.

k_ra8_dual_core_actcsr_act_mask 

CPU1ACTCSR.ACT.

k_ra8_dual_core_actcsr_key_shift 

Key byte position.

k_ra8_dual_core_actcsr_key_value 

Required key code.

Definition at line 87 of file ra8_dual_core.h.

◆ ra8_dual_core_off_t

enum ra8_dual_core_off_t : uint16_t

Offsets within the CPU_CTRL window for the CPU1 lifecycle registers (HUM Ch 2.9.1 p 128-130, section indices 2.9.1.7 / 2.9.1.8 / 2.9.1.9).

Enumerator
k_ra8_dual_core_off_cpu1_initvtor 

CPU1INITVTOR (32-bit).

k_ra8_dual_core_off_cpu1_waitcr 

CPU1WAITCR (8-bit).

k_ra8_dual_core_off_cpu1_actcsr 

CPU1ACTCSR (16-bit).

Definition at line 72 of file ra8_dual_core.h.

Function Documentation

◆ ra8_cpu1_halt()

ra8_err_t ra8_cpu1_halt ( void )
nodiscard

Park CPU1 by asserting CPU1WAITCR.CPUWAIT.

RA8D2 does not document a clean deactivation path once CPU1ACTCSR.ACT has gone to 1, so this driver stalls CPU1 by writing CPUWAIT=1 instead. The ACT bit may still read 1 (CPU1 remains powered/clocked) but no instructions retire. ra8_cpu1_is_running() will return false after this call.

Returns
ra8_err_t Error code.
Return values
k_ra8_okCPU1 stalled.
k_ra8_err_not_supportedCaller is not CPU0.
Precondition
Caller is running on CPU0.
CPU1 was previously released via ra8_cpu1_release().
Postcondition
CPU1 is stalled (CPUWAIT=1).
ra8_cpu1_is_running() returns false.
Note
Not thread-safe.
See also
ra8_cpu1_release()
Since
0.1.0

See ra8_dual_core.h for the public contract. The RA8D2 HUM does not document a clean "go back to inactive" transition for the already-activated secondary core, so this driver stalls CPU1 by writing CPUWAIT=1. The chip remains powered/clocked but no instructions retire on the M33. ra8_cpu1_is_running() returns false while CPUWAIT is asserted.

Returns
ra8_err_t Error code.
Return values
k_ra8_okCPU1 stalled.
k_ra8_err_not_supportedCaller is not CPU0.
Precondition
Caller is CPU0.
CPU1 was previously released via ra8_cpu1_release().
Postcondition
On success, CPU1WAITCR.CPUWAIT reads 1.
On success, ra8_cpu1_is_running() returns false.
Note
Not thread-safe; caller must serialise CPU1 lifecycle ops.
See also
ra8_cpu1_release()
Since
0.1.0

Definition at line 561 of file ra8_dual_core.c.

References internal_is_cpu0(), internal_waitcr_write(), k_ra8_dual_core_waitcr_cpuwait_mask, k_ra8_err_not_supported, k_ra8_ok, ra8_log_error, and s_tag.

◆ ra8_cpu1_is_running()

bool ra8_cpu1_is_running ( void )

Return whether CPU1 is currently fetching instructions.

A truth-table of (ACT, CPUWAIT) -> running: (0, x) -> false (not yet activated / power-gated) (1, 0) -> true (out of reset, running) (1, 1) -> false (out of reset, stalled by CPUWAIT)

Returns
bool True if CPU1 is fetching, false otherwise.
Return values
trueCPU1 is fetching instructions.
falseCPU1 is in the stopped or stalled state.
Precondition
None.
None.
Postcondition
No side effects.
Module state unchanged.
Note
Re-entrant.
Since
0.1.0

Combines two reads: CPU1ACTCSR.ACT tells us the core has been activated (out of power-gating), and CPU1WAITCR.CPUWAIT tells us whether the application has subsequently stalled it. CPU1 is "running" only when ACT=1 and CPUWAIT=0.

Returns
bool True if CPU1 is fetching, false otherwise.
Return values
trueCPU1 active and not stalled.
falseCPU1 inactive, or active but CPUWAIT=1.
Precondition
CPU control window is powered.
Caller is CPU0.
Postcondition
No registers are modified.
Two registers are sampled once each and the boolean result returned.
Note
Re-entrant (read-only volatile access).
See also
ra8_cpu1_release()
ra8_cpu1_halt()
Since
0.1.0

Definition at line 596 of file ra8_dual_core.c.

References internal_actcsr_read(), internal_waitcr_read(), k_ra8_dual_core_actcsr_act_mask, and k_ra8_dual_core_waitcr_cpuwait_mask.

◆ ra8_cpu1_release()

ra8_err_t ra8_cpu1_release ( void * entry,
void * sp )
nodiscard

Release CPU1 (Cortex-M33) from reset and start it executing.

Writes the vector-table base into CPU1INITVTOR, clears CPU1WAITCR.CPUWAIT (so CPU1 starts immediately rather than stalling), then writes (KEY << 8 | ACTREQ) into CPU1ACTCSR and bounded-polls CPU1ACTCSR.ACT for the active transition. The Cortex-M33 fetches its initial MSP from the first word of the vector table at entry (Armv8-M reset behaviour), so sp is validated for alignment but does not drive a separate register write – the application is responsible for placing the stack-top value at entry[0].

Parameters
[in]entryCPU1 reset vector base (128-byte aligned). The first word at this address must be the initial MSP.
[in]spCPU1 initial main stack pointer (8-byte aligned). Validated only; the M33 reads SP from entry[0].
Returns
ra8_err_t Error code.
Return values
k_ra8_okCore released and confirmed active.
k_ra8_err_null_ptrentry or sp was NULL.
k_ra8_err_invalid_argentry or sp mis-aligned.
k_ra8_err_not_supportedCaller is not CPU0.
k_ra8_err_timeoutACTCSR.ACT did not assert within the bounded poll budget.
Precondition
Caller is running on CPU0 (Cortex-M85).
The vector table at entry contains a valid Reset_Handler at offset +4 and a valid initial MSP at offset 0.
Postcondition
On success, CPU1 is fetching from entry and ACT == 1.
On success, ra8_cpu1_is_running() returns true.
Note
Not thread-safe.
See also
ra8_cpu1_halt()
Since
0.1.0

See ra8_dual_core.h for the full public contract. This implementation validates entry and sp (non-NULL, alignment), confirms the caller is CPU0, programs CPU1INITVTOR, clears CPU1WAITCR.CPUWAIT so CPU1 runs immediately on activation, then issues a key-protected ACTREQ via CPU1ACTCSR and bounded-polls ACTCSR.ACT for the active transition. The Cortex-M33 reads its initial SP from the first word of the vector table at entry (Armv8-M reset behaviour), so the sp argument is validated for alignment only – ensuring the caller has actually populated entry[0] with the intended stack top is the application's responsibility.

Parameters
[in]entryCPU1 reset vector base, 128-byte aligned.
[in]spCPU1 initial main stack pointer, 8-byte aligned.
Returns
ra8_err_t Error code.
Return values
k_ra8_okCPU1 released and observed active.
k_ra8_err_null_ptrentry or sp was NULL.
k_ra8_err_invalid_argAlignment check failed.
k_ra8_err_not_supportedCaller is not CPU0.
k_ra8_err_timeoutACTCSR.ACT did not assert within bound.
Precondition
Caller is CPU0 (the M85 primary).
CPU control window is powered (it is at boot on this MCU).
Postcondition
On success, CPU1 is fetching from entry with MSP loaded from entry[0].
On error, no further CPU_CTRL registers are touched after the initial INITVTOR/WAITCR pair (which are harmless until ACTREQ fires).
Note
Not thread-safe; caller must serialise CPU1 lifecycle ops.
See also
ra8_cpu1_halt()
ra8_cpu1_is_running()
Since
0.1.0

Definition at line 494 of file ra8_dual_core.c.

References internal_actcsr_write(), internal_initvtor_write(), internal_is_cpu0(), internal_wait_act_set(), internal_waitcr_write(), k_ra8_dual_core_actcsr_actreq_mask, k_ra8_dual_core_actcsr_key_shift, k_ra8_dual_core_actcsr_key_value, k_ra8_dual_core_align_sp, k_ra8_dual_core_align_vtor, k_ra8_err_invalid_arg, k_ra8_err_not_supported, k_ra8_err_null_ptr, ra8_log_error, and s_tag.

Referenced by main().