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

SD/MMC Host Interface driver implementation. More...

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

Go to the source code of this file.

Enumerations

enum  ra8_sdhi_init_const_t : uint32_t {
  k_ra8_sdhi_soft_rst_assert = 0x00000000U ,
  k_ra8_sdhi_soft_rst_release = 0x00000001U ,
  k_ra8_sdhi_clk_ctrl_default = 0x00000020U ,
  k_ra8_sdhi_clk_ctrl_clken_mask = 0x00000100U ,
  k_ra8_sdhi_clk_ctrl_clkctrlen_mask = 0x00000200U ,
  k_ra8_sdhi_clk_ctrl_setting_mask = 0x000000FFU ,
  k_ra8_sdhi_info1_rspend_mask = 0x00000001U
}
 SDHI register-bring-up constants mirrored from FSP r_sdhi.c. More...
enum  ra8_sdhi_timing_t : uint32_t { k_ra8_sdhi_cmd_spin = 2000000U }
 Bounded spin budget for ra8_sdhi_send_command response wait. More...
enum  ra8_sdhi_fifo_timing_t : uint32_t { k_ra8_sdhi_fifo_spin = 1000000U }
 Bounded spin budget for the per-word BRE / BWE poll. More...
enum  ra8_sdhi_byte_split_t : uint32_t {
  k_ra8_sdhi_byte_mask = 0xFFU ,
  k_ra8_sdhi_shift_b1 = 8U ,
  k_ra8_sdhi_shift_b2 = 16U ,
  k_ra8_sdhi_shift_b3 = 24U
}
 Byte / shift constants for the 32-bit FIFO word splitter. More...

Functions

ra8_err_t ra8_sdhi_init (uint8_t instance)
 Initialise an SDHI instance.
ra8_err_t ra8_sdhi_deinit (uint8_t instance)
 Tear down an SDHI instance.
ra8_err_t ra8_sdhi_send_command (uint8_t instance, uint32_t cmd, uint32_t arg, uint32_t *out_rsp)
 Issue a single SD command and read the 4-word response.
ra8_err_t ra8_sdhi_set_clock (uint8_t instance, uint32_t divider)
 Set the SD bus clock divider (SD_CLK_CTRL).
ra8_err_t ra8_sdhi_set_bus_width (uint8_t instance, ra8_sdhi_bus_width_t width)
 Program the host-side SD data-bus width (SD_OPTION.WIDTH / WIDTH8).
ra8_err_t ra8_sdhi_set_bus_width_4bit (uint8_t instance, uint16_t rca)
 Negotiate a 4-bit data bus with the card via CMD55 + ACMD6.
ra8_err_t ra8_sdhi_set_bus_width_8bit (uint8_t instance)
 Negotiate an 8-bit data bus with an eMMC device via CMD6 SWITCH.
ra8_err_t ra8_sdhi_get_status (uint8_t instance, uint32_t *out_mask)
 Read the SD_INFO1 status register.
ra8_err_t ra8_sdhi_clear_status (uint8_t instance, uint32_t mask)
 Clear SD_INFO1 status bits via write-0-to-clear.
ra8_err_t ra8_sdhi_attach_handler (ra8_sdhi_event_fn_t fn, void *ctx)
 Attach an SDHI event callback (shared across instances).
void ra8_sdhi_dispatch (uint8_t instance)
 Dispatch an SDHI event – snapshot status + fire callback.
ra8_err_t ra8_sdhi_enter_stop (uint8_t instance)
 Put an SDHI instance into MSTP-gated stop.
ra8_err_t ra8_sdhi_exit_stop (uint8_t instance)
 Exit MSTP-gated stop.
static ra8_err_t internal_sdhi_send (volatile r_sdhi_regs_t *reg, uint32_t cmd, uint32_t arg)
 Issue a data-transfer command and wait for RSPEND.
static void internal_sdhi_setup_xfer (volatile r_sdhi_regs_t *reg, uint32_t block_count)
 Common data-phase setup shared by read_block / write_block.
static ra8_err_t internal_sdhi_drain (volatile r_sdhi_regs_t *reg, uint8_t *buf, uint32_t words)
 Drain words 32-bit FIFO words from SD_BUF0 into buf.
static ra8_err_t internal_sdhi_fill (volatile r_sdhi_regs_t *reg, const uint8_t *buf, uint32_t words)
 Push words 32-bit FIFO words from buf into SD_BUF0.
static ra8_err_t internal_sdhi_finish_xfer (volatile r_sdhi_regs_t *reg, uint32_t block_count)
 Tear down the data phase: optional CMD12 + flag cleanup.
ra8_err_t ra8_sdhi_read_block (uint8_t instance, uint32_t lba, uint8_t *buf, uint32_t block_count)
 Read one or more 512-byte SD blocks via the SD_BUF0 FIFO.
ra8_err_t ra8_sdhi_write_block (uint8_t instance, uint32_t lba, const uint8_t *buf, uint32_t block_count)
 Write one or more 512-byte SD blocks via the SD_BUF0 FIFO.
