mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-28 04:17:47 +00:00
usb: dwc3: support new revisions of DWC3 core
Recent cores (>= 1.94a) have a set of new features, commands and a slightly different programming model. This patch aims to support those changes. Signed-off-by: Paul Zimmerman <paulz@synopsys.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
d7a46a8dfc
commit
802fde983e
@ -100,6 +100,23 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
||||
int retries = 10000;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Wait until device controller is ready. Only applies to 1.94a and
|
||||
* later RTL.
|
||||
*/
|
||||
if (dwc->revision >= DWC3_REVISION_194A) {
|
||||
while (--retries) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
|
||||
if (reg & DWC3_DSTS_DCNRD)
|
||||
udelay(5);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (retries <= 0)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
|
||||
|
||||
@ -107,6 +124,13 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
||||
reg |= DWC3_DCTL_ULSTCHNGREQ(state);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
/*
|
||||
* The following code is racy when called from dwc3_gadget_wakeup,
|
||||
* and is not needed, at least on newer versions
|
||||
*/
|
||||
if (dwc->revision >= DWC3_REVISION_194A)
|
||||
return 0;
|
||||
|
||||
/* wait for a change in DSTS */
|
||||
retries = 10000;
|
||||
while (--retries) {
|
||||
@ -266,8 +290,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
|
||||
return "Clear Stall";
|
||||
case DWC3_DEPCMD_SETSTALL:
|
||||
return "Set Stall";
|
||||
case DWC3_DEPCMD_GETSEQNUMBER:
|
||||
return "Get Data Sequence Number";
|
||||
case DWC3_DEPCMD_GETEPSTATE:
|
||||
return "Get Endpoint State";
|
||||
case DWC3_DEPCMD_SETTRANSFRESOURCE:
|
||||
return "Set Endpoint Transfer Resource";
|
||||
case DWC3_DEPCMD_SETEPCONFIG:
|
||||
@ -1280,9 +1304,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* write zeroes to Link Change Request */
|
||||
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
/* Recent versions do this automatically */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
/* write zeroes to Link Change Request */
|
||||
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
}
|
||||
|
||||
/* poll until Link State changes to ON */
|
||||
timeout = jiffies + msecs_to_jiffies(100);
|
||||
@ -1326,9 +1353,14 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (is_on) {
|
||||
reg &= ~DWC3_DCTL_TRGTULST_MASK;
|
||||
reg |= (DWC3_DCTL_RUN_STOP
|
||||
| DWC3_DCTL_TRGTULST_RX_DET);
|
||||
if (dwc->revision <= DWC3_REVISION_187A) {
|
||||
reg &= ~DWC3_DCTL_TRGTULST_MASK;
|
||||
reg |= DWC3_DCTL_TRGTULST_RX_DET;
|
||||
}
|
||||
|
||||
if (dwc->revision >= DWC3_REVISION_194A)
|
||||
reg &= ~DWC3_DCTL_KEEP_CONNECT;
|
||||
reg |= DWC3_DCTL_RUN_STOP;
|
||||
} else {
|
||||
reg &= ~DWC3_DCTL_RUN_STOP;
|
||||
}
|
||||
@ -1468,6 +1500,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct usb_gadget_ops dwc3_gadget_ops = {
|
||||
.get_frame = dwc3_gadget_get_frame,
|
||||
.wakeup = dwc3_gadget_wakeup,
|
||||
@ -1962,9 +1995,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
||||
/* after reset -> Default State */
|
||||
dwc->dev_state = DWC3_DEFAULT_STATE;
|
||||
|
||||
/* Resume PHYs */
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, false);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, false);
|
||||
/* Recent versions support automatic phy suspend and don't need this */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
/* Resume PHYs */
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, false);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, false);
|
||||
}
|
||||
|
||||
if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
|
||||
dwc3_disconnect_gadget(dwc);
|
||||
@ -2082,8 +2118,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Suspend unneded PHY */
|
||||
dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
|
||||
/* Recent versions support automatic phy suspend and don't need this */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
/* Suspend unneeded PHY */
|
||||
dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
|
||||
}
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
|
||||
@ -2389,6 +2428,24 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
||||
DWC3_DEVTEN_DISCONNEVTEN);
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
|
||||
|
||||
/* Enable USB2 LPM and automatic phy suspend only on recent versions */
|
||||
if (dwc->revision >= DWC3_REVISION_194A) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg |= DWC3_DCFG_LPM_CAP;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
|
||||
|
||||
/* TODO: This should be configurable */
|
||||
reg |= DWC3_DCTL_HIRD_THRES(31);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, true);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, true);
|
||||
}
|
||||
|
||||
ret = device_register(&dwc->gadget.dev);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to register gadget device\n");
|
||||
|
Loading…
Reference in New Issue
Block a user