Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: dwc2: Fix Stalling a Non-Isochronous OUT EP

Stalling a Non-Isochronous OUT Endpoint flow changed according
programming guide.
In dwc2_hsotg_ep_sethalt() function for OUT EP should not be set STALL bit.
Instead should set SGOUTNAK in DCTL register. Set STALL bit should be
set only after GOUTNAKEFF interrupt asserted.

Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Minas Harutyunyan and committed by
Greg Kroah-Hartman
6070636c 2e708fa3

+17 -5
+17 -5
drivers/usb/dwc2/gadget.c
··· 3784 3784 for (idx = 1; idx < hsotg->num_of_eps; idx++) { 3785 3785 hs_ep = hsotg->eps_out[idx]; 3786 3786 /* Proceed only unmasked ISOC EPs */ 3787 - if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 3787 + if (BIT(idx) & ~daintmsk) 3788 3788 continue; 3789 3789 3790 3790 epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 3791 3791 3792 - if (epctrl & DXEPCTL_EPENA) { 3792 + //ISOC Ep's only 3793 + if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) { 3793 3794 epctrl |= DXEPCTL_SNAK; 3794 3795 epctrl |= DXEPCTL_EPDIS; 3796 + dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 3797 + continue; 3798 + } 3799 + 3800 + //Non-ISOC EP's 3801 + if (hs_ep->halted) { 3802 + if (!(epctrl & DXEPCTL_EPENA)) 3803 + epctrl |= DXEPCTL_EPENA; 3804 + epctrl |= DXEPCTL_EPDIS; 3805 + epctrl |= DXEPCTL_STALL; 3795 3806 dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 3796 3807 } 3797 3808 } ··· 4321 4310 epctl = dwc2_readl(hs, epreg); 4322 4311 4323 4312 if (value) { 4324 - epctl |= DXEPCTL_STALL; 4313 + if (!(dwc2_readl(hs, GINTSTS) & GINTSTS_GOUTNAKEFF)) 4314 + dwc2_set_bit(hs, DCTL, DCTL_SGOUTNAK); 4315 + // STALL bit will be set in GOUTNAKEFF interrupt handler 4325 4316 } else { 4326 4317 epctl &= ~DXEPCTL_STALL; 4327 4318 xfertype = epctl & DXEPCTL_EPTYPE_MASK; 4328 4319 if (xfertype == DXEPCTL_EPTYPE_BULK || 4329 4320 xfertype == DXEPCTL_EPTYPE_INTERRUPT) 4330 4321 epctl |= DXEPCTL_SETD0PID; 4322 + dwc2_writel(hs, epctl, epreg); 4331 4323 } 4332 - dwc2_writel(hs, epctl, epreg); 4333 4324 } 4334 4325 4335 4326 hs_ep->halted = value; 4336 - 4337 4327 return 0; 4338 4328 } 4339 4329