aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoman Bacik <rbacik@broadcom.com>2015-09-10 21:13:43 -0400
committerFelipe Balbi <balbi@ti.com>2015-10-02 14:10:57 -0400
commitec1f9d9f01384fe656a6f92b90de274146fe35a1 (patch)
tree887910b527a8d43e756a8a2a1e623a332e4ab172
parent5ee2a003e8622d51e865ffa5547a5708e592a1a5 (diff)
usb: dwc2: gadget: parity fix in isochronous mode
USB OTG driver in isochronous mode has to set the parity of the receiving microframe. The parity is set to even by default. This causes problems for an audio gadget, if the host starts transmitting on odd microframes. This fix uses Incomplete Periodic Transfer interrupt to toggle between even and odd parity until the Transfer Complete interrupt is received. Signed-off-by: Roman Bacik <rbacik@broadcom.com> Reviewed-by: Abhinav Ratna <aratna@broadcom.com> Reviewed-by: Srinath Mannam <srinath.mannam@broadcom.com> Signed-off-by: Scott Branden <sbranden@broadcom.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/dwc2/core.h1
-rw-r--r--drivers/usb/dwc2/gadget.c71
-rw-r--r--drivers/usb/dwc2/hw.h1
3 files changed, 65 insertions, 8 deletions
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 305698109000..ebf25045b4e8 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -166,6 +166,7 @@ struct dwc2_hsotg_ep {
166 unsigned int periodic:1; 166 unsigned int periodic:1;
167 unsigned int isochronous:1; 167 unsigned int isochronous:1;
168 unsigned int send_zlp:1; 168 unsigned int send_zlp:1;
169 unsigned int has_correct_parity:1;
169 170
170 char name[10]; 171 char name[10];
171}; 172};
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 19202c1c79ff..7e5670c4532d 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1513,6 +1513,19 @@ static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in)
1513 dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 1513 dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]);
1514} 1514}
1515 1515
1516static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg,
1517 u32 epctl_reg)
1518{
1519 u32 ctrl;
1520
1521 ctrl = dwc2_readl(hsotg->regs + epctl_reg);
1522 if (ctrl & DXEPCTL_EOFRNUM)
1523 ctrl |= DXEPCTL_SETEVENFR;
1524 else
1525 ctrl |= DXEPCTL_SETODDFR;
1526 dwc2_writel(ctrl, hsotg->regs + epctl_reg);
1527}
1528
1516/** 1529/**
1517 * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 1530 * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
1518 * @hsotg: The device instance 1531 * @hsotg: The device instance
@@ -1583,6 +1596,16 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
1583 return; 1596 return;
1584 } 1597 }
1585 1598
1599 /*
1600 * Slave mode OUT transfers do not go through XferComplete so
1601 * adjust the ISOC parity here.
1602 */
1603 if (!using_dma(hsotg)) {
1604 hs_ep->has_correct_parity = 1;
1605 if (hs_ep->isochronous && hs_ep->interval == 1)
1606 dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum));
1607 }
1608
1586 dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 1609 dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
1587} 1610}
1588 1611
@@ -1955,13 +1978,9 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
1955 ints &= ~DXEPINT_XFERCOMPL; 1978 ints &= ~DXEPINT_XFERCOMPL;
1956 1979
1957 if (ints & DXEPINT_XFERCOMPL) { 1980 if (ints & DXEPINT_XFERCOMPL) {
1958 if (hs_ep->isochronous && hs_ep->interval == 1) { 1981 hs_ep->has_correct_parity = 1;
1959 if (ctrl & DXEPCTL_EOFRNUM) 1982 if (hs_ep->isochronous && hs_ep->interval == 1)
1960 ctrl |= DXEPCTL_SETEVENFR; 1983 dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
1961 else
1962 ctrl |= DXEPCTL_SETODDFR;
1963 dwc2_writel(ctrl, hsotg->regs + epctl_reg);
1964 }
1965 1984
1966 dev_dbg(hsotg->dev, 1985 dev_dbg(hsotg->dev,
1967 "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 1986 "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",
@@ -2321,7 +2340,8 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
2321 GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 2340 GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF |
2322 GINTSTS_USBRST | GINTSTS_RESETDET | 2341 GINTSTS_USBRST | GINTSTS_RESETDET |
2323 GINTSTS_ENUMDONE | GINTSTS_OTGINT | 2342 GINTSTS_ENUMDONE | GINTSTS_OTGINT |
2324 GINTSTS_USBSUSP | GINTSTS_WKUPINT; 2343 GINTSTS_USBSUSP | GINTSTS_WKUPINT |
2344 GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT;
2325 2345
2326 if (hsotg->core_params->external_id_pin_ctl <= 0) 2346 if (hsotg->core_params->external_id_pin_ctl <= 0)
2327 intmsk |= GINTSTS_CONIDSTSCHNG; 2347 intmsk |= GINTSTS_CONIDSTSCHNG;
@@ -2582,6 +2602,40 @@ irq_retry:
2582 dwc2_hsotg_dump(hsotg); 2602 dwc2_hsotg_dump(hsotg);
2583 } 2603 }
2584 2604
2605 if (gintsts & GINTSTS_INCOMPL_SOIN) {
2606 u32 idx, epctl_reg;
2607 struct dwc2_hsotg_ep *hs_ep;
2608
2609 dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOIN\n", __func__);
2610 for (idx = 1; idx < hsotg->num_of_eps; idx++) {
2611 hs_ep = hsotg->eps_in[idx];
2612
2613 if (!hs_ep->isochronous || hs_ep->has_correct_parity)
2614 continue;
2615
2616 epctl_reg = DIEPCTL(idx);
2617 dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
2618 }
2619 dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS);
2620 }
2621
2622 if (gintsts & GINTSTS_INCOMPL_SOOUT) {
2623 u32 idx, epctl_reg;
2624 struct dwc2_hsotg_ep *hs_ep;
2625
2626 dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
2627 for (idx = 1; idx < hsotg->num_of_eps; idx++) {
2628 hs_ep = hsotg->eps_out[idx];
2629
2630 if (!hs_ep->isochronous || hs_ep->has_correct_parity)
2631 continue;
2632
2633 epctl_reg = DOEPCTL(idx);
2634 dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
2635 }
2636 dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS);
2637 }
2638
2585 /* 2639 /*
2586 * if we've had fifo events, we should try and go around the 2640 * if we've had fifo events, we should try and go around the
2587 * loop again to see if there's any point in returning yet. 2641 * loop again to see if there's any point in returning yet.
@@ -2668,6 +2722,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
2668 hs_ep->periodic = 0; 2722 hs_ep->periodic = 0;
2669 hs_ep->halted = 0; 2723 hs_ep->halted = 0;
2670 hs_ep->interval = desc->bInterval; 2724 hs_ep->interval = desc->bInterval;
2725 hs_ep->has_correct_parity = 0;
2671 2726
2672 if (hs_ep->interval > 1 && hs_ep->mc > 1) 2727 if (hs_ep->interval > 1 && hs_ep->mc > 1)
2673 dev_err(hsotg->dev, "MC > 1 when interval is not 1\n"); 2728 dev_err(hsotg->dev, "MC > 1 when interval is not 1\n");
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index d0a5ed8fa15a..553f24606c43 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -142,6 +142,7 @@
142#define GINTSTS_RESETDET (1 << 23) 142#define GINTSTS_RESETDET (1 << 23)
143#define GINTSTS_FET_SUSP (1 << 22) 143#define GINTSTS_FET_SUSP (1 << 22)
144#define GINTSTS_INCOMPL_IP (1 << 21) 144#define GINTSTS_INCOMPL_IP (1 << 21)
145#define GINTSTS_INCOMPL_SOOUT (1 << 21)
145#define GINTSTS_INCOMPL_SOIN (1 << 20) 146#define GINTSTS_INCOMPL_SOIN (1 << 20)
146#define GINTSTS_OEPINT (1 << 19) 147#define GINTSTS_OEPINT (1 << 19)
147#define GINTSTS_IEPINT (1 << 18) 148#define GINTSTS_IEPINT (1 << 18)