[PATCH 4.14 101/115] usb: dwc3: core: Fix ULPI PHYs and prevent phy_get/ulpi_init during suspend/resume

From: Greg Kroah-Hartman
Date: Thu Sep 13 2018 - 09:48:29 EST


4.14-stable review patch. If anyone has any objections, please let me know.

------------------

From: Roger Quadros <rogerq@xxxxxx>

commit 98112041bcca164676367e261c8c1073ef70cb51 upstream.

In order for ULPI PHYs to work, dwc3_phy_setup() and dwc3_ulpi_init()
must be doene before dwc3_core_get_phy().

commit 541768b08a40 ("usb: dwc3: core: Call dwc3_core_get_phy() before initializing phys")
broke this.

The other issue is that dwc3_core_get_phy() and dwc3_ulpi_init() should
be called only once during the life cycle of the driver. However,
as dwc3_core_init() is called during system suspend/resume it will
result in multiple calls to dwc3_core_get_phy() and dwc3_ulpi_init()
which is wrong.

Fix this by moving dwc3_ulpi_init() out of dwc3_phy_setup()
into dwc3_core_ulpi_init(). Use a flag 'ulpi_ready' to ensure that
dwc3_core_ulpi_init() is called only once from dwc3_core_init().

Use another flag 'phys_ready' to call dwc3_core_get_phy() only once from
dwc3_core_init().

Fixes: 541768b08a40 ("usb: dwc3: core: Call dwc3_core_get_phy() before initializing phys")
Fixes: f54edb539c11 ("usb: dwc3: core: initialize ULPI before trying to get the PHY")
Cc: linux-stable <stable@xxxxxxxxxxxxxxx> # >= v4.13
Signed-off-by: Roger Quadros <rogerq@xxxxxx>
Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>
Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@xxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/usb/dwc3/core.c | 47 ++++++++++++++++++++++++++++++++++++-----------
drivers/usb/dwc3/core.h | 5 +++++
2 files changed, 41 insertions(+), 11 deletions(-)

--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -511,6 +511,22 @@ static void dwc3_cache_hwparams(struct d
parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
}

+static int dwc3_core_ulpi_init(struct dwc3 *dwc)
+{
+ int intf;
+ int ret = 0;
+
+ intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3);
+
+ if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI ||
+ (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI &&
+ dwc->hsphy_interface &&
+ !strncmp(dwc->hsphy_interface, "ulpi", 4)))
+ ret = dwc3_ulpi_init(dwc);
+
+ return ret;
+}
+
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
@@ -522,7 +538,6 @@ static void dwc3_cache_hwparams(struct d
static int dwc3_phy_setup(struct dwc3 *dwc)
{
u32 reg;
- int ret;

reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));

@@ -593,9 +608,6 @@ static int dwc3_phy_setup(struct dwc3 *d
}
/* FALLTHROUGH */
case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
- ret = dwc3_ulpi_init(dwc);
- if (ret)
- return ret;
/* FALLTHROUGH */
default:
break;
@@ -752,6 +764,7 @@ static void dwc3_core_setup_global_contr
}

static int dwc3_core_get_phy(struct dwc3 *dwc);
+static int dwc3_core_ulpi_init(struct dwc3 *dwc);

/**
* dwc3_core_init - Low-level initialization of DWC3 Core
@@ -783,17 +796,27 @@ static int dwc3_core_init(struct dwc3 *d
dwc->maximum_speed = USB_SPEED_HIGH;
}

- ret = dwc3_core_get_phy(dwc);
+ ret = dwc3_phy_setup(dwc);
if (ret)
goto err0;

- ret = dwc3_core_soft_reset(dwc);
- if (ret)
- goto err0;
+ if (!dwc->ulpi_ready) {
+ ret = dwc3_core_ulpi_init(dwc);
+ if (ret)
+ goto err0;
+ dwc->ulpi_ready = true;
+ }

- ret = dwc3_phy_setup(dwc);
+ if (!dwc->phys_ready) {
+ ret = dwc3_core_get_phy(dwc);
+ if (ret)
+ goto err0a;
+ dwc->phys_ready = true;
+ }
+
+ ret = dwc3_core_soft_reset(dwc);
if (ret)
- goto err0;
+ goto err0a;

dwc3_core_setup_global_control(dwc);
dwc3_core_num_eps(dwc);
@@ -866,6 +889,9 @@ err1:
phy_exit(dwc->usb2_generic_phy);
phy_exit(dwc->usb3_generic_phy);

+err0a:
+ dwc3_ulpi_exit(dwc);
+
err0:
return ret;
}
@@ -1256,7 +1282,6 @@ err4:

err3:
dwc3_free_event_buffers(dwc);
- dwc3_ulpi_exit(dwc);

err2:
pm_runtime_allow(&pdev->dev);
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -805,7 +805,9 @@ struct dwc3_scratchpad_array {
* @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to USB2 PHY
* @usb3_generic_phy: pointer to USB3 PHY
+ * @phys_ready: flag to indicate that PHYs are ready
* @ulpi: pointer to ulpi interface
+ * @ulpi_ready: flag to indicate that ULPI is initialized
* @isoch_delay: wValue from Set Isochronous Delay request;
* @u2sel: parameter from Set SEL request.
* @u2pel: parameter from Set SEL request.
@@ -903,7 +905,10 @@ struct dwc3 {
struct phy *usb2_generic_phy;
struct phy *usb3_generic_phy;

+ bool phys_ready;
+
struct ulpi *ulpi;
+ bool ulpi_ready;

void __iomem *regs;
size_t regs_size;