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

Host-side pass ladder for the OSPI USB self-loop app. More...

#include <stdint.h>
#include <string.h>
#include "ra8_board_ek_ra8d2.h"
#include "ra8_err.h"
#include "ra8_fs.h"
#include "ra8_io_blockdev.h"
#include "ra8_io_blockdev_usbmsc.h"
#include "ra8_time.h"
#include "ra8_usb_hmsc.h"
#include "usb_selftest_ospi_steps.h"
Include dependency graph for usb_selftest_ospi_host.c:

Go to the source code of this file.

Functions

static const char * selftest_fs_type_name (ra8_fs_type_t type)
 Map a detected filesystem type to a printable name.
static ra8_err_t selftest_mount_volume (ra8_fs_mount_t **out_mount)
 Mount the loop device's volume through the USB-MSC backend.
static ra8_err_t selftest_verify_ospi_raw (void)
 Raw multi-block READ(10) of the MRAM data region vs MRAM.
static ra8_err_t selftest_print_verify_verdict (void)
 Print the verify verdict line (bytes + duration + rate).
static ra8_err_t selftest_write_protect_probe (void)
 WRITE(10) into the read-only LUN must be rejected.
static ra8_err_t selftest_host_enumerate (ra8_usb_hmsc_device_t *out_device)
 Bring the host controller up and enumerate the loop device.
ra8_err_t selftest_host_pass (void)
 One full host-side pass: enumerate, mount, browse, verify, WP.

Variables

static volatile uint32_t s_dbg_phase
 Host-ladder phase marker (selftest_phase_t).
static volatile uint32_t s_dbg_verified_bytes
 Bytes content-verified so far this pass.
static volatile uint32_t s_dbg_mismatch_off = (uint32_t)k_selftest_no_mismatch
 First mismatching MRAM offset (k_selftest_no_mismatch = none).
static volatile uint32_t s_dbg_verify_ms
 Milliseconds the 1 MiB verify streamed for.
static volatile uint32_t s_dbg_pass_count
 Completed full passes (sticky success counter).
static ra8_io_blockdev_t s_selftest_usb_dev
 Block device fronting the hosted MSC volume for this ladder.
static ra8_io_blockdev_usbmsc_state_t s_selftest_usb_state
 Caller-owned backend state for s_selftest_usb_dev.

Detailed Description

Host-side pass ladder for the OSPI USB self-loop app.

Tag
[Ring 6 / APP] {World: S}

Host-facing half of the OSPI USB self-loop app, split out of main.c so every translation unit stays under the file-size cap. Runs the polled first-party host stack (ra8_usb_hmsc + ra8_fs) over the self-loop cable: it brings the USBHS host up, enumerates the downstream FS device, mounts the synthesized FAT16 volume, streams the 1 MiB OSPI data region back with raw multi-block READ(10) and checks it against the deterministic pattern, and finally proves the read-only LUN rejects WRITE(10). The pattern computation and the SCI8 console formatters it reuses live in usb_selftest_ospi_format.c; the shared constants and the cross-TU prototypes live in usb_selftest_ospi_steps.h. main.c's host worker drives selftest_host_pass.

Author
Brighton Sikarskie
Date
2026-06-13
Since
0.1.0

Definition in file usb_selftest_ospi_host.c.

Function Documentation

◆ selftest_fs_type_name()

const char * selftest_fs_type_name ( ra8_fs_type_t type)
static

Map a detected filesystem type to a printable name.

Total over the enum; unknown maps to "unknown".

Parameters
[in]typeMount-time detection result.
Returns
Static NUL-terminated name string.
Return values
fat16For k_ra8_fs_type_fat16 (the expected verdict).
Precondition
None – total over the enum.
type came from a populated mount struct.
Postcondition
No state changes.
Returned pointer references static storage.
Note
Pure function.
Since
0.1.0

Definition at line 109 of file usb_selftest_ospi_host.c.

References k_ra8_fs_type_exfat, k_ra8_fs_type_fat12, k_ra8_fs_type_fat16, k_ra8_fs_type_fat32, and k_ra8_fs_type_unknown.

Referenced by selftest_mount_volume().

◆ selftest_host_enumerate()

ra8_err_t selftest_host_enumerate ( ra8_usb_hmsc_device_t * out_device)
staticnodiscard

Bring the host controller up and enumerate the loop device.

Initializes the USBHS host, enumerates the downstream FS device over the cable, and prints its VID/PID. On any failure the host controller is closed so the caller's retry starts clean.

Parameters
[out]out_deviceReceives the enumerated device snapshot.
Returns
First failing step's error, or k_ra8_ok.
Return values
k_ra8_okHost up and device enumerated; identity printed.
Precondition
Device-side class is registered and attached (other thread).
out_device is non-NULL.
Postcondition
On k_ra8_ok the host controller is live and out_device filled.
On failure the host controller has been closed again.
Note
Blocking; runs on the low-priority host thread.
Since
0.1.0

Definition at line 373 of file usb_selftest_ospi_host.c.

References k_ra8_ok, k_ra8_usb_speed_hs, k_selftest_hex_chars_u16, k_selftest_phase_enum, k_selftest_phase_host_init, ra8_usb_hmsc_device_t::product_id, ra8_usb_hmsc_close(), ra8_usb_hmsc_enumerate(), ra8_usb_hmsc_init(), s_dbg_phase, selftest_print(), selftest_print_fail(), selftest_print_hex(), and ra8_usb_hmsc_device_t::vendor_id.

Referenced by selftest_host_pass().

◆ selftest_host_pass()

ra8_err_t selftest_host_pass ( void )
nodiscard

One full host-side pass: enumerate, mount, browse, verify, WP.

Run one full soak pass and print the verdict.

One full host-side pass: enumerate, mount, verify, WP.

Drives the host-side ladder over the self-loop cable: brings the USBHS host up and enumerates the FS device, mounts and parses the FAT16 volume, browses the root directory, raw-verifies the 1 MiB MRAM data region with multi-block READ(10) bursts, then probes the write-protect rejection. Phases are mirrored into the J-Link progress probe for readout. On any failure the host controller is closed so the next retry starts from a clean attach. The host worker thread (in main.c) loops this until it returns k_ra8_ok.

Returns
First failing step's error, or k_ra8_ok.
Return values
k_ra8_okThe pass printed the BROWSE PASS banner.
Precondition
Device-side class is registered and attached (other thread).
The self-loop cable connects J7 to J11.
Postcondition
On success the pass counter advanced and LED2 is on.
On failure the host controller is deinitialized again.
Note
Blocking; runs on the low-priority host thread.
Since
0.1.0

One full host-side pass: enumerate, mount, browse, verify, WP.

Definition at line 411 of file usb_selftest_ospi_host.c.

References k_ra8_board_led2, k_ra8_ok, k_selftest_phase_mount, k_selftest_phase_pass, k_selftest_phase_verify, k_selftest_phase_wp, ra8_board_led_on(), ra8_fs_unmount(), ra8_usb_hmsc_close(), s_dbg_pass_count, s_dbg_phase, selftest_host_enumerate(), selftest_mount_volume(), selftest_print(), selftest_print_verify_verdict(), selftest_verify_ospi_raw(), and selftest_write_protect_probe().

◆ selftest_mount_volume()

ra8_err_t selftest_mount_volume ( ra8_fs_mount_t ** out_mount)
staticnodiscard

Mount the loop device's volume through the USB-MSC backend.

Binds the ra8_io USB-MSC block device over the polled host class, bridges it to an ra8_fs backend, and prints the detected filesystem type (must be fat16 for this device).