ra8_err_t ra8_sdhi_attach_dma (uint8_t instance, uint8_t enable)
 Enable or disable DMAC-driven SDHI transfers.

Variables

static const char * s_tag = "SDHI"
static const ra8_mstp_t s_sdhi_mstp_table [k_ra8_sdhi_instance_count]
 Per-instance MSTP id lookup.
static ra8_sdhi_event_fn_t s_sdhi_fn
static void * s_sdhi_ctx

Detailed Description

SD/MMC Host Interface driver implementation.

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

Driver for the RA8D2 SDHI block. Covers lifecycle + status + IRQ + power-transition surface plus the command primitive set: ra8_sdhi_send_command (load SD_ARG + SD_CMD, poll SD_INFO1.RSPEND, copy SD_RSP*) and ra8_sdhi_set_clock for runtime bus-rate change. Bus-width control is ra8_sdhi_set_bus_width (host-side SD_OPTION WIDTH / WIDTH8) plus ra8_sdhi_set_bus_width_4bit (the CMD55 + ACMD6 card-side negotiation for SD) and ra8_sdhi_set_bus_width_8bit (the CMD6 SWITCH negotiation for eMMC). The default stays at the conservative 1-bit mode; SDR/DDR speed-class tuning still belongs to the consumer.

The bring-up sequence in ra8_sdhi_init mirrors FSP r_sdhi.c:

  1. clear MSTP gate (R_BSP_MODULE_START)
  2. clear stale SD_INFO1
  3. SOFT_RST = 0; SOFT_RST = 1 (assert / release reset)
  4. SD_CLK_CTRL = 0x20 (8x divisor, auto-control off)
  5. SDIO_MODE / SD_DMAEN / SDIF_MODE / EXT_SWAP -> 0
  6. SD_OPTION = 0xC0E0 (1-bit bus WIDTH=1, default timeouts)
  7. SD_INFO1_MASK / SD_INFO2_MASK -> 0 (caller-supplied IRQs land via ra8_sdhi_attach_handler)

Per HUM Ch 47.2.16 the 1-bit encoding is WIDTH=1 / WIDTH8=0 (0xC0E0); the literal 0x40E0 used by earlier scaffold revisions is actually the 4-bit encoding (WIDTH=0 / WIDTH8=0) and was a latent mislabel – see k_ra8_sdhi_option_bus_1bit.

Every register access carries a HUM Ch 47 "SD/MMC Host Interface (SDHI)" citation (HUM pages 3122-3179, Chapter 47 covers the full SDHI block).

Definition in file ra8_sdhi.c.

Enumeration Type Documentation

◆ ra8_sdhi_byte_split_t

enum ra8_sdhi_byte_split_t : uint32_t

Byte / shift constants for the 32-bit FIFO word splitter.

SD_BUF0 is a 32-bit register; the polled drain reassembles each word into four little-endian bytes in the destination buffer. These constants name the per-byte mask and shift amounts so the loop body avoids inline magic numbers.

Enumerator
k_ra8_sdhi_byte_mask 

low-byte select mask

k_ra8_sdhi_shift_b1 

bits 15..8 -> byte 1

k_ra8_sdhi_shift_b2 

bits 23..16 -> byte 2

k_ra8_sdhi_shift_b3 

bits 31..24 -> byte 3

Definition at line 420 of file ra8_sdhi.c.

◆ ra8_sdhi_fifo_timing_t

enum ra8_sdhi_fifo_timing_t : uint32_t

Bounded spin budget for the per-word BRE / BWE poll.

One iteration of the FIFO-drain loop polls SD_INFO2.BRE (or BWE) before each 4-byte access. On real hardware the flag asserts within microseconds; the budget is sized so the loop tolerates a 1ms scheduler glitch (roughly 1 GHz / 1 us = 1M spins) before returning k_ra8_err_hw_timeout.

Enumerator
k_ra8_sdhi_fifo_spin 

RA8 SDHI FIFO spin.

Definition at line 407 of file ra8_sdhi.c.

◆ ra8_sdhi_init_const_t

enum ra8_sdhi_init_const_t : uint32_t

SDHI register-bring-up constants mirrored from FSP r_sdhi.c.

These values match SDHI_PRV_SD_CLK_CTRL_DEFAULT and the soft-reset toggle used in r_sdhi_hw_cfg(). CLKSEL = 0x20 selects PCLKB / 64 – the slowest divider available, suitable for the 400 kHz identification phase. The SD_OPTION default (1-bit bus, TOP=0xE max timeout, CTOP=0) is built from the named field selectors in ra8_sdhi_option_bits_t (k_ra8_sdhi_option_bus_1bit) rather than a bare literal.

Enumerator
k_ra8_sdhi_soft_rst_assert 

drive RST low

k_ra8_sdhi_soft_rst_release 

release RST

k_ra8_sdhi_clk_ctrl_default 

CLKSEL=64, CLKEN/CLKCTRLEN=0.

k_ra8_sdhi_clk_ctrl_clken_mask 

