linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] usb: dwc2: drd: add support for role-switch-default-mode
@ 2021-12-06 15:56 Fabrice Gasnier
  2021-12-06 15:56 ` [PATCH 1/3] dt-bindings: usb: document role-switch-default-mode property in dwc2 Fabrice Gasnier
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Fabrice Gasnier @ 2021-12-06 15:56 UTC (permalink / raw)
  To: hminas, gregkh, robh+dt
  Cc: linux-usb, linux-kernel, linux-stm32, devicetree,
	amelie.delaunay, fabrice.gasnier, alexandre.torgue

This series adds support for the role-switch-default-mode binding, to configure
the controller default mode, when the role is USB_ROLE_NONE.

This has been tested on STM32MP15 DK2 board, with:
 &usbotg_hs {
 	phys = <&usbphyc_port1 0>;
 	phy-names = "usb2-phy";
 	usb-role-switch;
 	dr_mode = "peripheral";
 	role-switch-default-mode = "peripheral";
 	status = "okay";
 }

Fabrice Gasnier (3):
  dt-bindings: usb: document role-switch-default-mode property in dwc2
  usb: dwc2: drd: add role-switch-default-node support
  usb: dwc2: drd: restore role and overrides upon resume

 Documentation/devicetree/bindings/usb/dwc2.yaml |  3 ++
 drivers/usb/dwc2/core.h                         |  3 ++
 drivers/usb/dwc2/drd.c                          | 51 ++++++++++++++++++++++++-
 drivers/usb/dwc2/platform.c                     | 10 +++--
 4 files changed, 61 insertions(+), 6 deletions(-)

-- 
2.7.4


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

* [PATCH 1/3] dt-bindings: usb: document role-switch-default-mode property in dwc2
  2021-12-06 15:56 [PATCH 0/3] usb: dwc2: drd: add support for role-switch-default-mode Fabrice Gasnier
@ 2021-12-06 15:56 ` Fabrice Gasnier
  2021-12-13 22:16   ` Rob Herring
  2021-12-06 15:56 ` [PATCH 2/3] usb: dwc2: drd: add role-switch-default-node support Fabrice Gasnier
  2021-12-06 15:56 ` [PATCH 3/3] usb: dwc2: drd: restore role and overrides upon resume Fabrice Gasnier
  2 siblings, 1 reply; 7+ messages in thread
From: Fabrice Gasnier @ 2021-12-06 15:56 UTC (permalink / raw)
  To: hminas, gregkh, robh+dt
  Cc: linux-usb, linux-kernel, linux-stm32, devicetree,
	amelie.delaunay, fabrice.gasnier, alexandre.torgue

role-switch-default-mode property may be used with usb-role-switch
property to define the default operation mode (by forcing the a-valid or
b-valid) at init.

Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
 Documentation/devicetree/bindings/usb/dwc2.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml
index 94e7276..f00867e 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.yaml
+++ b/Documentation/devicetree/bindings/usb/dwc2.yaml
@@ -114,6 +114,8 @@ properties:
 
   usb-role-switch: true
 
+  role-switch-default-mode: true
+
   g-rx-fifo-size:
     $ref: /schemas/types.yaml#/definitions/uint32
     description: size of rx fifo size in gadget mode.
@@ -145,6 +147,7 @@ properties:
 
 dependencies:
   port: [ usb-role-switch ]
+  role-switch-default-mode: [ usb-role-switch ]
 
 required:
   - compatible
-- 
2.7.4


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

* [PATCH 2/3] usb: dwc2: drd: add role-switch-default-node support
  2021-12-06 15:56 [PATCH 0/3] usb: dwc2: drd: add support for role-switch-default-mode Fabrice Gasnier
  2021-12-06 15:56 ` [PATCH 1/3] dt-bindings: usb: document role-switch-default-mode property in dwc2 Fabrice Gasnier
