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

Generic DMA transfer substrate implementation. More...

#include "ra8_dma.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_dmac.h"
#include "ra8_err.h"
#include "ra8_log.h"
#include "ra8_mstp.h"
#include "ra8_mstp_regs.h"
Include dependency graph for ra8_dma.c:

Go to the source code of this file.

Data Structures

struct  ra8_dma_channel_state_t
 Per-channel dispatch-table entry. More...

Functions

static uint8_t internal_find_free (void)
 Find the first free channel.
static void internal_pack_dmac_cfg (const ra8_dma_request_t *req, ra8_dmac_config_t *out_cfg)
 Copy a high-level ra8_dma_request_t into the lower-level ra8_dmac_config_t the DMAC driver expects.
static ra8_err_t internal_validate_request (const ra8_dma_request_t *req)
 Validate a request descriptor before touching hardware.
ra8_err_t ra8_dma_init (void)
 Bring up the generic DMA substrate.
ra8_err_t ra8_dma_deinit (void)
 Tear down the generic DMA substrate.
ra8_err_t ra8_dma_request (const ra8_dma_request_t *req, uint8_t *out_channel)
 Allocate a channel and arm a DMAC transfer.
ra8_err_t ra8_dma_release (uint8_t channel)
 Release a previously allocated channel.
ra8_err_t ra8_dma_channel_is_busy (uint8_t channel, bool *out_busy)
 Query the allocation state of a channel.
void ra8_dma_dispatch_complete (uint8_t channel)
 Fire the per-channel completion callback.

Variables

static const char * s_tag = "DMA"
static ra8_dma_channel_state_t s_channels [k_ra8_dma_channel_count]
 Channel allocation + dispatch table.
static bool s_initialized = false
 true while the substrate is live (between ra8_dma_init and ra8_dma_deinit).

Detailed Description

Generic DMA transfer substrate implementation.

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

See ra8_dma.h for the API contract. This file owns the channel-allocation table and the completion dispatch table. Per-channel register writes go through ra8_dmac_start / ra8_dmac_stop. Callers that need the DTC's vector-table transfer model use ra8_dtc_* directly.

Definition in file ra8_dma.c.

Function Documentation

◆ internal_find_free()

uint8_t internal_find_free ( void )
static

Find the first free channel.

Linear scan over the static s_channels[] table looking for the first slot whose in_use flag is false. Used by ra8_dma_request() to allocate a channel; tests may also call it to assert table consistency. Loop is bounded by k_ra8_dma_channel_count.

Returns
Channel index on success, k_ra8_dma_channel_none when every channel is allocated.
Return values
0..k_ra8_dma_channel_count-1First free channel index.
k_ra8_dma_channel_noneEvery channel slot is currently in use.
Precondition
s_channels[] has been initialized (ra8_dma_init() called).
Caller holds an implicit lock against concurrent allocation.
Postcondition
No state mutated by the scan itself.
Returned index, if valid, references a free slot.
Note
Not thread-safe; pair with IRQ masking.
Since
0.1.0

Definition at line 113 of file ra8_dma.c.

References k_ra8_dma_channel_count, k_ra8_dma_channel_none, RA8_INTERNAL, and s_channels.

Referenced by ra8_dma_request().

◆ internal_pack_dmac_cfg()

void internal_pack_dmac_cfg ( const ra8_dma_request_t * req,
ra8_dmac_config_t * out_cfg )
static

Copy a high-level ra8_dma_request_t into the lower-level ra8_dmac_config_t the DMAC driver expects.

Translates the user-facing request descriptor (typed addresses, width enum, increment direction) into the register-level config struct consumed by ra8_dmac_start(). No validation – caller has already invoked internal_validate_request().

Parameters
[in]reqSource request descriptor (non-NULL).
[out]out_cfgDestination DMAC config struct (non-NULL).
Precondition
req != NULL and out_cfg != NULL.
internal_validate_request(req) == k_ra8_ok.
Postcondition
*out_cfg populated with values copied from *req.
No state mutated outside *out_cfg.
Note
Not thread-safe; caller must own out_cfg.
Since
0.1.0

Definition at line 144 of file ra8_dma.c.

References ra8_dma_request_t::count, ra8_dmac_config_t::count, ra8_dmac_config_t::dst, ra8_dma_request_t::dst_addr, ra8_dma_request_t::dst_inc, ra8_dmac_config_t::dst_inc, RA8_INTERNAL, ra8_dmac_config_t::src, ra8_dma_request_t::src_addr, ra8_dma_request_t::src_inc, ra8_dmac_config_t::src_inc, ra8_dma_request_t::width, and ra8_dmac_config_t::width.