SD_CLK_CTRL.CLKEN bit-8.

k_ra8_sdhi_clk_ctrl_clkctrlen_mask 

SD_CLK_CTRL.CLKCTRLEN bit-9.

k_ra8_sdhi_clk_ctrl_setting_mask 

CLKSEL[7:0].

k_ra8_sdhi_info1_rspend_mask 

SD_INFO1.RSPEND bit-0.

Definition at line 82 of file ra8_sdhi.c.

◆ ra8_sdhi_timing_t

enum ra8_sdhi_timing_t : uint32_t

Bounded spin budget for ra8_sdhi_send_command response wait.

2M spins on a 1 GHz CPU is ~2 ms of wall clock – a sane SDHI command-response timeout on real silicon. Host tests never race this budget: they assert RSPEND synchronously from the ra8_fake_mmio poll-hook, which runs inline on each iteration of this loop, so the flag is observed on the very next poll regardless of host load.

Enumerator
k_ra8_sdhi_cmd_spin 

RA8 SDHI cmd spin.

Definition at line 102 of file ra8_sdhi.c.

Function Documentation

◆ internal_sdhi_drain()

ra8_err_t internal_sdhi_drain ( volatile r_sdhi_regs_t * reg,
uint8_t * buf,
uint32_t words )
static

Drain words 32-bit FIFO words from SD_BUF0 into buf.

Polls SD_INFO2.BRE before each 4-byte read, returning k_ra8_err_hw_timeout if the BRE flag never asserts inside the k_ra8_sdhi_fifo_spin budget. The split into a helper keeps ra8_sdhi_read_block under the NASA Rule 4 (60 statements) limit.

Parameters
[in]regSDHI register window pointer.
[out]bufDestination byte buffer, at least words * 4 bytes.
[in]wordsNumber of 32-bit FIFO words to drain.
Returns
ra8_err_t error code.
Return values
k_ra8_okAll words words were read into buf.
k_ra8_err_hw_timeoutSD_INFO2.BRE never asserted within k_ra8_sdhi_fifo_spin polls.
Precondition
reg and buf are non-NULL.
A read data phase is already armed (see internal_sdhi_setup_xfer).
Postcondition
On success buf[0 .. words * 4 - 1] holds the FIFO payload, little-endian per word.
On timeout buf holds only the words drained before the stall.
Note
Not thread-safe; the polled SDHI API assumes one caller.
Since
0.1.0

Definition at line 551 of file ra8_sdhi.c.

References k_ra8_err_hw_timeout, k_ra8_ok, k_ra8_sdhi_byte_mask, k_ra8_sdhi_fifo_spin, k_ra8_sdhi_fifo_word_bytes, k_ra8_sdhi_info2_bre_mask, k_ra8_sdhi_shift_b1, k_ra8_sdhi_shift_b2, k_ra8_sdhi_shift_b3, RA8_INTERNAL, r_sdhi_regs_t::SD_BUF0, and r_sdhi_regs_t::SD_INFO2.

Referenced by ra8_sdhi_read_block().

◆ internal_sdhi_fill()

ra8_err_t internal_sdhi_fill ( volatile r_sdhi_regs_t * reg,
const uint8_t * buf,
uint32_t words )
static

Push words 32-bit FIFO words from buf into SD_BUF0.

Polls SD_INFO2.BWE before each 4-byte write, returning k_ra8_err_hw_timeout if the BWE flag never asserts inside the k_ra8_sdhi_fifo_spin budget. Mirror image of internal_sdhi_drain, also factored out to keep ra8_sdhi_write_block under the NASA Rule 4 limit.

Parameters
[in]regSDHI register window pointer.
[in]bufSource byte buffer, at least words * 4 bytes.
[in]wordsNumber of 32-bit FIFO words to push.
Returns
ra8_err_t error code.
Return values
k_ra8_okAll words words were written to SD_BUF0.
k_ra8_err_hw_timeoutSD_INFO2.BWE never asserted within k_ra8_sdhi_fifo_spin polls.
Precondition
reg and buf are non-NULL.
A write data phase is already armed (see internal_sdhi_setup_xfer).
Postcondition
On success the controller has accepted words * 4 bytes.
buf is not modified.
Note
Not thread-safe; the polled SDHI API assumes one caller.
Since
0.1.0

Definition at line 609 of file ra8_sdhi.c.

References k_ra8_err_hw_timeout, k_ra8_ok, k_ra8_sdhi_fifo_spin, k_ra8_sdhi_fifo_word_bytes, k_ra8_sdhi_info2_bwe_mask, k_ra8_sdhi_shift_b1, k_ra8_sdhi_shift_b2, k_ra8_sdhi_shift_b3, RA8_INTERNAL, r_sdhi_regs_t::SD_BUF0, and r_sdhi_regs_t::SD_INFO2.

Referenced by ra8_sdhi_write_block().

◆ internal_sdhi_finish_xfer()

ra8_err_t internal_sdhi_finish_xfer ( volatile r_sdhi_regs_t * reg,
uint32_t block_count )
static