@ 2021-12-06 15:56 ` Fabrice Gasnier
  2021-12-16 10:26   ` Minas Harutyunyan
  2021-12-06 15:56 ` [PATCH 3/3] usb: dwc2: drd: restore role and overrides upon resume Fabrice Gasnier
  2 siblings, 1 reply; 7+ messages in thread
From: Fabrice Gasnier @ 2021-12-06 15:56 UTC (permalink / raw)
  To: hminas, gregkh, robh+dt
  Cc: linux-usb, linux-kernel, linux-stm32, devicetree,
	amelie.delaunay, fabrice.gasnier, alexandre.torgue

When using usb-role-switch, while the usb role is not yet define
(USB_ROLE_NONE), the user may want to configure the default mode to host
or device.
Use role-switch-default-mode for that purpose.

Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
 drivers/usb/dwc2/core.h |  3 +++
 drivers/usb/dwc2/drd.c  | 13 +++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 37185eb..e2fe642 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -869,6 +869,8 @@ struct dwc2_hregs_backup {
  *                      - USB_DR_MODE_HOST
  *                      - USB_DR_MODE_OTG
  * @role_sw:		usb_role_switch handle
+ * @role_sw_default_mode: default operation mode of controller while usb role
+ *			is USB_ROLE_NONE
  * @hcd_enabled:	Host mode sub-driver initialization indicator.
  * @gadget_enabled:	Peripheral mode sub-driver initialization indicator.
  * @ll_hw_enabled:	Status of low-level hardware resources.
@@ -1065,6 +1067,7 @@ struct dwc2_hsotg {
 	enum usb_otg_state op_state;
 	enum usb_dr_mode dr_mode;
 	struct usb_role_switch *role_sw;
+	enum usb_dr_mode role_sw_default_mode;
 	unsigned int hcd_enabled:1;
 	unsigned int gadget_enabled:1;
 	unsigned int ll_hw_enabled:1;
diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c
index aa6eb76..4f453ec 100644
--- a/drivers/usb/dwc2/drd.c
+++ b/drivers/usb/dwc2/drd.c
@@ -24,6 +24,10 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
 	gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN;
 	gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
 	gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL);
+	if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
+		gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
+	else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL)
+		gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL;
 	dwc2_writel(hsotg, gotgctl, GOTGCTL);
 
 	spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -105,6 +109,14 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
 
 	spin_lock_irqsave(&hsotg->lock, flags);
 
+	if (role == USB_ROLE_NONE) {
+		/* default operation mode when usb role is USB_ROLE_NONE */
+		if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
+			role = USB_ROLE_HOST;
+		else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL)
+			role = USB_ROLE_DEVICE;
+	}
+
 	if (role == USB_ROLE_HOST) {
 		already = dwc2_ovr_avalid(hsotg, true);
 	} else if (role == USB_ROLE_DEVICE) {
@@ -146,6 +158,7 @@ int dwc2_drd_init(struct dwc2_hsotg *hsotg)
 	if (!device_property_read_bool(hsotg->dev, "usb-role-switch"))
 		return 0;
 
+	hsotg->role_sw_default_mode = usb_get_role_switch_default_mode(hsotg->dev);
 	role_sw_desc.driver_data = hsotg;
 	role_sw_desc.fwnode = dev_fwnode(hsotg->dev);
 	role_sw_desc.set = dwc2_drd_role_sw_set;
-- 
2.7.4


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

* [PATCH 3/3] usb: dwc2: drd: restore role and overrides upon resume
  2021-12-06 15:56 [PATCH 0/3] usb: dwc2: drd: add support for role-switch-default-mode Fabrice Gasnier
  2021-12-06 15:56 ` [PATCH 1/3] dt-bindings: usb: document role-switch-default-mode property in dwc2 Fabrice Gasnier
  2021-12-06 15:56 ` [PATCH 2/3] usb: dwc2: drd: add role-switch-default-node support Fabrice Gasnier
@ 2021-12-06 15:56 ` Fabrice Gasnier
  2021-12-16 10:26   ` Minas Harutyunyan
  2 siblings, 1 reply; 7+ messages in thread
From: Fabrice Gasnier @ 2021-12-06 15:56 UTC (permalink / raw)
  To: hminas, gregkh, robh+dt
  Cc: linux-usb, linux-kernel, linux-stm32, devicetree,
	amelie.delaunay, fabrice.gasnier, alexandre.torgue

Override enable bits may not be restored when going to low power mode
(e.g. when in DWC2_POWER_DOWN_PARAM_NONE).
These bits are set when probing/initializing drd (role switch). Restore
them upon resume from low power mode (in case these have been lost).

To achieve this, the last known role is restored upon resume. And the
override enable bits are always set when configuring aval, bval and vbval.

When resuming, forcing the role should be done only once, or this can cause
port changes in HOST mode for instance.
So, only restore FORCEDEVMODE/FORCEHOSTMODE when role_sw is unused

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
 drivers/usb/dwc2/drd.c      | 38 ++++++++++++++++++++++++++++++++++++--
 drivers/usb/dwc2/platform.c | 10 ++++++----
 2 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c
index 4f453ec..1b39c47 100644
--- a/drivers/usb/dwc2/drd.c
+++ b/drivers/usb/dwc2/drd.c
@@ -13,6 +13,10 @@
 #include <linux/usb/role.h>
 #include "core.h"
 
+#define dwc2_ovr_gotgctl(gotgctl) \
+	((gotgctl) |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN | \
+	 GOTGCTL_DBNCE_FLTR_BYPASS)
+
 static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
 {
 	unsigned long flags;
@@ -21,8 +25,7 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
 	spin_lock_irqsave(&hsotg->lock, flags);
 
 	gotgctl = dwc2_readl(hsotg, GOTGCTL);
-	gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN;
-	gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
+	dwc2_ovr_gotgctl(gotgctl);
 	gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL);
 	if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
 		gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
@@ -44,6 +47,9 @@ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid)
 	    (!valid && !(gotgctl & GOTGCTL_ASESVLD)))
 		return -EALREADY;
 
+	/* Always enable overrides to handle the resume case */
+	dwc2_ovr_gotgctl(gotgctl);
+
 	gotgctl &= ~GOTGCTL_BVALOVAL;
 	if (valid)
 		gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
@@ -63,6 +69,9 @@ static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid)
 	    (!valid && !(gotgctl & GOTGCTL_BSESVLD)))
 		return -EALREADY;
 
+	/* Always enable overrides to handle the resume case */
+	dwc2_ovr_gotgctl(gotgctl);
+
 	gotgctl &= ~GOTGCTL_AVALOVAL;
 	if (valid)
 		gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL;
@@ -196,6 +205,31 @@ void dwc2_drd_suspend(struct dwc2_hsotg *hsotg)
 void dwc2_drd_resume(struct dwc2_hsotg *hsotg)
 {
 	u32 gintsts, gintmsk;
+	enum usb_role role;
+
+	if (hsotg->role_sw) {
+		/* get last known role (as the get ops isn't implemented by this driver) */
+		role = usb_role_switch_get_role(hsotg->role_sw);
+
+		if (role == USB_ROLE_NONE) {
+			if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
+				role = USB_ROLE_HOST;
+			else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL)
+				role = USB_ROLE_DEVICE;
+		}
+
+		/* restore last role that may have been lost */
+		if (role == USB_ROLE_HOST)
+			dwc2_ovr_avalid(hsotg, true);
+		else if (role == USB_ROLE_DEVICE)
+			dwc2_ovr_bvalid(hsotg, true);
+
+		dwc2_force_mode(hsotg, role == USB_ROLE_HOST);
+
+		dev_dbg(hsotg->dev, "resuming %s-session valid\n",
+			role == USB_ROLE_NONE ? "No" :
+			role == USB_ROLE_HOST ? "A" : "B");
+	}
 
 	if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) {
 		gintsts = dwc2_readl(hsotg, GINTSTS);
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index c8f18f3..e6a7fc0 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -748,10 +748,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
 		spin_unlock_irqrestore(&dwc2->lock, flags);
 	}
 
-	/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
-	dwc2_force_dr_mode(dwc2);
-
-	dwc2_drd_resume(dwc2);
+	if (!dwc2->role_sw) {
+		/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
+		dwc2_force_dr_mode(dwc2);
+	} else {
+		dwc2_drd_resume(dwc2);
+	}
 
 	if (dwc2_is_device_mode(dwc2))
 		ret = dwc2_hsotg_resume(dwc2);
-- 
2.7.4


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

* Re: [PATCH 1/3] dt-bindings: usb: document role-switch-default-mode property in dwc2
  2021-12-06 15:56 ` [PATCH 1/3] dt-bindings: usb: document role-switch-default-mode property in dwc2 Fabrice Gasnier
