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

Cortex-M85 L1 cache maintenance, enable/disable, and I-cache invalidate. More...

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

Go to the source code of this file.

Functions

uint32_t ra8_cache_dcache_line_bytes (void)
 Smallest Cortex-M85 D-cache line size, in bytes.
ra8_err_t ra8_cache_dcache_clean_by_addr (const void *addr, uint32_t size)
 Clean (write back) the D-cache lines covering a byte range.
ra8_err_t ra8_cache_dcache_invalidate_by_addr (const void *addr, uint32_t size)
 Invalidate (drop) the D-cache lines covering a byte range.
ra8_err_t ra8_cache_dcache_clean_invalidate_by_addr (const void *addr, uint32_t size)
 Clean and invalidate the D-cache lines covering a byte range.
void ra8_cache_dcache_invalidate_all (void)
 Invalidate the entire D-cache by set/way.
void ra8_cache_icache_invalidate_all (void)
 Invalidate the entire Cortex-M85 L1 instruction cache (ICIALLU).
void ra8_cache_icache_enable (void)
 Invalidate then enable the Cortex-M85 L1 instruction cache (CCR.IC).
void ra8_cache_icache_disable (void)
 Disable the Cortex-M85 L1 instruction cache and invalidate it (CCR.IC).
void ra8_cache_dcache_enable (void)
 Invalidate then enable the Cortex-M85 L1 data cache (CCR.DC).
void ra8_cache_dcache_disable (void)
 Disable the Cortex-M85 L1 data cache, cleaning dirty lines (CCR.DC).
void ra8_cache_enable (void)
 Enable both Cortex-M85 L1 caches (I-cache then D-cache).

Detailed Description

Cortex-M85 L1 cache maintenance, enable/disable, and I-cache invalidate.

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

Provides the cache-maintenance primitives that the dual-core mailbox and every DMA path must call before the Cortex-M85 L1 data cache can be safely enabled:

  • clean – write dirty lines back to memory before a peripheral or the secondary core reads the buffer (use before starting a TX DMA);
  • invalidate – drop stale lines before the CPU reads a buffer that a peripheral or the secondary core wrote (use after an RX DMA completes);
  • clean + invalidate – both, for a bidirectional buffer.