Tear down the data phase: optional CMD12 + flag cleanup.

Issues CMD12 STOP_TRANSMISSION when block_count > 1 to close the open-ended multi-block transfer the way FSP does at r_sdhi.c, then zeroes SD_INFO1 / SD_INFO2 so the next caller sees a clean slate. Factored out so the public read/write helpers stay under the NASA Rule 4 statement limit.

Parameters
[in]regSDHI register window pointer.
[in]block_countBlock count of the transfer being torn down.
Returns
ra8_err_t error code.
Return values
k_ra8_okData phase closed and flags cleared.
k_ra8_err_hw_timeoutCMD12 STOP_TRANSMISSION never saw RSPEND.
Precondition
reg points at a mapped SDHI register window.
The data phase this call closes has already drained or filled.
Postcondition
SD_INFO1 and SD_INFO2 are zeroed.
CMD12 has been issued when block_count > 1.
Note
Not thread-safe; the polled SDHI API assumes one caller.
Since
0.1.0

Definition at line 664 of file ra8_sdhi.c.

References internal_sdhi_send(), k_ra8_ok, k_ra8_sdhi_cmd_stop_transmission, RA8_RETURN_ON_ERROR, s_tag, r_sdhi_regs_t::SD_INFO1, and r_sdhi_regs_t::SD_INFO2.

Referenced by ra8_sdhi_read_block(), and ra8_sdhi_write_block().

◆ internal_sdhi_send()

ra8_err_t internal_sdhi_send ( volatile r_sdhi_regs_t * reg,
uint32_t cmd,
uint32_t arg )
static

Issue a data-transfer command and wait for RSPEND.

Loads SD_ARG with arg, writes cmd (bare command index, 0..63) to SD_CMD, then polls SD_INFO1.RSPEND with the existing k_ra8_sdhi_cmd_spin budget. The hardware infers the data-phase direction from the command index for CMD17/18/24/25, so the caller does not need to pre-encode response-type or data-direction bits. Mirrors the FSP r_sdhi_command_send_no_wait() prologue at r_sdhi.c minus the IRQ-mask bookkeeping that the polled API does not need.

Parameters
[in]regSDHI register window pointer.
[in]cmdBare SD command index (e.g. k_ra8_sdhi_cmd_read_single_block).
[in]arg32-bit command argument.
Returns
k_ra8_ok on RSPEND, k_ra8_err_hw_timeout otherwise.
Return values
k_ra8_okRSPEND asserted; the flag has been cleared.
k_ra8_err_hw_timeoutRSPEND never asserted within k_ra8_sdhi_cmd_spin polls.
Precondition
reg points at a mapped SDHI register window.
The card is out of the busy state from any prior command.
Postcondition
SD_ARG and SD_CMD hold arg and cmd.
On success SD_INFO1.RSPEND is cleared, so the next command observes a fresh flag.
Note
Not thread-safe; the polled SDHI API assumes one caller.
Since
0.1.0

Definition at line 460 of file ra8_sdhi.c.

References k_ra8_err_hw_timeout, k_ra8_ok, k_ra8_sdhi_cmd_spin, k_ra8_sdhi_info1_rspend_mask, RA8_INTERNAL, r_sdhi_regs_t::SD_ARG, r_sdhi_regs_t::SD_CMD, and r_sdhi_regs_t::SD_INFO1.

Referenced by internal_sdhi_finish_xfer(), ra8_sdhi_read_block(), and ra8_sdhi_write_block().

◆ internal_sdhi_setup_xfer()

void internal_sdhi_setup_xfer ( volatile r_sdhi_regs_t * reg,
uint32_t block_count )
static

Common data-phase setup shared by read_block / write_block.

Mirrors FSP r_sdhi_read_write_common (r_sdhi.c). For multi-block transfers, SD_STOP.SEC must be set so the IP stops the data phase after SD_SECCNT blocks; for single-block transfers SD_STOP must be cleared. SD_SIZE is always 512 bytes for SD card sector access.

Parameters
[in]regSDHI register window pointer.
[in]block_countNumber of 512-byte blocks in this transfer.
Precondition
reg points at a mapped SDHI register window.
block_count is at least 1.
Postcondition
SD_STOP.SEC reflects single- vs multi-block, and SD_SECCNT holds block_count for the multi-block case.
SD_SIZE is k_ra8_sdhi_block_bytes.
Note
Not thread-safe; the polled SDHI API assumes one caller.
Since
0.1.0

Definition at line 507 of file ra8_sdhi.c.

References k_ra8_sdhi_block_bytes, k_ra8_sdhi_stop_seccnt_en, r_sdhi_regs_t::SD_SECCNT, r_sdhi_regs_t::SD_SIZE, and r_sdhi_regs_t::SD_STOP.

Referenced by ra8_sdhi_read_block(), and ra8_sdhi_write_block().

◆ ra8_sdhi_attach_dma()

ra8_err_t ra8_sdhi_attach_dma ( uint8_t instance,
uint8_t enable )
nodiscard

Enable or disable DMAC-driven SDHI transfers.