@ 2021-12-13 22:16   ` Rob Herring
  0 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2021-12-13 22:16 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: alexandre.torgue, gregkh, amelie.delaunay, linux-kernel,
	devicetree, linux-stm32, robh+dt, hminas, linux-usb

On Mon, 06 Dec 2021 16:56:41 +0100, Fabrice Gasnier wrote:
> role-switch-default-mode property may be used with usb-role-switch
> property to define the default operation mode (by forcing the a-valid or
> b-valid) at init.
> 
> Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> ---
>  Documentation/devicetree/bindings/usb/dwc2.yaml | 3 +++
>  1 file changed, 3 insertions(+)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH 2/3] usb: dwc2: drd: add role-switch-default-node support
  2021-12-06 15:56 ` [PATCH 2/3] usb: dwc2: drd: add role-switch-default-node support Fabrice Gasnier
@ 2021-12-16 10:26   ` Minas Harutyunyan
  0 siblings, 0 replies; 7+ messages in thread
From: Minas Harutyunyan @ 2021-12-16 10:26 UTC (permalink / raw)
  To: Fabrice Gasnier, gregkh, robh+dt
  Cc: linux-usb, linux-kernel, linux-stm32, devicetree,
	amelie.delaunay, alexandre.torgue

On 12/6/2021 7:56 PM, Fabrice Gasnier wrote:
> When using usb-role-switch, while the usb role is not yet define
> (USB_ROLE_NONE), the user may want to configure the default mode to host
> or device.
> Use role-switch-default-mode for that purpose.
> 
> Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>

Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
> ---
>   drivers/usb/dwc2/core.h |  3 +++
>   drivers/usb/dwc2/drd.c  | 13 +++++++++++++
>   2 files changed, 16 insertions(+)
> 
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index 37185eb..e2fe642 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -869,6 +869,8 @@ struct dwc2_hregs_backup {
>    *                      - USB_DR_MODE_HOST
>    *                      - USB_DR_MODE_OTG
>    * @role_sw:		usb_role_switch handle
> + * @role_sw_default_mode: default operation mode of controller while usb role
> + *			is USB_ROLE_NONE
>    * @hcd_enabled:	Host mode sub-driver initialization indicator.
>    * @gadget_enabled:	Peripheral mode sub-driver initialization indicator.
>    * @ll_hw_enabled:	Status of low-level hardware resources.
> @@ -1065,6 +1067,7 @@ struct dwc2_hsotg {
>   	enum usb_otg_state op_state;
>   	enum usb_dr_mode dr_mode;
>   	struct usb_role_switch *role_sw;
> +	enum usb_dr_mode role_sw_default_mode;
>   	unsigned int hcd_enabled:1;
>   	unsigned int gadget_enabled:1;
>   	unsigned int ll_hw_enabled:1;
> diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c
> index aa6eb76..4f453ec 100644
> --- a/drivers/usb/dwc2/drd.c
> +++ b/drivers/usb/dwc2/drd.c
> @@ -24,6 +24,10 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
>   	gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN;
>   	gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
>   	gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL);
> +	if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
> +		gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
> +	else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL)
> +		gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL;
>   	dwc2_writel(hsotg, gotgctl, GOTGCTL);
>   
>   	spin_unlock_irqrestore(&hsotg->lock, flags);
> @@ -105,6 +109,14 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
>   
>   	spin_lock_irqsave(&hsotg->lock, flags);
>   
> +	if (role == USB_ROLE_NONE) {
> +		/* default operation mode when usb role is USB_ROLE_NONE */
> +		if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
> +			role = USB_ROLE_HOST;
> +		else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL)
> +			role = USB_ROLE_DEVICE;
> +	}
> +
>   	if (role == USB_ROLE_HOST) {
>   		already = dwc2_ovr_avalid(hsotg, true);
>   	} else if (role == USB_ROLE_DEVICE) {
> @@ -146,6 +158,7 @@ int dwc2_drd_init(struct dwc2_hsotg *hsotg)
>   	if (!device_property_read_bool(hsotg->dev, "usb-role-switch"))
>   		return 0;
>   
> +	hsotg->role_sw_default_mode = usb_get_role_switch_default_mode(hsotg->dev);
>   	role_sw_desc.driver_data = hsotg;
>   	role_sw_desc.fwnode = dev_fwnode(hsotg->dev);
>   	role_sw_desc.set = dwc2_drd_role_sw_set;


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

* Re: [PATCH 3/3] usb: dwc2: drd: restore role and overrides upon resume
  2021-12-06 15:56 ` [PATCH 3/3] usb: dwc2: drd: restore role and overrides upon resume Fabrice Gasnier
