summaryrefslogtreecommitdiff
path: root/src/portable/raspberrypi
diff options
context:
space:
mode:
authorMengsk <[email protected]>2022-11-07 12:47:41 +0100
committerMengsk <[email protected]>2022-11-07 12:47:41 +0100
commit9d3d8fd5b0788b811ad283d10d37dfd1b1005224 (patch)
treef66b39fe968cc1a6e46e3074bbda9b907064bc15 /src/portable/raspberrypi
parent1eae139aa94130a63ecc4725852cb69c02566c82 (diff)
parente434a1dc0584e841da1ae4ff525bbe81a0f5514b (diff)
Merge branch 'master' of https://github.com/hathach/tinyusb into bsp_412
Diffstat (limited to 'src/portable/raspberrypi')
-rw-r--r--src/portable/raspberrypi/pio_usb/dcd_pio_usb.c210
-rw-r--r--src/portable/raspberrypi/pio_usb/hcd_pio_usb.c225
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c94
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c271
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c32
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h23
6 files changed, 706 insertions, 149 deletions
diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
new file mode 100644
index 000000000..1bc5594d8
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
@@ -0,0 +1,210 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUD_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+//------------- -------------//
+static usb_device_t *usb_device = NULL;
+static usb_descriptor_buffers_t desc;
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+
+// Initialize controller to device mode
+void dcd_init (uint8_t rhport)
+{
+ (void) rhport;
+
+ static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG;
+ usb_device = pio_usb_device_init(&config, &desc);
+}
+
+// Enable device interrupt
+void dcd_int_enable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disable device interrupt
+void dcd_int_disable (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Receive Set Address request, mcu port must also include status IN response
+void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
+{
+ // must be called before queuing status
+ pio_usb_device_set_address(dev_addr);
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+}
+
+// Wake up host
+void dcd_remote_wakeup (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
+{
+ (void) rhport;
+ return pio_usb_device_endpoint_open((uint8_t const*) desc_ep);
+}
+
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+}
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ return pio_usb_ll_transfer_start(ep, buffer, total_bytes);
+}
+
+// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
+//bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+//{
+// (void) rhport;
+// (void) ep_addr;
+// (void) ff;
+// (void) total_bytes;
+// return false;
+//}
+
+// Stall endpoint
+void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->has_transfer = false;
+ ep->stalled = true;
+}
+
+// clear stall, data toggle is also reset to DATA0
+void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr);
+ ep->data_id = 0;
+ ep->stalled = false;
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(uint8_t tu_rhport, xfer_result_t result, volatile uint32_t* ep_reg)
+{
+ const uint32_t ep_all = *ep_reg;
+
+ for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++)
+ {
+ uint32_t const mask = (1u << ep_idx);
+
+ if (ep_all & mask)
+ {
+ endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx);
+ dcd_event_xfer_complete(tu_rhport, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_device_irq_handler)(uint8_t root_id)
+{
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t* rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if (ints & PIO_USB_INTS_RESET_END_BITS)
+ {
+ dcd_event_bus_reset(tu_rhport, TUSB_SPEED_FULL, true);
+ }
+
+ if (ints & PIO_USB_INTS_SETUP_REQ_BITS)
+ {
+ dcd_event_setup_received(tu_rhport, rport->setup_packet, true);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS )
+ {
+ handle_endpoint_irq(tu_rhport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
new file mode 100644
index 000000000..58b153ac3
--- /dev/null
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -0,0 +1,225 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUH_RPI_PIO_USB
+
+#include "pico.h"
+#include "pio_usb.h"
+#include "pio_usb_ll.h"
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "osal/osal.h"
+
+#include "host/hcd.h"
+#include "host/usbh.h"
+
+#define RHPORT_OFFSET 1
+#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET)
+
+static pio_usb_configuration_t pio_host_cfg = PIO_USB_DEFAULT_CONFIG;
+
+//--------------------------------------------------------------------+
+// HCD API
+//--------------------------------------------------------------------+
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param)
+{
+ (void) rhport;
+ TU_VERIFY(cfg_id == TUH_CFGID_RPI_PIO_USB_CONFIGURATION);
+ memcpy(&pio_host_cfg, cfg_param, sizeof(pio_usb_configuration_t));
+ return true;
+}
+
+bool hcd_init(uint8_t rhport)
+{
+ (void) rhport;
+
+ // To run USB SOF interrupt in core1, call this init in core1
+ pio_usb_host_init(&pio_host_cfg);
+
+ return true;
+}
+
+void hcd_port_reset(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_start(pio_rhport);
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_port_reset_end(pio_rhport);
+}
+
+bool hcd_port_connect_status(uint8_t rhport)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+
+ root_port_t *root = PIO_USB_ROOT_PORT(pio_rhport);
+ port_pin_status_t line_state = pio_usb_bus_get_line_state(root);
+
+ return line_state != PORT_PIN_SE0;
+}
+
+tusb_speed_t hcd_port_speed_get(uint8_t rhport)
+{
+ // TODO determine link speed
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return PIO_USB_ROOT_PORT(pio_rhport)->is_fullspeed ? TUSB_SPEED_FULL : TUSB_SPEED_LOW;
+}
+
+// Close all opened endpoint belong to this device
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ pio_usb_host_close_device(pio_rhport, dev_addr);
+}
+
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void) rhport;
+ return 0;
+}
+
+void hcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+void hcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
+{
+ hcd_devtree_info_t dev_tree;
+ hcd_devtree_get_info(dev_addr, &dev_tree);
+ bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW);
+
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const*) desc_ep, need_pre);
+}
+
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen);
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
+{
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_send_setup(pio_rhport, dev_addr, setup_packet);
+}
+
+//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+//{
+// // EPX is shared, so multiple device addresses and endpoint addresses share that
+// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
+// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
+// // on that device
+// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
+// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
+// assert(ep);
+// bool busy = ep->active;
+// pico_trace("busy == %d\n", busy);
+// return busy;
+//}
+
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+{
+ (void) dev_addr;
+ (void) ep_addr;
+
+ return true;
+}
+
+static void __no_inline_not_in_flash_func(handle_endpoint_irq)(root_port_t* rport, xfer_result_t result, volatile uint32_t* ep_reg)
+{
+ (void) rport;
+ const uint32_t ep_all = *ep_reg;
+
+ for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++)
+ {
+ uint32_t const mask = (1u << ep_idx);
+
+ if (ep_all & mask)
+ {
+ endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx);
+ hcd_event_xfer_complete(ep->dev_addr, ep->ep_num, ep->actual_len, result, true);
+ }
+ }
+
+ // clear all
+ (*ep_reg) &= ~ep_all;
+}
+
+// IRQ Handler
+void __no_inline_not_in_flash_func(pio_usb_host_irq_handler)(uint8_t root_id)
+{
+ uint8_t const tu_rhport = root_id + 1;
+ root_port_t* rport = PIO_USB_ROOT_PORT(root_id);
+ uint32_t const ints = rport->ints;
+
+ if ( ints & PIO_USB_INTS_CONNECT_BITS )
+ {
+ hcd_event_device_attach(tu_rhport, true);
+ }
+
+ if ( ints & PIO_USB_INTS_DISCONNECT_BITS )
+ {
+ hcd_event_device_remove(tu_rhport, true);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_SUCCESS, &rport->ep_complete);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_STALLED, &rport->ep_stalled);
+ }
+
+ if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS )
+ {
+ handle_endpoint_irq(rport, XFER_RESULT_FAILED, &rport->ep_error);
+ }
+
+ // clear all
+ rport->ints &= ~ints;
+}
+
+#endif
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index e084478e0..4952d29b1 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -26,7 +26,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB
#include "pico.h"
#include "rp2040_usb.h"
@@ -55,7 +55,10 @@ static uint8_t *next_buffer_ptr;
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
-static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
+// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
+static bool _sof_enable = false;
+
+TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
{
return &hw_endpoints[num][dir];
}
@@ -83,9 +86,9 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
- assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
+ hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
- pico_info(" Alloced %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
+ pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
// Fill in endpoint control register with buffer offset
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
@@ -93,7 +96,6 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
*ep->endpoint_control = reg;
}
-#if 0 // todo unused
static void _hw_endpoint_close(struct hw_endpoint *ep)
{
// Clear hardware registers and then zero the struct
@@ -103,6 +105,21 @@ static void _hw_endpoint_close(struct hw_endpoint *ep)
*ep->buffer_control = 0;
// Clear any endpoint state
memset(ep, 0, sizeof(struct hw_endpoint));
+
+ // Reclaim buffer space if all endpoints are closed
+ bool reclaim_buffers = true;
+ for ( uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++ )
+ {
+ if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL || hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL)
+ {
+ reclaim_buffers = false;
+ break;
+ }
+ }
+ if (reclaim_buffers)
+ {
+ next_buffer_ptr = &usb_dpram->epx_data[0];
+ }
}
static void hw_endpoint_close(uint8_t ep_addr)
@@ -110,7 +127,6 @@ static void hw_endpoint_close(uint8_t ep_addr)
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_close(ep);
}
-#endif
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
@@ -172,7 +188,7 @@ static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_by
hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
-static void hw_handle_buff_status(void)
+static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
pico_trace("buf_status = 0x%08x\n", remaining_buffers);
@@ -201,7 +217,7 @@ static void hw_handle_buff_status(void)
}
}
-static void reset_ep0_pid(void)
+TU_ATTR_ALWAYS_INLINE static inline void reset_ep0_pid(void)
{
// If we have finished this transfer on EP0 set pid back to 1 for next
// setup transfer. Also clear a stall in case
@@ -213,7 +229,7 @@ static void reset_ep0_pid(void)
}
}
-static void reset_non_control_endpoints(void)
+static void __tusb_irq_path_func(reset_non_control_endpoints)(void)
{
// Disable all non-control
for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS-1; i++ )
@@ -224,14 +240,34 @@ static void reset_non_control_endpoints(void)
// clear non-control hw endpoints
tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2*sizeof(hw_endpoint_t));
+
+ // reclaim buffer space
next_buffer_ptr = &usb_dpram->epx_data[0];
}
-static void dcd_rp2040_irq(void)
+static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
{
uint32_t const status = usb_hw->ints;
uint32_t handled = 0;
+ if (status & USB_INTF_DEV_SOF_BITS)
+ {
+ handled |= USB_INTF_DEV_SOF_BITS;
+
+ // disable SOF interrupt if it is used for RESUME in remote wakeup
+ if (!_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+
+ dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
+ }
+
+ // xfer events are handled before setup req. So if a transfer completes immediately
+ // before closing the EP, the events will be delivered in same order.
+ if (status & USB_INTS_BUFF_STATUS_BITS)
+ {
+ handled |= USB_INTS_BUFF_STATUS_BITS;
+ hw_handle_buff_status();
+ }
+
if (status & USB_INTS_SETUP_REQ_BITS)
{
handled |= USB_INTS_SETUP_REQ_BITS;
@@ -245,12 +281,6 @@ static void dcd_rp2040_irq(void)
usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
}
- if (status & USB_INTS_BUFF_STATUS_BITS)
- {
- handled |= USB_INTS_BUFF_STATUS_BITS;
- hw_handle_buff_status();
- }
-
#if FORCE_VBUS_DETECT == 0
// Since we force VBUS detect On, device will always think it is connected and
// couldn't distinguish between disconnect and suspend
@@ -340,7 +370,7 @@ void dcd_init (uint8_t rhport)
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
#endif
- irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);
+ irq_add_shared_handler(USBCTRL_IRQ, dcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
// Init control endpoints
tu_memclr(hw_endpoints[0], 2*sizeof(hw_endpoint_t));
@@ -388,9 +418,13 @@ void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
void dcd_remote_wakeup(__unused uint8_t rhport)
{
- pico_info("dcd_remote_wakeup %d\n", rhport);
- assert(rhport == 0);
- usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
+ pico_info("dcd_remote_wakeup %d\n", rhport);
+ assert(rhport == 0);
+
+ // since RESUME interrupt is not triggered if we are the one initiate
+ // briefly enable SOF to notify usbd when bus is ready
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
}
// disconnect by disabling internal pull-up resistor on D+/D-
@@ -407,6 +441,21 @@ void dcd_connect(__unused uint8_t rhport)
usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
}
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+
+ _sof_enable = en;
+
+ if (en)
+ {
+ usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
+ }else
+ {
+ usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ }
+}
+
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
@@ -479,13 +528,12 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
- (void) ep_addr;
- // usbd.c says: In progress transfers on this EP may be delivered after this call
pico_trace("dcd_edpt_close %02x\n", ep_addr);
+ hw_endpoint_close(ep_addr);
}
-void dcd_int_handler(uint8_t rhport)
+void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport)
{
(void) rhport;
dcd_rp2040_irq();
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 768cccc86..10237d1f9 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -27,7 +27,7 @@
#include "tusb_option.h"
-#if TUSB_OPT_HOST_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040
+#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB
#include "pico.h"
#include "rp2040_usb.h"
@@ -40,7 +40,8 @@
#include "host/hcd.h"
#include "host/usbh.h"
-#define ROOT_PORT 0
+// port 0 is native USB port, other is counted as software PIO
+#define RHPORT_NATIVE 0
//--------------------------------------------------------------------+
// Low level rp2040 controller functions
@@ -78,7 +79,7 @@ static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
return NULL;
}
-static inline uint8_t dev_speed(void)
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void)
{
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
}
@@ -90,7 +91,7 @@ static bool need_pre(uint8_t dev_addr)
return hcd_port_speed_get(0) != tuh_speed_get(dev_addr);
}
-static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
+static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result)
{
// Mark transfer as done before we tell the tinyusb stack
uint8_t dev_addr = ep->dev_addr;
@@ -100,9 +101,11 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
}
-static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep)
{
usb_hw_clear->buf_status = bit;
+ // EP may have been stalled?
+ assert(ep->active);
bool done = hw_endpoint_xfer_continue(ep);
if (done)
{
@@ -110,7 +113,7 @@ static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
}
}
-static void hw_handle_buff_status(void)
+static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
pico_trace("buf_status 0x%08x\n", remaining_buffers);
@@ -135,20 +138,25 @@ static void hw_handle_buff_status(void)
_handle_buff_status_bit(bit, ep);
}
- // Check interrupt endpoints
+ // Check "interrupt" (asynchronous) endpoints for both IN and OUT
for (uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++)
{
- // EPX is bit 0
- // IEP1 is bit 2
- // IEP2 is bit 4
- // IEP3 is bit 6
+ // EPX is bit 0 & 1
+ // IEP1 IN is bit 2
+ // IEP1 OUT is bit 3
+ // IEP2 IN is bit 4
+ // IEP2 OUT is bit 5
+ // IEP3 IN is bit 6
+ // IEP3 OUT is bit 7
// etc
- bit = 1 << (i*2);
-
- if (remaining_buffers & bit)
+ for(uint j = 0; j < 2; j++)
{
- remaining_buffers &= ~bit;
- _handle_buff_status_bit(bit, &ep_pool[i]);
+ bit = 1 << (i*2+j);
+ if (remaining_buffers & bit)
+ {
+ remaining_buffers &= ~bit;
+ _handle_buff_status_bit(bit, &ep_pool[i]);
+ }
}
}
@@ -158,13 +166,15 @@ static void hw_handle_buff_status(void)
}
}
-static void hw_trans_complete(void)
+static void __tusb_irq_path_func(hw_trans_complete)(void)
{
if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS)
{
pico_trace("Sent setup packet\n");
struct hw_endpoint *ep = &epx;
assert(ep->active);
+ // Set transferred length to 8 for a setup packet
+ ep->xferred_len = 8;
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
}
else
@@ -174,7 +184,7 @@ static void hw_trans_complete(void)
}
}
-static void hcd_rp2040_irq(void)
+static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
{
uint32_t status = usb_hw->ints;
uint32_t handled = 0;
@@ -185,17 +195,29 @@ static void hcd_rp2040_irq(void)
if (dev_speed())
{
- hcd_event_device_attach(ROOT_PORT, true);
+ hcd_event_device_attach(RHPORT_NATIVE, true);
}
else
{
- hcd_event_device_remove(ROOT_PORT, true);
+ hcd_event_device_remove(RHPORT_NATIVE, true);
}
// Clear speed change interrupt
usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
}
+ if (status & USB_INTS_STALL_BITS)
+ {
+ // We have rx'd a stall from the device
+ // NOTE THIS SHOULD HAVE PRIORITY OVER BUFF_STATUS
+ // AND TRANS_COMPLETE as the stall is an alternative response
+ // to one of those events
+ pico_trace("Stall REC\n");
+ handled |= USB_INTS_STALL_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
+ hw_xfer_complete(&epx, XFER_RESULT_STALLED);
+ }
+
if (status & USB_INTS_BUFF_STATUS_BITS)
{
handled |= USB_INTS_BUFF_STATUS_BITS;
@@ -211,15 +233,6 @@ static void hcd_rp2040_irq(void)
hw_trans_complete();
}
- if (status & USB_INTS_STALL_BITS)
- {
- // We have rx'd a stall from the device
- pico_trace("Stall REC\n");
- handled |= USB_INTS_STALL_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
- hw_xfer_complete(&epx, XFER_RESULT_STALLED);
- }
-
if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS)
{
handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
@@ -239,6 +252,12 @@ static void hcd_rp2040_irq(void)
}
}
+void __tusb_irq_path_func(hcd_int_handler)(uint8_t rhport)
+{
+ (void) rhport;
+ hcd_rp2040_irq();
+}
+
static struct hw_endpoint *_next_free_interrupt_ep(void)
{
struct hw_endpoint *ep = NULL;
@@ -248,7 +267,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
if (!ep->configured)
{
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
- ep->interrupt_num = i - 1;
+ ep->interrupt_num = (uint8_t) (i - 1);
return ep;
}
}
@@ -259,10 +278,12 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
{
struct hw_endpoint *ep = NULL;
- if (transfer_type == TUSB_XFER_INTERRUPT)
+ if (transfer_type != TUSB_XFER_CONTROL)
{
+ // Note: even though datasheet name these "Interrupt" endpoints. These are actually
+ // "Asynchronous" endpoints and can be used for other type such as: Bulk (ISO need confirmation)
ep = _next_free_interrupt_ep();
- pico_info("Allocate interrupt ep %d\n", ep->interrupt_num);
+ pico_info("Allocate %s ep %d\n", tu_edpt_type_str(transfer_type), ep->interrupt_num);
assert(ep);
ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
@@ -283,7 +304,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
return ep;
}
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
+static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
{
// Already has data buffer, endpoint control, and buffer control allocated at this point
assert(ep->endpoint_control);
@@ -315,22 +336,27 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
| EP_CTRL_INTERRUPT_PER_BUFFER
| (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
| dpram_offset;
- ep_reg |= bmInterval ? (bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB : 0;
+ if (bmInterval)
+ {
+ ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
+ }
*ep->endpoint_control = ep_reg;
pico_trace("endpoint control (0x%p) <- 0x%x\n", ep->endpoint_control, ep_reg);
ep->configured = true;
- if (bmInterval)
+ if (ep != &epx)
{
- // This is an interrupt endpoint
- // so need to set up interrupt endpoint address control register with:
- // device address
- // endpoint number / direction
- // preamble
- uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB);
- // Assert the interrupt endpoint is IN_TO_HOST
- // TODO Interrupt can also be OUT
- assert(dir == TUSB_DIR_IN);
+ // Endpoint has its own addr_endp and interrupt bits to be setup!
+ // This is an interrupt/async endpoint. so need to set up ADDR_ENDP register with:
+ // - device address
+ // - endpoint number / direction
+ // - preamble
+ uint32_t reg = (uint32_t) (dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
+
+ if (dir == TUSB_DIR_OUT)
+ {
+ reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
+ }
if (need_pre(dev_addr))
{
@@ -351,71 +377,101 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
//--------------------------------------------------------------------+
bool hcd_init(uint8_t rhport)
{
- pico_trace("hcd_init %d\n", rhport);
- assert(rhport == 0);
+ (void) rhport;
+ pico_trace("hcd_init %d\n", rhport);
+ assert(rhport == 0);
- // Reset any previous state
- rp2040_usb_init();
+ // Reset any previous state
+ rp2040_usb_init();
- // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
- usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+ // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
+ usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
- irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
+ // Remove shared irq if it was previously added so as not to fill up shared irq slots
+ irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq);
- // clear epx and interrupt eps
- memset(&ep_pool, 0, sizeof(ep_pool));
+ irq_add_shared_handler(USBCTRL_IRQ, hcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
- // Enable in host mode with SOF / Keep alive on
- usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
- usb_hw->sie_ctrl = SIE_CTRL_BASE;
- usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
- USB_INTE_HOST_CONN_DIS_BITS |
- USB_INTE_HOST_RESUME_BITS |
- USB_INTE_STALL_BITS |
- USB_INTE_TRANS_COMPLETE_BITS |
- USB_INTE_ERROR_RX_TIMEOUT_BITS |
- USB_INTE_ERROR_DATA_SEQ_BITS ;
+ // clear epx and interrupt eps
+ memset(&ep_pool, 0, sizeof(ep_pool));
- return true;
+ // Enable in host mode with SOF / Keep alive on
+ usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
+ usb_hw->sie_ctrl = SIE_CTRL_BASE;
+ usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
+ USB_INTE_HOST_CONN_DIS_BITS |
+ USB_INTE_HOST_RESUME_BITS |
+ USB_INTE_STALL_BITS |
+ USB_INTE_TRANS_COMPLETE_BITS |
+ USB_INTE_ERROR_RX_TIMEOUT_BITS |
+ USB_INTE_ERROR_DATA_SEQ_BITS ;
+
+ return true;
}
void hcd_port_reset(uint8_t rhport)
{
- pico_trace("hcd_port_reset\n");
- assert(rhport == 0);
- // TODO: Nothing to do here yet. Perhaps need to reset some state?
+ (void) rhport;
+ pico_trace("hcd_port_reset\n");
+ assert(rhport == 0);
+ // TODO: Nothing to do here yet. Perhaps need to reset some state?
+}
+
+void hcd_port_reset_end(uint8_t rhport)
+{
+ (void) rhport;
}
bool hcd_port_connect_status(uint8_t rhport)
{
- pico_trace("hcd_port_connect_status\n");
- assert(rhport == 0);
- return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
+ (void) rhport;
+ pico_trace("hcd_port_connect_status\n");
+ assert(rhport == 0);
+ return usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS;
}
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
{
- assert(rhport == 0);
- // TODO: Should enumval this register
- switch (dev_speed())
- {
- case 1:
- return TUSB_SPEED_LOW;
- case 2:
- return TUSB_SPEED_FULL;
- default:
- panic("Invalid speed\n");
- return TUSB_SPEED_INVALID;
- }
+ (void) rhport;
+ assert(rhport == 0);
+ // TODO: Should enumval this register
+ switch (dev_speed())
+ {
+ case 1:
+ return TUSB_SPEED_LOW;
+ case 2:
+ return TUSB_SPEED_FULL;
+ default:
+ panic("Invalid speed\n");
+ return TUSB_SPEED_INVALID;
+ }
}
// Close all opened endpoint belong to this device
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
{
- (void) rhport;
- (void) dev_addr;
+ pico_trace("hcd_device_close %d\n", dev_addr);
+ (void) rhport;
+
+ if (dev_addr == 0) return;
- pico_trace("hcd_device_close %d\n", dev_addr);
+ for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
+ {
+ hw_endpoint_t* ep = &ep_pool[i];
+
+ if (ep->dev_addr == dev_addr && ep->configured)
+ {
+ // in case it is an interrupt endpoint, disable it
+ usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1));
+ usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0;
+
+ // unconfigure the endpoint
+ ep->configured = false;
+ *ep->endpoint_control = 0;
+ *ep->buffer_control = 0;
+ hw_endpoint_reset_transfer(ep);
+ }
+ }
}
uint32_t hcd_frame_number(uint8_t rhport)
@@ -426,15 +482,17 @@ uint32_t hcd_frame_number(uint8_t rhport)
void hcd_int_enable(uint8_t rhport)
{
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, true);
+ (void) rhport;
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, true);
}
void hcd_int_disable(uint8_t rhport)
{
- // todo we should check this is disabling from the correct core; note currently this is never called
- assert(rhport == 0);
- irq_set_enabled(USBCTRL_IRQ, false);
+ (void) rhport;
+ // todo we should check this is disabling from the correct core; note currently this is never called
+ assert(rhport == 0);
+ irq_set_enabled(USBCTRL_IRQ, false);
}
//--------------------------------------------------------------------+
@@ -449,6 +507,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
// Allocated differently based on if it's an interrupt endpoint or not
struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
+ TU_ASSERT(ep);
_hw_endpoint_init(ep,
dev_addr,
@@ -471,7 +530,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
// Get appropriate ep. Either EPX or interrupt endpoint
struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
- assert(ep);
+
+ TU_ASSERT(ep);
+
+ // EP should be inactive
+ assert(!ep->active);
// Control endpoint can change direction 0x00 <-> 0x80
if ( ep_addr != ep->ep_addr )
@@ -490,7 +553,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
- usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB);
+ usb_hw->dev_addr_ctrl = (uint32_t) (dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB));
uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
(ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS);
@@ -511,10 +574,17 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
(void) rhport;
// Copy data into setup packet buffer
- memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8);
+ for(uint8_t i=0; i<8; i++)
+ {
+ usbh_dpram->setup_packet[i] = setup_packet[i];
+ }
// Configure EP0 struct with setup info for the trans complete
struct hw_endpoint *ep = _hw_endpoint_allocate(0);
+ TU_ASSERT(ep);
+
+ // EPX should be inactive
+ assert(!ep->active);
// EP0 out
_hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
@@ -535,21 +605,6 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
return true;
}
-
-//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
-//{
-// // EPX is shared, so multiple device addresses and endpoint addresses share that
-// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
-// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
-// // on that device
-// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
-// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
-// assert(ep);
-// bool busy = ep->active;
-// pico_trace("busy == %d\n", busy);
-// return busy;
-//}
-
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
{
(void) dev_addr;
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index c9e2f6b26..25c013bd2 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -38,7 +38,7 @@ const char *ep_dir_string[] = {
"in",
};
-static inline void _hw_endpoint_lock_update(__unused struct hw_endpoint * ep, __unused int delta) {
+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...
// note that this is perhaps as simple as disabling IRQs because it would make
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
@@ -58,14 +58,20 @@ void rp2040_usb_init(void)
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
// Clear any previous state just in case
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#if __GNUC__ > 6
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
+#pragma GCC diagnostic pop
// Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
}
-void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
+void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint *ep)
{
ep->active = false;
ep->remaining_len = 0;
@@ -73,7 +79,7 @@ void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
ep->user_buf = 0;
}
-void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
+void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
uint32_t value = 0;
if (and_mask) {
value = *ep->buffer_control & and_mask;
@@ -87,7 +93,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
*ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
// 12 cycle delay.. (should be good for 48*12Mhz = 576Mhz)
// Don't need delay in host mode as host is in charge
-#if !TUSB_OPT_HOST_ENABLED
+#if !CFG_TUH_ENABLED
__asm volatile (
"b 1f\n"
"1: b 1f\n"
@@ -104,7 +110,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
}
// prepare buffer, return buffer control
-static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
{
uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
ep->remaining_len = (uint16_t)(ep->remaining_len - buflen);
@@ -139,7 +145,7 @@ static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
}
// Prepare buffer control register value
-static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_hw_endpoint_start_next_buffer)(struct hw_endpoint *ep)
{
uint32_t ep_ctrl = *ep->endpoint_control;
@@ -170,7 +176,7 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
*ep->endpoint_control = ep_ctrl;
- TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
@@ -201,7 +207,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to
}
// sync endpoint buffer and return transferred bytes
-static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id)
{
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
if (buf_id) buf_ctrl = buf_ctrl >> 16;
@@ -237,13 +243,13 @@ static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
return xferred_bytes;
}
-static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
+static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (struct hw_endpoint *ep)
{
// Update hw endpoint struct with info from hardware
// after a buff status interrupt
uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- TU_LOG(3, " Sync BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
// always sync buffer 0
uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
@@ -281,20 +287,20 @@ static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
usb_hw->abort &= ~TU_BIT(ep_id);
TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr);
- TU_LOG(3, " BufCtrl: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ TU_LOG(3, " BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
#endif
}
}
}
// Returns true if transfer is complete
-bool hw_endpoint_xfer_continue(struct hw_endpoint *ep)
+bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
{
_hw_endpoint_lock_update(ep, 1);
// Part way through a transfer
if (!ep->active)
{
- panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
+ panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
}
// Update EP struct from hardware state
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index a9cf1dd07..c72dae64c 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -16,6 +16,15 @@
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
#endif
+#ifndef PICO_RP2040_USB_FAST_IRQ
+#define PICO_RP2040_USB_FAST_IRQ 0
+#endif
+
+#if PICO_RP2040_USB_FAST_IRQ
+#define __tusb_irq_path_func(x) __no_inline_not_in_flash_func(x)
+#else
+#define __tusb_irq_path_func(x) x
+#endif
#define pico_info(...) TU_LOG(2, __VA_ARGS__)
#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
@@ -56,7 +65,7 @@ typedef struct hw_endpoint
// Interrupt, bulk, etc
uint8_t transfer_type;
-#if TUSB_OPT_HOST_ENABLED
+#if CFG_TUH_ENABLED
// Only needed for host
uint8_t dev_addr;
@@ -72,16 +81,20 @@ bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
-static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
return *ep->buffer_control;
}
-static inline void _hw_endpoint_buffer_control_set_value32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_value32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, 0, value);
}
-static inline void _hw_endpoint_buffer_control_set_mask32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_mask32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, ~value, value);
}
-static inline void _hw_endpoint_buffer_control_clear_mask32(struct hw_endpoint *ep, uint32_t value) {
+
+TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_clear_mask32(struct hw_endpoint *ep, uint32_t value) {
return _hw_endpoint_buffer_control_update32(ep, ~value, 0);
}