Toggles SD_DMAEN.DMAEN and the SD_INFO2_MASK BREM/BWEM bits in lock-step the way FSP r_sdhi_transfer_read / r_sdhi_transfer_write do. With DMA enabled the polled BRE / BWE wait in the read/write helpers above must be replaced by an external transfer primitive that targets SD_BUF0; this function is the toggle point.

Parameters
[in]instanceSDHI instance.
[in]enableNon-zero to enable DMA, 0 to fall back to PIO.
Return values
k_ra8_okSuccess.
k_ra8_err_null_ptrinstance invalid.
Precondition
ra8_sdhi_init has been called for instance.
Postcondition
SD_DMAEN reflects enable.
Note
The DMAC channel itself must be wired up by the caller via ra8_dmac before any transfer is started.
Since
0.1.0

Definition at line 726 of file ra8_sdhi.c.

References k_ra8_ok, k_ra8_sdhi_dmaen_set, k_ra8_sdhi_info2_brem_bwem, RA8_CHECK_NULL_PTR, ra8_sdhi(), s_tag, r_sdhi_regs_t::SD_DMAEN, and r_sdhi_regs_t::SD_INFO2_MASK.

◆ ra8_sdhi_attach_handler()

ra8_err_t ra8_sdhi_attach_handler ( ra8_sdhi_event_fn_t fn,
void * ctx )
nodiscard

Attach an SDHI event callback (shared across instances).

Since
0.1.0

Definition at line 357 of file ra8_sdhi.c.

References k_ra8_ok, s_sdhi_ctx, and s_sdhi_fn.

◆ ra8_sdhi_clear_status()

ra8_err_t ra8_sdhi_clear_status ( uint8_t instance,
uint32_t mask )
nodiscard

Clear SD_INFO1 status bits via write-0-to-clear.

Since
0.1.0

Definition at line 345 of file ra8_sdhi.c.

References k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_sdhi(), s_tag, and r_sdhi_regs_t::SD_INFO1.

◆ ra8_sdhi_deinit()

◆ ra8_sdhi_dispatch()

void ra8_sdhi_dispatch ( uint8_t instance)

Dispatch an SDHI event – snapshot status + fire callback.

Called from the SDHI access / DMA-end / SDIO ISR (HUM Ch 50 "SD/MMC Host Interface (SDHI)", p 2655) to snapshot SD_INFO1 / SD_INFO2 and invoke the registered handler. Spurious IRQs and out-of-range instance values are silently ignored.

Parameters
[in]instanceSDHI instance index (0 or 1).
Precondition
Called from ISR context or a host-test driver.
instance < 2.
Postcondition
Stored callback (if any) has been invoked exactly once.
Status latch is left for the caller to clear via ra8_sdhi_clear_status.
Note
Not thread-safe; pair with NVIC masking.
Since
0.1.0

Definition at line 365 of file ra8_sdhi.c.

References ra8_sdhi(), s_sdhi_ctx, s_sdhi_fn, and r_sdhi_regs_t::SD_INFO1.

◆ ra8_sdhi_enter_stop()

ra8_err_t ra8_sdhi_enter_stop ( uint8_t instance)
nodiscard

Put an SDHI instance into MSTP-gated stop.

Since
0.1.0

Definition at line 381 of file ra8_sdhi.c.

References k_ra8_err_invalid_arg, k_ra8_sdhi_instance_count, ra8_mstp_disable(), and s_sdhi_mstp_table.

◆ ra8_sdhi_exit_stop()

ra8_err_t ra8_sdhi_exit_stop ( uint8_t instance)
nodiscard

Exit MSTP-gated stop.

Since
0.1.0

Definition at line 389 of file ra8_sdhi.c.

References k_ra8_err_invalid_arg, k_ra8_sdhi_instance_count, ra8_mstp_enable(), and s_sdhi_mstp_table.

◆ ra8_sdhi_get_status()

ra8_err_t ra8_sdhi_get_status ( uint8_t instance,
uint32_t * out_mask )
nodiscard

Read the SD_INFO1 status register.

Since
0.1.0

Definition at line 335 of file ra8_sdhi.c.

References k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_sdhi(), s_tag, and r_sdhi_regs_t::SD_INFO1.

◆ ra8_sdhi_init()

◆ ra8_sdhi_read_block()

ra8_err_t ra8_sdhi_read_block ( uint8_t instance,
uint32_t lba,
uint8_t * buf,
uint32_t block_count )
nodiscard

Read one or more 512-byte SD blocks via the SD_BUF0 FIFO.

Polled (PIO-style) block-read primitive. Mirrors FSP R_SDHI_Read -> r_sdhi_read_write_common (file r_sdhi.c, lines 450..490 and 1383..1405) without the DMA/DTC machinery: the driver loads SD_SECCNT / SD_SIZE, kicks the READ_SINGLE_BLOCK (CMD17) or READ_MULTIPLE_BLOCK (CMD18) command, waits for SD_INFO1.RSPEND, then drains 512 bytes per block from SD_BUF0 in 4-byte words while polling SD_INFO2.BRE.