@ 2021-12-16 10:26   ` Minas Harutyunyan
  0 siblings, 0 replies; 7+ messages in thread
From: Minas Harutyunyan @ 2021-12-16 10:26 UTC (permalink / raw)
  To: Fabrice Gasnier, gregkh, robh+dt
  Cc: linux-usb, linux-kernel, linux-stm32, devicetree,
	amelie.delaunay, alexandre.torgue

On 12/6/2021 7:56 PM, Fabrice Gasnier wrote:
> Override enable bits may not be restored when going to low power mode
> (e.g. when in DWC2_POWER_DOWN_PARAM_NONE).
> These bits are set when probing/initializing drd (role switch). Restore
> them upon resume from low power mode (in case these have been lost).
> 
> To achieve this, the last known role is restored upon resume. And the
> override enable bits are always set when configuring aval, bval and vbval.
> 
> When resuming, forcing the role should be done only once, or this can cause
> port changes in HOST mode for instance.
> So, only restore FORCEDEVMODE/FORCEHOSTMODE when role_sw is unused
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>

Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>

> ---
>   drivers/usb/dwc2/drd.c      | 38 ++++++++++++++++++++++++++++++++++++--
>   drivers/usb/dwc2/platform.c | 10 ++++++----
>   2 files changed, 42 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c
> index 4f453ec..1b39c47 100644
> --- a/drivers/usb/dwc2/drd.c
> +++ b/drivers/usb/dwc2/drd.c
> @@ -13,6 +13,10 @@
>   #include <linux/usb/role.h>
>   #include "core.h"
>   
> +#define dwc2_ovr_gotgctl(gotgctl) \
> +	((gotgctl) |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN | \
> +	 GOTGCTL_DBNCE_FLTR_BYPASS)
> +
>   static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
>   {
>   	unsigned long flags;
> @@ -21,8 +25,7 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
>   	spin_lock_irqsave(&hsotg->lock, flags);
>   
>   	gotgctl = dwc2_readl(hsotg, GOTGCTL);
> -	gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN;
> -	gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
> +	dwc2_ovr_gotgctl(gotgctl);
>   	gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL);
>   	if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
>   		gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
> @@ -44,6 +47,9 @@ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid)
>   	    (!valid && !(gotgctl & GOTGCTL_ASESVLD)))
>   		return -EALREADY;
>   
> +	/* Always enable overrides to handle the resume case */
> +	dwc2_ovr_gotgctl(gotgctl);
> +
>   	gotgctl &= ~GOTGCTL_BVALOVAL;
>   	if (valid)
>   		gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
> @@ -63,6 +69,9 @@ static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid)
>   	    (!valid && !(gotgctl & GOTGCTL_BSESVLD)))
>   		return -EALREADY;
>   
> +	/* Always enable overrides to handle the resume case */
> +	dwc2_ovr_gotgctl(gotgctl);
> +
>   	gotgctl &= ~GOTGCTL_AVALOVAL;
>   	if (valid)
>   		gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL;
> @@ -196,6 +205,31 @@ void dwc2_drd_suspend(struct dwc2_hsotg *hsotg)
>   void dwc2_drd_resume(struct dwc2_hsotg *hsotg)
>   {
>   	u32 gintsts, gintmsk;
> +	enum usb_role role;
> +
> +	if (hsotg->role_sw) {
> +		/* get last known role (as the get ops isn't implemented by this driver) */
> +		role = usb_role_switch_get_role(hsotg->role_sw);
> +
> +		if (role == USB_ROLE_NONE) {
> +			if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST)
> +				role = USB_ROLE_HOST;
> +			else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL)
> +				role = USB_ROLE_DEVICE;
> +		}
> +
> +		/* restore last role that may have been lost */
> +		if (role == USB_ROLE_HOST)
> +			dwc2_ovr_avalid(hsotg, true);
> +		else if (role == USB_ROLE_DEVICE)
> +			dwc2_ovr_bvalid(hsotg, true);
> +
> +		dwc2_force_mode(hsotg, role == USB_ROLE_HOST);
> +
> +		dev_dbg(hsotg->dev, "resuming %s-session valid\n",
> +			role == USB_ROLE_NONE ? "No" :
> +			role == USB_ROLE_HOST ? "A" : "B");
> +	}
>   
>   	if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) {
>   		gintsts = dwc2_readl(hsotg, GINTSTS);
> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
> index c8f18f3..e6a7fc0 100644
> --- a/drivers/usb/dwc2/platform.c
> +++ b/drivers/usb/dwc2/platform.c
> @@ -748,10 +748,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
>   		spin_unlock_irqrestore(&dwc2->lock, flags);
>   	}
>   
> -	/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
> -	dwc2_force_dr_mode(dwc2);
> -
> -	dwc2_drd_resume(dwc2);
> +	if (!dwc2->role_sw) {
> +		/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
> +		dwc2_force_dr_mode(dwc2);
> +	} else {
> +		dwc2_drd_resume(dwc2);
> +	}
>   
>   	if (dwc2_is_device_mode(dwc2))
>   		ret = dwc2_hsotg_resume(dwc2);


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

end of thread, other threads:[~2021-12-16 10:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-06 15:56 [PATCH 0/3] usb: dwc2: drd: add support for role-switch-default-mode Fabrice Gasnier
2021-12-06 15:56 ` [PATCH 1/3] dt-bindings: usb: document role-switch-default-mode property in dwc2 Fabrice Gasnier
2021-12-13 22:16   ` Rob Herring
2021-12-06 15:56 ` [PATCH 2/3] usb: dwc2: drd: add role-switch-default-node support Fabrice Gasnier
2021-12-16 10:26   ` Minas Harutyunyan
2021-12-06 15:56 ` [PATCH 3/3] usb: dwc2: drd: restore role and overrides upon resume Fabrice Gasnier
2021-12-16 10:26   ` Minas Harutyunyan

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).