ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_irq.c
Go to the documentation of this file.
1
29
30#include <stdint.h>
31
32#include "ra8_attributes.h"
33#include "ra8_check.h"
34#include "ra8_err.h"
35#include "ra8_log.h"
36#include "ra8_mstp.h"
37#include "ra8_usb.h"
38#include "ra8_usb_internal.h"
39#include "ra8_usb_regs.h"
40
41static const char* s_tag = "USB";
42
43/* =============================================================================
44 * IRQ delivery + power
45 * =============================================================================
46 */
47
48/* Per-controller callbacks. Two slots so USBFS and USBHS can have
49 * independent event handlers -- this is what lets one firmware image
50 * run the DCD bridge on one controller and a different driver (e.g.
51 * bare-CDC) on the other. */
57
60
84static uint8_t internal_cb_slot(ra8_usb_speed_t speed)
85{
86 return (speed == k_ra8_usb_speed_hs) ? (uint8_t)k_ra8_usb_cb_slot_hs
87 : (uint8_t)k_ra8_usb_cb_slot_fs;
88}
89
91{
92 const uint8_t slot = internal_cb_slot(speed);
93 s_usb_fn[slot] = fn;
94 s_usb_ctx[slot] = ctx;
95}
96
110{
111 volatile r_usb_regs_t* reg = priv_pick(speed);
112 if (reg == nullptr) {
113 return;
114 }
115 /* HUM Ch 36.2.14 "INTSTS0 : Interrupt Status Register 0", p 1986.
116 *
117 * INTSTS0 is W0C: writing 0 to a bit clears it, writing 1 has no
118 * effect. The previous mask-and-back pattern
119 * INTSTS0 = mask & ~ack_bits
120 * unconditionally writes 0 to every bit in ack_bits, even bits that
121 * were 0 in the snapshot. That means a CTRT (or DVST) edge that
122 * asserts in HW *between* the read of `mask` and the write of the
123 * ack pattern is silently cleared before the dispatcher can act on
124 * it. With a free-running polled worker (1.7M ticks/sec) and SETUP
125 * tokens arriving at ~1 ms cadence, almost every CTRT edge falls
126 * inside this race window, which is why s_ctrt_irq_count stayed at
127 * 0 even though DVST was caught (DVST edges hold longer because the
128 * device-state remains in default until the next reset).
129 *
130 * Correct W0C ack: write 0 ONLY to the bits we observed set, and 1
131 * (no-op) everywhere else. ``~(mask & ack_bits)`` does exactly that:
132 * for any bit not in ack_bits, we write 1 (preserve); for an
133 * ack_bits position that was 0 in the snapshot, we write 1 (no-op,
134 * does not clobber a freshly-set edge); for an ack_bits position
135 * that was 1 in the snapshot, we write 0 (clear).
136 *
137 * VALID is intentionally NOT in ack_bits -- the SETUP handlers
138 * (ra8_usb_read_setup_if_valid / _unconditional) drain
139 * USBREQ/USBVAL/USBINDX/USBLENG and clear VALID themselves.
140 * CTSQ/DVSQ are read-only fields. */
141 const uint16_t mask = reg->INTSTS0;
142
143 const uint16_t ack_bits = (uint16_t)((1U << k_ra8_int0_bit_ctrt) | (1U << k_ra8_int0_bit_dvst) |
144 (1U << k_ra8_int0_bit_bemp) | (1U << k_ra8_int0_bit_brdy) |
145 (1U << k_ra8_int0_bit_nrdy) | (1U << k_ra8_int0_bit_vbse) |
146 (1U << k_ra8_int0_bit_rsme) | (1U << k_ra8_int0_bit_sofr));
147 reg->INTSTS0 = (uint16_t)~(uint16_t)(mask & ack_bits);
148
149 const uint8_t slot = internal_cb_slot(speed);
150 const ra8_usb_event_fn_t fn = s_usb_fn[slot];
151 void* const ctx = s_usb_ctx[slot];
152 if (fn != nullptr) {
153 fn(ctx, speed, mask);
154 }
155}
156
171{
172 volatile const r_usb_regs_t* reg = priv_pick(speed);
173 if (reg == nullptr) {
174 return 0U;
175 }
176 return reg->INTSTS0;
177}
178
193{
194 if ((speed != k_ra8_usb_speed_fs) && (speed != k_ra8_usb_speed_hs)) {
196 }
197 return ra8_mstp_disable(priv_mstp(speed));
198}
199
214{
215 if ((speed != k_ra8_usb_speed_fs) && (speed != k_ra8_usb_speed_hs)) {
217 }
218 return ra8_mstp_enable(priv_mstp(speed));
219}
220/* =============================================================================
221 * Host-mode bring-up (peer of the device-mode lifecycle above)
222 *
223 * Mirrors FSP's `r_usb_basic/src/hw/r_usb_hreg_access.c` host bits.
224 * Device and host share the same register block; the only mode-bit
225 * differences live inside SYSCFG (DCFM/DRPD vs DPRPU) and DVSTCTR0
226 * (UACT / USBRST, host-only).
227 * =============================================================================
228 */
229
245
264{
265 uint16_t syscfg = (uint16_t)(1U << k_ra8_syscfg_bit_scke);
266 syscfg = (uint16_t)(syscfg | (uint16_t)(1U << k_ra8_syscfg_bit_dcfm));
267 syscfg = (uint16_t)(syscfg | (uint16_t)(1U << k_ra8_syscfg_bit_drpd));
268 syscfg = (uint16_t)(syscfg | (uint16_t)(1U << k_ra8_syscfg_bit_usbe));
269 if (speed == k_ra8_usb_speed_hs) {
270 syscfg = (uint16_t)(syscfg | (uint16_t)(1U << k_ra8_syscfg_bit_hse));
271 }
272 return syscfg;
273}
274
295{
296 /* HUM Ch 36.2.7 "CFIFOSEL : CFIFO Port Select Register", p 1976 */
300
301 /* HUM Ch 36.2.20 "DCPMAXP : DCP Max Packet Size Register", p 1999 */
302 reg->DCPCFG = 0U;
304 reg->DCPCTR = 0U;
305
306 /* HUM Ch 36.2.16 "USBADDR : USB Address Register", p 1994 -- target
307 * device address for the host's outgoing tokens. Default to 0
308 * (newly-attached devices respond at address 0). */
309 reg->USBADDR = 0U;
310
311 /* HUM Ch 36.2.10 "INTENB0 : Interrupt Enable Register 0", p 1980 */
312 reg->INTENB0 = (uint16_t)((1U << k_ra8_int0_bit_bemp) | (1U << k_ra8_int0_bit_brdy) |
313 (1U << k_ra8_int0_bit_nrdy) | (1U << k_ra8_int0_bit_ctrt) |
314 (1U << k_ra8_int0_bit_dvst) | (1U << k_ra8_int0_bit_vbse));
315 reg->INTENB1 = 0U;
316 reg->BRDYENB = 0U;
317 reg->NRDYENB = 0U;
318 reg->BEMPENB = 0U;
319}
320
347{
348 const ra8_err_t phy_err = priv_usbhs_phy_bringup(reg);
349 /* GCOVR_EXCL_BR_START -- HW bring-up fault */
350 RA8_RETURN_ON_ERROR(phy_err, s_tag, "host_init: HS PHY bring-up");
351 /* GCOVR_EXCL_BR_STOP */
352 priv_rmw16(&reg->SYSCFG, 0U, (uint16_t)(1U << k_ra8_syscfg_bit_usbe));
353 priv_rmw16(&reg->SYSCFG,
354 (uint16_t)((uint16_t)(1U << k_ra8_syscfg_bit_dcfm) |
355 (uint16_t)((uint16_t)(1U << k_ra8_syscfg_bit_drpd) |
356 (uint16_t)(1U << k_ra8_syscfg_bit_cnen))),
357 0U);
358 priv_rmw16(&reg->SYSCFG, (uint16_t)(1U << k_ra8_syscfg_bit_usbe), 0U);
359 return k_ra8_ok;
360}
361
376{
377 volatile r_usb_regs_t* reg = priv_pick(speed);
378 if (reg == nullptr) {
380 }
381
382 /* HUM Ch 11.2.7 "MSTPCRB : Module Stop Control Register B", p 444 */
383 const ra8_err_t mst_err = ra8_mstp_enable(priv_mstp(speed));
384 RA8_RETURN_ON_ERROR(mst_err, s_tag, "host_init: mstp enable");
385
386 if (speed == k_ra8_usb_speed_hs) {
387 const ra8_err_t hs_err = internal_host_hs_bringup(reg);
388 /* GCOVR_EXCL_BR_START -- HW bring-up fault */
389 RA8_RETURN_ON_ERROR(hs_err, s_tag, "host_init: HS bring-up");
390 /* GCOVR_EXCL_BR_STOP */
391 } else {
392 /* HUM Ch 36.2.1 "SYSCFG : System Configuration Control Register", p 1967 */
393 reg->SYSCFG = internal_host_syscfg_word(speed);
394 }
395
396 /* HUM Ch 36.2.5 "DVSTCTR0 : Device State Control Register 0", p 1971 */
397 reg->DVSTCTR0 = 0U;
398 if (speed == k_ra8_usb_speed_hs) {
399 /* HUM Ch 37.2.5 DVSTCTR0.VBUSEN: the USBHS jack's external VBUS
400 * switch is driven by this bit (FSP hw_usb_hmodule_init); without
401 * it an attached device never powers and LNST stays SE0. */
402 priv_rmw16(&reg->DVSTCTR0, (uint16_t)(1U << k_ra8_dvstctr_bit_vbusen), 0U);
403 }
404
406
407 ra8_log_info_val(s_tag, "usb host init speed", (uint32_t)speed);
408 return k_ra8_ok;
409}
410
425{
426 volatile r_usb_regs_t* reg = priv_pick(speed);
427 if (reg == nullptr) {
429 }
430 /* HUM Ch 36.2.5 "DVSTCTR0 : Device State Control Register 0", p 1971 */
431 reg->DVSTCTR0 = 0U;
432 reg->INTENB0 = 0U;
433 reg->INTENB1 = 0U;
434 reg->BRDYENB = 0U;
435 reg->NRDYENB = 0U;
436 reg->BEMPENB = 0U;
437 reg->SYSCFG = 0U;
438 return ra8_mstp_disable(priv_mstp(speed));
439}
440
456{
457 volatile r_usb_regs_t* reg = priv_pick(speed);
458 if (reg == nullptr) {
460 }
461 /* HUM Ch 36.2.5 "DVSTCTR0 : Device State Control Register 0", p 1971 */
462 const uint16_t rst_bit = (uint16_t)(1U << k_ra8_dvstctr_bit_usbrst);
463 const uint16_t uact_bit = (uint16_t)(1U << k_ra8_dvstctr_bit_uact);
464 if (assert_reset) {
465 /* USBRST=1 forces UACT low; FSP atomically sets RST + clears UACT. */
466 priv_rmw16(&reg->DVSTCTR0, rst_bit, uact_bit);
467 } else {
468 priv_rmw16(&reg->DVSTCTR0, 0U, rst_bit);
469 }
470 return k_ra8_ok;
471}
472
488{
489 volatile r_usb_regs_t* reg = priv_pick(speed);
490 if (reg == nullptr) {
492 }
493 /* HUM Ch 36.2.5 "DVSTCTR0 : Device State Control Register 0", p 1971 */
494 const uint16_t uact_bit = (uint16_t)(1U << k_ra8_dvstctr_bit_uact);
495 if (enable) {
496 priv_rmw16(&reg->DVSTCTR0, uact_bit, 0U);
497 } else {
498 priv_rmw16(&reg->DVSTCTR0, 0U, uact_bit);
499 }
500 return k_ra8_ok;
501}
502
518{
519 RA8_CHECK_NULL_PTR(setup, s_tag, "host_setup_request: setup");
520 volatile r_usb_regs_t* reg = priv_pick(speed);
521 if (reg == nullptr) {
523 }
524 /* HUM Ch 36.2.21 "DCPCTR : DCP Control Register", p 1999 -- guard
525 * against a still-pending request. */
526 const uint16_t sureq_bit = (uint16_t)(1U << k_ra8_dcpctr_bit_sureq);
527 if ((reg->DCPCTR & sureq_bit) != 0U) {
528 return k_ra8_err_busy;
529 }
530
531 /* HUM Ch 36.2.17 "USBREQ : USB Request Type Register", p 1995 */
532 const uint16_t req = (uint16_t)((uint16_t)setup->bm_request_type |
533 (uint16_t)((uint16_t)setup->b_request << k_ra8_usb_byte_bits));
534 reg->USBREQ = req;
535 reg->USBVAL = setup->w_value;
536 reg->USBINDX = setup->w_index;
537 reg->USBLENG = setup->w_length;
538
539 /* SUREQ tells the SIE to issue the SETUP token on the next frame. */
540 priv_rmw16(&reg->DCPCTR, sureq_bit, 0U);
541 return k_ra8_ok;
542}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
ra8_err_t ra8_mstp_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
void priv_rmw16(volatile uint16_t *reg, uint16_t set_mask, uint16_t clr_mask)
Apply a generic read-modify-write to a 16-bit register.
Definition ra8_usb.c:154
ra8_mstp_t priv_mstp(ra8_usb_speed_t speed)
Resolve the per-speed MSTP id.
Definition ra8_usb.c:135
volatile r_usb_regs_t * priv_pick(ra8_usb_speed_t speed)
Resolve the per-speed register pointer.
Definition ra8_usb.c:110
Native USB controller driver public API (device + host modes).
void(* ra8_usb_event_fn_t)(void *ctx, ra8_usb_speed_t speed, uint16_t status_mask)
USB event callback signature.
ra8_usb_speed_t
Selects which controller instance the call targets.
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
@ k_ra8_usb_speed_fs
Full-Speed controller (USBFS @ 0x40250000).
Cross-TU surface for the ra8_usb driver split.
ra8_err_t priv_usbhs_phy_bringup(volatile r_usb_regs_t *reg)
USBHS embedded-PHY bring-up (HUM Figure 37.2 p 2121).
@ k_ra8_usb_byte_bits
Bits per byte (shift constant).
@ k_ra8_usb_dcp_max_packet
EP0 default packet size.
ra8_usb_dvstctr_bit_t
DVSTCTR0 host-mode bit positions (HUM Ch 36.2.5 "DVSTCTR0").
@ k_ra8_dvstctr_bit_usbrst
Bus reset signal (host).
@ k_ra8_dvstctr_bit_rwupe
Remote-wake detect enable (host).
@ k_ra8_dvstctr_bit_uact
Bus enable (host SOF generation).
@ k_ra8_dvstctr_bit_vbusen
External VBUS-switch enable (HS).
@ k_ra8_dvstctr_bit_resume
Resume signal output (host).
uint16_t ra8_usb_intsts0_snapshot(ra8_usb_speed_t speed)
Implementation of ra8_usb_intsts0_snapshot().
static ra8_err_t internal_host_hs_bringup(volatile r_usb_regs_t *reg)
Bring the USBHS instance up in HOST role (PHY + SYSCFG bits).
static void * s_usb_ctx[k_ra8_usb_cb_slot_n]
Definition ra8_usb_irq.c:59
ra8_usb_cb_slot_t
Definition ra8_usb_irq.c:52
@ k_ra8_usb_cb_slot_hs
RA8 USB cb slot hs.
Definition ra8_usb_irq.c:54
@ k_ra8_usb_cb_slot_n
RA8 USB cb slot n.
Definition ra8_usb_irq.c:55
@ k_ra8_usb_cb_slot_fs
RA8 USB cb slot fs.
Definition ra8_usb_irq.c:53
ra8_err_t ra8_usb_host_bus_reset(ra8_usb_speed_t speed, bool assert_reset)
Implementation of ra8_usb_host_bus_reset().
static uint8_t internal_cb_slot(ra8_usb_speed_t speed)
Map a USB speed enum to the per-controller callback slot index.
Definition ra8_usb_irq.c:84
void ra8_usb_dispatch(ra8_usb_speed_t speed)
Implementation of ra8_usb_dispatch().
ra8_err_t ra8_usb_exit_stop(ra8_usb_speed_t speed)
Implementation of ra8_usb_exit_stop().
static uint16_t internal_host_syscfg_word(ra8_usb_speed_t speed)
Build the host-mode SYSCFG word.
ra8_err_t ra8_usb_host_init(ra8_usb_speed_t speed)
Implementation of ra8_usb_host_init().
ra8_err_t ra8_usb_host_deinit(ra8_usb_speed_t speed)
Implementation of ra8_usb_host_deinit().
static ra8_usb_event_fn_t s_usb_fn[k_ra8_usb_cb_slot_n]
Definition ra8_usb_irq.c:58
ra8_err_t ra8_usb_enter_stop(ra8_usb_speed_t speed)
Implementation of ra8_usb_enter_stop().
ra8_err_t ra8_usb_host_setup_request(ra8_usb_speed_t speed, const ra8_usb_setup_t *setup)
Implementation of ra8_usb_host_setup_request().
void ra8_usb_attach_handler(ra8_usb_speed_t speed, ra8_usb_event_fn_t fn, void *ctx)
Install (or detach) the per-controller USB event handler.
Definition ra8_usb_irq.c:90
ra8_err_t ra8_usb_host_set_uact(ra8_usb_speed_t speed, bool enable)
Implementation of ra8_usb_host_set_uact().
static void internal_host_init_defaults(volatile r_usb_regs_t *reg)
Program the host-mode FIFO / DCP / interrupt-enable defaults.
USB Full-Speed + High-Speed controller layout for the Renesas RA8D2.
@ k_ra8_syscfg_bit_usbe
USB module enable.
@ k_ra8_syscfg_bit_cnen
Single-end receiver enable.
@ k_ra8_syscfg_bit_hse
HS enable (HS instance only).
@ k_ra8_syscfg_bit_drpd
D+/D- pull-down (host).
@ k_ra8_syscfg_bit_dcfm
1 = host mode, 0 = device.
@ k_ra8_syscfg_bit_scke
USB clock enable.
@ k_ra8_dcpctr_bit_sureq
Send USB request (host mode).
@ k_ra8_fifosel_mbw_16
16-bit FIFO access width.
@ k_ra8_int0_bit_bemp
Buffer-empty interrupt.
@ k_ra8_int0_bit_dvst
Device-state transition.
@ k_ra8_int0_bit_brdy
Buffer-ready interrupt.
@ k_ra8_int0_bit_ctrt
Control-transfer-stage transition.
@ k_ra8_int0_bit_sofr
Start-of-Frame.
@ k_ra8_int0_bit_vbse
VBUS change.
@ k_ra8_int0_bit_nrdy
Buffer-not-ready interrupt.
@ k_ra8_int0_bit_rsme
Resume.
USB FS / HS register window (device-mode subset).
volatile uint16_t USBINDX
+0x058 USB Request wIndex.
volatile uint16_t NRDYENB
+0x038 NRDY Interrupt Enable.
volatile uint16_t DCPCTR
+0x060 DCP Control.
volatile uint16_t USBVAL
+0x056 USB Request wValue.
volatile uint16_t CFIFOSEL
+0x020 Control FIFO select.
volatile uint16_t DCPMAXP
+0x05E DCP Max Packet.
volatile uint16_t USBADDR
+0x050 USB Address.
volatile uint16_t INTENB0
+0x030 Interrupt Enable 0.
volatile uint16_t INTSTS0
+0x040 Interrupt Status 0.
volatile uint16_t USBLENG
+0x05A USB Request wLength.
volatile uint16_t SYSCFG
+0x000 System Configuration.
volatile uint16_t DVSTCTR0
+0x008 Device State Control.
volatile uint16_t BRDYENB
+0x036 BRDY Interrupt Enable.
volatile uint16_t INTENB1
+0x032 Interrupt Enable 1.
volatile uint16_t DCPCFG
+0x05C DCP Configuration.
volatile uint16_t D0FIFOSEL
+0x028 DMA FIFO 0 select.
volatile uint16_t BEMPENB
+0x03A BEMP Interrupt Enable.
volatile uint16_t D1FIFOSEL
+0x02C DMA FIFO 1 select.
volatile uint16_t USBREQ
+0x054 USB Request type/bRequest.
Decoded 8-byte USB SETUP packet.
uint16_t w_length
wLength.
uint8_t b_request
bRequest code.
uint8_t bm_request_type
Request direction / type / recipient.
uint16_t w_index
wIndex.
uint16_t w_value
wValue.