[PATCH] RFT: usb: dwc2: bus suspend/resume that's not hibernate

From: Douglas Anderson
Date: Fri Oct 30 2015 - 16:33:10 EST


This is an attempt to rehash commit 0cf884e819e0 ("usb: dwc2: add bus
suspend/resume for dwc2") on ToT. That commit was reverted in commit
b0bb9bb6ce01 ("Revert "usb: dwc2: add bus suspend/resume for dwc2"")
because apparently it broke the Altera SOCFPGA.

With all the changes that have happened to dwc2 in the meantime, it's
possible that the Altera SOCFPGA will just magically work with this
change now. ...and it would be good to get bus suspend/resume
implemented.

Signed-off-by: Douglas Anderson <dianders@xxxxxxxxxxxx>
---
I've posted up a bunch of patches recently but tried to keep them in
separate series where it makes sense. A summary of known patches:
All patches can be found with: https://patchwork.kernel.org/patch/<ID>/

ACKed (thanks!) and not yet landed:
7453801 usb: dwc2: host: Fix ahbcfg for rk3066
7467521 usb: dwc2: host: Fix remote wakeup when not in DWC2_L2

Important, not yet reviewed:
7421171 [1/2] usb: dwc2: host: Fix missing device insertions

Fixes no known issues, not yet reviewed:
7421181 [2/2] usb: dwc2: host: Clear interrupts before handling them

Optimization to reduce probe time (may require simple rebase):
7348131 [1/5] usb: dwc2: Restore GUSBCFG in dwc2_get_hwparams()
7348221 [2/5] usb: dwc2: reset dwc2 core before dwc2_get_hwparams()
7348191 [3/5] CHROMIUM: usb: dwc2: Avoid double-reset at boot time
7348211 [4/5] usb: dwc2: Speed dwc2_get_hwparams() on some host-only ports
7348201 [5/5] usb: dwc2: reduce dwc2 driver probe time
7355241 usb: dwc2: Avoid more calls to dwc2_core_reset()

Fix host port:
7529101 usb: dwc2: optionally assert phy "full reset" when waking up
7529081 ARM: dts: rockchip: Point rk3288 dwc2 usb at the full PHY reset

This patch:
RFT: usb: dwc2: bus suspend/resume that's not hibernate

Abandoned for now (can't get wakeup to work on mainline):
6727091 [REPOST,1/3] USB: Export usb_wakeup_enabled_descendants()
6727101 [REPOST,2/3] Documentation: dt-bindings: Add snps,need-phy-for-wake for dwc2 USB
6727121 [REPOST,3/3] USB: dwc2: Don't turn off the usbphy in suspend if wakeup is enabled

drivers/usb/dwc2/hcd.c | 79 ++++++++++++++++++++++++++++++--------------------
1 file changed, 47 insertions(+), 32 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index e79baf73c234..0771fa667d0f 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -2381,6 +2381,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
unsigned long flags;
int ret = 0;
u32 hprt0;
+ u32 pcgctl;

spin_lock_irqsave(&hsotg->lock, flags);

@@ -2390,27 +2391,41 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
if (!HCD_HW_ACCESSIBLE(hcd))
goto unlock;

- if (!hsotg->core_params->hibernation)
- goto skip_power_saving;
-
/*
* Drive USB suspend and disable port Power
* if usb bus is not suspended.
*/
if (!hsotg->bus_suspended) {
hprt0 = dwc2_read_hprt0(hsotg);
- hprt0 |= HPRT0_SUSP;
- hprt0 &= ~HPRT0_PWR;
- dwc2_writel(hprt0, hsotg->regs + HPRT0);
+ if (hprt0 & HPRT0_CONNSTS) {
+ hprt0 |= HPRT0_SUSP;
+ if (hsotg->core_params->hibernation)
+ hprt0 &= ~HPRT0_PWR;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+ }
+
+ if (!hsotg->core_params->hibernation) {
+ pcgctl = readl(hsotg->regs + PCGCTL);
+ pcgctl |= PCGCTL_STOPPCLK;
+ writel(pcgctl, hsotg->regs + PCGCTL);
+ }
}

- /* Enter hibernation */
- ret = dwc2_enter_hibernation(hsotg);
- if (ret) {
- if (ret != -ENOTSUPP)
- dev_err(hsotg->dev,
- "enter hibernation failed\n");
- goto skip_power_saving;
+ if (hsotg->core_params->hibernation) {
+ /* Enter hibernation */
+ ret = dwc2_enter_hibernation(hsotg);
+ if (ret) {
+ if (ret != -ENOTSUPP)
+ dev_err(hsotg->dev,
+ "enter hibernation failed\n");
+ goto skip_power_saving;
+ }
+
+ /*
+ * After entering hibernation, hardware is no
+ * more accessible
+ */
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
}

/* Ask phy to be suspended */
@@ -2420,9 +2435,6 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
spin_lock_irqsave(&hsotg->lock, flags);
}

- /* After entering hibernation, hardware is no more accessible */
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
skip_power_saving:
hsotg->lx_state = DWC2_L2;
unlock:
@@ -2435,6 +2447,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
+ u32 pcgctl;
int ret = 0;

spin_lock_irqsave(&hsotg->lock, flags);
@@ -2442,17 +2455,6 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
if (hsotg->lx_state != DWC2_L2)
goto unlock;

- if (!hsotg->core_params->hibernation) {
- hsotg->lx_state = DWC2_L0;
- goto unlock;
- }
-
- /*
- * Set HW accessible bit before powering on the controller
- * since an interrupt may rise.
- */
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
/*
* Enable power if not already done.
* This must not be spinlocked since duration
@@ -2464,10 +2466,22 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
spin_lock_irqsave(&hsotg->lock, flags);
}

- /* Exit hibernation */
- ret = dwc2_exit_hibernation(hsotg, true);
- if (ret && (ret != -ENOTSUPP))
- dev_err(hsotg->dev, "exit hibernation failed\n");
+ if (hsotg->core_params->hibernation) {
+ /*
+ * Set HW accessible bit before powering on the controller
+ * since an interrupt may rise.
+ */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ /* Exit hibernation */
+ ret = dwc2_exit_hibernation(hsotg, true);
+ if (ret && (ret != -ENOTSUPP))
+ dev_err(hsotg->dev, "exit hibernation failed\n");
+ } else {
+ pcgctl = readl(hsotg->regs + PCGCTL);
+ pcgctl &= ~PCGCTL_STOPPCLK;
+ writel(pcgctl, hsotg->regs + PCGCTL);
+ }

hsotg->lx_state = DWC2_L0;

@@ -2480,7 +2494,8 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
dwc2_port_resume(hsotg);
} else {
/* Wait for controller to correctly update D+/D- level */
- usleep_range(3000, 5000);
+ if (hsotg->core_params->hibernation)
+ usleep_range(3000, 5000);

/*
* Clear Port Enable and Port Status changes.
--
2.6.0.rc2.230.g3dd15c0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/