Algorithm:

  1. Validate buf non-NULL and block_count > 0
  2. Write SD_STOP = SECCNT_ENABLE (multi-block only)
  3. Write SD_SECCNT = block_count
  4. Write SD_SIZE = 512 (block size)
  5. Write SD_ARG = lba (sector address)
  6. Write SD_CMD = CMD17 (single) or CMD18 (multi)
  7. Poll SD_INFO1.RSPEND for command-response complete
  8. For each of block_count * 128 words: poll SD_INFO2.BRE, copy SD_BUF0 -> buf
  9. For multi-block: issue CMD12 STOP_TRANSMISSION
  10. Clear SD_INFO1 / SD_INFO2 flags
Parameters
[in]instanceSDHI instance (0 or 1).
[in]lbaLogical block address (sector number).
[out]bufDestination buffer; must hold at least block_count * 512 bytes.
[in]block_countNumber of 512-byte blocks to read; must be > 0.
Return values
k_ra8_okSuccess.
k_ra8_err_null_ptrbuf was NULL or instance invalid.
k_ra8_err_invalid_argblock_count was 0.
k_ra8_err_hw_timeoutRSPEND or BRE poll exceeded the spin budget.
Precondition
Card has been initialized through CMD0..ACMD41 + CMD2/3/7 by the consumer.
ra8_sdhi_init has been called for instance.
Postcondition
On success buf[0..block_count*512] holds card data.
SD_INFO1.RSPEND and SD_INFO2 BRE bits are cleared.
Note
Blocking, polled implementation; not safe to call from an ISR.
Since
0.1.0

Definition at line 677 of file ra8_sdhi.c.

References internal_sdhi_drain(), internal_sdhi_finish_xfer(), internal_sdhi_send(), internal_sdhi_setup_xfer(), k_ra8_err_invalid_arg, k_ra8_sdhi_cmd_read_multi_block, k_ra8_sdhi_cmd_read_single_block, k_ra8_sdhi_words_per_block, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, ra8_sdhi(), and s_tag.

Referenced by ra8_sdcard_read_blocks().

◆ ra8_sdhi_send_command()

ra8_err_t ra8_sdhi_send_command ( uint8_t instance,
uint32_t cmd,
uint32_t arg,
uint32_t * out_rsp )
nodiscard

Issue a single SD command and read the 4-word response.

polling primitive. Loads SD_ARG with arg, writes cmd to SD_CMD, polls SD_INFO1.RSPEND for completion, and copies SD_RSP10/32/54/76 into out_rsp[0..3]. The caller encodes the SD command index + response type in cmd.

Parameters
[in]instanceSDHI instance.
[in]cmdPre-encoded SD_CMD register value.
[in]arg32-bit command argument (zero-extended).
[out]out_rsp4-word response buffer; may be NULL if the command type returns no response.
Since
0.1.0

Definition at line 184 of file ra8_sdhi.c.

References k_ra8_err_hw_timeout, k_ra8_ok, k_ra8_sdhi_cmd_spin, k_ra8_sdhi_info1_rspend_mask, RA8_CHECK_NULL_PTR, ra8_sdhi(), s_tag, r_sdhi_regs_t::SD_ARG, r_sdhi_regs_t::SD_CMD, r_sdhi_regs_t::SD_INFO1, r_sdhi_regs_t::SD_RSP10, r_sdhi_regs_t::SD_RSP32, r_sdhi_regs_t::SD_RSP54, and r_sdhi_regs_t::SD_RSP76.

Referenced by internal_run_acmd41(), internal_sdcard_identify(), internal_sdcard_publish_and_select(), internal_sdcard_publish_rca(), ra8_sdhi_set_bus_width_4bit(), and ra8_sdhi_set_bus_width_8bit().

◆ ra8_sdhi_set_bus_width()

ra8_err_t ra8_sdhi_set_bus_width ( uint8_t instance,
ra8_sdhi_bus_width_t width )
nodiscard

Program the host-side SD data-bus width (SD_OPTION.WIDTH / WIDTH8).

Low-level, host-only setter: it flips the SD_OPTION.WIDTH (bit 15) and WIDTH8 (bit 13) bits per the HUM Ch 47.2.16 truth table while preserving the TOP / CTOP / TOUTMASK timeout fields with a read-modify-write. It does NOT touch the card – the card's own bus width must already match (negotiate it with ra8_sdhi_set_bus_width_4bit first), otherwise transfers corrupt.

Parameters
[in]instanceSDHI instance (0 or 1).
[in]widthDesired width: k_ra8_sdhi_bus_width_1bit, k_ra8_sdhi_bus_width_4bit, or k_ra8_sdhi_bus_width_8bit.
Returns
ra8_err_t error code.
Return values
k_ra8_okSD_OPTION updated to the requested width.
k_ra8_err_null_ptrinstance out of range.
k_ra8_err_invalid_argwidth not one of the three valid widths.
Precondition
ra8_sdhi_init has been called for instance.
The card has been moved to width on its side (or is in 1-bit).
Postcondition
On success SD_OPTION.WIDTH / WIDTH8 reflect width.
Timeout fields (TOP / CTOP / TOUTMASK) are unchanged.
Note
Not thread-safe; serialize with the rest of the SDHI command path.
Warning
Widening the host before the card corrupts every transfer.
See also
ra8_sdhi_set_bus_width_4bit() Negotiate the card side via ACMD6.
Since
0.1.0

