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
Go to the documentation of this file.
1
21
22#define UX_SOURCE_CODE
23
24#include <stdint.h>
25#include <string.h>
26
27#include "ra8_check.h"
28#include "ra8_elc_regs.h"
29#include "ra8_isr.h"
30#include "ra8_log.h"
31#include "ra8_usb_regs.h"
32#include "tx_api.h"
33#include "ux_api.h"
34#include "ux_dcd_ra8_usb.h"
36#include "ux_device_stack.h"
37#include "ux_system.h"
38#include "ux_utility.h"
39
51volatile uint32_t g_dvst_irq_count = 0U;
52
57typedef enum : uint16_t {
60
73volatile uint16_t g_dvstctr0_at_first_dvst = (uint16_t)k_ra8_usb_u16_unset;
74
79typedef enum : uint8_t {
82
96volatile uint8_t g_rhst_history[(uint32_t)k_ra8_usb_dcd_rhst_hist_n] = {};
97
106volatile uint32_t g_rhst_history_count = 0U;
107
132volatile uint16_t g_dvstctr0_history[(uint32_t)k_ra8_usb_dcd_rhst_hist_n] = {};
133
143volatile uint32_t g_dvstctr0_history_count = 0U;
144
160volatile uint16_t g_intsts1_history[(uint32_t)k_ra8_usb_dcd_rhst_hist_n] = {};
161
177volatile uint8_t g_dvst_state_history[(uint32_t)k_ra8_usb_dcd_rhst_hist_n] = {};
178
188volatile uint32_t g_dvst_state_history_count = 0U;
189
198typedef enum : uint8_t {
202
226RA8_INTERNAL static unsigned long internal_dvst_map_dvsq_to_ux_state(uint16_t dvsq)
227{
228 if ((dvsq & (uint16_t)k_ra8_dvsq_suspend) != 0U) {
229 return (unsigned long)UX_DEVICE_SUSPENDED;
230 }
231 switch (dvsq & (uint16_t)k_ra8_intsts0_mask_dvsq) {
232 case (uint16_t)k_ra8_dvsq_default: /* Default -- bus reset complete */
233 return (unsigned long)UX_DEVICE_ATTACHED;
234 case (uint16_t)k_ra8_dvsq_address: /* Address state */
235 return (unsigned long)UX_DEVICE_ADDRESSED;
236 case (uint16_t)k_ra8_dvsq_configured: /* Configured state */
237 return (unsigned long)UX_DEVICE_CONFIGURED;
238 case (uint16_t)k_ra8_dvsq_powered: /* Powered -- pre-bus-reset */
239 default:
240 return (unsigned long)UX_DEVICE_ATTACHED;
241 }
242}
243
263{
264 const uint8_t dvst_slot =
266 uint8_t entry_state = (uint8_t)k_dcd_trace_nibble;
267 if (_ux_system_slave != UX_NULL) {
268 entry_state = (uint8_t)(_ux_system_slave->ux_system_slave_device.ux_slave_device_state &
269 (unsigned long)k_dcd_trace_nibble);
270 }
271 const uint8_t packed = (uint8_t)((uint8_t)((dvsq >> (uint8_t)k_ra8_int0_dvsq_shift)
272 << (uint8_t)k_dcd_trace_nib_shift) |
273 entry_state);
274 g_dvst_state_history[dvst_slot] = packed;
276 priv_trace_event((uint8_t)k_dcd_trace_kind_dvst, packed, 0U);
277}
278
322RA8_INTERNAL static bool
323internal_dvst_policy_apply(UX_SLAVE_DEVICE* device, uint16_t dvsq, unsigned long new_state)
324{
325 bool apply = false;
326 if (new_state == (unsigned long)UX_DEVICE_SUSPENDED) {
327 apply = false;
328 } else if (new_state > device->ux_slave_device_state) {
329 apply = true; /* upgrade */
330 } else if (dvsq == (uint16_t)k_ra8_dvsq_default) {
331 (void)_ux_device_stack_disconnect(); /* deactivates iff configured */
332 apply = true;
333 }
334 return apply;
335}
336
360RA8_INTERNAL static void internal_handle_dvst(ra8_usb_speed_t speed, uint16_t intsts0)
361{
362 /* DVSQ field bits 6:4 on BOTH controllers (suspend = bit 6). USBHS
363 * additionally reports VBUS status in bit 7, which must be stripped
364 * -- keeping it made every event decode as "suspended" and the
365 * mirror went inert (bus resets were ignored, see below). */
366 const uint16_t dvsq = (uint16_t)(intsts0 & (uint16_t)k_ra8_intsts0_mask_dvsq);
367
369
370 /* On Default-state entry (DVSQ == 0x10), re-arm DCP per FSP
371 * usb_pstd_busreset reference flow. Without rearm the IP silently
372 * drops the host's first SETUP token after bus reset. */
373 if (dvsq == (uint16_t)k_ra8_dvsq_default) {
375 }
376 /* Suspended sub-states must not be treated as bus transitions. */
377
378 if (_ux_system_slave == UX_NULL) {
379 return;
380 }
381 UX_SLAVE_DEVICE* device = &_ux_system_slave->ux_system_slave_device;
382 const unsigned long new_state = internal_dvst_map_dvsq_to_ux_state(dvsq);
383 if ((dvsq & (uint16_t)k_ra8_dvsq_suspend) == 0U) {
384 /* Any non-suspend bus-state transition invalidates the SETUP
385 * de-dup fingerprint. */
387 }
388 /* Upgrade-only mirror; disconnect + apply on true bus reset only --
389 * rationale in internal_dvst_policy_apply's header. */
390 if (internal_dvst_policy_apply(device, dvsq, new_state)) {
391 device->ux_slave_device_state = new_state;
392 if (_ux_system_slave->ux_system_slave_change_function != UX_NULL) {
393 (void)_ux_system_slave->ux_system_slave_change_function(new_state);
394 }
395 }
396}
397
431{
432 if (_ux_system_slave == UX_NULL) {
433 return;
434 }
435 if (rhst == (uint8_t)k_ra8_usb_rhst_fs) {
436 _ux_system_slave->ux_system_slave_speed = UX_FULL_SPEED_DEVICE;
437 _ux_system_slave->ux_system_slave_device_framework =
438 _ux_system_slave->ux_system_slave_device_framework_full_speed;
439 _ux_system_slave->ux_system_slave_device_framework_length =
440 _ux_system_slave->ux_system_slave_device_framework_length_full_speed;
441 } else if (rhst == (uint8_t)k_ra8_usb_rhst_hs) {
442 _ux_system_slave->ux_system_slave_speed = UX_HIGH_SPEED_DEVICE;
443 _ux_system_slave->ux_system_slave_device_framework =
444 _ux_system_slave->ux_system_slave_device_framework_high_speed;
445 _ux_system_slave->ux_system_slave_device_framework_length =
446 _ux_system_slave->ux_system_slave_device_framework_length_high_speed;
447 } else {
448 /* Transient RHST (LS / in-reset / undefined): leave the mirror. */
449 }
450}
451
472void priv_irq_dvst_prelude(ra8_usb_speed_t speed, uint16_t intsts0)
473{
475 volatile r_usb_regs_t* reg = (speed == k_ra8_usb_speed_hs) ? ra8_usb_hs() : ra8_usb_fs();
476 const uint16_t dvstctr0 = reg->DVSTCTR0;
478 g_dvstctr0_at_first_dvst = dvstctr0;
479 }
480 /* RHST occupies DVSTCTR0[2:0]. HUM Ch 36.2.5 p 1971. */
481 const uint8_t rhst_mask = (uint8_t)k_ra8_usb_dvsq_field_mask;
482 const uint8_t rhst = (uint8_t)(dvstctr0 & rhst_mask);
483 const uint8_t hist_slot = (uint8_t)(g_rhst_history_count % (uint32_t)k_ra8_usb_dcd_rhst_hist_n);
484 g_rhst_history[hist_slot] = rhst;
487 internal_handle_dvst(speed, intsts0);
488}
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
Event Link Controller (ELC) register layout for the Renesas RA8D2.
NVIC + ICU IELSR allocator.
Lightweight Logging Interface for ra8-firmware.
ra8_usb_speed_t
Selects which controller instance the call targets.
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
USB Full-Speed + High-Speed controller layout for the Renesas RA8D2.
static volatile r_usb_regs_t * ra8_usb_hs(void)
Get pointer to the USB HS controller register block.
@ k_ra8_intsts0_mask_dvsq
Device state.
@ k_ra8_dvsq_suspend
Suspended (any sub-state).
@ k_ra8_dvsq_address
Address assigned.
@ k_ra8_dvsq_default
Default (post bus reset).
@ k_ra8_dvsq_configured
Configured.
@ k_ra8_dvsq_powered
Powered (no reset yet).
static volatile r_usb_regs_t * ra8_usb_fs(void)
Compile-time offset and size insurance for r_usb_regs_t.
USB FS / HS register window (device-mode subset).
volatile uint16_t DVSTCTR0
+0x008 Device State Control.
USBX device-controller-driver (DCD) bridge to ra8_usb.
ra8_usb_dcd_sentinel_t
"Not yet captured" sentinel for 16-bit register snapshots.
@ k_ra8_usb_u16_unset
Snapshot has not been latched yet.
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.
volatile uint16_t g_dvstctr0_at_first_dvst
Snapshot of DVSTCTR0 (RHST field) on first DVST event.
volatile uint32_t g_dvst_state_history_count
Total DVST events recorded into g_dvst_state_history.
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.
ra8_usb_dcd_rhst_hist_t
Sizing for the DVSTCTR0.RHST history ring.
@ k_ra8_usb_dcd_rhst_hist_n
Slots in g_rhst_history.
static void internal_dvst_track_speed(uint8_t rhst)
Mirror the negotiated link speed from DVSTCTR0.RHST into USBX.
volatile uint32_t g_dvstctr0_history_count
Total dispatch ticks observed; modulo k_ra8_usb_dcd_rhst_hist_n is the next write slot in g_dvstctr0_...
volatile uint32_t g_dvst_irq_count
Counter of INTSTS0.DVST (device-state-transition) events.
volatile uint16_t g_intsts1_history[(uint32_t) k_ra8_usb_dcd_rhst_hist_n]
Per-dispatch-tick capture of the full INTSTS1 register.
static void internal_dvst_record_history(uint16_t dvsq)
Record one DVST event into the JLink-readable causal history.
ra8_usb_dcd_rhst_t
DVSTCTR0.RHST[2:0] settled link-speed encodings.
@ k_ra8_usb_rhst_fs
Full speed settled.
@ k_ra8_usb_rhst_hs
High speed settled.
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
Total DVST events seen; modulo k_ra8_usb_dcd_rhst_hist_n is the next write slot.
void priv_irq_dvst_prelude(ra8_usb_speed_t speed, uint16_t intsts0)
Capture DVSTCTR0 / RHST history, mirror speed, dispatch DVST.
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 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.
USBX device-controller-driver bridge to ra8_usb – per-module cross-translation-unit contract.
volatile uint64_t g_last_dispatched_setup_fp
64-bit fingerprint of the last dispatched SETUP packet.
void priv_trace_event(uint8_t kind, uint8_t code, uint16_t length)
Append one packed event to the JLink-readable trace ring.
@ k_ra8_int0_dvsq_shift
DVSQ[2:0] field starts at bit 4.
@ k_dcd_trace_nib_shift
High-nibble shift.
@ k_dcd_trace_nibble
Low-nibble mask for packed bytes.
@ k_dcd_trace_kind_dvst
DVST event (code = dvsq|state).
void priv_dvst_default_state(ra8_usb_speed_t speed)
Process the DVSQ=Default branch of the DVST handler.
@ k_ra8_usb_dvsq_field_mask
3-bit DVSQ/RHST field after shift.