OSDN Git Service

usb: dwc2: Fix Stalling a Non-Isochronous OUT EP
authorMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Thu, 24 Oct 2019 09:44:15 +0000 (13:44 +0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 15 Jan 2020 09:39:20 +0000 (10:39 +0100)
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>
drivers/usb/dwc2/gadget.c

index 6be10e4..d3335f7 100644 (file)
@@ -3784,15 +3784,26 @@ irq_retry:
                for (idx = 1; idx < hsotg->num_of_eps; idx++) {
                        hs_ep = hsotg->eps_out[idx];
                        /* Proceed only unmasked ISOC EPs */
-                       if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous)
+                       if (BIT(idx) & ~daintmsk)
                                continue;
 
                        epctrl = dwc2_readl(hsotg, DOEPCTL(idx));
 
-                       if (epctrl & DXEPCTL_EPENA) {
+                       //ISOC Ep's only
+                       if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) {
                                epctrl |= DXEPCTL_SNAK;
                                epctrl |= DXEPCTL_EPDIS;
                                dwc2_writel(hsotg, epctrl, DOEPCTL(idx));
+                               continue;
+                       }
+
+                       //Non-ISOC EP's
+                       if (hs_ep->halted) {
+                               if (!(epctrl & DXEPCTL_EPENA))
+                                       epctrl |= DXEPCTL_EPENA;
+                               epctrl |= DXEPCTL_EPDIS;
+                               epctrl |= DXEPCTL_STALL;
+                               dwc2_writel(hsotg, epctrl, DOEPCTL(idx));
                        }
                }
 
@@ -4310,19 +4321,20 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
                epctl = dwc2_readl(hs, epreg);
 
                if (value) {
-                       epctl |= DXEPCTL_STALL;
+                       if (!(dwc2_readl(hs, GINTSTS) & GINTSTS_GOUTNAKEFF))
+                               dwc2_set_bit(hs, DCTL, DCTL_SGOUTNAK);
+                       // STALL bit will be set in GOUTNAKEFF interrupt handler
                } else {
                        epctl &= ~DXEPCTL_STALL;
                        xfertype = epctl & DXEPCTL_EPTYPE_MASK;
                        if (xfertype == DXEPCTL_EPTYPE_BULK ||
                            xfertype == DXEPCTL_EPTYPE_INTERRUPT)
                                epctl |= DXEPCTL_SETD0PID;
+                       dwc2_writel(hs, epctl, epreg);
                }
-               dwc2_writel(hs, epctl, epreg);
        }
 
        hs_ep->halted = value;
-
        return 0;
 }