Definition at line 239 of file ra8_sdhi.c.

References k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_sdhi_bus_width_1bit, k_ra8_sdhi_bus_width_4bit, k_ra8_sdhi_bus_width_8bit, k_ra8_sdhi_option_width8_bit, k_ra8_sdhi_option_width_bit, k_ra8_sdhi_option_width_mask, RA8_CHECK_NULL_PTR, ra8_sdhi(), s_tag, and r_sdhi_regs_t::SD_OPTION.

Referenced by ra8_sdhi_set_bus_width_4bit(), and ra8_sdhi_set_bus_width_8bit().

◆ ra8_sdhi_set_bus_width_4bit()

ra8_err_t ra8_sdhi_set_bus_width_4bit ( uint8_t instance,
uint16_t rca )
nodiscard

Negotiate a 4-bit data bus with the card via CMD55 + ACMD6.

Runs the SD application-command handshake that switches an SD card from its power-on 1-bit bus to 4-bit, then widens the host side to match. The sequence is:

  1. CMD55 APP_CMD (arg = rca << 16) – prefix the next command as an application command. The R1 response must echo APP_CMD.
  2. ACMD6 SET_BUS_WIDTH (arg = 0b10) – request 4-bit on the card. The R1 response must carry no error/violation bits.
  3. On a clean acknowledgement, call ra8_sdhi_set_bus_width with k_ra8_sdhi_bus_width_4bit so the host SD_OPTION follows.

If the card declines (missing APP_CMD echo or any R1 error bit) the host is left in 1-bit mode and k_ra8_err_not_supported is returned – the conservative default is preserved.

Parameters
[in]instanceSDHI instance (0 or 1).
[in]rcaCard relative address published by CMD3.
Returns
ra8_err_t error code.
Return values
k_ra8_okCard and host both switched to 4-bit.
k_ra8_err_null_ptrinstance out of range.
k_ra8_err_hw_timeoutCMD55 or ACMD6 RSPEND never asserted.
k_ra8_err_not_supportedCard declined ACMD6; host stays 1-bit.
Precondition
Card is in TRAN state (CMD7 selected) with a known rca.
ra8_sdhi_init has been called for instance.
Postcondition
On success the card and host are both 4-bit.
On failure the host bus width is unchanged (1-bit).
Note
Blocking, polled; not safe to call from an ISR.
See also
ra8_sdhi_set_bus_width() Host-only width setter this drives.
Since
0.1.0

Definition at line 269 of file ra8_sdhi.c.

References k_ra8_err_not_supported, k_ra8_sdhi_acmd6_arg_4bit, k_ra8_sdhi_bus_width_4bit, k_ra8_sdhi_cmd_app_cmd, k_ra8_sdhi_cmd_set_bus_width, k_ra8_sdhi_r1_app_cmd_mask, k_ra8_sdhi_r1_error_mask, k_ra8_sdhi_rca_arg_shift, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, ra8_sdhi(), ra8_sdhi_send_command(), ra8_sdhi_set_bus_width(), and s_tag.

Referenced by internal_sdcard_negotiate_width().

◆ ra8_sdhi_set_bus_width_8bit()

ra8_err_t ra8_sdhi_set_bus_width_8bit ( uint8_t instance)
nodiscard

Negotiate an 8-bit data bus with an eMMC device via CMD6 SWITCH.

The 8-bit data bus is an eMMC-only capability (SD cards top out at the 4-bit ACMD6 path). Unlike ACMD6 this uses the native JEDEC CMD6 SWITCH command – no CMD55 application prefix – to write the EXT_CSD BUS_WIDTH byte (index 183) with value 2 (8-bit SDR). The sequence is:

  1. CMD6 SWITCH (arg = k_ra8_sdhi_cmd6_arg_8bit) – request the EXT_CSD BUS_WIDTH write. The R1b response must carry no error or status-violation bits (k_ra8_sdhi_r1_error_mask).
  2. On a clean acknowledgement, call ra8_sdhi_set_bus_width with k_ra8_sdhi_bus_width_8bit so the host SD_OPTION follows.

If the device declines (any R1 error bit) the host is left at its current width and k_ra8_err_not_supported is returned – an SD card, which cannot do 8-bit, lands here and stays narrow.