...plus the L1 bring-up primitives the boot path uses (issue #577): the I-cache invalidate (ICIALLU), and the enable/disable pair for each cache (CCR.IC / CCR.DC) with the unified ra8_cache_enable. Each enable runs its architectural invalidate before setting the CCR bit; ra8_cache_dcache_disable clean+invalidates (not just invalidates) so no dirty line is lost as the cache goes cold. These lift the identical ICIALLU + CCR pokes that every system_init.c copy previously hand-rolled at boot.

Each by-address operation acts on the whole cache lines spanning the requested byte range, with the line size discovered at run time from the Cortex-M85 Cache Type Register (CTR.DminLine). These are Arm v8-M architectural registers in the System Control Block (PPB window 0xE000Exxx), NOT RA8D2 peripherals, so they carry Arm-architecture references rather than Hardware-User's-Manual citations.

Warning
Enabling a cache is now a first-class primitive here (ra8_cache_dcache_enable / ra8_cache_icache_enable / ra8_cache_enable), but turning the D-cache on remains a deliberate, strictly ordered step (issue #173 / the T4 chain): do it only after every DMA path and the inter-core mailbox invoke the by-address maintenance primitives above – otherwise a cached write the peer never sees, or a stale line the CPU reads, silently corrupts data. Each enable is safe to call once from a cold cache at boot because it runs the architectural invalidate first.
Note
On a host build (RA8_OFF_TARGET) the SCB window is backed by the fake MMIO map, so the maintenance writes are observable to tests but have no real cache effect; the loop and line-size logic are exercised exactly as on silicon.

Definition in file ra8_cache.h.

Function Documentation

◆ ra8_cache_dcache_clean_by_addr()

ra8_err_t ra8_cache_dcache_clean_by_addr ( const void * addr,
uint32_t size )

Clean (write back) the D-cache lines covering a byte range.

Writes every cache line that overlaps [addr, addr + size) back to main memory via DCCMVAC, bracketed by data barriers. Call this on a buffer the CPU has filled, immediately before handing it to a TX DMA or to the secondary core, so the consumer sees the latest bytes.

Parameters
[in]addrStart of the range. Must not be NULL.
[in]sizeRange length in bytes; 0 is a no-op success.
Returns
Error code.
Return values
k_ra8_okLines cleaned (or size == 0).
k_ra8_err_null_ptraddr was NULL.
Precondition
addr is non-NULL (unless size == 0).
The range lies in cacheable memory (SRAM / SDRAM / OSPI XIP).
Postcondition
Every dirty line overlapping the range has been written to the point of coherency.
No line is invalidated – the data remains resident and valid.
Note
Not interrupt-safe against concurrent maintenance on the same range.
Since
0.1.0

Definition at line 180 of file ra8_cache.c.

References internal_ra8_cache_maintain_range(), and k_ra8_cache_dccmvac.

Referenced by cam_image_clean_outputs(), dtc_coh_run_once(), internal_lcd_clear(), internal_lcd_flush(), internal_run_copy(), ra8_dtc_enable(), ra8_dtc_reconfigure(), and ra8_spi_write_dma().

◆ ra8_cache_dcache_clean_invalidate_by_addr()

ra8_err_t ra8_cache_dcache_clean_invalidate_by_addr ( const void * addr,
uint32_t size )

Clean and invalidate the D-cache lines covering a byte range.

Writes back then drops every cache line overlapping [addr, addr + size) via DCCIMVAC, bracketed by data barriers. Use for a buffer that is both produced and re-read across a DMA or a cross-core handoff.

Parameters
[in]addrStart of the range. Must not be NULL.
[in]sizeRange length in bytes; 0 is a no-op success.
Returns
Error code.
Return values
k_ra8_okLines cleaned and invalidated (or size == 0).
k_ra8_err_null_ptraddr was NULL.
Precondition
addr is non-NULL (unless size == 0).
The range lies in cacheable memory.
Postcondition
Every dirty line is written to memory and then marked invalid.
The next read of the range fetches from memory.
Note
Not interrupt-safe against concurrent maintenance on the same range.
Since
0.1.0

Definition at line 190 of file ra8_cache.c.

References internal_ra8_cache_maintain_range(), and k_ra8_cache_dccimvac.

Referenced by cache_hal_test_cacheable_rw(), cache_mpu_test_cacheable_rw(), and internal_ceu_capture().

◆ ra8_cache_dcache_disable()

void ra8_cache_dcache_disable ( void )

Disable the Cortex-M85 L1 data cache, cleaning dirty lines (CCR.DC).

Clears SCB.CCR bit DC (preserving the other CCR controls) to stop new allocations, then walks the cache geometry and issues DCCISW to clean AND invalidate every set/way – so any dirty line is written back to memory as the cache goes cold. Unlike ra8_cache_dcache_enable, the disable path must not discard dirty data, hence clean+invalidate rather than a bare invalidate.

Returns
None.
Precondition
Runs single-threaded with interrupts masked.
The D-cache may currently hold dirty lines (they are written back).
Postcondition
CCR.DC is clear; data accesses bypass the cache.
Every set/way has been cleaned to memory and invalidated.
Note
Not thread-safe; boot / single-threaded use only.
Since
0.1.0

Definition at line 299 of file ra8_cache.c.

References internal_ra8_cache_reg(), internal_ra8_cache_setway_all(), k_ra8_cache_ccr, k_ra8_cache_ccr_dc_bit, and k_ra8_cache_dccisw.

◆ ra8_cache_dcache_enable()

void ra8_cache_dcache_enable ( void )

Invalidate then enable the Cortex-M85 L1 data cache (CCR.DC).

Runs ra8_cache_dcache_invalidate_all (the set/way invalidate) first so no random power-on line is treated as valid, then read-modify-writes SCB.CCR to set bit DC, preserving the other CCR controls. This encodes the exact set/way-invalidate + CCR.DC sequence the boot internal_enable_dcache helper hand-rolled.

Returns
None.
Precondition
The D-cache is currently DISABLED (cold); calling with dirty lines present would lose them (the invalidate discards, it does not clean).
Every DMA path and the inter-core mailbox already invoke the by-address maintenance primitives (see the module
Warning
).
Postcondition
CCR.DC is set; data accesses are cached.
The set/way invalidate ran first, so no stale line is ever hit.
Note
Not thread-safe; boot / single-threaded use only.
Since
0.1.0

Definition at line 286 of file ra8_cache.c.

References internal_ra8_cache_reg(), k_ra8_cache_ccr, k_ra8_cache_ccr_dc_bit, ra8_cache_dcache_invalidate_all(), ra8_hw_dsb(), and ra8_hw_isb().

Referenced by ra8_cache_enable(), and SystemInit().

◆ ra8_cache_dcache_invalidate_all()

void ra8_cache_dcache_invalidate_all ( void )

Invalidate the entire D-cache by set/way.

Walks the cache geometry from CCSIDR (selected via CSSELR) and invalidates every set and way via DCISW, bracketed by data barriers. This is the bulk invalidate a safe cache-enable sequence runs once at boot before setting CCR.DC, so the cache starts from a known-clean state. It does NOT clean – any dirty lines are discarded, which is correct only when the cache has not yet been enabled.

Returns
None.
Precondition
The D-cache is currently DISABLED (this discards, it does not clean).
Runs single-threaded with interrupts masked (boot context).
Postcondition
Every set/way of the L1 D-cache is invalid.
No architectural register other than CSSELR is left modified.
Note
Not thread-safe; boot / single-threaded use only.
Warning
Calling this with the cache enabled and dirty lines present loses those writes; use ra8_cache_dcache_clean_invalidate_by_addr instead.
Since
0.1.0

Definition at line 243 of file ra8_cache.c.

References internal_ra8_cache_setway_all(), and k_ra8_cache_dcisw.

Referenced by internal_enable_dcache(), and ra8_cache_dcache_enable().

◆ ra8_cache_dcache_invalidate_by_addr()

ra8_err_t ra8_cache_dcache_invalidate_by_addr ( const void * addr,
uint32_t size )

Invalidate (drop) the D-cache lines covering a byte range.

Discards every cache line overlapping [addr, addr + size) via DCIMVAC, bracketed by data barriers, so the next CPU read fetches from memory. Call this on a buffer after an RX DMA (or the secondary core) has written it, before the CPU reads it.

Parameters
[in,out]addrStart of the range. Must not be NULL.
[in]sizeRange length in bytes; 0 is a no-op success.
Returns
Error code.
Return values
k_ra8_okLines invalidated (or size == 0).
k_ra8_err_null_ptraddr was NULL.
Precondition
addr is non-NULL (unless size == 0).
The buffer is cache-line aligned and a whole number of lines, OR the caller accepts that partially-overlapped lines are dropped (any dirty bytes in them are lost – clean first if that matters).
Postcondition
Every line overlapping the range is marked invalid.
The next read of the range misses the cache and fetches from memory.
Note
Not interrupt-safe against concurrent maintenance on the same range.
Since
0.1.0

Definition at line 185 of file ra8_cache.c.

References internal_ra8_cache_maintain_range(), and k_ra8_cache_dcimvac.

Referenced by dtc_coh_run_once(), internal_ceu_capture(), internal_run_copy(), and internal_spi_dma_rx_complete().

◆ ra8_cache_dcache_line_bytes()

uint32_t ra8_cache_dcache_line_bytes ( void )
nodiscard

Smallest Cortex-M85 D-cache line size, in bytes.

Reads CTR.DminLine (the log2 of the line size in words) from the Arm v8-M Cache Type Register and returns the line size in bytes (4 << DminLine). On the RA8D2's Cortex-M85 this is 32 bytes.

Returns
Line size in bytes (a power of two, >= 4).
Return values
32The Cortex-M85 L1 D-cache line size.
Precondition
The Cortex-M85 core is running (CTR is always readable in any mode).
No precondition on cache enable state – CTR reports the geometry regardless of whether the cache is on.
Postcondition
No architectural state is modified (pure read).
The return value is a power-of-two byte count usable as a loop stride.
Note
Thread-safe; reads a read-only architectural register.
Since
0.1.0

Definition at line 97 of file ra8_cache.c.

References internal_ra8_cache_reg(), k_ra8_cache_ctr, k_ra8_cache_ctr_dmin_mask, k_ra8_cache_ctr_dmin_shift, and k_ra8_cache_word_bytes.

Referenced by internal_ra8_cache_maintain_range(), and internal_round_up_to_cache_line().

◆ ra8_cache_enable()

void ra8_cache_enable ( void )

Enable both Cortex-M85 L1 caches (I-cache then D-cache).

Convenience bring-up that calls ra8_cache_icache_enable then ra8_cache_dcache_enable, matching the order every system_init.c boot copy uses. Each half runs its own architectural invalidate before setting its CCR enable bit, so this is the single call a cold-boot path needs to turn the L1 caches on through the HAL.

Returns
None.
Precondition
Both caches are currently DISABLED (cold-boot context).
Runs single-threaded with interrupts masked.
Postcondition
CCR.IC and CCR.DC are both set; instruction and data accesses are cached.
Each cache was invalidated before its enable bit was set.
Note
Not thread-safe; boot / single-threaded use only.
Warning
Do NOT call once the D-cache is already live with dirty lines – the nested set/way invalidate would discard them; this is a cold-boot bring-up call only.
Since
0.1.0

Definition at line 310 of file ra8_cache.c.

References ra8_cache_dcache_enable(), and ra8_cache_icache_enable().

◆ ra8_cache_icache_disable()

void ra8_cache_icache_disable ( void )

Disable the Cortex-M85 L1 instruction cache and invalidate it (CCR.IC).

Clears SCB.CCR bit IC (preserving the other CCR controls) then runs ICIALLU so no stale line survives a later re-enable. The I-cache holds no dirty state, so a plain invalidate (not clean) is correct here.

Returns
None.
Precondition
Runs single-threaded with interrupts masked.
The caller no longer needs cached instruction fetches.
Postcondition
CCR.IC is clear; fetches bypass the I-cache.
The I-cache is invalid, so a later enable starts clean.
Note
Not thread-safe; boot / single-threaded use only.
Since
0.1.0

Definition at line 272 of file ra8_cache.c.

References internal_ra8_cache_reg(), k_ra8_cache_ccr, k_ra8_cache_ccr_ic_bit, k_ra8_cache_iciallu, ra8_hw_dsb(), and ra8_hw_isb().

◆ ra8_cache_icache_enable()

void ra8_cache_icache_enable ( void )

Invalidate then enable the Cortex-M85 L1 instruction cache (CCR.IC).

Runs ra8_cache_icache_invalidate_all so no random power-on line is treated as valid, then read-modify-writes SCB.CCR to set bit IC, preserving the other CCR controls. This encodes the exact ICIALLU + CCR.IC sequence the boot internal_enable_icache helpers hand-rolled.

Returns
None.
Precondition
The I-cache is currently DISABLED (cold), typically at boot.
Runs single-threaded with interrupts masked.
Postcondition
CCR.IC is set; instruction fetches are cached.
The invalidate ran first, so no stale line is ever hit.
Note
Not thread-safe; boot / single-threaded use only.
Since
0.1.0

Definition at line 260 of file ra8_cache.c.

References internal_ra8_cache_reg(), k_ra8_cache_ccr, k_ra8_cache_ccr_ic_bit, ra8_cache_icache_invalidate_all(), ra8_hw_dsb(), and ra8_hw_isb().

Referenced by ra8_cache_enable(), and SystemInit().

◆ ra8_cache_icache_invalidate_all()

void ra8_cache_icache_invalidate_all ( void )

Invalidate the entire Cortex-M85 L1 instruction cache (ICIALLU).

Writes the Arm v8-M ICIALLU register to drop every I-cache line to the point of unification, bracketed by data + instruction barriers so the invalidate completes and the pipeline refetches before execution continues. Run once at boot before enabling the I-cache, or after overwriting instruction memory (e.g. a copy-to-run loader) so the core fetches the new code rather than a stale cached copy.

Returns
None.
Precondition
Runs single-threaded with interrupts masked (boot / self-modifying-code context).
The instruction memory to be fetched next is already in place.
Postcondition
Every L1 I-cache line is invalid; the next fetch misses to memory.
A dsb/isb pair has retired the invalidate before later instructions run.
Note
Not thread-safe; boot / single-threaded use only.
Since
0.1.0

Definition at line 248 of file ra8_cache.c.

References internal_ra8_cache_reg(), k_ra8_cache_iciallu, ra8_hw_dsb(), and ra8_hw_isb().

Referenced by ra8_cache_icache_enable().