linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFT PATCH v3 0/3] usb: dwc2: Fix core reset and force mode delays
@ 2016-08-25 21:26 John Youn
  2016-08-25 21:26 ` [RFT PATCH v3 1/3] usb: dwc2: gadget: Only initialize device if in device mode John Youn
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: John Youn @ 2016-08-25 21:26 UTC (permalink / raw)
  To: linux-usb
  Cc: johnyoun, Stefan Wahren, Michael Niewoehner, Felipe Balbi,
	Tao Huang, Julius Werner, linux-kernel, Caesar Wang,
	Heiko Stuebner, Remi Pommarel, Kever Yang, Doug Anderson,
	Stephen Warren, linux-rpi-kernel, linux-arm-kernel

This series tries to account for a delay from the IDDIG debounce
filter when switching modes. This delay is a function of the PHY clock
speed and can range from 5-50 ms. This delay must be taken into
account on core reset and force modes. A full explanation is provided
in the patch commit log and code comments.

Patch 1 is a prerequisite to this fix.

Patch 2 implements the delay for core reset.

Patch 3 implements the delay for set/clear force modes.

Appreciate any testing, especially on RK3188 and RPi platforms.

Patch 1-2 can probably be merged right now as they shouldn't break
anything.

Patch 3 should solve RPi issues, but has problems in RK3188 that need
to be debugged.

v3:
* Added tested-bys for patch 1-2
* Fixed an issue where a function was not returning a value
* Dropped patch 4

v2:
* Broke up the last patch of the original series

Regards,
John

John Youn (3):
  usb: dwc2: gadget: Only initialize device if in device mode
  usb: dwc2: Add delay to core soft reset
  usb: dwc2: Properly account for the force mode delays

 drivers/usb/dwc2/core.c   | 128 ++++++++++++++++++++++++++++++++++++++++------
 drivers/usb/dwc2/core.h   |   1 +
 drivers/usb/dwc2/gadget.c |   7 ++-
 drivers/usb/dwc2/hw.h     |   1 +
 4 files changed, 118 insertions(+), 19 deletions(-)

-- 
2.9.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [RFT PATCH v3 1/3] usb: dwc2: gadget: Only initialize device if in device mode
  2016-08-25 21:26 [RFT PATCH v3 0/3] usb: dwc2: Fix core reset and force mode delays John Youn
@ 2016-08-25 21:26 ` John Youn
  2016-08-25 21:26 ` [RFT PATCH v3 2/3] usb: dwc2: Add delay to core soft reset John Youn
  2016-08-25 21:26 ` [RFT PATCH v3 3/3] usb: dwc2: Properly account for the force mode delays John Youn
  2 siblings, 0 replies; 4+ messages in thread
From: John Youn @ 2016-08-25 21:26 UTC (permalink / raw)
  To: linux-usb
  Cc: johnyoun, Stefan Wahren, Michael Niewoehner, Felipe Balbi,
	Tao Huang, Julius Werner, linux-kernel, Caesar Wang,
	Heiko Stuebner, Remi Pommarel, Kever Yang, Doug Anderson,
	Stephen Warren, linux-rpi-kernel, linux-arm-kernel

In dwc2_hsotg_udc_start(), don't initialize the controller for device
mode unless we are actually in device mode.

Tested-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: John Youn <johnyoun@synopsys.com>
---
 drivers/usb/dwc2/gadget.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index af46adf..358ba5a 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -3475,8 +3475,11 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
 		otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget);
 
 	spin_lock_irqsave(&hsotg->lock, flags);
-	dwc2_hsotg_init(hsotg);
-	dwc2_hsotg_core_init_disconnected(hsotg, false);
+	if (dwc2_hw_is_device(hsotg)) {
+		dwc2_hsotg_init(hsotg);
+		dwc2_hsotg_core_init_disconnected(hsotg, false);
+	}
+
 	hsotg->enabled = 0;
 	spin_unlock_irqrestore(&hsotg->lock, flags);
 
