ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_host_ctrl.c
Go to the documentation of this file.
1
25
26#include <stdint.h>
27
28#include "ra8_attributes.h"
29#include "ra8_check.h"
30#include "ra8_err.h"
31#include "ra8_hw_err.h"
32#include "ra8_usb.h"
33#include "ra8_usb_internal.h"
34#include "ra8_usb_regs.h"
35
36static const char* s_tag = "USB";
37
38/* =============================================================================
39 * Host-mode control-transfer engine (polled, synchronous)
40 *
41 * The RA SIE signals host control-transfer progress through SUREQ-clear
42 * (SETUP done), BRDY (a DATA packet landed in the DCP buffer) and BEMP
43 * (the STATUS stage completed) -- NOT through CTRT, which is a device-mode
44 * control-stage signal. This block composes the existing FIFO/PID helpers
45 * into a blocking GET/SET control transfer over the DCP (pipe 0).
46 * =============================================================================
47 */
48
50typedef enum : uint32_t {
53
65
67static volatile uint8_t s_host_ctrl_stage = (uint8_t)k_ra8_usb_cs_begin;
68
70{
71 return s_host_ctrl_stage;
72}
73
91void priv_host_program_devadd(volatile r_usb_regs_t* reg, uint8_t dev_addr)
92{
93 const uint16_t rhst = (uint16_t)(reg->DVSTCTR0 & (uint16_t)k_ra8_usb_rhst_mask);
94 const uintptr_t off =
95 (uintptr_t)k_ra8_usb_devadd0_off + ((uintptr_t)dev_addr * (uintptr_t)k_ra8_usb_devadd_stride);
96 volatile uint16_t* const devadd = (volatile uint16_t*)((uintptr_t)reg + off);
97 *devadd = (uint16_t)(rhst << (uint16_t)k_ra8_usb_usbspd_shift);
98}
99
120static ra8_err_t internal_host_wait_sts(volatile const uint16_t* sts, uint16_t mask)
121{
122 for (uint32_t i = 0U; i < (uint32_t)k_ra8_usb_ctrl_poll_limit; ++i) {
123 if ((*sts & mask) != 0U) {
124 return k_ra8_ok;
125 }
126 }
128}
129
152{
153 for (uint32_t i = 0U; i < (uint32_t)k_ra8_usb_ctrl_poll_limit; ++i) {
154 if ((reg->BRDYSTS & (uint16_t)k_ra8_usb_dcp_pipe0_bit) != 0U) {
155 return k_ra8_ok;
156 }
157 if ((reg->DCPCTR & (uint16_t)k_ra8_usb_pid_stall_bit) != 0U) {
158 return k_ra8_err_hw_error;
159 }
160 if ((reg->NRDYSTS & (uint16_t)k_ra8_usb_dcp_pipe0_bit) != 0U) {
161 reg->NRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
163 }
164 }
166}
167
196{
197 const uint16_t sack = (uint16_t)(1U << k_ra8_int1_bit_sack);
198 const uint16_t sign = (uint16_t)(1U << k_ra8_int1_bit_sign);
199 const uint16_t sureq = (uint16_t)(1U << k_ra8_dcpctr_bit_sureq);
200#if !(defined(RA8_OFF_TARGET) && defined(UNIT_TEST))
201 /* Clear the stale SACK/SIGN latches before asserting SUREQ. Skipped on the
202 * host unit-test build: its plain-RAM INTSTS1 cannot be re-latched by a SIE
203 * after a W0C clear, so wiping it here would erase the SACK/SIGN outcome a
204 * test pre-loaded and the poll below would never observe it. */
205 reg->INTSTS1 = (uint16_t)~(uint16_t)(sack | sign);
206#endif
207 priv_rmw16(&reg->DCPCTR, sureq, 0U);
208 for (uint32_t i = 0U; i < (uint32_t)k_ra8_usb_ctrl_poll_limit; ++i) {
209 const uint16_t sts1 = reg->INTSTS1;
210#if defined(RA8_OFF_TARGET) && defined(UNIT_TEST)
211 const bool got_sack = ra8_fake_mmio_wait_eval(&reg->INTSTS1, i, ((sts1 & sack) != 0U));
212#else
213 const bool got_sack = ((sts1 & sack) != 0U);
214#endif
215 if (got_sack) {
216 reg->INTSTS1 = (uint16_t)~sack;
217 return k_ra8_ok;
218 }
219 if ((sts1 & sign) != 0U) {
220 reg->INTSTS1 = (uint16_t)~sign;
221 return k_ra8_err_hw_error;
222 }
223 }
225}
226
249{
250 const uint16_t sureq = (uint16_t)(1U << k_ra8_dcpctr_bit_sureq);
251 if ((reg->DCPCTR & sureq) != 0U) {
252 /* A SETUP issued with the port inactive (e.g. before any device was
253 * attached) leaves SUREQ wedged. The USBHS instance provides
254 * SUREQCLR to abort it; try that before reporting busy. */
255 if (priv_is_hs(reg)) {
256 priv_rmw16(&reg->DCPCTR, (uint16_t)(1U << k_ra8_dcpctr_bit_sureqclr), 0U);
257 }
258 if ((reg->DCPCTR & sureq) != 0U) {
259 return k_ra8_err_busy;
260 }
261 }
263 /* Clear any stale CCPL left by a prior transfer's status stage. With
264 * CCPL still set, arming PID=BUF for the new DATA stage makes the SIE
265 * run a status stage instead, so the data stage never moves (observed
266 * as stage=2 with DCPCTR=0x0004 on hardware). */
267 priv_rmw16(&reg->DCPCTR, 0U, (uint16_t)(1U << k_ra8_dcpctr_bit_ccpl));
268 /* Refresh the DEVADD slot of the address the DCP currently targets
269 * (DCPMAXP.DEVSEL); 0 before SET_ADDRESS, the assigned address after
270 * ra8_usb_host_set_target. */
271 const uint8_t devsel = (uint8_t)((uint16_t)(reg->DCPMAXP >> (uint16_t)k_ra8_usb_devsel_shift) &
273 priv_host_program_devadd(reg, devsel);
274#ifdef RA8_OFF_TARGET
275 /* BEMPSTS/BRDYSTS are W1C: on hardware, writing ~DCP clears every set status
276 * bit EXCEPT the DCP pipe. A plain-RAM fake would blind-assign 0xFFFE and zero
277 * the DCP bit a test pre-loaded for the DATA stage, so model the W1C (preserve
278 * DCP, clear the rest) explicitly off-target. */
279 reg->BEMPSTS = (uint16_t)(reg->BEMPSTS & (uint16_t)k_ra8_usb_dcp_pipe0_bit);
280 reg->BRDYSTS = (uint16_t)(reg->BRDYSTS & (uint16_t)k_ra8_usb_dcp_pipe0_bit);
281#else
282 reg->BEMPSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
283 reg->BRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
284#endif
285 const uint16_t req = (uint16_t)((uint16_t)setup->bm_request_type |
286 (uint16_t)((uint16_t)setup->b_request << k_ra8_usb_byte_bits));
287 reg->USBREQ = req;
288 reg->USBVAL = setup->w_value;
289 reg->USBINDX = setup->w_index;
290 reg->USBLENG = setup->w_length;
291 /* Arm + clear the SETUP outcome flags: SACK latches when the device
292 * ACKs the SETUP, SIGN when three transmission attempts fail. SUREQ
293 * self-clearing alone is NOT an ACK indication, so gate on these. */
294 const uint16_t sack = (uint16_t)(1U << k_ra8_int1_bit_sack);
295 const uint16_t sign = (uint16_t)(1U << k_ra8_int1_bit_sign);
296 reg->INTENB1 = (uint16_t)(reg->INTENB1 | (uint16_t)(sack | sign));
297 return internal_host_setup_wait(reg);
298}
299
319{
320 priv_select_cfifo(reg, 0U, false);
321 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
322 reg->BRDYENB = (uint16_t)(reg->BRDYENB | (uint16_t)k_ra8_usb_dcp_pipe0_bit);
323 reg->NRDYENB = (uint16_t)(reg->NRDYENB | (uint16_t)k_ra8_usb_dcp_pipe0_bit);
324 priv_rmw16(&reg->DCPCTR, (uint16_t)(1U << k_ra8_dcpctr_bit_sqset), 0U);
326}
327
352 uint8_t* data,
353 uint16_t want,
354 uint16_t mxps,
355 uint16_t* out_rx)
356{
357 uint16_t rx = 0U;
358 bool done = false;
360 while (!done) {
361 const ra8_err_t br = internal_host_dcp_in_wait(reg);
362 if (br != k_ra8_ok) {
364 return br;
365 }
367 priv_select_cfifo(reg, 0U, false);
368 if (priv_wait_frdy(reg) != k_ra8_ok) {
371 }
372 const uint16_t dtln = (uint16_t)(reg->CFIFOCTR & k_ra8_fifoctr_dtln);
373 uint16_t chunk = dtln;
374 if ((uint16_t)(rx + chunk) > want) {
375 chunk = (uint16_t)(want - rx);
376 }
377 if (chunk > 0U) {
378 priv_fifo_read(reg, &data[rx], chunk);
379 }
380 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
381 rx = (uint16_t)(rx + dtln);
382 reg->BRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
383 if (dtln < mxps) {
384 done = true;
385 }
386 if (rx >= want) {
387 done = true;
388 }
389 }
391 *out_rx = rx;
392 return k_ra8_ok;
393}
394
422static ra8_err_t internal_host_ctrl_status(volatile r_usb_regs_t* reg, bool write_zlp)
423{
424 const uint16_t ccpl = (uint16_t)(1U << k_ra8_dcpctr_bit_ccpl);
425 reg->BEMPSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
426 reg->BRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
427 reg->BEMPENB = (uint16_t)(reg->BEMPENB | (uint16_t)k_ra8_usb_dcp_pipe0_bit);
428 reg->BRDYENB = (uint16_t)(reg->BRDYENB | (uint16_t)k_ra8_usb_dcp_pipe0_bit);
429 /* A control-WRITE data stage left DCPCFG.DIR = 1 (OUT tokens); its IN-ZLP
430 * status stage needs DIR = 0 so the host issues an IN token to collect the
431 * device's status ZLP. Restore it for the write / no-data status (the
432 * control-READ OUT-ZLP status keeps the default DIR and is best-effort).
433 * HUM Ch 36.2.18 "DCPCFG : DCP Configuration" p 1989. */
434 if (!write_zlp) {
435 priv_rmw16(&reg->DCPCFG, 0U, (uint16_t)(1U << (uint8_t)k_ra8_dcpcfg_bit_dir));
436 }
437 /* The status stage is always DATA1; force the DCP sequence bit so the
438 * device does not NAK a toggle mismatch (seen as NRDYSTS bit 0). */
439 priv_rmw16(&reg->DCPCTR, (uint16_t)(1U << k_ra8_dcpctr_bit_sqset), 0U);
440 priv_select_cfifo(reg, 0U, write_zlp);
441 if (write_zlp) {
442 /* Control-read status is an OUT the host must drive: enqueue a
443 * zero-length packet (BVAL, no CFIFO write) and assert CCPL. This is
444 * best-effort -- the DATA-IN payload the caller wanted is already in
445 * hand, and a fresh SETUP re-syncs the control endpoint regardless, so
446 * a slow/NAKed OUT status does not invalidate the transfer. */
447 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bval;
449 priv_rmw16(&reg->DCPCTR, ccpl, 0U);
452 priv_rmw16(&reg->DCPCTR, 0U, ccpl);
453 return k_ra8_ok;
454 }
455 /* Control-write / no-data status is an IN: free the DCP receive buffer
456 * FIRST -- a stale BSTS blocks the incoming ZLP, the SIE NAKs it
457 * forever, and the request never takes effect on the device (observed
458 * on hardware as SET_CONFIGURATION "passing" while the bulk endpoints
459 * stayed dead). Then arm PID=BUF + CCPL and require the BRDY that
460 * marks the device's status ZLP received. */
461 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
462 reg->NRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
464 priv_rmw16(&reg->DCPCTR, ccpl, 0U);
465 const ra8_err_t ierr = internal_host_dcp_in_wait(reg);
467 priv_rmw16(&reg->DCPCTR, 0U, ccpl);
468 /* Drain the status ZLP so it cannot alias the next data stage. */
469 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
470 reg->BRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
471 return ierr;
472}
473
501 const uint8_t* data,
502 uint16_t want,
503 uint16_t mxps)
504{
505 /* Host DCP issues IN tokens by default (DCPCFG.DIR = 0, which serves the
506 * common control-READ data stage). A control-WRITE data stage must flip
507 * DIR = 1 so the controller issues OUT tokens; otherwise the device sees an
508 * IN token in its write-data stage and flags CTSQ = SQER, dropping the
509 * payload (CFIFOSEL.ISEL only sets the CPU FIFO-access direction, not the
510 * wire token direction). HUM Ch 36.2.18 "DCPCFG : DCP Configuration" p 1989. */
511 priv_rmw16(&reg->DCPCFG, (uint16_t)(1U << (uint8_t)k_ra8_dcpcfg_bit_dir), 0U);
512 priv_select_cfifo(reg, 0U, true);
513 /* HUM Ch 36.2.8 "CFIFOCTR : CFIFO Port Control Register", p 1979 -- discard
514 * any stale bank so FRDY re-asserts for the fresh write. */
515 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
516 /* First data packet after SETUP is DATA1; force the DCP sequence bit so the
517 * device does not drop it on a toggle mismatch. */
518 priv_rmw16(&reg->DCPCTR, (uint16_t)(1U << k_ra8_dcpctr_bit_sqset), 0U);
519 reg->BEMPSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
520 reg->BEMPENB = (uint16_t)(reg->BEMPENB | (uint16_t)k_ra8_usb_dcp_pipe0_bit);
521
522 const uint16_t step = (mxps == 0U) ? (uint16_t)1U : mxps;
523 uint16_t off = 0U;
524 while (off < want) {
525 uint16_t chunk = (uint16_t)(want - off);
526 if (chunk > step) {
527 chunk = step;
528 }
529 const ra8_err_t perr = priv_dcp_push_chunk(reg, &data[off], chunk);
530 if (perr != k_ra8_ok) {
532 return perr;
533 }
535 /* Best-effort drain wait. The DCP BEMP completion indication is unreliable
536 * on this silicon (see ::internal_host_ctrl_status) -- gating hard on it
537 * deadlocks an OUT that actually landed. Give the bank a bounded window to
538 * drain (back-pressure for multi-packet) but proceed regardless; the IN
539 * status stage + the class protocol (DFU_GETSTATUS) confirm delivery. */
541 reg->BEMPSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
542 off = (uint16_t)(off + chunk);
543 }
545 return k_ra8_ok;
546}
547
571{
572 volatile r_usb_regs_t* reg = priv_pick(speed);
573 if (reg == nullptr) {
575 }
576 /* Receiving the data stage of a control-WRITE on the DCP. The first data
577 * packet after a SETUP is ALWAYS DATA1 (USB 2.0 sec 8.6); a stale DCP
578 * sequence toggle makes the SIE silently ACK-and-discard the host's packet
579 * with NO BRDY -- the exact failure the host read-arm guards against in
580 * ::internal_host_ctrl_data_arm. So clear the stale BRDY latch, select the
581 * DCP read window, clear the receive bank (BCLR), enable the DCP BRDY
582 * interrupt, force the receive toggle to DATA1 via DCPCTR.SQSET, and set
583 * PID=BUF so the SIE ACKs the OUT token.
584 * HUM Ch 36.2.21 "DCPCTR" p 1991 (SQSET) / Ch 36.2.11 "BRDYENB" p 1982 /
585 * Ch 36.2.8 "CFIFOCTR" p 1979 (BCLR). */
587 /* Clear any stale CCPL left by the previous transfer's status stage. With
588 * CCPL still set, arming PID=BUF makes the SIE run a status stage instead of
589 * accepting the data stage -- CTSQ goes to SQER and the OUT data never lands.
590 * Device-side mirror of the host guard in ::internal_host_ctrl_setup.
591 * HUM Ch 36.2.21 "DCPCTR : DCP Control Register" p 1991 (CCPL). */
592 priv_rmw16(&reg->DCPCTR, 0U, (uint16_t)(1U << (uint8_t)k_ra8_dcpctr_bit_ccpl));
593 reg->BRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
594 priv_select_cfifo(reg, 0U, false);
595 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
596 reg->BRDYENB = (uint16_t)(reg->BRDYENB | (uint16_t)k_ra8_usb_dcp_pipe0_bit);
597 priv_rmw16(&reg->DCPCTR, (uint16_t)(1U << (uint8_t)k_ra8_dcpctr_bit_sqset), 0U);
599 if ((reg->BRDYENB & (uint16_t)k_ra8_usb_dcp_pipe0_bit) == 0U) {
600 /* The line above OR-set the DCP bit into BRDYENB and no helper touches
601 * BRDYENB before this re-read of the same word, so under RA8_OFF_TARGET
602 * (plain-RAM registers) the bit is always present; this timeout is only
603 * reachable on silicon where the SIE refuses the enable. */
604 return k_ra8_err_hw_timeout; /* GCOVR_EXCL_LINE -- SIE enable refusal seen only on silicon */
605 }
606 return k_ra8_ok;
607}
608
634ra8_err_t ra8_usb_dcp_out_read(ra8_usb_speed_t speed, uint8_t* buf, uint16_t cap, uint16_t* out_rx)
635{
636 volatile r_usb_regs_t* reg = priv_pick(speed);
637 if (reg == nullptr) {
639 }
640 if ((buf == nullptr) || (out_rx == nullptr)) {
642 }
643 *out_rx = 0U;
644
645 /* The BRDY ISR only calls this once the DCP BRDY latch is set; if it is
646 * not, the OUT packet has not landed -- report no-data so the caller can
647 * retry on the next IRQ rather than draining a stale or empty bank. */
648 if ((reg->BRDYSTS & (uint16_t)k_ra8_usb_dcp_pipe0_bit) == 0U) {
649 return k_ra8_err_no_data;
650 }
651 /* Disable the one-shot DCP BRDY and W0C-clear the latch before draining
652 * (FSP order; protects DBLB bank edges and prevents an ISR re-storm).
653 * HUM Ch 36.2.11 "BRDYENB" p 1982 / Ch 36.2.13 "BRDYSTS" p 1984. */
654 reg->BRDYENB = (uint16_t)(reg->BRDYENB & (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit);
655 reg->BRDYSTS = (uint16_t)~(uint16_t)k_ra8_usb_dcp_pipe0_bit;
656
657 priv_select_cfifo(reg, 0U, false);
658 if (priv_wait_frdy(reg) != k_ra8_ok) {
661 }
662 /* HUM Ch 36.2.8 "CFIFOCTR : CFIFO Port Control Register", p 1979 */
663 const uint16_t dtln = (uint16_t)(reg->CFIFOCTR & k_ra8_fifoctr_dtln);
664 if (dtln == 0U) {
665 reg->CFIFOCTR = (uint16_t)k_ra8_fifoctr_bclr;
666 } else {
667 const uint16_t take = (dtln < cap) ? dtln : cap;
668 priv_fifo_read(reg, buf, take);
669 }
670 *out_rx = dtln;
672 return k_ra8_ok;
673}
674
721 const ra8_usb_setup_t* setup,
722 uint8_t* data,
723 uint16_t data_len,
724 uint16_t* out_rx,
725 bool* out_is_read)
726{
727 *out_rx = 0U;
728 bool is_read = false;
729 if (setup->w_length > 0U) {
730 if ((setup->bm_request_type & (uint16_t)k_ra8_usb_setup_dir_in) != 0U) {
731 if (data != nullptr) {
732 is_read = true;
733 }
734 }
735 }
736 *out_is_read = is_read;
737 const uint16_t mxps = (uint16_t)(reg->DCPMAXP & (uint16_t)k_ra8_usb_dcpmaxp_mxps);
738 uint16_t want = setup->w_length;
739 if (data_len < want) {
740 want = data_len;
741 }
742 /* Control-OUT with a data stage (e.g. DFU_DNLOAD): drive the payload to the
743 * device; the opposite-direction (IN) zero-length status stage follows. */
744 if ((setup->w_length > 0U) && !is_read && (data != nullptr)) {
746 const ra8_err_t oerr = internal_host_ctrl_data_out(reg, data, want, mxps);
747 if (oerr == k_ra8_ok) {
749 }
750 return oerr;
751 }
752 if (!is_read) {
753 return k_ra8_ok;
754 }
756 const ra8_err_t derr = internal_host_ctrl_data_in(reg, data, want, mxps, out_rx);
757 if (derr == k_ra8_ok) {
759 }
760 return derr;
761}
762
764 const ra8_usb_setup_t* setup,
765 uint8_t* data,
766 uint16_t data_len,
767 uint16_t* out_received)
768{
769 RA8_CHECK_NULL_PTR(setup, s_tag, "host_control_xfer: setup");
770 volatile r_usb_regs_t* reg = priv_pick(speed);
771 if (reg == nullptr) {
773 }
775 const ra8_err_t serr = internal_host_ctrl_setup(reg, setup);
776 if (serr != k_ra8_ok) {
777 return serr;
778 }
780 uint16_t rx = 0U;
781 bool is_read = false;
782 const ra8_err_t derr = internal_host_data_phase(reg, setup, data, data_len, &rx, &is_read);
783 if (derr != k_ra8_ok) {
784 return derr;
785 }
786 if (out_received != nullptr) {
787 *out_received = rx;
788 }
790 const ra8_err_t sterr = internal_host_ctrl_status(reg, is_read);
791 if (sterr == k_ra8_ok) {
793 }
794 return sterr;
795}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#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_no_data
No application data available (e.g.
Definition ra8_err.h:202
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Bounded wait-flag primitives for RA8D2 HAL drivers.
void priv_dcp_pid(volatile r_usb_regs_t *reg, ra8_usb_pid_t pid)
Set DCPCTR PID field to a specific value while preserving the rest of the register.
Definition ra8_usb.c:288
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
void priv_select_cfifo(volatile r_usb_regs_t *reg, uint16_t pipe_num, bool is_in_dir)
Set CFIFOSEL.MBW + CURPIPE + ISEL for the given pipe / direction.
Definition ra8_usb.c:199
ra8_err_t priv_wait_frdy(volatile r_usb_regs_t *reg)
Spin until CFIFOCTR.FRDY asserts or a deadline elapses.
Definition ra8_usb.c:251
volatile r_usb_regs_t * priv_pick(ra8_usb_speed_t speed)
Resolve the per-speed register pointer.
Definition ra8_usb.c:110
bool priv_is_hs(volatile const r_usb_regs_t *reg)
Detect whether reg points at the USBHS (IP1) register block.
Definition ra8_usb.c:179
ra8_err_t priv_dcp_push_chunk(volatile r_usb_regs_t *reg, const uint8_t *p, uint16_t n)
Push a single DCP IN chunk: wait for FRDY, write FIFO, pulse BVAL.
Definition ra8_usb.c:770
void priv_fifo_read(volatile r_usb_regs_t *reg, uint8_t *data, uint16_t len)
Drain the CFIFO data port into a buffer.
Definition ra8_usb.c:712
Native USB controller driver public API (device + host modes).
ra8_usb_speed_t
Selects which controller instance the call targets.
ra8_err_t ra8_usb_dcp_out_arm(ra8_usb_speed_t speed)
Implementation of ra8_usb_dcp_out_arm() – arm the DCP for control-OUT.
static ra8_err_t internal_host_data_phase(volatile r_usb_regs_t *reg, const ra8_usb_setup_t *setup, uint8_t *data, uint16_t data_len, uint16_t *out_rx, bool *out_is_read)
Classify and execute the optional DATA stage of a host control transfer.
ra8_usb_host_ctrl_stage_code_t
Stage codes recorded by the host control-transfer engine.
@ k_ra8_usb_cs_status
STATUS stage entered.
@ k_ra8_usb_cs_done
STATUS done; transfer closed.
@ k_ra8_usb_cs_data_out
DATA-OUT stage entered.
@ k_ra8_usb_cs_begin
Before the SETUP stage.
@ k_ra8_usb_cs_setup
SETUP stage completed.
@ k_ra8_usb_cs_data_in
DATA-IN stage entered.
@ k_ra8_usb_cs_data_pkt
First DATA packet received.
@ k_ra8_usb_cs_data_done
DATA stage completed.
static volatile uint8_t s_host_ctrl_stage
Last host control-transfer stage reached (bring-up diagnostic).
static ra8_err_t internal_host_ctrl_data_in(volatile r_usb_regs_t *reg, uint8_t *data, uint16_t want, uint16_t mxps, uint16_t *out_rx)
Run the DATA-IN stage of a host control read into data.
static ra8_err_t internal_host_setup_wait(volatile r_usb_regs_t *reg)
Clear the SETUP outcome flags, launch SUREQ, and await SACK/SIGN.
static ra8_err_t internal_host_ctrl_status(volatile r_usb_regs_t *reg, bool write_zlp)
Run the zero-length STATUS stage and complete the control transfer.
static ra8_err_t internal_host_ctrl_setup(volatile r_usb_regs_t *reg, const ra8_usb_setup_t *setup)
Issue the SETUP stage of a host control transfer and wait for it.
static void internal_host_ctrl_data_arm(volatile r_usb_regs_t *reg)
Arm the DCP to receive a control-read data stage.
static ra8_err_t internal_host_dcp_in_wait(volatile r_usb_regs_t *reg)
Wait for a DCP IN packet (BRDY), re-arming on NRDY give-ups.
void priv_host_program_devadd(volatile r_usb_regs_t *reg, uint8_t dev_addr)
Program DEVADDn.USBSPD with the connected device's link speed.
ra8_usb_host_ctrl_lim_t
Tunables for the polled host control-transfer engine.
@ k_ra8_usb_ctrl_poll_limit
Spin bound per control stage.
static ra8_err_t internal_host_ctrl_data_out(volatile r_usb_regs_t *reg, const uint8_t *data, uint16_t want, uint16_t mxps)
Run the DATA-OUT stage of a host control write from data.
uint8_t ra8_usb_host_ctrl_stage(void)
Last stage reached by ra8_usb_host_control_xfer (bring-up diag).
ra8_err_t ra8_usb_host_control_xfer(ra8_usb_speed_t speed, const ra8_usb_setup_t *setup, uint8_t *data, uint16_t data_len, uint16_t *out_received)
Run a complete host control transfer (SETUP, optional DATA, STATUS).
ra8_err_t ra8_usb_dcp_out_read(ra8_usb_speed_t speed, uint8_t *buf, uint16_t cap, uint16_t *out_rx)
Implementation of ra8_usb_dcp_out_read() – drain an armed control-OUT.
static ra8_err_t internal_host_wait_sts(volatile const uint16_t *sts, uint16_t mask)
Spin until a W0C status bit asserts or the deadline elapses.
Cross-TU surface for the ra8_usb driver split.
@ k_ra8_usb_devadd0_off
DEVADD0 byte offset from base.
@ k_ra8_usb_usbspd_shift
DEVADDn.USBSPD field position.
@ k_ra8_usb_devadd_stride
Bytes between DEVADDn slots.
@ k_ra8_usb_byte_bits
Bits per byte (shift constant).
@ k_ra8_usb_devsel_shift
DCPMAXP/PIPEMAXP DEVSEL pos.
@ k_ra8_usb_devsel_field_mask
DEVSEL width once shifted.
@ k_ra8_usb_pid_stall_bit
PID[1]: set for either STALL.
@ k_ra8_usb_dcpmaxp_mxps
DCPMAXP MXPS (max packet) field.
@ k_ra8_usb_rhst_mask
DVSTCTR0.RHST connected-speed.
@ k_ra8_usb_dcp_pipe0_bit
BRDYSTS/BEMPSTS DCP (pipe 0) bit.
@ k_ra8_usb_setup_dir_in
bmRequestType device-to-host bit.
USB Full-Speed + High-Speed controller layout for the Renesas RA8D2.
@ k_ra8_int1_bit_sign
SETUP transaction failed (3x).
@ k_ra8_int1_bit_sack
SETUP transaction ACKed.
@ k_ra8_pid_buf
BUF response (transmit/receive).
@ k_ra8_pid_nak
NAK response.
@ k_ra8_fifoctr_bclr
Buffer clear.
@ k_ra8_fifoctr_dtln
Data length (write-bytes-rem).
@ k_ra8_fifoctr_bval
Buffer valid.
@ k_ra8_dcpctr_bit_sureq
Send USB request (host mode).
@ k_ra8_dcpctr_bit_sqset
Sequence toggle set.
@ k_ra8_dcpctr_bit_ccpl
Control transfer end enable.
@ k_ra8_dcpctr_bit_sureqclr
SUREQ clear (USBHS host only).
@ k_ra8_dcpcfg_bit_dir
Transfer direction (host: 0 = IN, 1 = OUT).
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 CFIFOCTR
+0x022 Control FIFO control.
volatile uint16_t DCPMAXP
+0x05E DCP Max Packet.
volatile uint16_t USBLENG
+0x05A USB Request wLength.
volatile uint16_t DVSTCTR0
+0x008 Device State Control.
volatile uint16_t BRDYENB
+0x036 BRDY Interrupt Enable.
volatile uint16_t BEMPSTS
+0x04A BEMP Interrupt Status.
volatile uint16_t INTSTS1
+0x042 Interrupt Status 1.
volatile uint16_t INTENB1
+0x032 Interrupt Enable 1.
volatile uint16_t DCPCFG
+0x05C DCP Configuration.
volatile uint16_t NRDYSTS
+0x048 NRDY Interrupt Status.
volatile uint16_t BEMPENB
+0x03A BEMP Interrupt Enable.
volatile uint16_t BRDYSTS
+0x046 BRDY Interrupt Status.
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.