aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2011-10-14 06:00:30 -0400
committerFelipe Balbi <balbi@ti.com>2011-12-12 04:48:34 -0500
commitfae2b904aa85beecd0950026de28921ae65fb3da (patch)
treeb8f5a84150854fedb435b4c90948b2ae10ef1178
parentd39ee7be2aaf0a53d7b5f43c13571bac95f7cc0c (diff)
usb: dwc3: workaround: U1/U2 -> U0 transiton
RTL revisions <1.83a have an issue where, depending on the link partner, the USB link might do multiple entry/exit of low power states before a transfer takes place causing degraded throughput. The suggested workaround is to clear bits 12:9 of DCTL register if we see a transition from U1|U2 to U0 and only re-enable that on a transfer complete IRQ and we have no pending transfers on any of the enabled endpoints. Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/gadget.c76
2 files changed, 76 insertions, 2 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index dc2db165412b..b901a4d3b068 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -569,6 +569,7 @@ struct dwc3_hwparams {
569 * @regs_size: address space size 569 * @regs_size: address space size
570 * @irq: IRQ number 570 * @irq: IRQ number
571 * @num_event_buffers: calculated number of event buffers 571 * @num_event_buffers: calculated number of event buffers
572 * @u1u2: only used on revisions <1.83a for workaround
572 * @maximum_speed: maximum speed requested (mainly for testing purposes) 573 * @maximum_speed: maximum speed requested (mainly for testing purposes)
573 * @revision: revision register contents 574 * @revision: revision register contents
574 * @mode: mode of operation 575 * @mode: mode of operation
@@ -614,6 +615,7 @@ struct dwc3 {
614 int irq; 615 int irq;
615 616
616 u32 num_event_buffers; 617 u32 num_event_buffers;
618 u32 u1u2;
617 u32 maximum_speed; 619 u32 maximum_speed;
618 u32 revision; 620 u32 revision;
619 u32 mode; 621 u32 mode;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 85cf392365cb..0a6deeaf3377 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1376,6 +1376,31 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
1376 dep->flags &= ~DWC3_EP_BUSY; 1376 dep->flags &= ~DWC3_EP_BUSY;
1377 dep->res_trans_idx = 0; 1377 dep->res_trans_idx = 0;
1378 } 1378 }
1379
1380 /*
1381 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
1382 * See dwc3_gadget_linksts_change_interrupt() for 1st half.
1383 */
1384 if (dwc->revision < DWC3_REVISION_183A) {
1385 u32 reg;
1386 int i;
1387
1388 for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
1389 struct dwc3_ep *dep = dwc->eps[i];
1390
1391 if (!(dep->flags & DWC3_EP_ENABLED))
1392 continue;
1393
1394 if (!list_empty(&dep->req_queued))
1395 return;
1396 }
1397
1398 reg = dwc3_readl(dwc->regs, DWC3_DCTL);
1399 reg |= dwc->u1u2;
1400 dwc3_writel(dwc->regs, DWC3_DCTL, reg);
1401
1402 dwc->u1u2 = 0;
1403 }
1379} 1404}
1380 1405
1381static void dwc3_gadget_start_isoc(struct dwc3 *dwc, 1406static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@@ -1794,8 +1819,55 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
1794static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, 1819static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
1795 unsigned int evtinfo) 1820 unsigned int evtinfo)
1796{ 1821{
1797 /* The fith bit says SuperSpeed yes or no. */ 1822 enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
1798 dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; 1823
1824 /*
1825 * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
1826 * on the link partner, the USB session might do multiple entry/exit
1827 * of low power states before a transfer takes place.
1828 *
1829 * Due to this problem, we might experience lower throughput. The
1830 * suggested workaround is to disable DCTL[12:9] bits if we're
1831 * transitioning from U1/U2 to U0 and enable those bits again
1832 * after a transfer completes and there are no pending transfers
1833 * on any of the enabled endpoints.
1834 *
1835 * This is the first half of that workaround.
1836 *
1837 * Refers to:
1838 *
1839 * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us
1840 * core send LGO_Ux entering U0
1841 */
1842 if (dwc->revision < DWC3_REVISION_183A) {
1843 if (next == DWC3_LINK_STATE_U0) {
1844 u32 u1u2;
1845 u32 reg;
1846
1847 switch (dwc->link_state) {
1848 case DWC3_LINK_STATE_U1:
1849 case DWC3_LINK_STATE_U2:
1850 reg = dwc3_readl(dwc->regs, DWC3_DCTL);
1851 u1u2 = reg & (DWC3_DCTL_INITU2ENA
1852 | DWC3_DCTL_ACCEPTU2ENA
1853 | DWC3_DCTL_INITU1ENA
1854 | DWC3_DCTL_ACCEPTU1ENA);
1855
1856 if (!dwc->u1u2)
1857 dwc->u1u2 = reg & u1u2;
1858
1859 reg &= ~u1u2;
1860
1861 dwc3_writel(dwc->regs, DWC3_DCTL, reg);
1862 break;
1863 default:
1864 /* do nothing */
1865 break;
1866 }
1867 }
1868 }
1869
1870 dwc->link_state = next;
1799 1871
1800 dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); 1872 dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
1801} 1873}