summaryrefslogtreecommitdiff
path: root/src/portable/raspberrypi
diff options
context:
space:
mode:
authorhathach <[email protected]>2023-01-31 14:48:11 +0700
committerhathach <[email protected]>2023-01-31 17:15:42 +0700
commit19b6cbc616e65dcb2ecdcac66f873ce416a4bf25 (patch)
treeb8ca29ebeedea56cb8310765317a6b161988fd31 /src/portable/raspberrypi
parent0cce42fcc672cb3e0d2fe16c20b46aab9d8f94d5 (diff)
add e15 prefix or walkaround related functions, also minor refactor
Diffstat (limited to 'src/portable/raspberrypi')
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c177
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c55
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h10
3 files changed, 124 insertions, 118 deletions
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index d5a105a29..ab1185102 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -244,128 +244,133 @@ static void __tusb_irq_path_func(reset_non_control_endpoints)(void)
static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
{
- uint32_t const status = usb_hw->ints;
- uint32_t handled = 0;
+ uint32_t const status = usb_hw->ints;
+ uint32_t handled = 0;
- if (status & USB_INTF_DEV_SOF_BITS)
- {
- bool keep_sof_alive = false;
+ if ( status & USB_INTF_DEV_SOF_BITS )
+ {
+ bool keep_sof_alive = false;
- handled |= USB_INTF_DEV_SOF_BITS;
+ handled |= USB_INTF_DEV_SOF_BITS;
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
- last_sof = time_us_32();
+ // Errata 15 Walkaround for Device Bulk-In endpoint
+ e15_last_sof = time_us_32();
+
+ for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++ )
+ {
+ struct hw_endpoint * ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
- for (uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++)
+ // Active Bulk IN endpoint requires SOF
+ if ( (ep->transfer_type == TUSB_XFER_BULK) && ep->active )
{
- struct hw_endpoint *ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
- hw_endpoint_lock_update(ep, 1);
+ keep_sof_alive = true;
- // Bulk IN endpoint in a transfer?
- if (rp2040_ep_needs_sof(ep) && ep->active) keep_sof_alive = true;
+ hw_endpoint_lock_update(ep, 1);
// Deferred enable?
- if (ep->pending)
+ if ( ep->pending )
{
- hw_endpoint_start_next_buffer(ep);
ep->pending = 0;
+ hw_endpoint_start_next_buffer(ep);
}
hw_endpoint_lock_update(ep, -1);
}
+ }
#endif
- // disable SOF interrupt if it is used for RESUME in remote wakeup
- if (!keep_sof_alive && !_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ // disable SOF interrupt if it is used for RESUME in remote wakeup
+ if ( !keep_sof_alive && !_sof_enable ) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
- dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
- }
+ 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();
- }
+ // 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;
- uint8_t const *setup = (uint8_t const *)&usb_dpram->setup_packet;
+ if ( status & USB_INTS_SETUP_REQ_BITS )
+ {
+ handled |= USB_INTS_SETUP_REQ_BITS;
+ uint8_t const * setup = (uint8_t const*) &usb_dpram->setup_packet;
- // reset pid to both 1 (data and ack)
- reset_ep0_pid();
+ // reset pid to both 1 (data and ack)
+ reset_ep0_pid();
- // Pass setup packet to tiny usb
- dcd_event_setup_received(0, setup, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
- }
+ // Pass setup packet to tiny usb
+ dcd_event_setup_received(0, setup, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
+ }
#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
- if (status & USB_INTS_DEV_CONN_DIS_BITS)
- {
- handled |= USB_INTS_DEV_CONN_DIS_BITS;
-
- if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
- {
- // Connected: nothing to do
- }else
- {
- // Disconnected
- dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
- }
+ // Since we force VBUS detect On, device will always think it is connected and
+ // couldn't distinguish between disconnect and suspend
+ if (status & USB_INTS_DEV_CONN_DIS_BITS)
+ {
+ handled |= USB_INTS_DEV_CONN_DIS_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
+ if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
+ {
+ // Connected: nothing to do
+ }else
+ {
+ // Disconnected
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
}
+
+ usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
+ }
#endif
- // SE0 for 2.5 us or more (will last at least 10ms)
- if (status & USB_INTS_BUS_RESET_BITS)
- {
- pico_trace("BUS RESET\n");
+ // SE0 for 2.5 us or more (will last at least 10ms)
+ if ( status & USB_INTS_BUS_RESET_BITS )
+ {
+ pico_trace("BUS RESET\n");
- handled |= USB_INTS_BUS_RESET_BITS;
+ handled |= USB_INTS_BUS_RESET_BITS;
- usb_hw->dev_addr_ctrl = 0;
- reset_non_control_endpoints();
- dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
+ usb_hw->dev_addr_ctrl = 0;
+ reset_non_control_endpoints();
+ dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
- // Only run enumeration walk-around if pull up is enabled
- if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
+ // Only run enumeration walk-around if pull up is enabled
+ if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
#endif
- }
+ }
- /* Note from pico datasheet 4.1.2.6.4 (v1.2)
- * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
- * the device is first connected but the bus is idle. The bus can be idle for a few ms before
- * the host begins sending start of frame packets. You will also see a suspend interrupt
- * when the device is disconnected if you do not have a VBUS detect circuit connected. This is
- * because without VBUS detection, it is impossible to tell the difference between
- * being disconnected and suspended.
- */
- if (status & USB_INTS_DEV_SUSPEND_BITS)
- {
- handled |= USB_INTS_DEV_SUSPEND_BITS;
- dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
- }
+ /* Note from pico datasheet 4.1.2.6.4 (v1.2)
+ * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
+ * the device is first connected but the bus is idle. The bus can be idle for a few ms before
+ * the host begins sending start of frame packets. You will also see a suspend interrupt
+ * when the device is disconnected if you do not have a VBUS detect circuit connected. This is
+ * because without VBUS detection, it is impossible to tell the difference between
+ * being disconnected and suspended.
+ */
+ if ( status & USB_INTS_DEV_SUSPEND_BITS )
+ {
+ handled |= USB_INTS_DEV_SUSPEND_BITS;
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
+ }
- if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS)
- {
- handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
- dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
- usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
- }
+ if ( status & USB_INTS_DEV_RESUME_FROM_HOST_BITS )
+ {
+ handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
+ }
- if (status ^ handled)
- {
- panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
- }
+ if ( status ^ handled )
+ {
+ panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
+ }
}
#define USB_INTS_ERROR_BITS ( \
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index b7790e0c1..d25e6c8fb 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -51,37 +51,41 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void)
//--------------------------------------------------------------------+
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
-volatile uint32_t last_sof = 0;
+// Errata 15 Walkaround for Device Bulk-In endpoint to avoid schedule an transfer
+// within last 20% of an USB frame.
-bool rp2040_critical_frame_period(struct hw_endpoint *ep)
-{
- uint32_t delta;
+volatile uint32_t e15_last_sof = 0;
- if (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) return false;
+// check if Errata 15 walkround is needed for this endpoint
+static bool __tusb_irq_path_func(e15_is_bulkin_ep) (struct hw_endpoint *ep)
+{
+ return (!is_host_mode() && tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN &&
+ ep->transfer_type == TUSB_XFER_BULK);
+}
- if (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_OUT ||
- ep->transfer_type == TUSB_XFER_INTERRUPT ||
- ep->transfer_type == TUSB_XFER_ISOCHRONOUS)
- {
- return false;
- }
+// check if we need to apply Errata 15 workaround: ie.g
+// Enpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame
+static bool __tusb_irq_path_func(e15_is_critical_frame_period) (struct hw_endpoint *ep)
+{
+ TU_VERIFY(e15_is_bulkin_ep(ep));
/* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
* The device state machine cannot recover from receiving an incorrect PID
* when it is expecting an ACK.
*/
- delta = time_us_32() - last_sof;
+ uint32_t delta = time_us_32() - e15_last_sof;
if (delta < 800 || delta > 998) {
return false;
}
- TU_LOG(3, "Avoiding sof %u now %lu last %lu\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, now, last_sof);
+ TU_LOG(3, "Avoiding sof %u now %lu last %lu\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, time_us_32(), e15_last_sof);
return true;
}
-bool rp2040_ep_needs_sof(struct hw_endpoint *ep) {
- return (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN &&
- ep->transfer_type == TUSB_XFER_BULK);
-}
+#else
+
+#define e15_is_bulkin_ep(x) false
+#define e15_is_critical_frame_period(x) false
+
#endif
void rp2040_usb_init(void)
@@ -249,17 +253,17 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to
ep->active = true;
ep->user_buf = buffer;
- if (rp2040_ep_needs_sof(ep))
+ if ( e15_is_bulkin_ep(ep) )
{
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
}
- if(!rp2040_critical_frame_period(ep))
+ if ( e15_is_critical_frame_period(ep) )
{
- hw_endpoint_start_next_buffer(ep);
+ ep->pending = 1;
} else
{
- ep->pending = 1;
+ hw_endpoint_start_next_buffer(ep);
}
hw_endpoint_lock_update(ep, -1);
@@ -356,6 +360,7 @@ static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (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)
{
@@ -377,10 +382,12 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
}
else
{
- if(!rp2040_critical_frame_period(ep)) {
- hw_endpoint_start_next_buffer(ep);
- } else {
+ if ( e15_is_critical_frame_period(ep) )
+ {
ep->pending = 1;
+ } else
+ {
+ hw_endpoint_start_next_buffer(ep);
}
}
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index d41abfee0..a06407f23 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -93,14 +93,8 @@ typedef struct hw_endpoint
} hw_endpoint_t;
-#if !TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
-#define rp2040_critical_frame_period(x) false
-#define rp2040_ep_needs_sof(x) false
-#else
-extern volatile uint32_t last_sof;
-
-bool rp2040_critical_frame_period(struct hw_endpoint *ep);
-bool rp2040_ep_needs_sof(struct hw_endpoint *ep);
+#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+extern volatile uint32_t e15_last_sof;
#endif
void rp2040_usb_init(void);