Referenced by ra8_dma_request().

◆ internal_validate_request()

ra8_err_t internal_validate_request ( const ra8_dma_request_t * req)
static

Validate a request descriptor before touching hardware.

Bounds-checks the byte count and width enum so a malformed request is rejected before a single DMAC register write. Width must be within the k_ra8_dmac_width_* range (HUM Ch 16.2.4 "DMTMD : DMA Transfer Mode Register", p 608).

Parameters
[in]reqRequest descriptor (non-NULL).
Returns
k_ra8_ok on valid, otherwise the specific rejection code.
Return values
k_ra8_okRequest is well-formed.
k_ra8_err_invalid_argcount == 0 or width out of range.
Precondition
req != NULL.
Caller has not yet armed the DMAC channel.
Postcondition
No state mutated.
On success, all fields of *req are within driver range.
Note
Pure function over the input pointer; thread-safe.
Since
0.1.0

Definition at line 178 of file ra8_dma.c.

References ra8_dma_request_t::count, k_ra8_dmac_width_word, k_ra8_err_invalid_arg, k_ra8_ok, RA8_INTERNAL, and ra8_dma_request_t::width.

Referenced by ra8_dma_request().

◆ ra8_dma_channel_is_busy()

ra8_err_t ra8_dma_channel_is_busy ( uint8_t channel,
bool * out_busy )
nodiscard

Query the allocation state of a channel.

Diagnostic accessor used by unit tests to verify the allocator state. Returns true if the channel is currently in use.

Parameters
[in]channelChannel number 0..k_ra8_dma_channel_count - 1.
[out]out_busyOn success, true if allocated.
Returns
ra8_err_t error code.
Return values
k_ra8_okQuery successful.
k_ra8_err_null_ptrout_busy NULL.
k_ra8_err_invalid_argchannel out of range.
Precondition
out_busy is non-NULL.
Postcondition
No hardware state is modified.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 428 of file ra8_dma.c.

References k_ra8_dma_channel_count, k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, s_channels, and s_tag.

◆ ra8_dma_deinit()

ra8_err_t ra8_dma_deinit ( void )
nodiscard

Tear down the generic DMA substrate.

Release the DMA substrate.

Stops every in-use channel via ra8_dmac_stop(), clears the dispatch table, and releases the MSTPA22 reference (HUM Ch 11.2.6, p 443). After this returns ra8_dma_request() rejects with k_ra8_err_not_initialized.

Returns
ra8_err_t error code.
Return values
k_ra8_okAll channels stopped and MSTP released.
k_ra8_err_hw_errorUnderlying ra8_mstp_disable() failed.
Precondition
ra8_dma_init() previously succeeded.
No outstanding interrupt expected from any channel.
Postcondition
All channels report in_use == false.
Driver re-enters uninitialized state.
Note
Not thread-safe; call once during system shutdown.
Since
0.1.0

Definition at line 257 of file ra8_dma.c.

References k_ra8_dma_channel_count, k_ra8_err_hw_error, k_ra8_mstp_dmac0_dtc0, k_ra8_ok, ra8_dmac_stop(), ra8_log_error_val, ra8_mstp_disable(), s_channels, s_initialized, and s_tag.

◆ ra8_dma_dispatch_complete()

void ra8_dma_dispatch_complete ( uint8_t channel)

Fire the per-channel completion callback.

Dispatch a transfer-end completion callback for one channel.

Looks up the stashed callback / context for channel and invokes the callback if non-NULL. Called from the DMAC IRQ trampoline (or from a unit-test driver in off-target mode). Out-of-range channels are silently ignored.

Parameters
[in]channelChannel whose completion just fired.
Precondition
ra8_dma_init() previously succeeded.
Called from ISR context or a test driver.
Postcondition
Registered callback invoked at most once with the stored context.
No state mutated by the dispatch itself.
Note
Thread safety: ISR context only; not re-entrant per channel.
Since
0.1.0

Definition at line 458 of file ra8_dma.c.

References k_ra8_dma_channel_count, and s_channels.

◆ ra8_dma_init()

ra8_err_t ra8_dma_init ( void )
nodiscard

Bring up the generic DMA substrate.

Initialise the DMA substrate.

Enables MSTPA22 (shared with DTC0, HUM Ch 11.2.6 "MSTPCRA : Module Stop Control Register A", p 443) and clears every entry in the channel-allocation / dispatch table. After this returns ra8_dma_request() may allocate channels.

Returns
ra8_err_t error code.
Return values
k_ra8_okChannel table reset and MSTP gate opened.
k_ra8_err_hw_init_failedUnderlying ra8_mstp_enable() failed.
Precondition
ra8_mstp_init() previously succeeded.
Single-threaded init context (or IRQs masked).
Postcondition
All channels report in_use == false.
DMAC0 + DTC0 MSTP reference held by this driver.
Note
Not thread-safe; call once during system init.
Since
0.1.0

