Commit 6070636c authored by Minas Harutyunyan's avatar Minas Harutyunyan Committed by Greg Kroah-Hartman

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: default avatarMinas Harutyunyan <hminas@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2e708fa3
...@@ -3784,15 +3784,26 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) ...@@ -3784,15 +3784,26 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
for (idx = 1; idx < hsotg->num_of_eps; idx++) { for (idx = 1; idx < hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_out[idx]; hs_ep = hsotg->eps_out[idx];
/* Proceed only unmasked ISOC EPs */ /* Proceed only unmasked ISOC EPs */
if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) if (BIT(idx) & ~daintmsk)
continue; continue;
epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 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_SNAK;
epctrl |= DXEPCTL_EPDIS; epctrl |= DXEPCTL_EPDIS;
dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 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) ...@@ -4310,19 +4321,20 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
epctl = dwc2_readl(hs, epreg); epctl = dwc2_readl(hs, epreg);
if (value) { 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 { } else {
epctl &= ~DXEPCTL_STALL; epctl &= ~DXEPCTL_STALL;
xfertype = epctl & DXEPCTL_EPTYPE_MASK; xfertype = epctl & DXEPCTL_EPTYPE_MASK;
if (xfertype == DXEPCTL_EPTYPE_BULK || if (xfertype == DXEPCTL_EPTYPE_BULK ||
xfertype == DXEPCTL_EPTYPE_INTERRUPT) xfertype == DXEPCTL_EPTYPE_INTERRUPT)
epctl |= DXEPCTL_SETD0PID; epctl |= DXEPCTL_SETD0PID;
}
dwc2_writel(hs, epctl, epreg); dwc2_writel(hs, epctl, epreg);
} }
}
hs_ep->halted = value; hs_ep->halted = value;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment