diff options
| author | hathach <[email protected]> | 2026-03-30 12:19:20 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-03-30 13:02:17 +0700 |
| commit | 31ec5a7d3afdb79c95cfc6eeaf9659066d83fd69 (patch) | |
| tree | e64699716a590f067b615c6030bee1800a2e2344 | |
| parent | dfcd271400c31e15a7d38b319c65173c3e4227c7 (diff) | |
hcd rp2 add double buffered for control endpoint transfers.
| -rw-r--r-- | src/portable/raspberrypi/rp2040/hcd_rp2040.c | 42 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/rp2040_usb.c | 34 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/rp2040_usb.h | 7 |
3 files changed, 39 insertions, 44 deletions
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 31bbfc0be..3a99e7275 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -55,12 +55,6 @@ static hw_endpoint_t ep_pool[USB_MAX_ENDPOINTS]; static hw_endpoint_t *epx = &ep_pool[0]; // current active endpoint -// Flags we set by default in sie_ctrl (we add other bits on top) -enum { - SIE_CTRL_BASE = USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS, - SIE_CTRL_BASE_MASK = USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS | USB_SIE_CTRL_SOF_EN_BITS | - USB_SIE_CTRL_KEEP_ALIVE_EN_BITS -}; enum { SIE_CTRL_SPEED_DISCONNECT = 0, @@ -187,7 +181,7 @@ static void __tusb_irq_path_func(epx_switch_ep)(hw_endpoint_t *ep) { io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl; epx_ctrl_prepare(ep); - rp2usb_buffer_start(ep, ep_reg, buf_reg, is_rx, is_rx || ep->transfer_type == TUSB_XFER_INTERRUPT); + rp2usb_buffer_start(ep, ep_reg, buf_reg, is_rx, ep->transfer_type == TUSB_XFER_INTERRUPT); usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB)); sie_start_xfer(false, is_rx, ep->need_pre); // start transfer @@ -340,26 +334,20 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) { // RP2040: on SOF, stop and switch if there's a pending ep if (status & USB_INTS_HOST_SOF_BITS) { (void)usb_hw->sof_rd; // clear SOF by reading SOF_RD - if (epx->active && tu_edpt_number(epx->ep_addr) != 0) { - hw_endpoint_t *next_ep = epx_next_pending(epx); - if (next_ep) { + hw_endpoint_t *next_ep = epx_next_pending(epx); + if (next_ep == NULL) { + // no more pending --> disable SOF + usb_hw_clear->inte = USB_INTE_HOST_SOF_BITS; + usb_hw->nak_poll = USB_NAK_POLL_RESET; + } else { + // stop transfer if is active + if (epx->active) { usb_hw_set->sie_ctrl = USB_SIE_CTRL_STOP_TRANS_BITS; while (usb_hw->sie_ctrl & USB_SIE_CTRL_STOP_TRANS_BITS) {} - busy_wait_at_least_cycles(12); - if (usb_hw->buf_status & 1u) { - usb_hw->nak_poll = USB_NAK_POLL_RESET; - handle_buf_status_isr(); - } else { - epx_switch_ep(next_ep); - } - } else { - usb_hw_clear->inte = USB_INTE_HOST_SOF_BITS; - usb_hw->nak_poll = USB_NAK_POLL_RESET; } - } else if (!epx_next_pending(epx)) { - // EPX is on control endpoint or inactive — disable SOF if nothing pending - usb_hw_clear->inte = USB_INTE_HOST_SOF_BITS; - usb_hw->nak_poll = USB_NAK_POLL_RESET; + + epx_save_context(); + epx_switch_ep(next_ep); } } #endif @@ -602,10 +590,8 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b usb_hw_set->nak_poll = USB_NAK_POLL_STOP_EPX_ON_NAK_BITS; #else // Only enable SOF round-robin for non-control endpoints - if (tu_edpt_number(epx->ep_addr) != 0) { - usb_hw->nak_poll = (300 << USB_NAK_POLL_DELAY_FS_LSB) | (300 << USB_NAK_POLL_DELAY_LS_LSB); - usb_hw_set->inte = USB_INTE_HOST_SOF_BITS; - } + usb_hw->nak_poll = (300 << USB_NAK_POLL_DELAY_FS_LSB) | (300 << USB_NAK_POLL_DELAY_LS_LSB); + usb_hw_set->inte = USB_INTE_HOST_SOF_BITS; #endif } else { const uint8_t ep_num = tu_edpt_number(ep->ep_addr); diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 49c948af6..ffb5fcbc6 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -283,7 +283,7 @@ void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, u const bool is_rx = (is_host == (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN)); #if CFG_TUH_ENABLED - const bool force_single = (is_host && (is_rx || ep->transfer_type == TUSB_XFER_INTERRUPT)); + const bool force_single = (is_host && ep->transfer_type == TUSB_XFER_INTERRUPT); #else const bool force_single = false; #endif @@ -339,23 +339,17 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_ return false; } - const bool is_double = (ep_reg != NULL && ((*ep_reg) & EP_CTRL_DOUBLE_BUFFERED_BITS)); const bool is_host = rp2usb_is_host_mode(); - - #if CFG_TUSB_RP2_ERRATA_E4 - const bool need_e4_fix = (is_host && !is_double); - #endif + const bool is_double = (ep_reg != NULL && ((*ep_reg) & EP_CTRL_DOUBLE_BUFFERED_BITS)); // Double-buffered: buf_id from BUFF_CPU_SHOULD_HANDLE indicates which buffer completed. - // RP2040-E4 (host only): in single-buffered multi-packet transfers, the controller may write completion status to - // BUF1 half instead of BUF0. The side effect that controller can execute an extra packet after writing to BUF1 - // since it leave BUF0 intact, which can be poll before buf_status interrupt is trigger. - // Workaround for the side effect, we will enable double-buffered for rx but only prepare 1 buf at a time. + // BUF1 half instead of BUF0. The side effect is that controller can execute an extra packet after writing to BUF1 + // since it leaves BUF0 intact, which can be polled before buf_status interrupt is triggered. uint8_t *dpram_buf = ep->dpram_buf; if (buf_id) { #if CFG_TUSB_RP2_ERRATA_E4 - if (!need_e4_fix) // incorrect buf_id, buffer pointer is still buf0 + if (!(is_host && !is_double)) // incorrect buf_id, buffer data is still buf0 #endif { dpram_buf += 64; // buf1 offset @@ -368,16 +362,24 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_ const uint16_t xact_bytes = bufctrl_sync16(ep, is_rx, buf_ctrl16, dpram_buf); const bool is_last = buf_ctrl16 & USB_BUF_CTRL_LAST; const bool is_short = xact_bytes < ep->max_packet_size; - const bool is_done = is_short || (buf_ctrl16 & USB_BUF_CTRL_LAST); + const bool is_done = is_short || is_last; - // Short packet on rx with double buffer: abort the other half (if not last) and reset double-buffer state. + // Short packet on rx with double buffer: abort the other half (if not last) and reset the buffer control. // The other buffer may be: (a) still AVAIL, (b) in-progress (controller receiving), or (c) already completed. // We must abort to safely reclaim it. If it has valid data (FULL), save as future for the next transfer. - // After abort, zero buf_ctrl. - // Note: Host mode we cannot save next transfer data due to shared epx --> force single + // Note: Host mode current does not save next transfer data due to shared epx --> potential issue. However, RP2040-E4 + // causes more or less of the same issue since it write to buf1 and next time it continues to transfer on buf0 (stale) if (is_short && is_double && is_rx && !is_last) { #if CFG_TUH_ENABLED - if (is_host) {} + if (is_host) { + // stop current transfer + uint32_t sie_ctrl = usb_hw->sie_ctrl & SIE_CTRL_BASE_MASK; + sie_ctrl |= USB_SIE_CTRL_STOP_TRANS_BITS; + usb_hw->sie_ctrl = sie_ctrl; + // maybe wait until STOP_TRANS bit is clear + + *buf_reg = 0; // reset buffer control + } #endif #if CFG_TUD_ENABLED diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index c4c7e625e..2ba9d018e 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -70,6 +70,13 @@ #define __tusb_irq_path_func(x) x #endif +// Flags we set by default in sie_ctrl (we add other bits on top) +enum { + SIE_CTRL_BASE = USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS, + SIE_CTRL_BASE_MASK = USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS | USB_SIE_CTRL_SOF_EN_BITS | + USB_SIE_CTRL_KEEP_ALIVE_EN_BITS +}; + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ |
