diff options
| author | hathach <[email protected]> | 2026-03-27 17:14:37 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-03-27 17:14:37 +0700 |
| commit | d9d28b7e94aac295e08db5fff8649e1467a37399 (patch) | |
| tree | 313d69b0757ccb6be46286ad2f9700ce25d040ae /src | |
| parent | dd08939f68cd5e41f45a942efee41dba85110619 (diff) | |
rename and clean up
Diffstat (limited to 'src')
| -rw-r--r-- | src/portable/raspberrypi/rp2040/dcd_rp2040.c | 33 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/hcd_rp2040.c | 233 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/rp2040_usb.c | 83 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/rp2040_usb.h | 27 |
4 files changed, 158 insertions, 218 deletions
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index ea791f4f6..b52c3114f 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -148,14 +148,9 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) { while ((usb_hw->abort_done & abort_mask) != abort_mask) {} } - uint32_t buf_ctrl = USB_BUF_CTRL_SEL; // reset to buffer 0 - if (ep->next_pid) { - buf_ctrl |= USB_BUF_CTRL_DATA1_PID; - } - - io_rw_32 *buf_ctrl_reg = get_buf_ctrl(epnum, dir); - hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl); - hw_endpoint_reset_transfer(ep); + io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); + *buf_reg = 0; // clear buffer control + rp2usb_reset_transfer(ep); if (rp2040_chip_version() >= 2) { usb_hw_clear->abort_done = abort_mask; @@ -185,9 +180,9 @@ static void __tusb_irq_path_func(handle_hw_buff_status)(void) { usb_hw_clear->buf_status = bit; buf_status &= ~bit; - if (hw_endpoint_xfer_continue(ep, ep_reg, buf_reg, buf_id)) { + if (rp2usb_xfer_continue(ep, ep_reg, buf_reg, buf_id)) { const uint16_t xferred_len = ep->xferred_len; - hw_endpoint_reset_transfer(ep); + rp2usb_reset_transfer(ep); dcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); } } @@ -281,7 +276,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) { if (buf0_idle && buf1_idle) { // both are idle, start fresh io_rw_32 *ep_reg = get_ep_ctrl(i, TUSB_DIR_IN); - hw_endpoint_buffer_start(ep, ep_reg, buf_reg32); + rp2usb_buffer_start(ep, ep_reg, buf_reg32); } else if (buf0_idle) { uint16_t buf0 = bufctrl_prepare16(ep, ep->dpram_buf, false); bufctrl_write16(buf_reg16, buf0); @@ -534,7 +529,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to hw_endpoint_t *ep = hw_endpoint_get(epnum, dir); io_rw_32 *ep_reg = get_ep_ctrl(epnum, dir); io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); - hw_endpoint_xfer_start(ep, ep_reg, buf_reg, buffer, NULL, total_bytes); + rp2usb_xfer_start(ep, ep_reg, buf_reg, buffer, NULL, total_bytes); return true; } @@ -545,7 +540,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t hw_endpoint_t *ep = hw_endpoint_get(epnum, dir); io_rw_32 *ep_reg = get_ep_ctrl(epnum, dir); io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); - hw_endpoint_xfer_start(ep, ep_reg, buf_reg, NULL, ff, total_bytes); + rp2usb_xfer_start(ep, ep_reg, buf_reg, NULL, ff, total_bytes); return true; } #endif @@ -554,15 +549,17 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; const uint8_t epnum = tu_edpt_number(ep_addr); const tusb_dir_t dir = tu_edpt_dir(ep_addr); + hw_endpoint_t *ep = hw_endpoint_get(epnum, dir); if (epnum == 0) { // A stall on EP0 has to be armed so it can be cleared on the next setup packet usb_hw_set->ep_stall_arm = (dir == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS; } - // stall and clear current pending buffer, may need to use EP_ABORT - io_rw_32 *buf_ctrl_reg = get_buf_ctrl(epnum, dir); - hwbuf_ctrl_set(buf_ctrl_reg, USB_BUF_CTRL_STALL); + // abort first then stall and clear current pending buffer + hw_endpoint_abort_xfer(ep); + io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); + *buf_reg = USB_BUF_CTRL_STALL; } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { @@ -573,8 +570,8 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { if (epnum != 0) { struct hw_endpoint* ep = hw_endpoint_get(epnum, dir); ep->next_pid = 0; // reset data toggle - io_rw_32 *buf_ctrl_reg = get_buf_ctrl(epnum, dir); - hwbuf_ctrl_clear_mask(buf_ctrl_reg, USB_BUF_CTRL_STALL); + io_rw_32 *buf_reg = get_buf_ctrl(epnum, dir); + *buf_reg = 0; } } diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 3f4c95422..379ba075d 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -119,14 +119,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr) { // forward declaration static void __tusb_irq_path_func(edpt_schedule_next)(void); TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer(uint32_t value); -static void edpt_xfer(hw_endpoint_t *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len); +static void epx_xfer(hw_endpoint_t *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len); static void __tusb_irq_path_func(hw_xfer_complete)(hw_endpoint_t *ep, xfer_result_t xfer_result) { // Mark transfer as done before we tell the tinyusb stack uint8_t dev_addr = ep->dev_addr; uint8_t ep_addr = ep->ep_addr; uint xferred_len = ep->xferred_len; - hw_endpoint_reset_transfer(ep); + rp2usb_reset_transfer(ep); hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true); // Schedule next pending EPX transfer (only for non-interrupt endpoints) @@ -150,7 +150,7 @@ static void __tusb_irq_path_func(handle_hwbuf_status)(void) { io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl; io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl; - if (hw_endpoint_xfer_continue(epx, ep_reg, buf_reg, buf_id)) { + if (rp2usb_xfer_continue(epx, ep_reg, buf_reg, buf_id)) { hw_xfer_complete(epx, XFER_RESULT_SUCCESS); } } @@ -174,7 +174,7 @@ static void __tusb_irq_path_func(handle_hwbuf_status)(void) { if (ep->interrupt_num == epnum) { io_rw_32 *ep_reg = dpram_int_ep_ctrl(ep->interrupt_num); io_rw_32 *buf_reg = dpram_int_ep_buffer_ctrl(ep->interrupt_num); - const bool done = hw_endpoint_xfer_continue(ep, ep_reg, buf_reg, 0); + const bool done = rp2usb_xfer_continue(ep, ep_reg, buf_reg, 0); if (done) { hw_xfer_complete(ep, XFER_RESULT_SUCCESS); } @@ -185,8 +185,7 @@ static void __tusb_irq_path_func(handle_hwbuf_status)(void) { } // All non-interrupt endpoints use shared EPX. -// Forward declared above hw_xfer_complete, defined after edpt_xfer below. - +// Forward declared above hw_xfer_complete, defined after epx_xfer below. // Save current EPX context, mark pending, switch to next_ep static void __tusb_irq_path_func(epx_switch_ep)(hw_endpoint_t *next_ep) { const uint32_t buf_ctrl = usbh_dpram->epx_buf_ctrl; @@ -214,7 +213,7 @@ static void __tusb_irq_path_func(epx_switch_ep)(hw_endpoint_t *next_ep) { } else { uint16_t prev_xferred = next_ep->xferred_len; next_ep->pending = 0; - edpt_xfer(next_ep, next_ep->user_buf, NULL, next_ep->remaining_len); + epx_xfer(next_ep, next_ep->user_buf, NULL, next_ep->remaining_len); epx->xferred_len += prev_xferred; } } @@ -344,57 +343,6 @@ void __tusb_irq_path_func(hcd_int_handler)(uint8_t rhport, bool in_isr) { hcd_rp2040_irq(); } -static void hw_endpoint_init(hw_endpoint_t *ep, uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc) { - const uint8_t ep_addr = ep_desc->bEndpointAddress; - const uint16_t wMaxPacketSize = tu_edpt_packet_size(ep_desc); - const uint8_t transfer_type = ep_desc->bmAttributes.xfer; - // const uint8_t bmInterval = ep_desc->bInterval; - - ep->max_packet_size = wMaxPacketSize; - ep->ep_addr = ep_addr; - ep->dev_addr = dev_addr; - ep->transfer_type = transfer_type; - ep->need_pre = need_pre(dev_addr); - ep->next_pid = 0u; - - if (transfer_type != TUSB_XFER_INTERRUPT) { - ep->dpram_buf = usbh_dpram->epx_data; - } else { - // from 15 interrupt endpoints pool - uint8_t int_idx; - for (int_idx = 0; int_idx < USB_HOST_INTERRUPT_ENDPOINTS; int_idx++) { - if (!tu_bit_test(usb_hw->int_ep_ctrl, 1 + int_idx)) { - ep->interrupt_num = int_idx + 1; - break; - } - } - assert(int_idx < USB_HOST_INTERRUPT_ENDPOINTS); - assert(ep_desc->bInterval > 0); - - //------------- dpram buf -------------// - // 15x64 last bytes of DPRAM for interrupt endpoint buffers - ep->dpram_buf = (uint8_t *)(USBCTRL_DPRAM_BASE + USB_DPRAM_MAX - (int_idx + 1u) * 64u); - uint32_t ep_ctrl = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER | - (TUSB_XFER_INTERRUPT << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->dpram_buf) | - (uint32_t)((ep_desc->bInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB); - usbh_dpram->int_ep_ctrl[int_idx].ctrl = ep_ctrl; - - //------------- address control -------------// - const uint8_t epnum = tu_edpt_number(ep_addr); - uint32_t addr_ctrl = (uint32_t)(dev_addr | (epnum << USB_ADDR_ENDP1_ENDPOINT_LSB)); - if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { - addr_ctrl |= USB_ADDR_ENDP1_INTEP_DIR_BITS; - } - if (ep->need_pre) { - addr_ctrl |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS; - } - usb_hw->int_ep_addr_ctrl[int_idx] = addr_ctrl; - - // Finally, activate interrupt endpoint - usb_hw_set->int_ep_ctrl = 1u << ep->interrupt_num; - } -} - //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ @@ -528,7 +476,55 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress); hw_endpoint_t *ep = edpt_alloc(); TU_ASSERT(ep); - hw_endpoint_init(ep, dev_addr, ep_desc); + + const uint8_t ep_addr = ep_desc->bEndpointAddress; + const uint16_t max_packet_size = tu_edpt_packet_size(ep_desc); + const uint8_t transfer_type = ep_desc->bmAttributes.xfer; + // const uint8_t bmInterval = ep_desc->bInterval; + + ep->max_packet_size = max_packet_size; + ep->ep_addr = ep_addr; + ep->dev_addr = dev_addr; + ep->transfer_type = transfer_type; + ep->need_pre = need_pre(dev_addr); + ep->next_pid = 0u; + + if (transfer_type != TUSB_XFER_INTERRUPT) { + ep->dpram_buf = usbh_dpram->epx_data; + } else { + // from 15 interrupt endpoints pool + uint8_t int_idx; + for (int_idx = 0; int_idx < USB_HOST_INTERRUPT_ENDPOINTS; int_idx++) { + if (!tu_bit_test(usb_hw->int_ep_ctrl, 1 + int_idx)) { + ep->interrupt_num = int_idx + 1; + break; + } + } + assert(int_idx < USB_HOST_INTERRUPT_ENDPOINTS); + assert(ep_desc->bInterval > 0); + + //------------- dpram buf -------------// + // 15x64 last bytes of DPRAM for interrupt endpoint buffers + ep->dpram_buf = (uint8_t *)(USBCTRL_DPRAM_BASE + USB_DPRAM_MAX - (int_idx + 1u) * 64u); + uint32_t ep_ctrl = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER | + (TUSB_XFER_INTERRUPT << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->dpram_buf) | + (uint32_t)((ep_desc->bInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB); + usbh_dpram->int_ep_ctrl[int_idx].ctrl = ep_ctrl; + + //------------- address control -------------// + const uint8_t epnum = tu_edpt_number(ep_addr); + uint32_t addr_ctrl = (uint32_t)(dev_addr | (epnum << USB_ADDR_ENDP1_ENDPOINT_LSB)); + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) { + addr_ctrl |= USB_ADDR_ENDP1_INTEP_DIR_BITS; + } + if (ep->need_pre) { + addr_ctrl |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS; + } + usb_hw->int_ep_addr_ctrl[int_idx] = addr_ctrl; + + // Finally, activate interrupt endpoint + usb_hw_set->int_ep_ctrl = 1u << ep->interrupt_num; + } return true; } @@ -551,54 +547,51 @@ TU_ATTR_ALWAYS_INLINE static inline void sie_start_xfer(uint32_t value) { usb_hw->sie_ctrl = value | USB_SIE_CTRL_START_TRANS_BITS; } -static void edpt_xfer(hw_endpoint_t *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len) { - if (ep->transfer_type == TUSB_XFER_INTERRUPT) { - // For interrupt endpoint control and buffer is already configured - // Note: Interrupt is single buffered only - io_rw_32 *ep_reg = dpram_int_ep_ctrl(ep->interrupt_num); - io_rw_32 *buf_reg = dpram_int_ep_buffer_ctrl(ep->interrupt_num); - hw_endpoint_xfer_start(ep, ep_reg, buf_reg, buffer, ff, total_len); - } else { - const uint8_t ep_num = tu_edpt_number(ep->ep_addr); - const tusb_dir_t ep_dir = tu_edpt_dir(ep->ep_addr); +// start a transfer on epx endpoint +static void epx_xfer(hw_endpoint_t *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len) { + const uint8_t ep_num = tu_edpt_number(ep->ep_addr); + const tusb_dir_t ep_dir = tu_edpt_dir(ep->ep_addr); - // RP2040-E4: USB host writes status to upper half of buffer control in single buffered mode. - // The buffer selector toggles even in single-buffered mode, so the previous transfer's status - // may have been written to BUF1 half, leaving BUF0 with stale AVAILABLE bit. Clear it here. -#if defined(PICO_RP2040) && PICO_RP2040 == 1 - usbh_dpram->epx_buf_ctrl = 0; -#endif + // RP2040-E4: USB host writes status to upper half of buffer control in single buffered mode. + // The buffer selector toggles even in single-buffered mode, so the previous transfer's status + // may have been written to BUF1 half, leaving BUF0 with stale AVAILABLE bit. Clear it here. + #if defined(PICO_RP2040) && PICO_RP2040 == 1 + usbh_dpram->epx_buf_ctrl = 0; + #endif - // ep control - const uint32_t dpram_offset = hw_data_offset(ep->dpram_buf); - const uint32_t ep_ctrl = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER | - ((uint32_t)ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset; - usbh_dpram->epx_ctrl = ep_ctrl; + // ep control + const uint32_t dpram_offset = hw_data_offset(ep->dpram_buf); + const uint32_t ep_ctrl = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER | + ((uint32_t)ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset; + usbh_dpram->epx_ctrl = ep_ctrl; - io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl; - io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl; - hw_endpoint_xfer_start(ep, ep_reg, buf_reg, buffer, ff, total_len); + io_rw_32 *ep_reg = &usbh_dpram->epx_ctrl; + io_rw_32 *buf_reg = &usbh_dpram->epx_buf_ctrl; + rp2usb_xfer_start(ep, ep_reg, buf_reg, buffer, ff, total_len); - // addr control - usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB)); + // addr control + usb_hw->dev_addr_ctrl = (uint32_t)(ep->dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB)); - epx = ep; + epx = ep; - // start transfer - const uint32_t sie_ctrl = (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS) | - (ep->need_pre ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0); - sie_start_xfer(sie_ctrl); - } + // start transfer + const uint32_t sie_ctrl = (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS) | + (ep->need_pre ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0); + sie_start_xfer(sie_ctrl); } // Schedule next pending EPX transfer from ISR context static void __tusb_irq_path_func(edpt_schedule_next)(void) { // EPX may already be active if the completion callback started a new transfer - if (epx->active) return; + if (epx->active) { + return; + } for (uint i = 0; i < TU_ARRAY_SIZE(ep_pool); i++) { hw_endpoint_t *ep = &ep_pool[i]; - if (ep->pending == 0) continue; + if (ep->pending == 0) { + continue; + } if (ep->pending == 2) { // Pending setup: DPRAM already has the setup packet @@ -618,7 +611,7 @@ static void __tusb_irq_path_func(edpt_schedule_next)(void) { // Pending data transfer: preserve partial progress from preemption uint16_t prev_xferred = ep->xferred_len; ep->pending = 0; - edpt_xfer(ep, ep->user_buf, NULL, ep->remaining_len); + epx_xfer(ep, ep->user_buf, NULL, ep->remaining_len); epx->xferred_len += prev_xferred; // restore partial progress } return; // start only one transfer @@ -631,31 +624,39 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b hw_endpoint_t *ep = edpt_find(dev_addr, ep_addr); TU_ASSERT(ep); - // Control endpoint can change direction 0x00 <-> 0x80 - if (ep_addr != ep->ep_addr) { - ep->ep_addr = ep_addr; - ep->next_pid = 1; // data and status stage start with DATA1 - } + if (ep->transfer_type == TUSB_XFER_INTERRUPT) { + // For interrupt endpoint control and buffer is already configured + // Note: Interrupt is single buffered only + io_rw_32 *ep_reg = dpram_int_ep_ctrl(ep->interrupt_num); + io_rw_32 *buf_reg = dpram_int_ep_buffer_ctrl(ep->interrupt_num); + rp2usb_xfer_start(ep, ep_reg, buf_reg, buffer, NULL, buflen); + } else { + // Control endpoint can change direction 0x00 <-> 0x80 when changing stages + if (ep_addr != ep->ep_addr) { + ep->ep_addr = ep_addr; + ep->next_pid = 1; // data and status stage start with DATA1 + } - // If EPX is busy with another transfer, mark as pending - if (ep->transfer_type != TUSB_XFER_INTERRUPT && epx->active) { - ep->user_buf = buffer; - ep->remaining_len = buflen; - ep->pending = 1; -#ifdef HAS_STOP_EPX_ON_NAK - usb_hw_set->nak_poll = USB_NAK_POLL_STOP_EPX_ON_NAK_BITS; -#else - // Only enable SOF preemption 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; + // If EPX is busy with another transfer, mark as pending + if (epx->active) { + ep->user_buf = buffer; + ep->remaining_len = buflen; + ep->pending = 1; + + #ifdef HAS_STOP_EPX_ON_NAK + 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; + } + #endif + return true; } -#endif - return true; - } - edpt_xfer(ep, buffer, NULL, buflen); + epx_xfer(ep, buffer, NULL, buflen); + } return true; } diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 433bd261d..44191092e 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -96,7 +96,7 @@ void rp2usb_init(void) { TU_LOG2_INT(sizeof(hw_endpoint_t)); } -void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) { +void __tusb_irq_path_func(rp2usb_reset_transfer)(hw_endpoint_t *ep) { ep->active = false; ep->remaining_len = 0; ep->xferred_len = 0; @@ -104,61 +104,23 @@ void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) { ep->is_xfer_fifo = false; } -void __tusb_irq_path_func(hwbuf_ctrl_update)(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask) { - const bool is_host = rp2usb_is_host_mode(); - uint32_t value = 0; - uint32_t buf_ctrl = *buf_ctrl_reg; - - if (and_mask) { - value = buf_ctrl & and_mask; - } - - if (or_mask) { - value |= or_mask; - if (or_mask & USB_BUF_CTRL_AVAIL) { - if (buf_ctrl & USB_BUF_CTRL_AVAIL) { - if (is_host) { -#if defined(PICO_RP2040) && PICO_RP2040 == 1 - // RP2040-E4: host buffer selector toggles in single-buffered mode, causing status - // to be written to BUF1 half and leaving stale AVAILABLE in BUF0 half. Clear it. - *buf_ctrl_reg = 0; -#else - panic("buf_ctrl @ 0x%lX already available (host)", (uintptr_t)buf_ctrl_reg); -#endif - } else { - panic("buf_ctrl @ 0x%lX already available", (uintptr_t)buf_ctrl_reg); - } - } - *buf_ctrl_reg = value & ~USB_BUF_CTRL_AVAIL; - - // Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access: after write to buffer control, - // wait for USB controller to see the update before setting AVAILABLE. - // Don't need delay in host mode as host is in charge of when to start the transaction. - if (!is_host) { - busy_wait_at_least_cycles(12); - } - } - } - - *buf_ctrl_reg = value; -} - void __tusb_irq_path_func(bufctrl_write32)(io_rw_32 *buf_reg, uint32_t value) { const uint32_t current = *buf_reg; const uint32_t avail_mask = USB_BUF_CTRL_AVAIL | (USB_BUF_CTRL_AVAIL << 16); if (current & value & avail_mask) { panic("buf_ctrl @ 0x%lX already available", (uintptr_t)buf_reg); } - *buf_reg = value & ~USB_BUF_CTRL_AVAIL; // write other bits first + *buf_reg = value & ~(USB_BUF_CTRL_AVAIL | (USB_BUF_CTRL_AVAIL << 16)); // write other bits first // Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access: after write to buffer control, // wait for USB controller to see the update before setting AVAILABLE. // Don't need delay in host mode as host is in charge of when to start the transaction. - if (!rp2usb_is_host_mode() && (value & (USB_BUF_CTRL_AVAIL | (USB_BUF_CTRL_AVAIL << 16)))) { - busy_wait_at_least_cycles(12); + if (value & (USB_BUF_CTRL_AVAIL | (USB_BUF_CTRL_AVAIL << 16))) { + if (!rp2usb_is_host_mode()) { + busy_wait_at_least_cycles(12); + } + *buf_reg = value; // then set AVAILABLE bit last } - - *buf_reg = value; // then set AVAILABLE bit (if set) last } void __tusb_irq_path_func(bufctrl_write16)(io_rw_16 *buf_reg16, uint16_t value) { @@ -171,10 +133,12 @@ void __tusb_irq_path_func(bufctrl_write16)(io_rw_16 *buf_reg16, uint16_t value) // Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access: after write to buffer control, // wait for USB controller to see the update before setting AVAILABLE. // Don't need delay in host mode as host is in charge of when to start the transaction. - if (!rp2usb_is_host_mode() && (value & USB_BUF_CTRL_AVAIL)) { - busy_wait_at_least_cycles(12); + if (value & USB_BUF_CTRL_AVAIL) { + if (!rp2usb_is_host_mode()) { + busy_wait_at_least_cycles(12); + } + *buf_reg16 = value; // then set AVAILABLE bit last } - *buf_reg16 = value; // then set AVAILABLE bit (if set) last } // prepare buffer, move data if tx, return buffer control @@ -217,7 +181,7 @@ uint16_t __tusb_irq_path_func(bufctrl_prepare16)(struct hw_endpoint *ep, uint8_t } // Start transaction on hw buffer -void __tusb_irq_path_func(hw_endpoint_buffer_start)(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg) { +void __tusb_irq_path_func(rp2usb_buffer_start)(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg) { const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr); const bool is_host = rp2usb_is_host_mode(); @@ -228,14 +192,6 @@ void __tusb_irq_path_func(hw_endpoint_buffer_start)(struct hw_endpoint *ep, io_r is_rx = (dir == TUSB_DIR_OUT); } - // 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 polled 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. - #if CFG_TUSB_RP2_ERRATA_E4 - - #endif - // always compute and start with buffer 0 uint32_t buf_ctrl = bufctrl_prepare16(ep, ep->dpram_buf, is_rx) | USB_BUF_CTRL_SEL; @@ -268,15 +224,15 @@ void __tusb_irq_path_func(hw_endpoint_buffer_start)(struct hw_endpoint *ep, io_r bufctrl_write32(buf_reg, buf_ctrl); } -void hw_endpoint_xfer_start(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t *buffer, tu_fifo_t *ff, - uint16_t total_len) { +void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t *buffer, tu_fifo_t *ff, + uint16_t total_len) { (void) ff; hw_endpoint_lock_update(ep, 1); if (ep->active) { // TODO: Is this acceptable for interrupt packets? TU_LOG(1, "WARN: starting new transfer on already active ep %02X\r\n", ep->ep_addr); - hw_endpoint_reset_transfer(ep); + rp2usb_reset_transfer(ep); } // Fill in info now that we're kicking off the hw @@ -310,7 +266,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 * // all data has been received, no need to start hw transfer ep->active = false; const uint16_t xferred_len = ep->xferred_len; - hw_endpoint_reset_transfer(ep); + rp2usb_reset_transfer(ep); const bool is_host = rp2usb_is_host_mode(); #if CFG_TUH_ENABLED @@ -342,7 +298,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 * } #endif - hw_endpoint_buffer_start(ep, ep_reg, buf_reg); + rp2usb_buffer_start(ep, ep_reg, buf_reg); hw_endpoint_lock_update(ep, -1); } @@ -382,7 +338,8 @@ static uint16_t __tusb_irq_path_func(hwbuf_sync)(hw_endpoint_t *ep, bool is_rx, // Returns true if transfer is complete. // buf_id: which buffer completed (from BUFF_CPU_SHOULD_HANDLE, only used for double-buffered). -bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t buf_id) { +bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, + uint8_t buf_id) { hw_endpoint_lock_update(ep, 1); const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr); diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index 7b79cd2b1..34687020f 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -132,11 +132,11 @@ TU_ATTR_ALWAYS_INLINE static inline bool rp2usb_is_host_mode(void) { //--------------------------------------------------------------------+ // Hardware Endpoint //--------------------------------------------------------------------+ -void hw_endpoint_xfer_start(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t *buffer, tu_fifo_t *ff, - uint16_t total_len); -bool hw_endpoint_xfer_continue(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t buf_id); -void hw_endpoint_buffer_start(struct hw_endpoint *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg); -void hw_endpoint_reset_transfer(struct hw_endpoint *ep); +void rp2usb_xfer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t *buffer, tu_fifo_t *ff, + uint16_t total_len); +bool rp2usb_xfer_continue(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg, uint8_t buf_id); +void rp2usb_buffer_start(hw_endpoint_t *ep, io_rw_32 *ep_reg, io_rw_32 *buf_reg); +void rp2usb_reset_transfer(hw_endpoint_t *ep); TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) { // todo add critsec as necessary to prevent issues between worker and IRQ... @@ -147,26 +147,11 @@ TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_lock_update(__unused struct //--------------------------------------------------------------------+ // Hardware Buffer //--------------------------------------------------------------------+ -void hwbuf_ctrl_update(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask); - void bufctrl_write32(io_rw_32 *buf_reg, uint32_t value); void bufctrl_write16(io_rw_16 *buf_reg16, uint16_t value); - uint16_t bufctrl_prepare16(struct hw_endpoint *ep, uint8_t *dpram_buf, bool is_rx); -TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set(io_rw_32 *buf_ctrl_reg, uint32_t value) { - hwbuf_ctrl_update(buf_ctrl_reg, 0, value); -} - -TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) { - hwbuf_ctrl_update(buf_ctrl_reg, ~value, value); -} - -TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_clear_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) { - hwbuf_ctrl_update(buf_ctrl_reg, ~value, 0); -} - -static inline uintptr_t hw_data_offset(uint8_t *buf) { +TU_ATTR_ALWAYS_INLINE static inline uintptr_t hw_data_offset(uint8_t *buf) { // Remove usb base from buffer pointer return (uintptr_t)buf ^ (uintptr_t)usb_dpram; } |
