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

USBX device-controller-driver bridge to ra8_usb – device-state (DVST) path. More...

#include <stdint.h>
#include <string.h>
#include "ra8_check.h"
#include "ra8_elc_regs.h"
#include "ra8_isr.h"
#include "ra8_log.h"
#include "ra8_usb_regs.h"
#include "tx_api.h"
#include "ux_api.h"
#include "ux_dcd_ra8_usb.h"
#include "ux_dcd_ra8_usb_internal.h"
#include "ux_device_stack.h"
#include "ux_system.h"
#include "ux_utility.h"
Include dependency graph for ux_dcd_ra8_usb_dvst.c:

Go to the source code of this file.

Macros

#define UX_SOURCE_CODE

Enumerations

enum  ra8_usb_dcd_sentinel_t : uint16_t { k_ra8_usb_u16_unset = 0xFFFFU }
 "Not yet captured" sentinel for 16-bit register snapshots. More...
enum  ra8_usb_dcd_rhst_hist_t : uint8_t { k_ra8_usb_dcd_rhst_hist_n = 16U }
 Sizing for the DVSTCTR0.RHST history ring. More...
enum  ra8_usb_dcd_rhst_t : uint8_t {
  k_ra8_usb_rhst_fs = 2U ,
  k_ra8_usb_rhst_hs = 3U
}
 DVSTCTR0.RHST[2:0] settled link-speed encodings. More...

Functions

static unsigned long internal_dvst_map_dvsq_to_ux_state (uint16_t dvsq)
 Map a DVSQ-bits-4..6 value to the USBX device-state enum.
static void internal_dvst_record_history (uint16_t dvsq)
 Record one DVST event into the JLink-readable causal history.
static bool internal_dvst_policy_apply (UX_SLAVE_DEVICE *device, uint16_t dvsq, unsigned long new_state)
 DVSQ mirror policy: may new_state be written into USBX?
static void internal_handle_dvst (ra8_usb_speed_t speed, uint16_t intsts0)
 Handle the DVST (device-state-changed) interrupt branch.
static void internal_dvst_track_speed (uint8_t rhst)
 Mirror the negotiated link speed from DVSTCTR0.RHST into USBX.
void priv_irq_dvst_prelude (ra8_usb_speed_t speed, uint16_t intsts0)
 Capture DVSTCTR0 / RHST history, mirror speed, dispatch DVST.

Variables

volatile uint32_t g_dvst_irq_count = 0U
 Counter of INTSTS0.DVST (device-state-transition) events.
volatile uint16_t g_dvstctr0_at_first_dvst = (uint16_t)k_ra8_usb_u16_unset
 Snapshot of DVSTCTR0 (RHST field) on first DVST event.
