@@ -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