RFT: usb: dwc2: bus suspend/resume that's not hibernate
diff mbox series

Message ID 1446237173-15263-1-git-send-email-dianders@chromium.org
State New, archived
Headers show
Series
  • RFT: usb: dwc2: bus suspend/resume that's not hibernate
Related show

Commit Message

Doug Anderson Oct. 30, 2015, 8:32 p.m. UTC
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@chromium.org>
---
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(-)

Comments

John Youn Nov. 5, 2015, 4:02 a.m. UTC | #1
On 10/30/2015 1:33 PM, Douglas Anderson wrote:
> 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@chromium.org>
> ---


Hi Dinh,

Are you familiar with this? Would you care to test it?

I'm not sure what the breakage was but if you provide steps to
reproduce on the SOCFPGA I could try as well.

Regards,
John


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

Patch
diff mbox series

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.