-- 
2.9.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [RFT PATCH v3 2/3] usb: dwc2: Add delay to core soft reset
  2016-08-25 21:26 [RFT PATCH v3 0/3] usb: dwc2: Fix core reset and force mode delays John Youn
  2016-08-25 21:26 ` [RFT PATCH v3 1/3] usb: dwc2: gadget: Only initialize device if in device mode John Youn
@ 2016-08-25 21:26 ` John Youn
  2016-08-25 21:26 ` [RFT PATCH v3 3/3] usb: dwc2: Properly account for the force mode delays John Youn
  2 siblings, 0 replies; 4+ messages in thread
From: John Youn @ 2016-08-25 21:26 UTC (permalink / raw)
  To: linux-usb
  Cc: johnyoun, Stefan Wahren, Michael Niewoehner, Felipe Balbi,
	Tao Huang, Julius Werner, linux-kernel, Caesar Wang,
	Heiko Stuebner, Remi Pommarel, Kever Yang, Doug Anderson,
	Stephen Warren, linux-rpi-kernel, linux-arm-kernel

Add a delay to the core soft reset function to account for the IDDIG
debounce filter.

If the current mode is host, either due to the force mode bit being
set (which persists after core reset) or the connector id pin, a core
soft reset will temporarily reset the mode to device and a delay from
the IDDIG debounce filter will occur before going back to host mode.

Tested-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: John Youn <johnyoun@synopsys.com>
---
 drivers/usb/dwc2/core.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc2/core.h |  1 +
 drivers/usb/dwc2/hw.h   |  1 +
 3 files changed, 99 insertions(+)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 4135a5f..bb903e2 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -238,6 +238,78 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
 	return ret;
 }
 
+/**
+ * dwc2_wait_for_mode() - Waits for the controller mode.
+ * @hsotg:	Programming view of the DWC_otg controller.
+ * @host_mode:	If true, waits for host mode, otherwise device mode.
+ * @timeout:	Time to wait in ms.
+ */
+static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg,
+			       bool host_mode,
+			       unsigned int timeout)
+{
+	ktime_t start;
+	ktime_t end;
+
+	dev_vdbg(hsotg->dev, "Waiting for %s mode\n",
+		 host_mode ? "host" : "device");
+
+	start = ktime_get();
+
+	while (1) {
+		s64 ms;
+
+		if (dwc2_is_host_mode(hsotg) == host_mode) {
+			dev_vdbg(hsotg->dev, "%s mode set\n",
+				 host_mode ? "Host" : "Device");
+			break;
+		}
+
+		end = ktime_get();
+		ms = ktime_to_ms(ktime_sub(end, start));
+
+		if (ms >= (s64)timeout) {
+			dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n",
+				 __func__, host_mode ? "host" : "device");
+			break;
+		}
+
+		usleep_range(1000, 2000);
+	}
+}
+
+/**
+ * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce
+ * filter is enabled.
+ */
+static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
+{
+	u32 gsnpsid;
+	u32 ghwcfg4;
+
+	if (!dwc2_hw_is_otg(hsotg))
+		return false;
+
+	/* Check if core configuration includes the IDDIG filter. */
+	ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
+	if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
+		return false;
+
+	/*
+	 * Check if the IDDIG debounce filter is bypassed. Available
+	 * in core version >= 3.10a.
+	 */
+	gsnpsid = dwc2_readl(hsotg->regs + GSNPSID);
+	if (gsnpsid >= DWC2_CORE_REV_3_10a) {
+		u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+
+		if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
+			return false;
+	}
+
+	return true;
+}
+
 /*
  * Do core a soft reset of the core.  Be careful with this because it
  * resets all the internal state machines of the core.
@@ -246,9 +318,30 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
 {
 	u32 greset;
 	int count = 0;
+	bool wait_for_host_mode = false;
 
 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
+	/*
+	 * If the current mode is host, either due to the force mode
+	 * bit being set (which persists after core reset) or the
+	 * connector id pin, a core soft reset will temporarily reset
+	 * the mode to device. A delay from the IDDIG debounce filter
+	 * will occur before going back to host mode.
+	 *
+	 * Determine whether we will go back into host mode after a
+	 * reset and account for this delay after the reset.
+	 */
+	if (dwc2_iddig_filter_enabled(hsotg)) {
+		u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+		u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+
+		if (!(gotgctl & GOTGCTL_CONID_B) ||
+		    (gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
+			wait_for_host_mode = true;
+		}
+	}
+
 	/* Core Soft Reset */
 	greset = dwc2_readl(hsotg->regs + GRSTCTL);
 	greset |= GRSTCTL_CSFTRST;
@@ -277,6 +370,10 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
 		}
 	} while (!(greset & GRSTCTL_AHBIDLE));
 
+	/* Wait up to 50 ms for the IDDIG debounce filter. */
+	if (wait_for_host_mode)
+		dwc2_wait_for_mode(hsotg, true, 50);
+
 	return 0;
 }
 
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 9fae029..a6b6103 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -889,6 +889,7 @@ struct dwc2_hsotg {
 #define DWC2_CORE_REV_2_92a	0x4f54292a
 #define DWC2_CORE_REV_2_94a	0x4f54294a
 #define DWC2_CORE_REV_3_00a	0x4f54300a
+#define DWC2_CORE_REV_3_10a	0x4f54310a
 
 #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 	union dwc2_hcd_internal_flags {
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index efc3bcd..9105844 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -48,6 +48,7 @@
 #define GOTGCTL_ASESVLD			(1 << 18)
 #define GOTGCTL_DBNC_SHORT		(1 << 17)
 #define GOTGCTL_CONID_B			(1 << 16)
+#define GOTGCTL_DBNCE_FLTR_BYPASS	(1 << 15)
 #define GOTGCTL_DEVHNPEN		(1 << 11)
 #define GOTGCTL_HSTSETHNPEN		(1 << 10)
 #define GOTGCTL_HNPREQ			(1 << 9)
-- 
2.9.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [RFT PATCH v3 3/3] usb: dwc2: Properly account for the force mode delays
  2016-08-25 21:26 [RFT PATCH v3 0/3] usb: dwc2: Fix core reset and force mode delays John Youn
  2016-08-25 21:26 ` [RFT PATCH v3 1/3] usb: dwc2: gadget: Only initialize device if in device mode John Youn
  2016-08-25 21:26 ` [RFT PATCH v3 2/3] usb: dwc2: Add delay to core soft reset John Youn
@ 2016-08-25 21:26 ` John Youn
  2 siblings, 0 replies; 4+ messages in thread
