1cd8ae19a9
Add backported patched from 5.x from usb related fixes Up kernel version to most recent lts
165 lines
5.8 KiB
Diff
165 lines
5.8 KiB
Diff
From c846b03ff767149d75d4d8dca6d3d4945a21074a Mon Sep 17 00:00:00 2001
|
|
From: Douglas Anderson <dianders@chromium.org>
|
|
Date: Mon, 20 May 2019 10:56:04 -0700
|
|
Subject: [PATCH 51/53] USB: dwc2: Don't turn off the usbphy in suspend if
|
|
wakeup is enabled
|
|
|
|
If the 'snps,need-phy-for-wake' is set in the device tree then:
|
|
|
|
- We know that we can wakeup, so call device_set_wakeup_capable().
|
|
The USB core will use this knowledge to enable wakeup by default.
|
|
- We know that we should keep the PHY on during suspend if something
|
|
on our root hub needs remote wakeup. This requires the patch (USB:
|
|
Export usb_wakeup_enabled_descendants()). Note that we don't keep
|
|
the PHY on at suspend time if it's not needed because it would be a
|
|
power draw.
|
|
|
|
If we later find some users of dwc2 that can support wakeup without
|
|
keeping the PHY on we may want to add a way to call
|
|
device_set_wakeup_capable() without keeping the PHY on at suspend
|
|
time.
|
|
|
|
Signed-off-by: Douglas Anderson <dianders@chromium.org>
|
|
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
|
|
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
|
|
---
|
|
drivers/usb/dwc2/core.h | 8 ++++++++
|
|
drivers/usb/dwc2/hcd.c | 19 +++++++++++++++++++
|
|
drivers/usb/dwc2/platform.c | 23 ++++++++++++++++++++---
|
|
3 files changed, 47 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
|
|
index 152ac41dfb2d..d08d070a0fb6 100644
|
|
--- a/drivers/usb/dwc2/core.h
|
|
+++ b/drivers/usb/dwc2/core.h
|
|
@@ -861,6 +861,9 @@ struct dwc2_hregs_backup {
|
|
* @hibernated: True if core is hibernated
|
|
* @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
|
|
* remote wakeup.
|
|
+ * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
|
|
+ * @need_phy_for_wake: Quirk saying that we should keep the PHY on at
|
|
+ * suspend if we need USB to wake us up.
|
|
* @frame_number: Frame number read from the core. For both device
|
|
* and host modes. The value ranges are from 0
|
|
* to HFNUM_MAX_FRNUM.
|
|
@@ -1049,6 +1052,8 @@ struct dwc2_hsotg {
|
|
unsigned int ll_hw_enabled:1;
|
|
unsigned int hibernated:1;
|
|
unsigned int reset_phy_on_wake:1;
|
|
+ unsigned int need_phy_for_wake:1;
|
|
+ unsigned int phy_off_for_suspend:1;
|
|
u16 frame_number;
|
|
|
|
struct phy *phy;
|
|
@@ -1438,6 +1443,7 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
|
|
int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
|
|
int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
|
|
int rem_wakeup, int reset);
|
|
+bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
|
|
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
|
|
{ schedule_work(&hsotg->phy_reset_work); }
|
|
#else
|
|
@@ -1463,6 +1469,8 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
|
|
static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
|
|
int rem_wakeup, int reset)
|
|
{ return 0; }
|
|
+static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
|
|
+{ return false; }
|
|
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
|
|
|
|
#endif
|
|
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
|
|
index 2192a2873c7c..4c78a390c958 100644
|
|
--- a/drivers/usb/dwc2/hcd.c
|
|
+++ b/drivers/usb/dwc2/hcd.c
|
|
@@ -5587,3 +5587,22 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
|
|
dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
|
|
return ret;
|
|
}
|
|
+
|
|
+bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
|
|
+{
|
|
+ struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub;
|
|
+
|
|
+ /* If the controller isn't allowed to wakeup then we can power off. */
|
|
+ if (!device_may_wakeup(dwc2->dev))
|
|
+ return true;
|
|
+
|
|
+ /*
|
|
+ * We don't want to power off the PHY if something under the
|
|
+ * root hub has wakeup enabled.
|
|
+ */
|
|
+ if (usb_wakeup_enabled_descendants(root_hub))
|
|
+ return false;
|
|
+
|
|
+ /* No reason to keep the PHY powered, so allow poweroff */
|
|
+ return true;
|
|
+}
|
|
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
|
|
index d10a7f8daec3..3e6c3c8a32ff 100644
|
|
--- a/drivers/usb/dwc2/platform.c
|
|
+++ b/drivers/usb/dwc2/platform.c
|
|
@@ -447,6 +447,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
if (retval)
|
|
goto error;
|
|
|
|
+ hsotg->need_phy_for_wake =
|
|
+ of_property_read_bool(dev->dev.of_node,
|
|
+ "snps,need-phy-for-wake");
|
|
+
|
|
/*
|
|
* Reset before dwc2_get_hwparams() then it could get power-on real
|
|
* reset value form registers.
|
|
@@ -478,6 +482,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
hsotg->gadget_enabled = 1;
|
|
}
|
|
|
|
+ /*
|
|
+ * If we need PHY for wakeup we must be wakeup capable.
|
|
+ * When we have a device that can wake without the PHY we
|
|
+ * can adjust this condition.
|
|
+ */
|
|
+ if (hsotg->need_phy_for_wake)
|
|
+ device_set_wakeup_capable(&dev->dev, true);
|
|
+
|
|
hsotg->reset_phy_on_wake =
|
|
of_property_read_bool(dev->dev.of_node,
|
|
"snps,reset-phy-on-wake");
|
|
@@ -516,13 +528,17 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
static int __maybe_unused dwc2_suspend(struct device *dev)
|
|
{
|
|
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
|
+ bool is_device_mode = dwc2_is_device_mode(dwc2);
|
|
int ret = 0;
|
|
|
|
- if (dwc2_is_device_mode(dwc2))
|
|
+ if (is_device_mode)
|
|
dwc2_hsotg_suspend(dwc2);
|
|
|
|
- if (dwc2->ll_hw_enabled)
|
|
+ if (dwc2->ll_hw_enabled &&
|
|
+ (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
|
|
ret = __dwc2_lowlevel_hw_disable(dwc2);
|
|
+ dwc2->phy_off_for_suspend = true;
|
|
+ }
|
|
|
|
return ret;
|
|
}
|
|
@@ -532,11 +548,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
|
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
|
int ret = 0;
|
|
|
|
- if (dwc2->ll_hw_enabled) {
|
|
+ if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
|
|
ret = __dwc2_lowlevel_hw_enable(dwc2);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
+ dwc2->phy_off_for_suspend = false;
|
|
|
|
if (dwc2_is_device_mode(dwc2))
|
|
ret = dwc2_hsotg_resume(dwc2);
|
|
--
|
|
2.11.0
|
|
|