Parameters
[out]out_mountReceives the mount handle on success.
Returns
ra8_err_t from the block-device bind, the ra8_fs bridge, or ra8_fs_mount.
Return values
k_ra8_okVolume mounted; the type line was printed.
Precondition
ra8_usb_hmsc_enumerate completed on the loop device.
out_mount is non-NULL.
Postcondition
On k_ra8_ok the mount handle is live and must be unmounted later.
The "mounted fs=" line is queued on success.
Note
Reads the BPB chain over the self-loop cable.
Since
0.1.0

Definition at line 147 of file usb_selftest_ospi_host.c.

References k_ra8_ok, k_selftest_target_lun, ra8_fs_mount(), ra8_io_blockdev_as_fs_backend(), ra8_io_blockdev_usbmsc_init(), s_selftest_usb_dev, s_selftest_usb_state, selftest_fs_type_name(), selftest_print(), and selftest_print_fail().

Referenced by selftest_host_pass().

◆ selftest_print_verify_verdict()

ra8_err_t selftest_print_verify_verdict ( void )
staticnodiscard

Print the verify verdict line (bytes + duration + rate).

"verified 1048576 bytes in N ms (M KiB/s)".

Returns
ra8_err_t propagated from the SCI helpers.
Return values
k_ra8_okThe verdict line is queued.
Precondition
::selftest_verify_mram_file returned k_ra8_ok this pass.
SCI8 init already ran.
Postcondition
One verdict line is in the SCI8 TX FIFO.
No other state changes.
Note
Rate math guards the divide against a zero duration.
Since
0.1.0

Definition at line 261 of file usb_selftest_ospi_host.c.

References k_ra8_ok, k_selftest_bytes_per_kib, k_selftest_ms_per_sec, s_dbg_verified_bytes, s_dbg_verify_ms, selftest_print(), and selftest_print_dec().

Referenced by selftest_host_pass().

◆ selftest_verify_ospi_raw()

ra8_err_t selftest_verify_ospi_raw ( void )
staticnodiscard

Raw multi-block READ(10) of the MRAM data region vs MRAM.

Streams the 1 MiB OSPI data region through the SCSI READ(10) entry point in 8-block (4 KiB) bursts – one CBW per burst, not per sector – and checks every 512-byte sector against the deterministic pattern the device programmed into the flash (selftest_pattern_fill). The host recomputes the expected bytes rather than reading the OSPI itself, so the single xSPI controller has exactly one user (the device class thread) and there is no contention. This is the direct integrity proof: "the bytes the device wrote to OSPI come back intact over USB". The mount step (separate phase) already proved the host can PARSE the FAT16 volume over the loop. ra8_fs is bypassed here because its per-cluster metadata re-reads throttle a 1 MiB sweep.

Data region: FAT16 LBA k_fat_data_lba is cluster 2 = OSPI window sector 0, so LBA (data_lba + b) holds window sector b.

Returns
ra8_err_t verdict.
Return values
k_ra8_okAll 1 MiB matched the pattern.
k_ra8_err_invalid_stateA byte differed from the pattern.
Precondition
ra8_usb_hmsc_enumerate completed on the loop device.
The device programmed the OSPI window at boot.
Postcondition
s_dbg_verified_bytes / s_dbg_verify_ms / s_dbg_mismatch_off reflect the outcome.
No filesystem handle is held (raw SCSI path).
Note
Blocking; 256 four-KiB READ(10) bursts over the self-loop.
Since
0.1.0

Definition at line 209 of file usb_selftest_ospi_host.c.

References k_fat_data_clusters, k_fat_data_lba, k_ra8_err_invalid_state, k_ra8_ok, k_selftest_block_size, k_selftest_burst_blocks, k_selftest_burst_bytes, k_selftest_no_mismatch, k_selftest_target_lun, memcmp(), ra8_time_ms(), ra8_usb_hmsc_read10(), s_dbg_mismatch_off, s_dbg_verified_bytes, s_dbg_verify_ms, selftest_pattern_fill(), and selftest_print_fail().

Referenced by selftest_host_pass().