From: John Youn @ 2016-08-25 21:26 UTC (permalink / raw)
  To: linux-usb
  Cc: johnyoun, Stefan Wahren, Michael Niewoehner, Felipe Balbi,
	Tao Huang, Julius Werner, linux-kernel, Caesar Wang,
	Heiko Stuebner, Remi Pommarel, Kever Yang, Doug Anderson,
	Stephen Warren, linux-rpi-kernel, linux-arm-kernel

When a force mode bit is set and the IDDIG debounce filter is enabled,
there is a delay for the forced mode to take effect. This delay is due
to the IDDIG debounce filter and is variable depending on the platform's
PHY clock speed. To account for this delay we can poll for the expected
mode.

On a clear force mode, since we don't know what mode to poll for, delay
for a fixed 50 ms. This is the maximum delay based on the slowest PHY
clock speed.

Signed-off-by: John Youn <johnyoun@synopsys.com>
---
 drivers/usb/dwc2/core.c | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index bb903e2..cbd7436 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -397,9 +397,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
  * Checks are done in this function to determine whether doing a force
  * would be valid or not.
  *
- * If a force is done, it requires a 25ms delay to take effect.
- *
- * Returns true if the mode was forced.
+ * If a force is done, it requires a IDDIG debounce filter delay if
+ * the filter is configured and enabled. We poll the current mode of
+ * the controller to account for this delay.
  */
 static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
 {
@@ -434,12 +434,18 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
 	gusbcfg |= set;
 	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
 
-	msleep(25);
+	dwc2_wait_for_mode(hsotg, host, 50);
 	return true;
 }
 
-/*
- * Clears the force mode bits.
+/**
+ * dwc2_clear_force_mode() - Clears the force mode bits.
+ *
+ * After clearing the bits, wait up to 50 ms to account for any
+ * potential IDDIG filter delay. We can't know if we expect this delay
+ * or not because the value of the connector ID status is affected by
+ * the force mode. We only need to call this once during probe if
+ * dr_mode == OTG.
  */
 static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
 {
@@ -450,11 +456,8 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
 	gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
 	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
 
-	/*
-	 * NOTE: This long sleep is _very_ important, otherwise the core will
-	 * not stay in host mode after a connector ID change!
-	 */
-	msleep(25);
+	if (dwc2_iddig_filter_enabled(hsotg))
+		msleep(50);
 }
 
 /*
@@ -477,12 +480,6 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
 			 __func__, hsotg->dr_mode);
 		break;
 	}
-
-	/*
-	 * NOTE: This is required for some rockchip soc based
-	 * platforms.
-	 */
-	msleep(50);
 }
 
 /*
-- 
2.9.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2016-08-25 21:29 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-25 21:26 [RFT PATCH v3 0/3] usb: dwc2: Fix core reset and force mode delays John Youn
2016-08-25 21:26 ` [RFT PATCH v3 1/3] usb: dwc2: gadget: Only initialize device if in device mode John Youn
2016-08-25 21:26 ` [RFT PATCH v3 2/3] usb: dwc2: Add delay to core soft reset John Youn
2016-08-25 21:26 ` [RFT PATCH v3 3/3] usb: dwc2: Properly account for the force mode delays John Youn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).