Definition at line 215 of file ra8_dma.c.

References k_ra8_dma_channel_count, k_ra8_err_hw_init_failed, k_ra8_mstp_dmac0_dtc0, k_ra8_ok, ra8_log_error_val, ra8_log_info, ra8_mstp_enable(), s_channels, s_initialized, and s_tag.

Referenced by internal_setup_or_halt(), and ra8_nsc_periph_init().

◆ ra8_dma_release()

ra8_err_t ra8_dma_release ( uint8_t channel)
nodiscard

Release a previously allocated channel.

Stop a channel and return it to the free pool.

Calls ra8_dmac_stop() to disable the channel at the hardware level, then clears the dispatch entry. The MSTP reference held by the substrate root is preserved – only ra8_dma_deinit() releases it.

Parameters
[in]channelChannel previously returned by ra8_dma_request().
Returns
ra8_err_t error code.
Return values
k_ra8_okChannel released.
k_ra8_err_invalid_argchannel >= k_ra8_dma_channel_count.
k_ra8_err_invalid_stateChannel was not in use.
k_ra8_err_hw_errorra8_dmac_stop() failed.
Precondition
ra8_dma_init() previously succeeded.
Caller has accepted any pending IRQs may still latch.
Postcondition
Channel slot reports in_use == false.
DMAC channel is disabled at the register level.
Note
Not thread-safe; pair with IRQ masking.
Since
0.1.0

Definition at line 370 of file ra8_dma.c.

References k_ra8_dma_channel_count, k_ra8_err_hw_error, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, ra8_dmac_stop(), ra8_log_error_val, s_channels, and s_tag.

Referenced by internal_run_one().

◆ ra8_dma_request()

ra8_err_t ra8_dma_request ( const ra8_dma_request_t * req,
uint8_t * out_channel )
nodiscard

Allocate a channel and arm a DMAC transfer.

Allocate a DMAC channel, programme it, and start the trigger wiring.

Validates *req, finds a free channel via internal_find_free(), packs a ra8_dmac_config_t and calls ra8_dmac_start(). On success the channel index is written through out_channel and the caller-supplied completion callback is stashed for later dispatch.

Parameters
[in]reqTransfer descriptor (non-NULL).
[out]out_channelAllocated channel index (non-NULL).
Returns
ra8_err_t error code.
Return values
k_ra8_okChannel allocated and DMAC armed.
k_ra8_err_invalid_argreq malformed.
k_ra8_err_not_initializedra8_dma_init() was not called.
k_ra8_err_no_memNo free channel.
k_ra8_err_hw_errorra8_dmac_start() failed.
Precondition
ra8_dma_init() previously succeeded.
req != NULL and out_channel != NULL.
Postcondition
On success *out_channel references an in-use channel.
On failure no channel is allocated and no DMAC register changed.
Note
Not thread-safe; pair with IRQ masking.
Since
0.1.0

Definition at line 308 of file ra8_dma.c.

References ra8_dma_request_t::ctx, internal_find_free(), internal_pack_dmac_cfg(), internal_validate_request(), k_ra8_dma_channel_none, k_ra8_err_hw_error, k_ra8_err_no_mem, k_ra8_err_not_initialized, k_ra8_ok, ra8_dma_request_t::on_complete, RA8_CHECK_NULL_PTR, ra8_dmac_start(), ra8_log_error, ra8_log_error_val, s_channels, s_initialized, and s_tag.

Referenced by ra8_gpt_read_dma(), ra8_gpt_write_dma(), ra8_sci_read_dma(), ra8_sci_write_dma(), ra8_spi_read_dma(), and ra8_spi_write_dma().

Variable Documentation

◆ s_channels

Channel allocation + dispatch table.

Indexed by DMAC channel number. Updated by ra8_dma_request / release and read by ra8_dma_dispatch_complete.

Note
Static so the table is zero-initialized at boot.

Definition at line 59 of file ra8_dma.c.

Referenced by internal_find_free(), ra8_dma_channel_is_busy(), ra8_dma_deinit(), ra8_dma_dispatch_complete(), ra8_dma_init(), ra8_dma_release(), and ra8_dma_request().

◆ s_initialized

bool s_initialized = false
static

true while the substrate is live (between ra8_dma_init and ra8_dma_deinit).

Definition at line 83 of file ra8_dma.c.

◆ s_tag

const char* s_tag = "DMA"
static

Definition at line 31 of file ra8_dma.c.