summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r--drivers/usb/dwc3/core.c108
1 files changed, 83 insertions, 25 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 2bbab3d86fff..5c110d8e293b 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -117,6 +117,33 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
}
/**
+ * dwc3_soft_reset - Issue soft reset
+ * @dwc: Pointer to our controller context structure
+ */
+static int dwc3_soft_reset(struct dwc3 *dwc)
+{
+ unsigned long timeout;
+ u32 reg;
+
+ timeout = jiffies + msecs_to_jiffies(500);
+ dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (!(reg & DWC3_DCTL_CSFTRST))
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(dwc->dev, "Reset Timed Out\n");
+ return -ETIMEDOUT;
+ }
+
+ cpu_relax();
+ } while (true);
+
+ return 0;
+}
+
+/**
* dwc3_free_one_event_buffer - Frees one event buffer
* @dwc: Pointer to our controller context structure
* @evt: Pointer to event buffer to be freed
@@ -367,10 +394,15 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success. The USB PHY interfaces are configured but not
+ * initialized. The PHY interfaces and the PHYs get initialized together with
+ * the core in dwc3_core_init.
*/
-static void dwc3_phy_setup(struct dwc3 *dwc)
+static int dwc3_phy_setup(struct dwc3 *dwc)
{
u32 reg;
+ int ret;
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
@@ -409,10 +441,41 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
- mdelay(100);
-
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ /* Select the HS PHY interface */
+ switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
+ case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
+ if (!strncmp(dwc->hsphy_interface, "utmi", 4)) {
+ reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
+ break;
+ } else if (!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
+ reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ } else {
+ dev_warn(dwc->dev, "HSPHY Interface not defined\n");
+
+ /* Relying on default value. */
+ if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
+ break;
+ }
+ /* FALLTHROUGH */
+ case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
+ /* Making sure the interface and PHY are operational */
+ ret = dwc3_soft_reset(dwc);
+ if (ret)
+ return ret;
+
+ udelay(1);
+
+ ret = dwc3_ulpi_init(dwc);
+ if (ret)
+ return ret;
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+
/*
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
* '0' during coreConsultant configuration. So default value will
@@ -427,7 +490,7 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
- mdelay(100);
+ return 0;
}
/**
@@ -438,7 +501,6 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
*/
static int dwc3_core_init(struct dwc3 *dwc)
{
- unsigned long timeout;
u32 hwparams4 = dwc->hwparams.hwparams4;
u32 reg;
int ret;
@@ -466,21 +528,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
}
/* issue device SoftReset too */
- timeout = jiffies + msecs_to_jiffies(500);
- dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
- do {
- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
- if (!(reg & DWC3_DCTL_CSFTRST))
- break;
-
- if (time_after(jiffies, timeout)) {
- dev_err(dwc->dev, "Reset Timed Out\n");
- ret = -ETIMEDOUT;
- goto err0;
- }
-
- cpu_relax();
- } while (true);
+ ret = dwc3_soft_reset(dwc);
+ if (ret)
+ goto err0;
ret = dwc3_core_soft_reset(dwc);
if (ret)
@@ -555,8 +605,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
- dwc3_phy_setup(dwc);
-
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err1;
@@ -836,6 +884,8 @@ static int dwc3_probe(struct platform_device *pdev)
"snps,tx_de_emphasis_quirk");
of_property_read_u8(node, "snps,tx_de_emphasis",
&tx_de_emphasis);
+ of_property_read_string(node, "snps,hsphy_interface",
+ &dwc->hsphy_interface);
} else if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
dwc->has_lpm_erratum = pdata->has_lpm_erratum;
@@ -863,6 +913,8 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
if (pdata->tx_de_emphasis)
tx_de_emphasis = pdata->tx_de_emphasis;
+
+ dwc->hsphy_interface = pdata->hsphy_interface;
}
/* default to superspeed if no maximum_speed passed */
@@ -875,12 +927,18 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->hird_threshold = hird_threshold
| (dwc->is_utmi_l1_suspend << 4);
+ platform_set_drvdata(pdev, dwc);
+ dwc3_cache_hwparams(dwc);
+
+ ret = dwc3_phy_setup(dwc);
+ if (ret)
+ goto err0;
+
ret = dwc3_core_get_phy(dwc);
if (ret)
goto err0;
spin_lock_init(&dwc->lock);
- platform_set_drvdata(pdev, dwc);
if (!dev->dma_mask) {
dev->dma_mask = dev->parent->dma_mask;
@@ -892,8 +950,6 @@ static int dwc3_probe(struct platform_device *pdev)
pm_runtime_get_sync(dev);
pm_runtime_forbid(dev);
- dwc3_cache_hwparams(dwc);
-
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
@@ -964,6 +1020,7 @@ err2:
err1:
dwc3_free_event_buffers(dwc);
+ dwc3_ulpi_exit(dwc);
err0:
/*
@@ -999,6 +1056,7 @@ static int dwc3_remove(struct platform_device *pdev)
phy_power_off(dwc->usb3_generic_phy);
dwc3_core_exit(dwc);
+ dwc3_ulpi_exit(dwc);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);