@@ -141,6 +141,7 @@ struct udc_dwc2_data {
141141 unsigned int enumdone : 1 ;
142142 unsigned int enumspd : 2 ;
143143 unsigned int pending_dout_feed : 1 ;
144+ unsigned int ignore_ep0_nakeff : 1 ;
144145 enum dwc2_suspend_type suspend_type ;
145146 /* Number of endpoints including control endpoint */
146147 uint8_t numdeveps ;
@@ -485,7 +486,6 @@ static int dwc2_tx_fifo_write(const struct device *dev,
485486 mem_addr_t dieptsiz_reg = (mem_addr_t )& base -> in_ep [ep_idx ].dieptsiz ;
486487 /* TODO: use dwc2_get_dxepctl_reg() */
487488 mem_addr_t diepctl_reg = (mem_addr_t )& base -> in_ep [ep_idx ].diepctl ;
488- mem_addr_t diepint_reg = (mem_addr_t )& base -> in_ep [ep_idx ].diepint ;
489489
490490 uint32_t diepctl ;
491491 uint32_t max_xfersize , max_pktcnt , pktcnt ;
@@ -617,9 +617,6 @@ static int dwc2_tx_fifo_write(const struct device *dev,
617617 }
618618 sys_write32 (diepctl , diepctl_reg );
619619
620- /* Clear IN Endpoint NAK Effective interrupt in case it was set */
621- sys_write32 (USB_DWC2_DIEPINT_INEPNAKEFF , diepint_reg );
622-
623620 if (dwc2_in_completer_mode (dev )) {
624621 const uint8_t * src = buf -> data ;
625622
@@ -811,7 +808,20 @@ static void dwc2_handle_xfer_next(const struct device *dev,
811808 if (USB_EP_DIR_IS_OUT (cfg -> addr )) {
812809 dwc2_prep_rx (dev , buf , cfg );
813810 } else {
814- int err = dwc2_tx_fifo_write (dev , cfg , buf );
811+ int err ;
812+
813+ if (cfg -> addr == USB_CONTROL_EP_IN &&
814+ udc_ctrl_stage_is_status_in (dev )) {
815+ /* It was observed that EPENA results in INEPNAKEFF
816+ * interrupt which leads to endpoint disable. It is not
817+ * clear how to prevent this without violating sequence
818+ * described in Programming Guide, so just set a flag
819+ * for interrupt handler to ignore it.
820+ */
821+ priv -> ignore_ep0_nakeff = 1 ;
822+ }
823+
824+ err = dwc2_tx_fifo_write (dev , cfg , buf );
815825
816826 if (cfg -> addr == USB_CONTROL_EP_IN ) {
817827 /* Feed a buffer for the next setup packet after arming
@@ -862,6 +872,7 @@ static int dwc2_handle_evt_setup(const struct device *dev)
862872 * transfer beforehand. In Buffer DMA the SETUP can be copied to any EP0
863873 * OUT buffer. If there is any buffer queued, it is obsolete now.
864874 */
875+ priv -> ignore_ep0_nakeff = 0 ;
865876 udc_dwc2_ep_disable (dev , cfg_in , false, true);
866877 atomic_and (& priv -> xfer_finished , ~(BIT (0 ) | BIT (16 )));
867878
@@ -2658,7 +2669,21 @@ static inline void dwc2_handle_iepint(const struct device *dev)
26582669 }
26592670
26602671 if (status & USB_DWC2_DIEPINT_INEPNAKEFF ) {
2661- sys_set_bits (diepctl_reg , USB_DWC2_DEPCTL_EPDIS );
2672+ uint32_t diepctl = sys_read32 (diepctl_reg );
2673+
2674+ if (!(diepctl & USB_DWC2_DEPCTL_NAKSTS )) {
2675+ /* Ignore stale NAK effective interrupt */
2676+ } else if (n == 0 && priv -> ignore_ep0_nakeff ) {
2677+ /* Status stage enabled endpoint. NAK will be
2678+ * cleared in STSPHSERCVD interrupt.
2679+ */
2680+ } else if (diepctl & USB_DWC2_DEPCTL_EPENA ) {
2681+ diepctl &= ~USB_DWC2_DEPCTL_EPENA ;
2682+ diepctl |= USB_DWC2_DEPCTL_EPDIS ;
2683+ sys_write32 (diepctl , diepctl_reg );
2684+ } else if (priv -> iso_in_rearm & (BIT (n ))) {
2685+ priv -> iso_in_rearm &= ~BIT (n );
2686+ }
26622687 }
26632688
26642689 if (status & USB_DWC2_DIEPINT_EPDISBLD ) {
@@ -2676,6 +2701,13 @@ static inline void dwc2_handle_iepint(const struct device *dev)
26762701 if ((usb_dwc2_get_depctl_eptype (diepctl ) == USB_DWC2_DEPCTL_EPTYPE_ISO ) &&
26772702 (priv -> iso_in_rearm & BIT (n ))) {
26782703 struct udc_ep_config * cfg = udc_get_ep_cfg (dev , n | USB_EP_DIR_IN );
2704+ struct net_buf * buf ;
2705+
2706+ /* Data is no longer relevant, discard it */
2707+ buf = udc_buf_get (cfg );
2708+ if (buf ) {
2709+ udc_submit_ep_event (dev , buf , 0 );
2710+ }
26792711
26802712 /* Try to queue next packet before SOF */
26812713 dwc2_handle_xfer_next (dev , cfg );
@@ -2837,9 +2869,17 @@ static inline void dwc2_handle_oepint(const struct device *dev)
28372869 if ((usb_dwc2_get_depctl_eptype (doepctl ) == USB_DWC2_DEPCTL_EPTYPE_ISO ) &&
28382870 (priv -> iso_out_rearm & BIT (n ))) {
28392871 struct udc_ep_config * cfg ;
2872+ struct net_buf * buf ;
28402873
2841- /* Try to queue next packet before SOF */
28422874 cfg = udc_get_ep_cfg (dev , n | USB_EP_DIR_OUT );
2875+
2876+ /* Discard disabled transfer buffer */
2877+ buf = udc_buf_get (cfg );
2878+ if (buf ) {
2879+ udc_submit_ep_event (dev , buf , 0 );
2880+ }
2881+
2882+ /* Try to queue next packet before SOF */
28432883 dwc2_handle_xfer_next (dev , cfg );
28442884
28452885 priv -> iso_out_rearm &= ~BIT (n );
@@ -2883,21 +2923,14 @@ static void dwc2_handle_incompisoin(const struct device *dev)
28832923 /* Check if endpoint didn't receive ISO IN data */
28842924 if ((diepctl & mask ) == val ) {
28852925 struct udc_ep_config * cfg ;
2886- struct net_buf * buf ;
28872926
28882927 cfg = udc_get_ep_cfg (dev , i | USB_EP_DIR_IN );
28892928 __ASSERT_NO_MSG (cfg && cfg -> stat .enabled &&
28902929 dwc2_ep_is_iso (cfg ));
28912930
28922931 udc_dwc2_ep_disable (dev , cfg , false, false);
28932932
2894- buf = udc_buf_get (cfg );
2895- if (buf ) {
2896- /* Data is no longer relevant */
2897- udc_submit_ep_event (dev , buf , 0 );
2898-
2899- rearm |= BIT (i );
2900- }
2933+ rearm |= BIT (i );
29012934 }
29022935
29032936 eps &= ~BIT (i );
@@ -2940,20 +2973,14 @@ static void dwc2_handle_incompisoout(const struct device *dev)
29402973 /* Check if endpoint didn't receive ISO OUT data */
29412974 if ((doepctl & mask ) == val ) {
29422975 struct udc_ep_config * cfg ;
2943- struct net_buf * buf ;
29442976
29452977 cfg = udc_get_ep_cfg (dev , i );
29462978 __ASSERT_NO_MSG (cfg && cfg -> stat .enabled &&
29472979 dwc2_ep_is_iso (cfg ));
29482980
29492981 udc_dwc2_ep_disable (dev , cfg , false, false);
29502982
2951- buf = udc_buf_get (cfg );
2952- if (buf ) {
2953- udc_submit_ep_event (dev , buf , 0 );
2954-
2955- rearm |= BIT (i );
2956- }
2983+ rearm |= BIT (i );
29572984 }
29582985
29592986 eps &= ~BIT (i );
@@ -2984,8 +3011,31 @@ static void dwc2_handle_goutnakeff(const struct device *dev)
29843011 doepctl_reg = (mem_addr_t )& base -> out_ep [ep_idx ].doepctl ;
29853012 doepctl = sys_read32 (doepctl_reg );
29863013
2987- /* The application cannot disable control OUT endpoint 0. */
2988- if (ep_idx != 0 ) {
3014+ if (!(doepctl & USB_DWC2_DEPCTL_EPENA )) {
3015+ /* While endpoint was enabled when application requested
3016+ * to disable it, there is a race window between setting
3017+ * DCTL SGOUTNAK bit and it becoming effective. During
3018+ * the window, it is possible for host to actually send
3019+ * OUT DATA packet ending the transfer which disables
3020+ * the endpoint.
3021+ *
3022+ * If we arrived here due to INCOMPISOOUT, clearing
3023+ * the rearm flag is enough.
3024+ */
3025+ if (priv -> iso_out_rearm & BIT (ep_idx )) {
3026+ priv -> iso_out_rearm &= ~BIT (ep_idx );
3027+ }
3028+
3029+ /* If application requested STALL then set it here, but
3030+ * otherwise there's nothing to do.
3031+ */
3032+ if (!(priv -> ep_out_stall & BIT (ep_idx ))) {
3033+ continue ;
3034+ }
3035+ } else if (ep_idx != 0 ) {
3036+ /* Only set EPDIS if EPENA is set, but do not set it for
3037+ * endpoint 0 which cannot be disabled by application.
3038+ */
29893039 doepctl |= USB_DWC2_DEPCTL_EPDIS ;
29903040 }
29913041
0 commit comments