Parameters
[in]instanceSDHI instance (0 or 1).
Returns
ra8_err_t error code.
Return values
k_ra8_okDevice and host both switched to 8-bit.
k_ra8_err_null_ptrinstance out of range.
k_ra8_err_hw_timeoutCMD6 RSPEND never asserted.
k_ra8_err_not_supportedDevice declined CMD6; host width unchanged.
Precondition
The device is an eMMC in TRAN state (CMD7 selected).
ra8_sdhi_init has been called for instance.
Postcondition
On success the device and host are both 8-bit.
On failure the host bus width is unchanged.
Note
Blocking, polled; not safe to call from an ISR.
See also
ra8_sdhi_set_bus_width_4bit() The SD ACMD6 4-bit counterpart.
ra8_sdhi_set_bus_width() Host-only width setter this drives.
Since
0.1.0

Definition at line 307 of file ra8_sdhi.c.

References k_ra8_err_not_supported, k_ra8_sdhi_bus_width_8bit, k_ra8_sdhi_cmd6_arg_8bit, k_ra8_sdhi_cmd_emmc_switch, k_ra8_sdhi_r1_error_mask, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, ra8_sdhi(), ra8_sdhi_send_command(), ra8_sdhi_set_bus_width(), and s_tag.

◆ ra8_sdhi_set_clock()

ra8_err_t ra8_sdhi_set_clock ( uint8_t instance,
uint32_t divider )
nodiscard

Set the SD bus clock divider (SD_CLK_CTRL).

Since
0.1.0

Definition at line 223 of file ra8_sdhi.c.

References k_ra8_ok, k_ra8_sdhi_clk_ctrl_clkctrlen_mask, k_ra8_sdhi_clk_ctrl_clken_mask, k_ra8_sdhi_clk_ctrl_setting_mask, RA8_CHECK_NULL_PTR, ra8_sdhi(), s_tag, and r_sdhi_regs_t::SD_CLK_CTRL.

Referenced by ra8_sdcard_init().

◆ ra8_sdhi_write_block()

ra8_err_t ra8_sdhi_write_block ( uint8_t instance,
uint32_t lba,
const uint8_t * buf,
uint32_t block_count )
nodiscard

Write one or more 512-byte SD blocks via the SD_BUF0 FIFO.

Polled (PIO-style) block-write primitive. Mirrors FSP R_SDHI_Write -> r_sdhi_read_write_common (file r_sdhi.c, lines 509..554 and 1383..1405) without the DMA/DTC machinery: the driver loads SD_SECCNT / SD_SIZE, kicks the WRITE_SINGLE_BLOCK (CMD24) or WRITE_MULTIPLE_BLOCK (CMD25) command, waits for SD_INFO1.RSPEND, then pushes 512 bytes per block into SD_BUF0 in 4-byte words while polling SD_INFO2.BWE.

Parameters
[in]instanceSDHI instance (0 or 1).
[in]lbaLogical block address (sector number).
[in]bufSource buffer; must hold at least block_count * 512 bytes.
[in]block_countNumber of 512-byte blocks to write; must be > 0.
Return values
k_ra8_okSuccess.
k_ra8_err_null_ptrbuf was NULL or instance invalid.
k_ra8_err_invalid_argblock_count was 0.
k_ra8_err_hw_timeoutRSPEND or BWE poll exceeded the spin budget.
Precondition
Card has been initialized through CMD0..ACMD41 + CMD2/3/7 by the consumer.
Card is not write-protected (caller responsibility).
Postcondition
On success the requested block range has been pushed into the SDHI FIFO.
For multi-block writes a CMD12 STOP_TRANSMISSION has been issued.
Note
Blocking, polled implementation; not safe to call from an ISR.
Since
0.1.0

Definition at line 702 of file ra8_sdhi.c.

References internal_sdhi_fill(), internal_sdhi_finish_xfer(), internal_sdhi_send(), internal_sdhi_setup_xfer(), k_ra8_err_invalid_arg, k_ra8_sdhi_cmd_write_multi_block, k_ra8_sdhi_cmd_write_single_block, k_ra8_sdhi_words_per_block, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, ra8_sdhi(), and s_tag.

Referenced by ra8_sdcard_write_blocks().

Variable Documentation

◆ s_sdhi_ctx

void* s_sdhi_ctx
static

Definition at line 68 of file ra8_sdhi.c.

Referenced by ra8_sdhi_attach_handler(), and ra8_sdhi_dispatch().

◆ s_sdhi_fn

ra8_sdhi_event_fn_t s_sdhi_fn
static

Definition at line 67 of file ra8_sdhi.c.

Referenced by ra8_sdhi_attach_handler(), and ra8_sdhi_dispatch().

◆ s_sdhi_mstp_table

const ra8_mstp_t s_sdhi_mstp_table[k_ra8_sdhi_instance_count]
static
Initial value:
= {
}
@ k_ra8_mstp_sdhi1
MSTPC11 SDHI1.
@ k_ra8_mstp_sdhi0
MSTPC12 SDHI0.

Per-instance MSTP id lookup.

Definition at line 62 of file ra8_sdhi.c.

Referenced by ra8_sdhi_deinit(), ra8_sdhi_enter_stop(), ra8_sdhi_exit_stop(), and ra8_sdhi_init().

◆ s_tag

const char* s_tag = "SDHI"
static

Definition at line 56 of file ra8_sdhi.c.