summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-03-27 17:14:37 +0700
committerhathach <[email protected]>2026-03-27 17:14:37 +0700
commitd9d28b7e94aac295e08db5fff8649e1467a37399 (patch)
tree313d69b0757ccb6be46286ad2f9700ce25d040ae /src
parentdd08939f68cd5e41f45a942efee41dba85110619 (diff)
rename and clean up
Diffstat (limited to 'src')
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c33
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c233
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c83
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h27
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;
}