From b22da3d8526a935aa31e086e63f60ff3246cb61c Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 07:24:11 +0000
Subject: [PATCH] add stmac read mac form eeprom
---
kernel/drivers/usb/dwc3/core.c | 834 +++++++++++++++++++++++++++-------------------------------
1 files changed, 391 insertions(+), 443 deletions(-)
diff --git a/kernel/drivers/usb/dwc3/core.c b/kernel/drivers/usb/dwc3/core.c
index b06b0d0..8384e53 100644
--- a/kernel/drivers/usb/dwc3/core.c
+++ b/kernel/drivers/usb/dwc3/core.c
@@ -1,14 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* core.c - DesignWare USB3 DRD Controller Core file
*
- * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*/
-#include <linux/async.h>
#include <linux/clk.h>
#include <linux/version.h>
#include <linux/module.h>
@@ -86,7 +85,9 @@
* specified or set to OTG, then set the mode to peripheral.
*/
if (mode == USB_DR_MODE_OTG &&
- dwc->revision >= DWC3_REVISION_330A)
+ (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
+ !device_property_read_bool(dwc->dev, "usb-role-switch")) &&
+ !DWC3_VER_IS_PRIOR(DWC3, 330A))
mode = USB_DR_MODE_PERIPHERAL;
}
@@ -118,24 +119,36 @@
struct dwc3 *dwc = work_to_dwc(work);
unsigned long flags;
int ret;
+ int retries = 1000;
+ u32 reg;
- if (dwc->dr_mode != USB_DR_MODE_OTG)
- return;
+ mutex_lock(&dwc->mutex);
+
+ pm_runtime_get_sync(dwc->dev);
+
+#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
+ if (dwc->desired_role_sw_mode == USB_DR_MODE_PERIPHERAL &&
+ dwc->desired_role_sw_mode != dwc->current_role_sw_mode)
+ pm_runtime_get(dwc->dev);
+ else if ((dwc->desired_role_sw_mode == USB_DR_MODE_UNKNOWN ||
+ dwc->desired_role_sw_mode == USB_DR_MODE_HOST) &&
+ dwc->current_role_sw_mode == USB_DR_MODE_PERIPHERAL)
+ pm_runtime_put(dwc->dev);
+
+ dwc->current_role_sw_mode = dwc->desired_role_sw_mode;
+#endif
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
dwc3_otg_update(dwc, 0);
if (!dwc->desired_dr_role)
- return;
-
- if (dwc->en_runtime)
- goto runtime;
+ goto out;
if (dwc->desired_dr_role == dwc->current_dr_role)
- return;
+ goto out;
if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
- return;
+ goto out;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
@@ -156,6 +169,30 @@
break;
}
+ /*
+ * When current_dr_role is not set, there's no role switching.
+ * Only perform GCTL.CoreSoftReset when there's DRD role switching.
+ */
+ if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
+ DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
+ dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg |= DWC3_GCTL_CORESOFTRESET;
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ /*
+ * Wait for internal clocks to synchronized. DWC_usb31 and
+ * DWC_usb32 may need at least 50ms (less for DWC_usb3). To
+ * keep it consistent across different IPs, let's wait up to
+ * 100ms before clearing GCTL.CORESOFTRESET.
+ */
+ msleep(100);
+
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~DWC3_GCTL_CORESOFTRESET;
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ }
+
spin_lock_irqsave(&dwc->lock, flags);
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
@@ -172,12 +209,35 @@
otg_set_vbus(dwc->usb2_phy->otg, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
- if (!of_device_is_compatible(dwc->dev->parent->of_node,
- "rockchip,rk3399-dwc3"))
- phy_calibrate(dwc->usb2_generic_phy);
+ if (dwc->dis_split_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
+ reg |= DWC3_GUCTL3_SPLITDISABLE;
+ dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
+ }
}
break;
case DWC3_GCTL_PRTCAP_DEVICE:
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg |= DWC3_DCTL_CSFTRST;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
+ retries = 10;
+
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (!(reg & DWC3_DCTL_CSFTRST))
+ goto done;
+
+ if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
+ msleep(20);
+ else
+ udelay(1);
+ } while (--retries);
+done:
+ if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A))
+ msleep(50);
+
dwc3_event_buffers_setup(dwc);
if (dwc->usb2_phy)
@@ -197,123 +257,18 @@
break;
}
- return;
-
-runtime:
- if (extcon_get_state(dwc->edev, EXTCON_USB) ||
- extcon_get_state(dwc->edev, EXTCON_USB_HOST)) {
- if (dwc->drd_connected) {
- /*
- * If the connected flag is true, and the DWC3 is
- * in device mode, it means that the Type-C cable
- * is doing data role swap (UFP -> DFP), so we need
- * to disconnect UFP first, and then switch DWC3 to
- * DFP depends on the next extcon notifier.
- */
- if (extcon_get_state(dwc->edev, EXTCON_USB_HOST) &&
- dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE)
- goto disconnect;
- else
- return;
- }
-
- dwc->current_dr_role = dwc->desired_dr_role;
- pm_runtime_get_sync(dwc->dev);
- /*
- * We should set drd_connected true after runtime_resume to
- * enable reset deassert.
- */
- dwc->drd_connected = true;
-
- spin_lock_irqsave(&dwc->lock, flags);
-
- dwc3_set_prtcap(dwc, dwc->desired_dr_role);
-
- spin_unlock_irqrestore(&dwc->lock, flags);
-
- switch (dwc->current_dr_role) {
- case DWC3_GCTL_PRTCAP_HOST:
- phy_power_on(dwc->usb3_generic_phy);
- ret = dwc3_host_init(dwc);
- if (ret) {
- dev_err(dwc->dev,
- "failed to initialize host\n");
- } else {
- if (dwc->usb2_phy)
- otg_set_vbus(dwc->usb2_phy->otg, true);
- phy_set_mode(dwc->usb2_generic_phy,
- PHY_MODE_USB_HOST);
- phy_set_mode(dwc->usb3_generic_phy,
- PHY_MODE_USB_HOST);
- if (!of_device_is_compatible(
- dwc->dev->parent->of_node,
- "rockchip,rk3399-dwc3"))
- phy_calibrate(dwc->usb2_generic_phy);
- }
- break;
- case DWC3_GCTL_PRTCAP_DEVICE:
- if (dwc->usb2_phy)
- otg_set_vbus(dwc->usb2_phy->otg, false);
- phy_set_mode(dwc->usb2_generic_phy,
- PHY_MODE_USB_DEVICE);
- phy_set_mode(dwc->usb3_generic_phy,
- PHY_MODE_USB_DEVICE);
- dwc->gadget.ops->udc_set_speed(&dwc->gadget,
- dwc->maximum_speed);
- break;
- case DWC3_GCTL_PRTCAP_OTG:
- break;
- default:
- break;
- }
- } else {
-disconnect:
- switch (dwc->current_dr_role) {
- case DWC3_GCTL_PRTCAP_HOST:
- if (dwc->drd_connected) {
- /*
- * Set device mode to disable otg-vbus supply
- * and enable vbus detect for inno USB2PHY.
- */
- phy_set_mode(dwc->usb2_generic_phy,
- PHY_MODE_USB_DEVICE);
- phy_set_mode(dwc->usb3_generic_phy,
- PHY_MODE_USB_DEVICE);
- phy_power_off(dwc->usb3_generic_phy);
- dwc3_host_exit(dwc);
- }
- break;
- case DWC3_GCTL_PRTCAP_DEVICE:
- if (dwc->connected) {
- ret = wait_for_completion_timeout(&dwc->discon_done,
- msecs_to_jiffies(DWC3_DISCON_TIMEOUT));
- if (!ret)
- dev_warn(dwc->dev,
- "timed out waiting for disconnect\n");
- }
-
- break;
- case DWC3_GCTL_PRTCAP_OTG:
- break;
- default:
- dwc->current_dr_role = dwc->desired_dr_role;
- return;
- }
-
- /*
- * We should set drd_connected to false before
- * runtime_suspend to enable reset assert.
- */
- if (dwc->drd_connected) {
- dwc->drd_connected = false;
- pm_runtime_put_sync_suspend(dwc->dev);
- }
- }
+out:
+ pm_runtime_mark_last_busy(dwc->dev);
+ pm_runtime_put_autosuspend(dwc->dev);
+ mutex_unlock(&dwc->mutex);
}
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
unsigned long flags;
+
+ if (dwc->dr_mode != USB_DR_MODE_OTG)
+ return;
spin_lock_irqsave(&dwc->lock, flags);
dwc->desired_dr_role = mode;
@@ -340,23 +295,10 @@
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
* @dwc: pointer to our context structure
*/
-static int dwc3_core_soft_reset(struct dwc3 *dwc)
+int dwc3_core_soft_reset(struct dwc3 *dwc)
{
u32 reg;
int retries = 1000;
- int ret;
-
- usb_phy_init(dwc->usb2_phy);
- usb_phy_init(dwc->usb3_phy);
- ret = phy_init(dwc->usb2_generic_phy);
- if (ret < 0)
- return ret;
-
- ret = phy_init(dwc->usb3_generic_phy);
- if (ret < 0) {
- phy_exit(dwc->usb2_generic_phy);
- return ret;
- }
/*
* We're resetting only the device side because, if we're in host mode,
@@ -368,38 +310,43 @@
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= DWC3_DCTL_CSFTRST;
- dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ reg &= ~DWC3_DCTL_RUN_STOP;
+ dwc3_gadget_dctl_write_safe(dwc, reg);
+
+ /*
+ * For DWC_usb31 controller 1.90a and later, the DCTL.CSFRST bit
+ * is cleared only after all the clocks are synchronized. This can
+ * take a little more than 50ms. Set the polling rate at 20ms
+ * for 10 times instead.
+ */
+ if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
+ retries = 10;
do {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (!(reg & DWC3_DCTL_CSFTRST))
goto done;
- udelay(1);
+ if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
+ msleep(20);
+ else
+ udelay(1);
} while (--retries);
- phy_exit(dwc->usb3_generic_phy);
- phy_exit(dwc->usb2_generic_phy);
-
+ dev_warn(dwc->dev, "DWC3 controller soft reset failed.\n");
return -ETIMEDOUT;
done:
/*
- * For DWC_usb31 controller, once DWC3_DCTL_CSFTRST bit is cleared,
- * we must wait at least 50ms before accessing the PHY domain
- * (synchronization delay). DWC_usb31 programming guide section 1.3.2.
+ * For DWC_usb31 controller 1.80a and prior, once DCTL.CSFRST bit
+ * is cleared, we must wait at least 50ms before accessing the PHY
+ * domain (synchronization delay).
*/
- if (dwc3_is_usb31(dwc))
+ if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A))
msleep(50);
return 0;
}
-
-static const struct clk_bulk_data dwc3_core_clks[] = {
- { .id = "ref" },
- { .id = "bus_early" },
- { .id = "suspend" },
-};
/*
* dwc3_frame_length_adjustment - Adjusts frame length if required
@@ -410,7 +357,7 @@
u32 reg;
u32 dft;
- if (dwc->revision < DWC3_REVISION_250A)
+ if (DWC3_VER_IS_PRIOR(DWC3, 250A))
return;
if (dwc->fladj == 0)
@@ -445,7 +392,7 @@
* otherwise ERR_PTR(errno).
*/
static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
- unsigned length)
+ unsigned int length)
{
struct dwc3_event_buffer *evt;
@@ -488,7 +435,7 @@
* Returns 0 on success otherwise negative errno. In the error case, dwc
* may contain some buffers allocated but not all which were requested.
*/
-static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
+static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length)
{
struct dwc3_event_buffer *evt;
@@ -644,6 +591,9 @@
parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+
+ if (DWC3_IP_IS(DWC32))
+ parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9);
}
static int dwc3_core_ulpi_init(struct dwc3 *dwc)
@@ -672,7 +622,10 @@
*/
static int dwc3_phy_setup(struct dwc3 *dwc)
{
+ unsigned int hw_mode;
u32 reg;
+
+ hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
@@ -688,8 +641,16 @@
* will be '0' when the core is reset. Application needs to set it
* to '1' after the core initialization is completed.
*/
- if (dwc->revision > DWC3_REVISION_194A)
+ if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+ /*
+ * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
+ * power-on reset, and it can be set after core initialization, which is
+ * after device soft-reset during initialization.
+ */
+ if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
+ reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
if (dwc->u2ss_inp3_quirk)
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
@@ -741,9 +702,8 @@
if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
break;
}
- /* FALLTHROUGH */
+ fallthrough;
case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
- /* FALLTHROUGH */
default:
break;
}
@@ -771,8 +731,16 @@
* be '0' when the core is reset. Application needs to set it to
* '1' after the core initialization is completed.
*/
- if (dwc->revision > DWC3_REVISION_194A)
+ if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+ /*
+ * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
+ * power-on reset, and it can be set after core initialization, which is
+ * after device soft-reset during initialization.
+ */
+ if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
@@ -794,20 +762,18 @@
{
dwc3_event_buffers_cleanup(dwc);
+ usb_phy_set_suspend(dwc->usb2_phy, 1);
+ usb_phy_set_suspend(dwc->usb3_phy, 1);
+ phy_power_off(dwc->usb2_generic_phy);
+ phy_power_off(dwc->usb3_generic_phy);
+
usb_phy_shutdown(dwc->usb2_phy);
usb_phy_shutdown(dwc->usb3_phy);
phy_exit(dwc->usb2_generic_phy);
phy_exit(dwc->usb3_generic_phy);
- usb_phy_set_suspend(dwc->usb2_phy, 1);
- usb_phy_set_suspend(dwc->usb3_phy, 1);
- phy_power_off(dwc->usb2_generic_phy);
- phy_power_off(dwc->usb3_generic_phy);
- clk_bulk_disable(dwc->num_clks, dwc->clks);
- clk_bulk_unprepare(dwc->num_clks, dwc->clks);
-
- if (!dwc->drd_connected && dwc->dr_mode == USB_DR_MODE_OTG)
- reset_control_assert(dwc->reset);
+ clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks);
+ reset_control_assert(dwc->reset);
}
static bool dwc3_core_is_valid(struct dwc3 *dwc)
@@ -815,15 +781,13 @@
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+ dwc->ip = DWC3_GSNPS_ID(reg);
/* This should read as U3 followed by revision number */
- if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
- /* Detected DWC_usb3 IP */
+ if (DWC3_IP_IS(DWC3)) {
dwc->revision = reg;
- } else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
- /* Detected DWC_usb31 IP */
+ } else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) {
dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
- dwc->revision |= DWC3_REVISION_IS_DWC31;
dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE);
} else {
return false;
@@ -856,8 +820,7 @@
*/
if ((dwc->dr_mode == USB_DR_MODE_HOST ||
dwc->dr_mode == USB_DR_MODE_OTG) &&
- (dwc->revision >= DWC3_REVISION_210A &&
- dwc->revision <= DWC3_REVISION_250A))
+ DWC3_VER_IS_WITHIN(DWC3, 210A, 250A))
reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
else
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
@@ -879,7 +842,7 @@
/* check if current dwc3 is on simulation board */
if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
- dev_info(dwc->dev, "Running with FPGA optmizations\n");
+ dev_info(dwc->dev, "Running with FPGA optimizations\n");
dwc->is_fpga = true;
}
@@ -900,7 +863,7 @@
* and falls back to high-speed mode which causes
* the device to enter a Connect/Disconnect loop
*/
- if (dwc->revision < DWC3_REVISION_190A)
+ if (DWC3_VER_IS_PRIOR(DWC3, 190A))
reg |= DWC3_GCTL_U2RSTECN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
@@ -932,8 +895,7 @@
* result = 1, means INCRx burst mode supported.
* result > 1, means undefined length burst mode supported.
*/
- ntype = device_property_read_u32_array(dev,
- "snps,incr-burst-type-adjustment", NULL, 0);
+ ntype = device_property_count_u32(dev, "snps,incr-burst-type-adjustment");
if (ntype <= 0)
return;
@@ -1012,21 +974,17 @@
*/
static int dwc3_core_init(struct dwc3 *dwc)
{
+ unsigned int hw_mode;
u32 reg;
int ret;
+
+ hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
/*
* Write Linux Version Code to our GUID register so it's easy to figure
* out which kernel version a bug was found.
*/
dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
-
- /* Handle USB2.0-only core configuration */
- if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
- DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
- if (dwc->maximum_speed == USB_SPEED_SUPER)
- dwc->maximum_speed = USB_SPEED_HIGH;
- }
ret = dwc3_phy_setup(dwc);
if (ret)
@@ -1046,9 +1004,36 @@
dwc->phys_ready = true;
}
+ usb_phy_init(dwc->usb2_phy);
+ usb_phy_init(dwc->usb3_phy);
+ ret = phy_init(dwc->usb2_generic_phy);
+ if (ret < 0)
+ goto err0a;
+
+ ret = phy_init(dwc->usb3_generic_phy);
+ if (ret < 0) {
+ phy_exit(dwc->usb2_generic_phy);
+ goto err0a;
+ }
+
ret = dwc3_core_soft_reset(dwc);
if (ret)
- goto err0a;
+ goto err1;
+
+ if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
+ !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
+ if (!dwc->dis_u3_susphy_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+ }
+
+ if (!dwc->dis_u2_susphy_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ }
+ }
dwc3_core_setup_global_control(dwc);
dwc3_core_num_eps(dwc);
@@ -1083,21 +1068,30 @@
* the DWC_usb3 controller. It is NOT available in the
* DWC_usb31 controller.
*/
- if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
+ if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
reg |= DWC3_GUCTL2_RST_ACTBITLATER;
dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
}
- if (dwc->revision >= DWC3_REVISION_250A) {
+ if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
/*
* Enable hardware control of sending remote wakeup
* in HS when the device is in the L1 state.
*/
- if (dwc->revision >= DWC3_REVISION_290A)
+ if (!DWC3_VER_IS_PRIOR(DWC3, 290A))
reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
+
+ /*
+ * Decouple USB 2.0 L1 & L2 events which will allow for
+ * gadget driver to only receive U3/L2 suspend & wakeup
+ * events and prevent the more frequent L1 LPM transitions
+ * from interrupting the driver.
+ */
+ if (!DWC3_VER_IS_PRIOR(DWC3, 300A))
+ reg |= DWC3_GUCTL1_DEV_DECOUPLE_L1L2_EVT;
if (dwc->dis_tx_ipgap_linecheck_quirk)
reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
@@ -1132,7 +1126,7 @@
* Must config both number of packets and max burst settings to enable
* RX and/or TX threshold.
*/
- if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) {
+ if (!DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) {
u8 rx_thr_num = dwc->rx_thr_num_pkt_prd;
u8 rx_maxburst = dwc->rx_max_burst_prd;
u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
@@ -1206,52 +1200,36 @@
if (IS_ERR(dwc->usb2_phy)) {
ret = PTR_ERR(dwc->usb2_phy);
- if (ret == -ENXIO || ret == -ENODEV) {
+ if (ret == -ENXIO || ret == -ENODEV)
dwc->usb2_phy = NULL;
- } else if (ret == -EPROBE_DEFER) {
- return ret;
- } else {
- dev_err(dev, "no usb2 phy configured\n");
- return ret;
- }
+ else
+ return dev_err_probe(dev, ret, "no usb2 phy configured\n");
}
if (IS_ERR(dwc->usb3_phy)) {
ret = PTR_ERR(dwc->usb3_phy);
- if (ret == -ENXIO || ret == -ENODEV) {
+ if (ret == -ENXIO || ret == -ENODEV)
dwc->usb3_phy = NULL;
- } else if (ret == -EPROBE_DEFER) {
- return ret;
- } else {
- dev_err(dev, "no usb3 phy configured\n");
- return ret;
- }
+ else
+ return dev_err_probe(dev, ret, "no usb3 phy configured\n");
}
dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
if (IS_ERR(dwc->usb2_generic_phy)) {
ret = PTR_ERR(dwc->usb2_generic_phy);
- if (ret == -ENOSYS || ret == -ENODEV) {
+ if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb2_generic_phy = NULL;
- } else if (ret == -EPROBE_DEFER) {
- return ret;
- } else {
- dev_err(dev, "no usb2 phy configured\n");
- return ret;
- }
+ else
+ return dev_err_probe(dev, ret, "no usb2 phy configured\n");
}
dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
if (IS_ERR(dwc->usb3_generic_phy)) {
ret = PTR_ERR(dwc->usb3_generic_phy);
- if (ret == -ENOSYS || ret == -ENODEV) {
+ if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb3_generic_phy = NULL;
- } else if (ret == -EPROBE_DEFER) {
- return ret;
- } else {
- dev_err(dev, "no usb3 phy configured\n");
- return ret;
- }
+ else
+ return dev_err_probe(dev, ret, "no usb3 phy configured\n");
}
return 0;
@@ -1272,28 +1250,10 @@
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to initialize gadget\n");
- return ret;
- }
-
- if (dwc->uwk_en)
- device_init_wakeup(dev, true);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize gadget\n");
break;
case USB_DR_MODE_HOST:
- /*
- * To prevent usb device be reenumerated when resume from PM
- * suspend, we set the flag dwc->power.can_wakeup which can
- * keep PD on and run phy_power_on again to avoid
- * phy_power_on failed (error -110) in Rockchip platform.
- */
- if (!of_machine_is_compatible("rockchip,rk3568") &&
- !of_machine_is_compatible("rockchip,rk3566"))
- device_init_wakeup(dev, true);
-
- phy_power_on(dwc->usb3_generic_phy);
-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
if (dwc->usb2_phy)
@@ -1302,37 +1262,14 @@
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
ret = dwc3_host_init(dwc);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to initialize host\n");
- return ret;
- }
- if (!of_device_is_compatible(dwc->dev->parent->of_node,
- "rockchip,rk3399-dwc3"))
- phy_calibrate(dwc->usb2_generic_phy);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize host\n");
break;
case USB_DR_MODE_OTG:
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
- if (dwc->en_runtime) {
- ret = dwc3_gadget_init(dwc);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to initialize gadget\n");
- return ret;
- }
- }
ret = dwc3_drd_init(dwc);
- if (ret) {
- if (dwc->en_runtime)
- dwc3_gadget_exit(dwc);
-
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to initialize dual-role\n");
- return ret;
- }
-
- if (dwc->uwk_en)
- device_init_wakeup(dev, true);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize dual-role\n");
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
@@ -1369,10 +1306,13 @@
u8 lpm_nyet_threshold;
u8 tx_de_emphasis;
u8 hird_threshold;
- u8 rx_thr_num_pkt_prd;
- u8 rx_max_burst_prd;
- u8 tx_thr_num_pkt_prd;
- u8 tx_max_burst_prd;
+ u8 rx_thr_num_pkt_prd = 0;
+ u8 rx_max_burst_prd = 0;
+ u8 tx_thr_num_pkt_prd = 0;
+ u8 tx_max_burst_prd = 0;
+ u8 tx_fifo_resize_max_num;
+ const char *usb_psy_name;
+ int ret;
/* default to highest possible threshold */
lpm_nyet_threshold = 0xf;
@@ -1386,7 +1326,15 @@
*/
hird_threshold = 12;
+ /*
+ * default to a TXFIFO size large enough to fit 6 max packets. This
+ * allows for systems with larger bus latencies to have some headroom
+ * for endpoints that have a large bMaxBurst value.
+ */
+ tx_fifo_resize_max_num = 6;
+
dwc->maximum_speed = usb_get_maximum_speed(dev);
+ dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev);
dwc->dr_mode = usb_get_dr_mode(dev);
dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
@@ -1396,6 +1344,13 @@
dwc->sysdev = dwc->dev->parent;
else
dwc->sysdev = dwc->dev;
+
+ ret = device_property_read_string(dev, "usb-psy-name", &usb_psy_name);
+ if (ret >= 0) {
+ dwc->usb_psy = power_supply_get_by_name(usb_psy_name);
+ if (!dwc->usb_psy)
+ dev_err(dev, "couldn't get usb power supply\n");
+ }
dwc->has_lpm_erratum = device_property_read_bool(dev,
"snps,has-lpm-erratum");
@@ -1411,6 +1366,8 @@
"snps,usb3_lpm_capable");
dwc->usb2_lpm_disable = device_property_read_bool(dev,
"snps,usb2-lpm-disable");
+ dwc->usb2_gadget_lpm_disable = device_property_read_bool(dev,
+ "snps,usb2-gadget-lpm-disable");
device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd",
&rx_thr_num_pkt_prd);
device_property_read_u8(dev, "snps,rx-max-burst-prd",
@@ -1419,6 +1376,11 @@
&tx_thr_num_pkt_prd);
device_property_read_u8(dev, "snps,tx-max-burst-prd",
&tx_max_burst_prd);
+ dwc->do_fifo_resize = device_property_read_bool(dev,
+ "tx-fifo-resize");
+ if (dwc->do_fifo_resize)
+ device_property_read_u8(dev, "tx-fifo-max-num",
+ &tx_fifo_resize_max_num);
dwc->disable_scramble_quirk = device_property_read_bool(dev,
"snps,disable_scramble_quirk");
@@ -1440,10 +1402,12 @@
"snps,dis_u3_susphy_quirk");
dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
"snps,dis_u2_susphy_quirk");
- dwc->dis_u1u2_quirk = device_property_read_bool(dev,
- "snps,dis-u1u2-quirk");
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
"snps,dis_enblslpm_quirk");
+ dwc->dis_u1_entry_quirk = device_property_read_bool(dev,
+ "snps,dis-u1-entry-quirk");
+ dwc->dis_u2_entry_quirk = device_property_read_bool(dev,
+ "snps,dis-u2-entry-quirk");
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
"snps,dis_rxdet_inp3_quirk");
dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
@@ -1454,12 +1418,6 @@
"snps,dis-tx-ipgap-linecheck-quirk");
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-ss-quirk");
- dwc->xhci_slow_suspend_quirk = device_property_read_bool(dev,
- "snps,xhci-slow-suspend-quirk");
- dwc->xhci_trb_ent_quirk = device_property_read_bool(dev,
- "snps,xhci-trb-ent-quirk");
- dwc->dis_u3_autosuspend_quirk = device_property_read_bool(dev,
- "snps,dis-u3-autosuspend-quirk");
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
"snps,tx_de_emphasis_quirk");
@@ -1472,18 +1430,14 @@
dwc->dis_metastability_quirk = device_property_read_bool(dev,
"snps,dis_metastability_quirk");
- dwc->needs_fifo_resize = device_property_read_bool(dev,
- "snps,tx-fifo-resize");
- dwc->xhci_warm_reset_on_suspend_quirk = device_property_read_bool(dev,
- "snps,xhci-warm-reset-on-suspend-quirk");
- dwc->uwk_en = device_property_read_bool(dev,
- "wakeup-source");
+
+ dwc->dis_split_quirk = device_property_read_bool(dev,
+ "snps,dis-split-quirk");
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;
- dwc->hird_threshold = hird_threshold
- | (dwc->is_utmi_l1_suspend << 4);
+ dwc->hird_threshold = hird_threshold;
dwc->rx_thr_num_pkt_prd = rx_thr_num_pkt_prd;
dwc->rx_max_burst_prd = rx_max_burst_prd;
@@ -1492,20 +1446,23 @@
dwc->tx_max_burst_prd = tx_max_burst_prd;
dwc->imod_interval = 0;
+
+ dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
}
/* check whether the core supports IMOD */
bool dwc3_has_imod(struct dwc3 *dwc)
{
- return ((dwc3_is_usb3(dwc) &&
- dwc->revision >= DWC3_REVISION_300A) ||
- (dwc3_is_usb31(dwc) &&
- dwc->revision >= DWC3_USB31_REVISION_120A));
+ return DWC3_VER_IS_WITHIN(DWC3, 300A, ANY) ||
+ DWC3_VER_IS_WITHIN(DWC31, 120A, ANY) ||
+ DWC3_IP_IS(DWC32);
}
static void dwc3_check_params(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
+ unsigned int hwparam_gen =
+ DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3);
/* Check for proper value of imod_interval */
if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
@@ -1521,7 +1478,7 @@
* affected version.
*/
if (!dwc->imod_interval &&
- (dwc->revision == DWC3_REVISION_300A))
+ DWC3_VER_IS(DWC3, 300A))
dwc->imod_interval = 1;
/* Check the maximum_speed parameter */
@@ -1529,64 +1486,95 @@
case USB_SPEED_LOW:
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
+ break;
case USB_SPEED_SUPER:
+ if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS)
+ dev_warn(dev, "UDC doesn't support Gen 1\n");
+ break;
case USB_SPEED_SUPER_PLUS:
+ if ((DWC3_IP_IS(DWC32) &&
+ hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) ||
+ (!DWC3_IP_IS(DWC32) &&
+ hwparam_gen != DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
+ dev_warn(dev, "UDC doesn't support SSP\n");
break;
default:
dev_err(dev, "invalid maximum_speed parameter %d\n",
dwc->maximum_speed);
- /* fall through */
+ fallthrough;
case USB_SPEED_UNKNOWN:
- /* default to superspeed */
- dwc->maximum_speed = USB_SPEED_SUPER;
-
- /*
- * default to superspeed plus if we are capable.
- */
- if (dwc3_is_usb31(dwc) &&
- (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
- DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
+ switch (hwparam_gen) {
+ case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2:
dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
-
+ break;
+ case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1:
+ if (DWC3_IP_IS(DWC32))
+ dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
+ else
+ dwc->maximum_speed = USB_SPEED_SUPER;
+ break;
+ case DWC3_GHWPARAMS3_SSPHY_IFC_DIS:
+ dwc->maximum_speed = USB_SPEED_HIGH;
+ break;
+ default:
+ dwc->maximum_speed = USB_SPEED_SUPER;
+ break;
+ }
break;
}
-}
-static void dwc3_rockchip_async_probe(void *data, async_cookie_t cookie)
-{
- struct dwc3 *dwc = data;
- struct device *dev = dwc->dev;
- int id;
-
- if (dwc->edev && !dwc->drd_connected) {
- id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
- if (id < 0)
- id = 0;
- dwc->current_dr_role = id ? DWC3_GCTL_PRTCAP_HOST :
- DWC3_GCTL_PRTCAP_DEVICE;
+ /*
+ * Currently the controller does not have visibility into the HW
+ * parameter to determine the maximum number of lanes the HW supports.
+ * If the number of lanes is not specified in the device property, then
+ * set the default to support dual-lane for DWC_usb32 and single-lane
+ * for DWC_usb31 for super-speed-plus.
+ */
+ if (dwc->maximum_speed == USB_SPEED_SUPER_PLUS) {
+ switch (dwc->max_ssp_rate) {
+ case USB_SSP_GEN_2x1:
+ if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_GEN1)
+ dev_warn(dev, "UDC only supports Gen 1\n");
+ break;
+ case USB_SSP_GEN_1x2:
+ case USB_SSP_GEN_2x2:
+ if (DWC3_IP_IS(DWC31))
+ dev_warn(dev, "UDC only supports single lane\n");
+ break;
+ case USB_SSP_GEN_UNKNOWN:
+ default:
+ switch (hwparam_gen) {
+ case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2:
+ if (DWC3_IP_IS(DWC32))
+ dwc->max_ssp_rate = USB_SSP_GEN_2x2;
+ else
+ dwc->max_ssp_rate = USB_SSP_GEN_2x1;
+ break;
+ case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1:
+ if (DWC3_IP_IS(DWC32))
+ dwc->max_ssp_rate = USB_SSP_GEN_1x2;
+ break;
+ }
+ break;
+ }
}
-
- pm_runtime_put_sync_suspend(dev);
}
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res, dwc_res;
+ struct dwc3_vendor *vdwc;
struct dwc3 *dwc;
int ret;
void __iomem *regs;
- dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
- if (!dwc)
+ vdwc = devm_kzalloc(dev, sizeof(*vdwc), GFP_KERNEL);
+ if (!vdwc)
return -ENOMEM;
-
- dwc->clks = devm_kmemdup(dev, dwc3_core_clks, sizeof(dwc3_core_clks),
- GFP_KERNEL);
- if (!dwc->clks)
- return -ENOMEM;
+ dwc = &vdwc->dwc;
dwc->dev = dev;
@@ -1616,58 +1604,46 @@
dwc->regs = regs;
dwc->regs_size = resource_size(&dwc_res);
- dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
+ dwc3_get_properties(dwc);
+
+ dwc->reset = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
- ret = reset_control_deassert(dwc->reset);
- if (ret)
- return ret;
-
- /* Reset the whole dwc3 controller */
- ret = reset_control_assert(dwc->reset);
- if (ret)
- return ret;
-
- udelay(1);
-
- ret = reset_control_deassert(dwc->reset);
- if (ret)
- return ret;
-
- if (!dwc3_core_is_valid(dwc)) {
- dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
- return -ENODEV;
- }
-
- dwc3_get_properties(dwc);
-
if (dev->of_node) {
- dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);
-
- ret = clk_bulk_get(dev, dwc->num_clks, dwc->clks);
+ ret = devm_clk_bulk_get_all(dev, &dwc->clks);
if (ret == -EPROBE_DEFER)
- goto assert_reset;
+ return ret;
/*
* Clocks are optional, but new DT platforms should support all
* clocks as required by the DT-binding.
*/
- if (ret)
+ if (ret < 0)
dwc->num_clks = 0;
+ else
+ dwc->num_clks = ret;
+
}
- ret = clk_bulk_prepare(dwc->num_clks, dwc->clks);
+ ret = reset_control_deassert(dwc->reset);
if (ret)
- goto put_clks;
+ return ret;
- ret = clk_bulk_enable(dwc->num_clks, dwc->clks);
+ ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks);
if (ret)
- goto unprepare_clks;
+ goto assert_reset;
+
+ if (!dwc3_core_is_valid(dwc)) {
+ dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+ ret = -ENODEV;
+ goto disable_clks;
+ }
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
spin_lock_init(&dwc->lock);
+ mutex_init(&dwc->mutex);
pm_runtime_set_active(dev);
pm_runtime_use_autosuspend(dev);
@@ -1690,21 +1666,13 @@
if (ret)
goto err3;
- if (dwc->dr_mode == USB_DR_MODE_OTG &&
- of_device_is_compatible(dev->parent->of_node,
- "rockchip,rk3399-dwc3")) {
- pm_runtime_allow(dev);
- dwc->en_runtime = true;
- }
-
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err3;
ret = dwc3_core_init(dwc);
if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to initialize core: %d\n", ret);
+ dev_err_probe(dev, ret, "failed to initialize core\n");
goto err4;
}
@@ -1715,10 +1683,17 @@
if (ret)
goto err5;
- if (dwc->en_runtime)
- async_schedule(dwc3_rockchip_async_probe, dwc);
- else
+ if (dwc->dr_mode == USB_DR_MODE_OTG &&
+ of_device_is_compatible(dev->parent->of_node,
+ "rockchip,rk3399-dwc3")) {
+#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
+ pm_runtime_set_autosuspend_delay(dev, 100);
+#endif
+ pm_runtime_allow(dev);
+ pm_runtime_put_sync_suspend(dev);
+ } else {
pm_runtime_put(dev);
+ }
return 0;
@@ -1726,15 +1701,15 @@
dwc3_debugfs_exit(dwc);
dwc3_event_buffers_cleanup(dwc);
- usb_phy_shutdown(dwc->usb2_phy);
- usb_phy_shutdown(dwc->usb3_phy);
- phy_exit(dwc->usb2_generic_phy);
- phy_exit(dwc->usb3_generic_phy);
-
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
phy_power_off(dwc->usb2_generic_phy);
phy_power_off(dwc->usb3_generic_phy);
+
+ usb_phy_shutdown(dwc->usb2_phy);
+ usb_phy_shutdown(dwc->usb3_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
dwc3_ulpi_exit(dwc);
@@ -1751,13 +1726,13 @@
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- clk_bulk_disable(dwc->num_clks, dwc->clks);
-unprepare_clks:
- clk_bulk_unprepare(dwc->num_clks, dwc->clks);
-put_clks:
- clk_bulk_put(dwc->num_clks, dwc->clks);
+disable_clks:
+ clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks);
assert_reset:
reset_control_assert(dwc->reset);
+
+ if (dwc->usb_psy)
+ power_supply_put(dwc->usb_psy);
return ret;
}
@@ -1780,7 +1755,9 @@
dwc3_free_event_buffers(dwc);
dwc3_free_scratch_buffers(dwc);
- clk_bulk_put(dwc->num_clks, dwc->clks);
+
+ if (dwc->usb_psy)
+ power_supply_put(dwc->usb_psy);
return 0;
}
@@ -1790,19 +1767,13 @@
{
int ret;
- if (!dwc->drd_connected && dwc->dr_mode == USB_DR_MODE_OTG) {
- ret = reset_control_deassert(dwc->reset);
- if (ret)
- return ret;
- }
+ ret = reset_control_deassert(dwc->reset);
+ if (ret)
+ return ret;
- ret = clk_bulk_prepare(dwc->num_clks, dwc->clks);
+ ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks);
if (ret)
goto assert_reset;
-
- ret = clk_bulk_enable(dwc->num_clks, dwc->clks);
- if (ret)
- goto unprepare_clks;
ret = dwc3_core_init(dwc);
if (ret)
@@ -1811,12 +1782,9 @@
return 0;
disable_clks:
- clk_bulk_disable(dwc->num_clks, dwc->clks);
-unprepare_clks:
- clk_bulk_unprepare(dwc->num_clks, dwc->clks);
+ clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks);
assert_reset:
- if (!dwc->drd_connected && dwc->dr_mode == USB_DR_MODE_OTG)
- reset_control_assert(dwc->reset);
+ reset_control_assert(dwc->reset);
return ret;
}
@@ -1828,14 +1796,14 @@
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
- spin_lock_irqsave(&dwc->lock, flags);
+ if (pm_runtime_suspended(dwc->dev))
+ break;
dwc3_gadget_suspend(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
synchronize_irq(dwc->irq_gadget);
dwc3_core_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
- if (!PMSG_IS_AUTO(msg) || dwc->en_runtime) {
+ if (!PMSG_IS_AUTO(msg)) {
dwc3_core_exit(dwc);
break;
}
@@ -1871,7 +1839,8 @@
dwc3_core_exit(dwc);
break;
default:
- /* do nothing */
+ if (!pm_runtime_suspended(dwc->dev))
+ dwc3_core_exit(dwc);
break;
}
@@ -1891,12 +1860,10 @@
return ret;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
- spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
break;
case DWC3_GCTL_PRTCAP_HOST:
- if (!PMSG_IS_AUTO(msg) || dwc->en_runtime) {
+ if (!PMSG_IS_AUTO(msg)) {
ret = dwc3_core_init_for_resume(dwc);
if (ret)
return ret;
@@ -1938,7 +1905,9 @@
break;
default:
- /* do nothing */
+ ret = dwc3_core_init_for_resume(dwc);
+ if (ret)
+ return ret;
break;
}
@@ -2032,40 +2001,12 @@
struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
- if (dwc->uwk_en) {
- dwc3_gadget_disable_irq(dwc);
- synchronize_irq(dwc->irq_gadget);
- return 0;
- }
-
if (pm_runtime_suspended(dwc->dev))
return 0;
ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
if (ret)
return ret;
-
- /*
- * If link state is Rx.Detect, it means that
- * no usb device is connecting with the DWC3
- * Host, and need to power off the USB3 PHY.
- *
- * If link state is in other state, like U0
- * or U3 state, it means that at least one
- * USB3 device is connecting with the Host
- * port, in this case, we don't power off
- * the USB3 PHY because some USB3 PHYs (like
- * RK3399 Type-C USB3 PHY) require that the
- * power on operation must be done while the
- * DWC3 controller is in P2 state, but the
- * state is in P0 after resume with a USB3
- * device connected. So we set the USB3 PHY
- * in power on state in this case.
- */
- dwc->link_state = dwc3_gadget_get_link_state(dwc);
- if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
- dwc->link_state == DWC3_LINK_STATE_RX_DET)
- phy_power_off(dwc->usb3_generic_phy);
pinctrl_pm_select_sleep_state(dev);
@@ -2077,19 +2018,10 @@
struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
- if (dwc->uwk_en) {
- dwc3_gadget_enable_irq(dwc);
- return 0;
- }
-
if (pm_runtime_suspended(dwc->dev))
return 0;
pinctrl_pm_select_default_state(dev);
-
- if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
- dwc->link_state == DWC3_LINK_STATE_RX_DET)
- phy_power_on(dwc->usb3_generic_phy);
ret = dwc3_resume_common(dwc, PMSG_RESUME);
if (ret)
@@ -2101,10 +2033,26 @@
return 0;
}
+
+static void dwc3_complete(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ u32 reg;
+
+ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
+ dwc->dis_split_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
+ reg |= DWC3_GUCTL3_SPLITDISABLE;
+ dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
+ }
+}
+#else
+#define dwc3_complete NULL
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dwc3_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
+ .complete = dwc3_complete,
SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
dwc3_runtime_idle)
};
--
Gitblit v1.6.2