◆ selftest_write_protect_probe()

ra8_err_t selftest_write_protect_probe ( void )
staticnodiscard

WRITE(10) into the read-only LUN must be rejected.

Issues a 1-block WRITE(10) into the data region. The device LUN is write-protected (MODE SENSE WP bit + media_write returns DATA PROTECT), so the host's write entry point must surface an error rather than k_ra8_ok – the MRAM is never modified. This is the write-protection proof.

It deliberately stops there: terminating a data-out phase against a write-protected device STALLs the bulk-OUT endpoint, and recovering the BOT transport afterwards (Bulk-Only Mass Storage Reset + Clear Feature ENDPOINT_HALT on both bulk pipes) is not yet implemented in the host class. That STALL/ClearFeature recovery path is tracked as GitHub issue #92's robustness sweep; this pass parks on success, so the post-STALL desync does not affect the verdict.

Returns
ra8_err_t verdict.
Return values
k_ra8_okThe write was rejected (protection works).
k_ra8_err_invalid_stateThe write was unexpectedly accepted.
Precondition
ra8_usb_hmsc_enumerate completed on the loop device.
The device LUN reports write-protected.
Postcondition
The device volume is untouched (the write never lands).
One verdict line is queued on the console.
Note
Leaves the bulk-OUT pipe halted (see details); pass parks next.
Since
0.1.0

Definition at line 326 of file usb_selftest_ospi_host.c.

References k_ra8_err_invalid_state, k_ra8_ok, k_selftest_block_size, k_selftest_hex_chars_u32, k_selftest_target_lun, k_selftest_wp_probe_lba, ra8_usb_hmsc_write10(), selftest_print(), selftest_print_fail(), and selftest_print_hex().

Referenced by selftest_host_pass().

Variable Documentation

◆ s_dbg_mismatch_off

volatile uint32_t s_dbg_mismatch_off = (uint32_t)k_selftest_no_mismatch
static

First mismatching MRAM offset (k_selftest_no_mismatch = none).

Definition at line 51 of file usb_selftest_ospi_host.c.

◆ s_dbg_pass_count

volatile uint32_t s_dbg_pass_count
static

Completed full passes (sticky success counter).

Definition at line 55 of file usb_selftest_ospi_host.c.

◆ s_dbg_phase

volatile uint32_t s_dbg_phase
static

Host-ladder phase marker (selftest_phase_t).

Definition at line 47 of file usb_selftest_ospi_host.c.

◆ s_dbg_verified_bytes

volatile uint32_t s_dbg_verified_bytes
static

Bytes content-verified so far this pass.

Definition at line 49 of file usb_selftest_ospi_host.c.

◆ s_dbg_verify_ms

volatile uint32_t s_dbg_verify_ms
static

Milliseconds the 1 MiB verify streamed for.

Definition at line 53 of file usb_selftest_ospi_host.c.

◆ s_selftest_usb_dev

ra8_io_blockdev_t s_selftest_usb_dev
static

Block device fronting the hosted MSC volume for this ladder.

Bound once in selftest_mount_volume by ra8_io_blockdev_usbmsc_init, which wires the ra8_io USB-MSC backend over the polled host-MSC class. File scope because ra8_io_blockdev_as_fs_backend keeps a pointer to this handle for the whole life of the mount.

Note
Single-threaded ladder; no locking.
Warning
Do not rebind while a mount is live.
Since
0.1.0

Definition at line 75 of file usb_selftest_ospi_host.c.

◆ s_selftest_usb_state

ra8_io_blockdev_usbmsc_state_t s_selftest_usb_state
static

Caller-owned backend state for s_selftest_usb_dev.

Records the logical unit the backend addresses. Private to the ra8_io USB-MSC backend and must out-live every call made through the device.

Note
Single-threaded ladder; no locking.
Warning
Treat the contents as private to ra8_io.
Since
0.1.0

Definition at line 89 of file usb_selftest_ospi_host.c.