3232#include <stdlib.h>
3333#include "rp2040_usb.h"
3434
35+ //--------------------------------------------------------------------+
36+ // MACRO CONSTANT TYPEDEF PROTOTYPE
37+ //--------------------------------------------------------------------+
38+
3539// Direction strings for debug
3640const char * ep_dir_string [] = {
3741 "out" ,
@@ -40,54 +44,24 @@ const char *ep_dir_string[] = {
4044
4145static void _hw_endpoint_xfer_sync (struct hw_endpoint * ep );
4246
47+ #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
48+ static bool e15_is_bulkin_ep (struct hw_endpoint * ep );
49+ static bool e15_is_critical_frame_period (struct hw_endpoint * ep );
50+ #else
51+ #define e15_is_bulkin_ep (x ) (false)
52+ #define e15_is_critical_frame_period (x ) (false)
53+ #endif
54+
4355// if usb hardware is in host mode
4456TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode (void )
4557{
4658 return (usb_hw -> main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS ) ? true : false;
4759}
4860
4961//--------------------------------------------------------------------+
50- //
62+ // Implementation
5163//--------------------------------------------------------------------+
5264
53- #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
54- // Errata 15 Walkaround for Device Bulk-In endpoint to avoid schedule an transfer
55- // within last 20% of an USB frame.
56-
57- volatile uint32_t e15_last_sof = 0 ;
58-
59- // check if Errata 15 walkround is needed for this endpoint
60- static bool __tusb_irq_path_func (e15_is_bulkin_ep ) (struct hw_endpoint * ep )
61- {
62- return (!is_host_mode () && tu_edpt_dir (ep -> ep_addr ) == TUSB_DIR_IN &&
63- ep -> transfer_type == TUSB_XFER_BULK );
64- }
65-
66- // check if we need to apply Errata 15 workaround: ie.g
67- // Enpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame
68- static bool __tusb_irq_path_func (e15_is_critical_frame_period ) (struct hw_endpoint * ep )
69- {
70- TU_VERIFY (e15_is_bulkin_ep (ep ));
71-
72- /* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
73- * The device state machine cannot recover from receiving an incorrect PID
74- * when it is expecting an ACK.
75- */
76- uint32_t delta = time_us_32 () - e15_last_sof ;
77- if (delta < 800 || delta > 998 ) {
78- return false;
79- }
80- 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 );
81- return true;
82- }
83-
84- #else
85-
86- #define e15_is_bulkin_ep (x ) false
87- #define e15_is_critical_frame_period (x ) false
88-
89- #endif
90-
9165void rp2040_usb_init (void )
9266{
9367 // Reset usb controller
@@ -396,4 +370,56 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
396370 return false;
397371}
398372
373+ //--------------------------------------------------------------------+
374+ // Errata 15
375+ //--------------------------------------------------------------------+
376+
377+ #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
378+
379+ /* Don't mark IN buffers as available during the last 200us of a full-speed
380+ frame. This avoids a situation seen with the USB2.0 hub on a Raspberry
381+ Pi 4 where a late IN token before the next full-speed SOF can cause port
382+ babble and a corrupt ACK packet. The nature of the data corruption has a
383+ chance to cause device lockup.
384+
385+ Use the next SOF to mark delayed buffers as available. This reduces
386+ available Bulk IN bandwidth by approximately 20%, and requires that the
387+ SOF interrupt is enabled while these transfers are ongoing.
388+
389+ Inherit the top-level enable from the corresponding Pico-SDK flag.
390+ Applications that will not use the device in a situation where it could
391+ be plugged into a Pi 4 or Pi 400 (for example, when directly connected
392+ to a commodity hub or other host) can turn off the flag in the SDK.
393+ */
394+
395+ volatile uint32_t e15_last_sof = 0 ;
396+
397+ // check if Errata 15 is needed for this endpoint i.e device bulk-in
398+ static bool __tusb_irq_path_func (e15_is_bulkin_ep ) (struct hw_endpoint * ep )
399+ {
400+ return (!is_host_mode () && tu_edpt_dir (ep -> ep_addr ) == TUSB_DIR_IN &&
401+ ep -> transfer_type == TUSB_XFER_BULK );
402+ }
403+
404+ // check if we need to apply Errata 15 walk-around : i.e
405+ // Endpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame
406+ static bool __tusb_irq_path_func (e15_is_critical_frame_period ) (struct hw_endpoint * ep )
407+ {
408+ TU_VERIFY (e15_is_bulkin_ep (ep ));
409+
410+ /* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
411+ * The device state machine cannot recover from receiving an incorrect PID
412+ * when it is expecting an ACK.
413+ */
414+ uint32_t delta = time_us_32 () - e15_last_sof ;
415+ if (delta < 800 || delta > 998 ) {
416+ return false;
417+ }
418+ 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 );
419+ return true;
420+ }
421+
422+ #endif
423+
424+
399425#endif
0 commit comments