volatile uint8_t g_rhst_history [(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}
 Per-DVST-event capture of DVSTCTR0.RHST[2:0].
volatile uint32_t g_rhst_history_count = 0U
 Total DVST events seen; modulo k_ra8_usb_dcd_rhst_hist_n is the next write slot.
volatile uint16_t g_dvstctr0_history [(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}
 Per-dispatch-tick capture of the full DVSTCTR0 register.
volatile uint32_t g_dvstctr0_history_count = 0U
 Total dispatch ticks observed; modulo k_ra8_usb_dcd_rhst_hist_n is the next write slot in g_dvstctr0_history.
volatile uint16_t g_intsts1_history [(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}
 Per-dispatch-tick capture of the full INTSTS1 register.
volatile uint8_t g_dvst_state_history [(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}
 Per-DVST-event capture of the decoded DVSQ[2:0] field.
volatile uint32_t g_dvst_state_history_count = 0U
 Total DVST events recorded into g_dvst_state_history.

Detailed Description

USBX device-controller-driver bridge to ra8_usb – device-state (DVST) path.

Tag
[Ring 5 / PORT] {World: S}

Device-state-change handling: DVSQ decode, the USBX device-state mirror policy, the negotiated-speed framework re-aim, and the DVST history ring.

Split out of ux_dcd_ra8_usb.c to keep each translation unit under the maintainability line cap; the cross-translation-unit contract lives in ux_dcd_ra8_usb_internal.h.

Since
0.1.0

Definition in file ux_dcd_ra8_usb_dvst.c.

Macro Definition Documentation

◆ UX_SOURCE_CODE

#define UX_SOURCE_CODE

Definition at line 22 of file ux_dcd_ra8_usb_dvst.c.

Enumeration Type Documentation

◆ ra8_usb_dcd_rhst_hist_t

enum ra8_usb_dcd_rhst_hist_t : uint8_t

Sizing for the DVSTCTR0.RHST history ring.

Enumerator
k_ra8_usb_dcd_rhst_hist_n 

Slots in g_rhst_history.

Definition at line 79 of file ux_dcd_ra8_usb_dvst.c.

◆ ra8_usb_dcd_rhst_t

enum ra8_usb_dcd_rhst_t : uint8_t

DVSTCTR0.RHST[2:0] settled link-speed encodings.

HUM Ch 36.2.5 / Ch 37 DVSTCTR0 p 1971: the controller writes this after the reset/chirp handshake. Only the two settled, addressable speeds matter to the speed mirror; LS (1), in-reset (4) and undefined (0) are transient and leave the mirror untouched.

Enumerator
k_ra8_usb_rhst_fs 

Full speed settled.

k_ra8_usb_rhst_hs 

High speed settled.

Definition at line 198 of file ux_dcd_ra8_usb_dvst.c.

◆ ra8_usb_dcd_sentinel_t

enum ra8_usb_dcd_sentinel_t : uint16_t

"Not yet captured" sentinel for 16-bit register snapshots.

Enumerator
k_ra8_usb_u16_unset 

Snapshot has not been latched yet.

Definition at line 57 of file ux_dcd_ra8_usb_dvst.c.

Function Documentation

◆ internal_dvst_map_dvsq_to_ux_state()

unsigned long internal_dvst_map_dvsq_to_ux_state ( uint16_t dvsq)
static

Map a DVSQ-bits-4..6 value to the USBX device-state enum.

DVSQ bit 6 set => Suspended-from-X variants. Non-suspend Powered (0x00) is treated as ATTACHED for the chapter-9 gate.

Parameters
[in]dvsqDVSQ bits extracted from INTSTS0 (mask 0x70 plus suspend bit).
Returns
The USBX device state to mirror.
Return values
UX_DEVICE_SUSPENDEDSuspend variant observed.
UX_DEVICE_ATTACHEDDefault or Powered.
UX_DEVICE_ADDRESSEDDVSQ=010 Address state.
UX_DEVICE_CONFIGUREDDVSQ=011 Configured state.
Precondition
Caller masked dvsq to the DVSQ field.
Bridge is past ux_dcd_ra8_usb_initialize.
Postcondition
No state mutated.
Pure function.
Note
Pure; safe in IRQ context.
Since
0.1.0

Definition at line 226 of file ux_dcd_ra8_usb_dvst.c.

References k_ra8_dvsq_address, k_ra8_dvsq_configured, k_ra8_dvsq_default, k_ra8_dvsq_powered, k_ra8_dvsq_suspend, k_ra8_intsts0_mask_dvsq, and RA8_INTERNAL.

Referenced by internal_handle_dvst().

◆ internal_dvst_policy_apply()

bool internal_dvst_policy_apply ( UX_SLAVE_DEVICE * device,
uint16_t dvsq,
unsigned long new_state )
static

DVSQ mirror policy: may new_state be written into USBX?

The chapter-9 stack owns the ADDRESSED/CONFIGURED transitions (it sets them while processing SET_ADDRESS / SET_CONFIGURATION) and the mirror must never demote that state asynchronously: USBX class threads (storage) gate on CONFIGURED and suspend themselves permanently when they wake to anything else. Policy: suspends are not propagated (traffic pauses, gates keep); upgrades apply directly; a disconnect + apply happens ONLY on a genuine Default-state entry (true bus reset). A generic "any downgrade is a reset" rule does not work because the hardware DVSQ LAGS the stack during configuration – it sits in Address state until SET_CONFIGURATION's status stage completes, and ISR INTSTS0 snapshots can be staler still – so it tears the just-built configuration down microseconds after activation (observed against macOS at HS as a sub-millisecond configure/deactivate loop with the storage thread never scheduled). The Default-entry disconnect is required: macOS's MSC driver resets the device at start-of-probe, and without the teardown the stack treats the re-issued SET_CONFIGURATION as a same-value no-op (no interface mount, no class re-activation) and the storage thread parks forever.

Parameters
[in,out]deviceUSBX device instance (state read; on Default entry the configuration is torn down).
[in]dvsqMasked DVSQ field from the INTSTS0 snapshot.
[in]new_statedvsq mapped to a UX_DEVICE_* state.
Returns
Whether the caller may write new_state into the stack.
Return values
trueUpgrade, or Default-state entry (post-disconnect).
falseSuspend or a stale/lagging downgrade; do not touch.
Precondition
device is non-NULL (caller checked _ux_system_slave).
new_state is the internal_dvst_map_dvsq_to_ux_state mapping of dvsq (the pair must describe the same event).
Postcondition
On Default-state entry the stack configuration has been torn down via _ux_device_stack_disconnect (no-op if none).
device->ux_slave_device_state itself is NOT written here; that is the caller's job iff the return value is true.
Note
ISR-callback context; must not block.
Since
0.1.0

Definition at line 323 of file ux_dcd_ra8_usb_dvst.c.

References k_ra8_dvsq_default.

Referenced by internal_handle_dvst().

◆ internal_dvst_record_history()

void internal_dvst_record_history ( uint16_t dvsq)
static

Record one DVST event into the JLink-readable causal history.

One byte per event: high nibble = the raw DVSQ field (shifted), low nibble = ux_slave_device_state at IRQ entry (0xF when USBX is not bound yet). Reading the ring alongside the SETUP trace reconstructs who demoted/upgraded the chapter-9 state.

Parameters
[in]dvsqMasked INTSTS0.DVSQ field for this event.
Precondition
Called from the DVST IRQ path only (single writer).
g_dvst_state_history_count monotonicity is maintained.
Postcondition
One ring slot holds the packed event; count incremented.
No other state changes.
Note
Diagnostic only; never read by production code.
Since
0.1.0

Definition at line 262 of file ux_dcd_ra8_usb_dvst.c.

References g_dvst_state_history, g_dvst_state_history_count, k_dcd_trace_kind_dvst, k_dcd_trace_nib_shift, k_dcd_trace_nibble, k_ra8_int0_dvsq_shift, k_ra8_usb_dcd_rhst_hist_n, priv_trace_event(), and RA8_INTERNAL.

Referenced by internal_handle_dvst().

◆ internal_dvst_track_speed()

void internal_dvst_track_speed ( uint8_t rhst)
static

Mirror the negotiated link speed from DVSTCTR0.RHST into USBX.

The HS controller does not know its link speed until the host's reset/chirp handshake settles: connected to an HS host it runs at high speed, to an FS host it falls back to full speed. USBX serves descriptors from the CURRENT framework pointer (ux_system_slave_device_framework), which ux_dcd_ra8_usb_init seeds from the HS slot for the HS controller. If the link settles at FS, that pointer must be re-aimed at the full-speed framework (64-byte bulk MPS), otherwise the host reads a 512-byte-MPS bulk descriptor on a full-speed link and the bulk pipes never carry a CBW (observed in the chip-to-chip self-loop: an FS host drives the HS device, device sticks at ADDRESSED, storage class thread never runs media_read). This mirrors both ux_system_slave_speed and the current framework to the settled RHST. Only settled FS/HS values act; transient RHST (LS / in-reset / undefined) leaves both alone.

Parameters
[in]rhstMasked DVSTCTR0.RHST[2:0] from the DVST snapshot.
Returns
Nothing.
Note
Speed + current framework reflect a settled FS/HS link.
Precondition
_ux_system_slave is bound (init has run).
rhst is the 3-bit RHST field (already masked).
Postcondition
ux_system_slave_speed and ..._device_framework match the settled link speed, or are unchanged for a transient RHST value.
No register or pipe state is touched; USBX bookkeeping only.
Note
ISR-callback context; a few field writes, never blocks.
Since
0.1.0

Definition at line 430 of file ux_dcd_ra8_usb_dvst.c.

References k_ra8_usb_rhst_fs, k_ra8_usb_rhst_hs, and RA8_INTERNAL.

Referenced by priv_irq_dvst_prelude().

◆ internal_handle_dvst()

void internal_handle_dvst ( ra8_usb_speed_t speed,
uint16_t intsts0 )
static

Handle the DVST (device-state-changed) interrupt branch.

Extracts the DVSQ field from intsts0, records it in the ring-buffer history for JLink readout, mirrors the decoded state into the USBX device-state field via internal_dvst_map_dvsq_to_ux_state under the internal_dvst_policy_apply policy, and re-arms the DCP after bus reset (Default-state entry) per the FSP usb_pstd_busreset reference flow. Without the rearm the IP silently drops the host's first SETUP token after bus reset.

Parameters
[in]speedWhich controller fired (k_ra8_usb_speed_fs or k_ra8_usb_speed_hs).
[in]intsts0INTSTS0 snapshot captured at the top of the ISR.
Precondition
Caller has masked intsts0 against the event mask.
Bridge is past ux_dcd_ra8_usb_initialize.
Postcondition
g_dvst_state_history ring buffer captures the new DVSQ.
USBX device state mirrored to match the controller's DVSQ.
Note
ISR-callback context; must not block.
Since
0.1.0

Definition at line 360 of file ux_dcd_ra8_usb_dvst.c.

References g_last_dispatched_setup_fp, internal_dvst_map_dvsq_to_ux_state(), internal_dvst_policy_apply(), internal_dvst_record_history(), k_ra8_dvsq_default, k_ra8_dvsq_suspend, k_ra8_intsts0_mask_dvsq, priv_dvst_default_state(), and RA8_INTERNAL.

Referenced by priv_irq_dvst_prelude().

◆ priv_irq_dvst_prelude()

void priv_irq_dvst_prelude ( ra8_usb_speed_t speed,
uint16_t intsts0 )

Capture DVSTCTR0 / RHST history, mirror speed, dispatch DVST.

Pulled out of ux_dcd_ra8_usb_irq so the outer ISR fits in one page. Reads DVSTCTR0 (HUM Ch 36.2.5 p 1971) for RHST history, latches the first-observed value into g_dvstctr0_at_first_dvst, mirrors the settled link speed via internal_dvst_track_speed, then calls internal_handle_dvst for the state-machine update.

Parameters
[in]speedWhich controller fired (FS or HS).
[in]intsts0INTSTS0 snapshot (forwarded to internal_handle_dvst).
Precondition
Caller has already verified the DVST bit is set in intsts0.
Bridge is past ux_dcd_ra8_usb_initialize.
Postcondition
g_dvst_irq_count and g_rhst_history_count incremented.
Speed mirror updated and internal_handle_dvst has run.
Note
ISR-only; must not block.
Since
0.1.0

Definition at line 472 of file ux_dcd_ra8_usb_dvst.c.

References r_usb_regs_t::DVSTCTR0, g_dvst_irq_count, g_dvstctr0_at_first_dvst, g_rhst_history, g_rhst_history_count, internal_dvst_track_speed(), internal_handle_dvst(), k_ra8_usb_dcd_rhst_hist_n, k_ra8_usb_dvsq_field_mask, k_ra8_usb_speed_hs, k_ra8_usb_u16_unset, ra8_usb_fs(), and ra8_usb_hs().

Referenced by ux_dcd_ra8_usb_irq().

Variable Documentation

◆ g_dvst_irq_count

volatile uint32_t g_dvst_irq_count = 0U

Counter of INTSTS0.DVST (device-state-transition) events.

Bisect probe. Each bus reset / set-address / set-config raises DVST; zero after attach means the host isn't reaching the device. HUM Ch 36.2.14 p 1985.

Note
Written only by ux_dcd_ra8_usb_irq.
Since
0.1.0

Definition at line 51 of file ux_dcd_ra8_usb_dvst.c.

Referenced by priv_irq_dvst_prelude().

◆ g_dvst_state_history

volatile uint8_t g_dvst_state_history[(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}

Per-DVST-event capture of the decoded DVSQ[2:0] field.

JLink-readable trace of every device-state transition (independent of the "interesting tick" filter that gates g_dvsq_history). Each DVST IRQ writes the pre-shifted DVSQ value (0=Powered, 1=Default, 2=Address, 3=Configured, 4..7=Suspend variant per HUM Ch 36.2.16 p 1986). A healthy enumeration shows 1, 1, 2, 2, 3, ...; the "stuck-in-default" symptom shows 1, 5, 1, 5, 1, 5, ... (Default <-> Suspended-from-Default loop).

Note
Single-writer (internal_handle_dvst).
Since
0.1.0

Definition at line 177 of file ux_dcd_ra8_usb_dvst.c.

Referenced by internal_dvst_record_history().

◆ g_dvst_state_history_count

volatile uint32_t g_dvst_state_history_count = 0U

Total DVST events recorded into g_dvst_state_history.

Modulo k_ra8_usb_dcd_rhst_hist_n is the next write slot.

Note
Single-writer (internal_handle_dvst).
Since
0.1.0

Definition at line 188 of file ux_dcd_ra8_usb_dvst.c.

Referenced by internal_dvst_record_history().

◆ g_dvstctr0_at_first_dvst

volatile uint16_t g_dvstctr0_at_first_dvst = (uint16_t)k_ra8_usb_u16_unset

Snapshot of DVSTCTR0 (RHST field) on first DVST event.

Bisect probe. RHST[2:0] (HUM Ch 36.2.5 p 1971) reports the negotiated bus speed. 1=LS, 2=FS, 3=HS, 4=reset. If the HS chirp handshake succeeded this should latch 3 (HS); 2 means the chip is stuck in FS termination after bus reset.

Note
Latched once on the first DVST after attach; never overwritten.
Since
0.1.0

Definition at line 73 of file ux_dcd_ra8_usb_dvst.c.

Referenced by priv_irq_dvst_prelude().

◆ g_dvstctr0_history

volatile uint16_t g_dvstctr0_history[(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}

Per-dispatch-tick capture of the full DVSTCTR0 register.

Bisect probe for the post-chirp HS bring-up stall. After a successful HS chirp the controller settles DVSTCTR0.RHST = 011 (HUM Ch 37.2.5 DVSTCTR0 / Ch 36.2.5 mirror, p 1971). The hypothesis under test is whether DVSTCTR0.HSPROC (bit 2 of the RHST 3-bit encoding – value 0b100 = 4 – per FSP r_usb_bitdefine.h USB_HSPROC = 0x0004) auto-clears or wedges, and whether any other DVSTCTR0 bit (UACT bit 6, RESUME bit 5, USBRST bit 6 in host mirror, WKUP bit 8, RWUPE bit 9, USBRESM bit 10, HNPBTOA bit 11, EXICEN bit 12, VBUSEN bit 13) flips between the chirp completion and the host's first SETUP/SOF token. INTSTS1.BCHG-only events with no SACK/CTRT mean the host stopped after chirp; capturing the full DVSTCTR0 word per tick lets the bench confirm the field is stable at 0x???3 (RHST=HS) and not silently flapping.

Ring size 16 chosen to match g_rhst_history so JLink scripts can read both arrays in one transaction.

Note
Single-writer (::internal_dispatch_worker tick).
Since
0.1.0

Definition at line 132 of file ux_dcd_ra8_usb_dvst.c.

◆ g_dvstctr0_history_count

volatile uint32_t g_dvstctr0_history_count = 0U

Total dispatch ticks observed; modulo k_ra8_usb_dcd_rhst_hist_n is the next write slot in g_dvstctr0_history.

Note
Single-writer (::internal_dispatch_worker tick).
Since
0.1.0

Definition at line 143 of file ux_dcd_ra8_usb_dvst.c.

◆ g_intsts1_history

volatile uint16_t g_intsts1_history[(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}

Per-dispatch-tick capture of the full INTSTS1 register.

Companion probe to g_dvstctr0_history. INTSTS1 (HUM Ch 36.2.17 p 2001) carries BCHG (bit 14), DTCH (bit 12), ATTCH (bit 11), EOFERR (bit 6), SIGN (bit 5), SACK (bit 4) for host mode and the bus-change shadow for device mode. The 0.2.0 bring-up symptom is BCHG-only (bit 14) with no SACK ever; this ring lets the bench confirm whether any SACK / EOFERR / SIGN edge arrives in the dispatch window after RHST settles.

Note
Single-writer (::internal_dispatch_worker tick).
Since
0.1.0

Definition at line 160 of file ux_dcd_ra8_usb_dvst.c.

◆ g_rhst_history

volatile uint8_t g_rhst_history[(uint32_t) k_ra8_usb_dcd_rhst_hist_n] = {}

Per-DVST-event capture of DVSTCTR0.RHST[2:0].

JLink-readable.

RHST encoding (HUM Ch 36.2.5 p 1971 / Ch 37 DVSTCTR0): 0=undefined / chirp limbo, 1=LS, 2=FS, 3=HS, 4=in-reset. On a successful HS attach the array typically reads 0,4,3,...; on FS-fallback 0,4,2,...; on chirp failure (the 0.2.0 USB-HS bring-up symptom) every slot reads 0 even after dozens of host resets.

Note
Single-writer (internal_handle_dvst from the polled worker).
Since
0.1.0

Definition at line 96 of file ux_dcd_ra8_usb_dvst.c.

Referenced by priv_irq_dvst_prelude().

◆ g_rhst_history_count

volatile uint32_t g_rhst_history_count = 0U

Total DVST events seen; modulo k_ra8_usb_dcd_rhst_hist_n is the next write slot.

Note
Single-writer (internal_handle_dvst).
Since
0.1.0

Definition at line 106 of file ux_dcd_ra8_usb_dvst.c.

Referenced by priv_irq_dvst_prelude().