[PATCH v2 15/15] usb: dwc2: Get rid of useless error checks in suspend interrupt

2021-04-16 Thread Artur Petrosyan
Squashed from Douglas Anderson's suggested commit
"usb: dwc2: Get rid of useless error checks for
hibernation/partial power down"

 - After this commit there should never be any
case where dwc2_enter_partial_power_down() and
dwc2_enter_hibernation() are called when
'params.power_down' is not correct.  Get rid of
the pile of error checking.

- As part of this cleanup some of the error messages
not to have __func__ in them.  That's not needed
for dev_err() calls since they already have the
device name as part of the message.

Signed-off-by: Artur Petrosyan 
Signed-off-by: Douglas Anderson 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/core.c  |  3 ---
 drivers/usb/dwc2/core_intr.c | 18 +++---
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 576c262dba55..6f70ab9577b4 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -391,9 +391,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg 
*hsotg)
  */
 int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host)
 {
-   if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION)
-   return -ENOTSUPP;
-
if (is_host)
return dwc2_host_enter_hibernation(hsotg);
else
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 470458ac664b..a5ab03808da6 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -535,13 +535,10 @@ static void dwc2_handle_usb_suspend_intr(struct 
dwc2_hsotg *hsotg)
switch (hsotg->params.power_down) {
case DWC2_POWER_DOWN_PARAM_PARTIAL:
ret = dwc2_enter_partial_power_down(hsotg);
-   if (ret) {
-   if (ret != -ENOTSUPP)
-   dev_err(hsotg->dev,
-   "%s: enter 
partial_power_down failed\n",
-   __func__);
-   goto skip_power_saving;
-   }
+   if (ret)
+   dev_err(hsotg->dev,
+   "enter partial_power_down 
failed\n");
+
udelay(100);
 
/* Ask phy to be suspended */
@@ -550,10 +547,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg 
*hsotg)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
ret = dwc2_enter_hibernation(hsotg, 0);
-   if (ret && ret != -ENOTSUPP)
+   if (ret)
dev_err(hsotg->dev,
-   "%s: enter hibernation 
failed\n",
-   __func__);
+   "enter hibernation failed\n");
break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
@@ -562,7 +558,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg 
*hsotg)
 */
dwc2_gadget_enter_clock_gating(hsotg);
}
-skip_power_saving:
+
/*
 * Change to L2 (suspend) state before releasing
 * spinlock
-- 
2.25.1



[PATCH v2 11/15] usb: dwc2: Add hibernation entering flow by system suspend

2021-04-16 Thread Artur Petrosyan
Adds a new flow of entering hibernation when PC is
hibernated or suspended.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 093b1717df01..92848629cc61 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4387,6 +4387,16 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   /* Enter hibernation */
+   spin_unlock_irqrestore(>lock, flags);
+   ret = dwc2_enter_hibernation(hsotg, 1);
+   if (ret)
+   dev_err(hsotg->dev, "enter hibernation failed\n");
+   spin_lock_irqsave(>lock, flags);
+
+   /* After entering suspend, hardware is not accessible */
+   clear_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
-- 
2.25.1



[PATCH v2 12/15] usb: dwc2: Add hibernation exiting flow by system resume

2021-04-16 Thread Artur Petrosyan
Adds a new flow of exiting hibernation when PC is resumed
from suspend state.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 92848629cc61..035d4911a3c3 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4470,6 +4470,16 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   if (ret)
+   dev_err(hsotg->dev, "exit hibernation failed.\n");
+
+   /*
+* Set HW accessible bit before powering on the controller
+* since an interrupt may rise.
+*/
+   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
-- 
2.25.1



[PATCH v2 14/15] usb: dwc2: Update dwc2_handle_usb_suspend_intr function.

2021-04-16 Thread Artur Petrosyan
To avoid working in two modes (partial power down
and hibernation) changed conditions for entering
partial power down or hibernation.

Instead of checking hw_params.power_optimized and
hw_params.hibernation now checking power_down
param which already set to one of the options
(Hibernation or Partial Power Down) based on
OTG_EN_PWROPT.

Signed-off-by: Artur Petrosyan 
Signed-off-by: Minas Harutyunyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index f8963c0cf6af..470458ac664b 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -532,7 +532,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg 
*hsotg)
return;
}
if (dsts & DSTS_SUSPSTS) {
-   if (hsotg->hw_params.power_optimized) {
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
ret = dwc2_enter_partial_power_down(hsotg);
if (ret) {
if (ret != -ENOTSUPP)
@@ -541,21 +542,22 @@ static void dwc2_handle_usb_suspend_intr(struct 
dwc2_hsotg *hsotg)
__func__);
goto skip_power_saving;
}
-
udelay(100);
 
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy))
usb_phy_set_suspend(hsotg->uphy, true);
-   } else if (hsotg->hw_params.hibernation) {
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
ret = dwc2_enter_hibernation(hsotg, 0);
if (ret && ret != -ENOTSUPP)
dev_err(hsotg->dev,
"%s: enter hibernation 
failed\n",
__func__);
-   } else {
+   break;
+   case DWC2_POWER_DOWN_PARAM_NONE:
/*
-* If not hibernation nor partial power down 
are supported,
+* If neither hibernation nor partial power 
down are supported,
 * clock gating is used to save power.
 */
dwc2_gadget_enter_clock_gating(hsotg);
-- 
2.25.1



[PATCH v2 13/15] usb: dwc2: Add exit hibernation mode before removing drive

2021-04-16 Thread Artur Petrosyan
When dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.

In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()"
function. If core is in hibernation, then checking the
operational mode of the driver. To check whether dwc2 core
is operating in host mode or device mode there is one way
which is retrieving the backup value of "gotgctl" and compare
the "CurMod" value. If previously core entered hibernation
in host mode then the exit is performed for host if not then
exit is performed for device mode. The introduced checking
is because in hibernation state all registers are not
accessible.

Signed-off-by: Artur Petrosyan 
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 
---
 drivers/usb/dwc2/platform.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index f8b819cfa80e..8ad33e042a14 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -316,8 +316,23 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
 static int dwc2_driver_remove(struct platform_device *dev)
 {
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
+   struct dwc2_gregs_backup *gr;
int ret = 0;
 
+   gr = >gr_backup;
+
+   /* Exit Hibernation when driver is removed. */
+   if (hsotg->hibernated) {
+   if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   else
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
+
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   }
+
/* Exit Partial Power Down when driver is removed. */
if (hsotg->in_ppd) {
ret = dwc2_exit_partial_power_down(hsotg, 0, true);
-- 
2.25.1



[PATCH v2 10/15] usb: dwc2: Allow exit hibernation in urb enqueue

2021-04-16 Thread Artur Petrosyan
When core is in hibernation state and an external
hub is connected, upper layer sends URB enqueue request,
which results in port reset issue.

- Added exit from hibernation state to avoid port
reset issue and process upper layer request properly.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - Moved duplicated error checking *if* conditions from innermost to outside if.

 drivers/usb/dwc2/hcd.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index cc9ad6cf02d9..093b1717df01 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4631,12 +4631,26 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, 
struct urb *urb,
struct dwc2_qh *qh;
bool qh_allocated = false;
struct dwc2_qtd *qtd;
+   struct dwc2_gregs_backup *gr;
+
+   gr = >gr_backup;
 
if (dbg_urb(urb)) {
dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
}
 
+   if (hsotg->hibernated) {
+   if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
+   retval = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   else
+   retval = dwc2_exit_hibernation(hsotg, 0, 0, 0);
+
+   if (retval)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   }
+
if (hsotg->in_ppd) {
retval = dwc2_exit_partial_power_down(hsotg, 0, true);
if (retval)
-- 
2.25.1



[PATCH v2 09/15] usb: dwc2: Move exit hibernation to dwc2_port_resume() function

2021-04-16 Thread Artur Petrosyan
This move is done to call hibernation exit handler in
"dwc2_port_resume()" function when core receives port resume.
Otherwise it could be confusing to exit hibernation in
"dwc2_hcd_hub_control()" function but other power saving modes
in "dwc2_port_resume()" function.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 43a2298b7d42..cc9ad6cf02d9 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3383,6 +3383,11 @@ int dwc2_port_resume(struct dwc2_hsotg *hsotg)
"exit partial_power_down failed.\n");
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   /* Exit host hibernation. */
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   if (ret)
+   dev_err(hsotg->dev, "exit hibernation failed.\n");
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
@@ -3446,12 +3451,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
 
-   if (hsotg->bus_suspended) {
-   if (hsotg->hibernated)
-   dwc2_exit_hibernation(hsotg, 0, 0, 1);
-   else
-   dwc2_port_resume(hsotg);
-   }
+   if (hsotg->bus_suspended)
+   retval = dwc2_port_resume(hsotg);
break;
 
case USB_PORT_FEAT_POWER:
-- 
2.25.1



[PATCH v2 08/15] usb: dwc2: Move enter hibernation to dwc2_port_suspend() function

2021-04-16 Thread Artur Petrosyan
This move is done to call enter hibernation handler in
"dwc2_port_suspend()" function when core receives port suspend.
Otherwise it could be confusing to enter to hibernation in
"dwc2_hcd_hub_control()" function but other power saving modes
in "dwc2_port_suspend()" function.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 18 ++
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index ff945c40ef8a..43a2298b7d42 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3321,6 +3321,18 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
"enter partial_power_down failed.\n");
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   /*
+* Perform spin unlock and lock because in
+* "dwc2_host_enter_hibernation()" function there is a spinlock
+* logic which prevents servicing of any IRQ during entering
+* hibernation.
+*/
+   spin_unlock_irqrestore(>lock, flags);
+   ret = dwc2_enter_hibernation(hsotg, 1);
+   if (ret)
+   dev_err(hsotg->dev, "enter hibernation failed.\n");
+   spin_lock_irqsave(>lock, flags);
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
@@ -3650,10 +3662,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
"SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
if (windex != hsotg->otg_port)
goto error;
-   if (hsotg->params.power_down == 
DWC2_POWER_DOWN_PARAM_HIBERNATION)
-   dwc2_enter_hibernation(hsotg, 1);
-   else
-   dwc2_port_suspend(hsotg, windex);
+   if (!hsotg->bus_suspended)
+   retval = dwc2_port_suspend(hsotg, windex);
break;
 
case USB_PORT_FEAT_POWER:
-- 
2.25.1



[PATCH v2 07/15] usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.

2021-04-16 Thread Artur Petrosyan
When hibernation exit is performed the dwc2_hib_restore_common()
function is called. In that function we wait until GINTSTS_RESTOREDONE
bit is set. However, after the setting of that bit we get a lot of
(dwc2_hsotg_irq:) interrupts which indicates that (GINTSTS.RstrDoneInt)
restore done interrupt is asserted.

To avoid restore done interrupt storm after restore is generated
clear GINTSTS_RESTOREDONE bit in GINTSTS register.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index eccd96fa164e..576c262dba55 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -299,6 +299,12 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int 
rem_wakeup,
__func__);
} else {
dev_dbg(hsotg->dev, "restore done  generated here\n");
+
+   /*
+* To avoid restore done interrupt storm after restore is
+* generated clear GINTSTS_RESTOREDONE bit.
+*/
+   dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTSTS);
}
 }
 
-- 
2.25.1



[PATCH v2 06/15] usb: dwc2: Clear fifo_map when resetting core.

2021-04-16 Thread Artur Petrosyan
Switching from device mode to host mode by disconnecting
device cable core enters and exits form hibernation.
However, the fifo map remains not cleared. It results
to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/
gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2])
if in host mode we disconnect the micro a to b host
cable. Because core reset occurs.

To avoid the WARNING, fifo_map should be cleared
in dwc2_core_reset() function by taking into account configs.
fifo_map must be cleared only if driver is configured in
"CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE"
mode.

- Added "static inline void dwc2_clear_fifo_map()" helper
function to clear fifo_map with peripheral or dual role mode.

- Added a dummy version of "dwc2_clear_fifo_map()" helper
for host-only mode.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.c | 16 
 drivers/usb/dwc2/core.h |  3 +++
 2 files changed, 19 insertions(+)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index cb65f7f60573..eccd96fa164e 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -470,6 +470,22 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool 
skip_wait)
dwc2_writel(hsotg, greset, GRSTCTL);
}
 
+   /*
+* Switching from device mode to host mode by disconnecting
+* device cable core enters and exits form hibernation.
+* However, the fifo map remains not cleared. It results
+* to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/
+* gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2])
+* if in host mode we disconnect the micro a to b host
+* cable. Because core reset occurs.
+* To avoid the WARNING, fifo_map should be cleared
+* in dwc2_core_reset() function by taking into account configs.
+* fifo_map must be cleared only if driver is configured in
+* "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE"
+* mode.
+*/
+   dwc2_clear_fifo_map(hsotg);
+
/* Wait for AHB master IDLE state */
if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 1)) {
dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL 
GRSTCTL_AHBIDLE\n",
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 8c12b3061f7f..e1f432095565 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1423,6 +1423,8 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg 
*hsotg);
 int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
 void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
 void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg);
+static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg)
+{ hsotg->fifo_map = 0; }
 #else
 static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
 { return 0; }
@@ -1467,6 +1469,7 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct 
dwc2_hsotg *hsotg)
 { return 0; }
 static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
 static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) {}
 #endif
 
 #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
-- 
2.25.1



[PATCH v2 05/15] usb: dwc2: Allow exiting hibernation from gpwrdn rst detect

2021-04-16 Thread Artur Petrosyan
When device cable is disconnected core receives suspend
interrupt and enters hibernation. After entering
into hibernation GPWRDN_RST_DET and GPWRDN_STS_CHGINT
interrupts are asserted.

Allowed exit from gadget hibernation from
GPWRDN_RST_DET by checking only linestate.

Changed the return type of "dwc2_handle_gpwrdn_intr()"
function from void to int because exit from hibernation
functions have a return value.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 23 ++-
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 27d729fad227..f8963c0cf6af 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -751,10 +751,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct 
dwc2_hsotg *hsotg,
  * The GPWRDN interrupts are those that occur in both Host and
  * Device mode while core is in hibernated state.
  */
-static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
+static int dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
 {
u32 gpwrdn;
int linestate;
+   int ret = 0;
 
gpwrdn = dwc2_readl(hsotg, GPWRDN);
/* clear all interrupt */
@@ -778,17 +779,27 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg 
*hsotg)
if (hsotg->hw_params.hibernation &&
hsotg->hibernated) {
if (gpwrdn & GPWRDN_IDSTS) {
-   dwc2_exit_hibernation(hsotg, 0, 0, 0);
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
call_gadget(hsotg, resume);
} else {
-   dwc2_exit_hibernation(hsotg, 1, 0, 1);
+   ret = dwc2_exit_hibernation(hsotg, 1, 0, 1);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
}
}
} else if ((gpwrdn & GPWRDN_RST_DET) &&
   (gpwrdn & GPWRDN_RST_DET_MSK)) {
dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__);
-   if (!linestate && (gpwrdn & GPWRDN_BSESSVLD))
-   dwc2_exit_hibernation(hsotg, 0, 1, 0);
+   if (!linestate) {
+   ret = dwc2_exit_hibernation(hsotg, 0, 1, 0);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   }
} else if ((gpwrdn & GPWRDN_STS_CHGINT) &&
   (gpwrdn & GPWRDN_STS_CHGINT_MSK)) {
dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__);
@@ -800,6 +811,8 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg 
*hsotg)
 */
dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn);
}
+
+   return ret;
 }
 
 /*
-- 
2.25.1



[PATCH v2 04/15] usb: dwc2: Fix hibernation between host and device modes.

2021-04-16 Thread Artur Petrosyan
When core is in hibernation in host mode and a device cable
was connected then driver exited from device hibernation.
However, registers saved for host mode and when exited from
device hibernation register restore would be done for device
register which was wrong because there was no device registers
stored to restore.

- Added dwc_handle_gpwrdn_disc_det() function which handles
  gpwrdn disconnect detect flow and exits hibernation
  without restoring the registers.
- Updated exiting from hibernation in GPWRDN_STS_CHGINT with
  calling dwc_handle_gpwrdn_disc_det() function. Here no register
  is restored which is the solution described above.

Fixes: 65c9c4c6b01f ("usb: dwc2: Add dwc2_handle_gpwrdn_intr() handler")
Signed-off-by: Artur Petrosyan 
Signed-off-by: Minas Harutyunyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 154 +++
 1 file changed, 83 insertions(+), 71 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 550c52c1a0c7..27d729fad227 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -680,6 +680,71 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
return 0;
 }
 
+/**
+ * dwc_handle_gpwrdn_disc_det() - Handles the gpwrdn disconnect detect.
+ * Exits hibernation without restoring registers.
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @gpwrdn: GPWRDN register
+ */
+static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg,
+ u32 gpwrdn)
+{
+   u32 gpwrdn_tmp;
+
+   /* Switch-on voltage to the core */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Reset core */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Disable Power Down Clamp */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Deassert reset core */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Disable PMU interrupt */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+
+   /* De-assert Wakeup Logic */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PMUACTV;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+
+   hsotg->hibernated = 0;
+   hsotg->bus_suspended = 0;
+
+   if (gpwrdn & GPWRDN_IDSTS) {
+   hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+   dwc2_core_init(hsotg, false);
+   dwc2_enable_global_interrupts(hsotg);
+   dwc2_hsotg_core_init_disconnected(hsotg, false);
+   dwc2_hsotg_core_connect(hsotg);
+   } else {
+   hsotg->op_state = OTG_STATE_A_HOST;
+
+   /* Initialize the Core for Host mode */
+   dwc2_core_init(hsotg, false);
+   dwc2_enable_global_interrupts(hsotg);
+   dwc2_hcd_start(hsotg);
+   }
+}
+
 /*
  * GPWRDN interrupt handler.
  *
@@ -701,64 +766,14 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg 
*hsotg)
 
if ((gpwrdn & GPWRDN_DISCONN_DET) &&
(gpwrdn & GPWRDN_DISCONN_DET_MSK) && !linestate) {
-   u32 gpwrdn_tmp;
-
dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);
-
-   /* Switch-on voltage to the core */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Reset core */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Disable Power Down Clamp */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Deassert reset core */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Disable PMU interrupt */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-

[PATCH v2 03/15] usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.

2021-04-16 Thread Artur Petrosyan
Added setting "port_connect_status_change" flag to "1" in order
to re-enumerate, because after exit from hibernation port
connection status is not detected.

Fixes: c5c403dc4336 ("usb: dwc2: Add host/device hibernation functions")
Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index cda3f931195d..ff945c40ef8a 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5650,7 +5650,15 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, 
int rem_wakeup,
return ret;
}
 
-   dwc2_hcd_rem_wakeup(hsotg);
+   if (rem_wakeup) {
+   dwc2_hcd_rem_wakeup(hsotg);
+   /*
+* Change "port_connect_status_change" flag to re-enumerate,
+* because after exit from hibernation port connection status
+* is not detected.
+*/
+   hsotg->flags.b.port_connect_status_change = 1;
+   }
 
hsotg->hibernated = 0;
hsotg->bus_suspended = 0;
-- 
2.25.1



[PATCH v2 02/15] usb: dwc2: Reset DEVADDR after exiting gadget hibernation.

2021-04-16 Thread Artur Petrosyan
Initially resetting device address was done in dwc2_hsotg_irq()
interrupt handler. However, when core is hibernated USB RESET
is not handled in dwc2_hsotg_irq() handler, instead USB RESET
interrupt is handled in dwc2_handle_gpwrdn_intr() handler.

- Added reset device address to zero when core exits from gadget
  hibernation.

Signed-off-by: Artur Petrosyan 
Signed-off-by: Minas Harutyunyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/gadget.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 2f50f3e62caa..e6bb1bdb2760 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -5305,6 +5305,10 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg 
*hsotg,
dwc2_writel(hsotg, dr->dcfg, DCFG);
dwc2_writel(hsotg, dr->dctl, DCTL);
 
+   /* On USB Reset, reset device address to zero */
+   if (reset)
+   dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK);
+
/* De-assert Wakeup Logic */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PMUACTV;
-- 
2.25.1



[PATCH v2 01/15] usb: dwc2: Update exit hibernation when port reset is asserted

2021-04-16 Thread Artur Petrosyan
No need to check for "DWC2_POWER_DOWN_PARAM_HIBERNATION" param
as "hsotg->hibernated" flag is already enough for exiting from
hibernation mode.

- Removes checking of "DWC2_POWER_DOWN_PARAM_HIBERNATION" param.

- For code readability Hibernation exit code moved after
debug message print.

- Added "dwc2_exit_hibernation()" function error checking.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 04a1b53d65af..cda3f931195d 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3668,9 +3668,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
break;
 
case USB_PORT_FEAT_RESET:
-   if (hsotg->params.power_down == 
DWC2_POWER_DOWN_PARAM_HIBERNATION &&
-   hsotg->hibernated)
-   dwc2_exit_hibernation(hsotg, 0, 1, 1);
+   dev_dbg(hsotg->dev,
+   "SetPortFeature - USB_PORT_FEAT_RESET\n");
+
+   hprt0 = dwc2_read_hprt0(hsotg);
+
+   if (hsotg->hibernated) {
+   retval = dwc2_exit_hibernation(hsotg, 0, 1, 1);
+   if (retval)
+   dev_err(hsotg->dev,
+   "exit hibernation failed\n");
+   }
 
if (hsotg->in_ppd) {
retval = dwc2_exit_partial_power_down(hsotg, 1,
@@ -3684,9 +3692,6 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, 
u16 typereq,
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
dwc2_host_exit_clock_gating(hsotg, 0);
 
-   hprt0 = dwc2_read_hprt0(hsotg);
-   dev_dbg(hsotg->dev,
-   "SetPortFeature - USB_PORT_FEAT_RESET\n");
pcgctl = dwc2_readl(hsotg, PCGCTL);
pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
dwc2_writel(hsotg, pcgctl, PCGCTL);
-- 
2.25.1



[PATCH v2 00/15] usb: dwc2: Fix Hibernation issues.

2021-04-16 Thread Artur Petrosyan
This patch set fixes and improves hibernation mode for dwc2 core.
It adds support for the following cases
1. Hibernation entering/exiting flow by system suspend/resume.
2. Exiting hibernation mode before removing driver and urb enqueue.
3. Exiting hibernation from gpwrdn rst detect.

It updates the implementation of dwc2 entering and exiting
hibernation mode when a port is suspended or resumed or reset asserted.

It fixes hibernation issues between host and device mode when core
enters to hibernation in host mode and mode change happens. Also, a fix
is introduced for remote wakeup flow.

The patch set also improves implementation of entering to hibernation
from dwc2_handle_usb_suspend_intr() handler.

Changes since V1:
Updated bellow patches. Moved duplicated error checking *if* conditions
from innermost to outside if.
1. usb: dwc2: Add exit hibernation mode before removing drive
2. usb: dwc2: Allow exit hibernation in urb enqueue

Fixed an uninitialized pointer variable which was reported by
kernel test robot in "usb: dwc2: Add exit hibernation mode before
removing drive" patch. After fixing added Reported-by tags for
kernel test robot and Dan Carpenter.

Also removed some text from cover letter because I think that is
why vger.kernel.org was rejecting it.


Artur Petrosyan (15):
  usb: dwc2: Update exit hibernation when port reset is asserted
  usb: dwc2: Reset DEVADDR after exiting gadget hibernation.
  usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
  usb: dwc2: Fix hibernation between host and device modes.
  usb: dwc2: Allow exiting hibernation from gpwrdn rst detect
  usb: dwc2: Clear fifo_map when resetting core.
  usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.
  usb: dwc2: Move enter hibernation to dwc2_port_suspend() function
  usb: dwc2: Move exit hibernation to dwc2_port_resume() function
  usb: dwc2: Allow exit hibernation in urb enqueue
  usb: dwc2: Add hibernation entering flow by system suspend
  usb: dwc2: Add hibernation exiting flow by system resume
  usb: dwc2: Add exit hibernation mode before removing drive
  usb: dwc2: Update dwc2_handle_usb_suspend_intr function.
  usb: dwc2: Get rid of useless error checks in suspend interrupt

 drivers/usb/dwc2/core.c  |  25 -
 drivers/usb/dwc2/core.h  |   3 +
 drivers/usb/dwc2/core_intr.c | 205 +++
 drivers/usb/dwc2/gadget.c|   4 +
 drivers/usb/dwc2/hcd.c   |  92 +---
 drivers/usb/dwc2/platform.c  |  15 +++
 6 files changed, 233 insertions(+), 111 deletions(-)


base-commit: 4b853c236c7b5161a2e444bd8b3c76fe5aa5ddcb
-- 
2.25.1



Re: [PATCH 10/15] usb: dwc2: Allow exit hibernation in urb enqueue

2021-04-16 Thread Artur Petrosyan
Hi Sergei,

On 4/16/2021 09:43, Artur Petrosyan wrote:
> Hi Sergei,
> 
> On 4/15/2021 13:12, Sergei Shtylyov wrote:
>> On 15.04.2021 8:40, Artur Petrosyan wrote:
>>
>>> When core is in hibernation state and an external
>>> hub is connected, upper layer sends URB enqueue request,
>>> which results in port reset issue.
>>>
>>> - Added exit from hibernation state to avoid port
>>> reset issue and process upper layer request properly.
>>>
>>> Signed-off-by: Artur Petrosyan 
>>> ---
>>> drivers/usb/dwc2/hcd.c | 17 +
>>> 1 file changed, 17 insertions(+)
>>>
>>> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
>>> index cc9ad6cf02d9..3b03b2d73aaa 100644
>>> --- a/drivers/usb/dwc2/hcd.c
>>> +++ b/drivers/usb/dwc2/hcd.c
>>> @@ -4631,12 +4631,29 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd 
>>> *hcd, struct urb *urb,
>>> struct dwc2_qh *qh;
>>> bool qh_allocated = false;
>>> struct dwc2_qtd *qtd;
>>> +   struct dwc2_gregs_backup *gr;
>>> +
>>> +   gr = >gr_backup;
>>> 
>>> if (dbg_urb(urb)) {
>>> dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
>>> dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
>>> }
>>> 
>>> +   if (hsotg->hibernated) {
>>> +   if (gr->gotgctl & GOTGCTL_CURMODE_HOST) {
>>> +   retval = dwc2_exit_hibernation(hsotg, 0, 0, 1);
>>> +   if (retval)
>>> +   dev_err(hsotg->dev,
>>> +   "exit hibernation failed.\n");
>>> +   } else {
>>> +   retval = dwc2_exit_hibernation(hsotg, 0, 0, 0);
>>> +   if (retval)
>>> +   dev_err(hsotg->dev,
>>> +   "exit hibernation failed.\n");
>>
>>   Why not put these identical *if*s outside the the outer *if*?
>>
> Well the reason that the conditions are implemented like they are, is
> that the inner if checks whether core operates in host mode or device
> mode and the outside if checks if the core is hibernated or not.
> 
> So now imagine that the ifs are combined and core is not hibernated but
> the operational mode of the driver is let's say gadget. If the case is
> such then the driver will try to exit from gadget hibernation because of
> the else condition as the if condition will be false again because core
> is not hibernated. As a result if we combine the outside and inner ifs
> then it will try to exit from gadget hibernation but core is not
> hibernated and that would be an issue.
> 

Sorry I got your point wrong there. You meant the ifs for dev_err().
Thank you for the review I will update them.

> 
>>
>>> +   }
>>> +   }
>>> +
>>> if (hsotg->in_ppd) {
>>> retval = dwc2_exit_partial_power_down(hsotg, 0, true);
>>> if (retval)
>>
>> MBR, Sergei
>>
> 
> Regards,
> Artur
> 


Re: [PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive

2021-04-15 Thread Artur Petrosyan
Hi Sergei,

On 4/15/2021 13:24, Sergei Shtylyov wrote:
> On 15.04.2021 8:41, Artur Petrosyan wrote:
> 
>> When dwc2 core is in hibernation mode loading
>> driver again causes driver fail. Because in
>> that mode registers are not accessible.
>>
>> In order to exit from hibernation checking
>> dwc2 core power saving state in "dwc2_driver_remove()"
>> function. If core is in hibernation, then checking the
>> operational mode of the driver. To check whether dwc2 core
>> is operating in host mode or device mode there is one way
>> which is retrieving the backup value of "gotgctl" and compare
>> the "CurMod" value. If previously core entered hibernation
>> in host mode then the exit is performed for host if not then
>> exit is performed for device mode. The introduced checking
>> is because in hibernation state all registers are not
>> accessible.
>>
>> Signed-off-by: Artur Petrosyan 
>> ---
>>drivers/usb/dwc2/platform.c | 16 
>>1 file changed, 16 insertions(+)
>>
>> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
>> index f8b819cfa80e..2ae4748ed5ec 100644
>> --- a/drivers/usb/dwc2/platform.c
>> +++ b/drivers/usb/dwc2/platform.c
>> @@ -316,8 +316,24 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg 
>> *hsotg)
>>static int dwc2_driver_remove(struct platform_device *dev)
>>{
>>  struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
>> +struct dwc2_gregs_backup *gr;
>>  int ret = 0;
>>
>> +/* Exit Hibernation when driver is removed. */
>> +if (hsotg->hibernated) {
>> +if (gr->gotgctl & GOTGCTL_CURMODE_HOST) {
>> +ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
>> +if (ret)
>> +dev_err(hsotg->dev,
>> +"exit hibernation failed.\n");
>> +} else {
>> +ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
>> +if (ret)
>> +dev_err(hsotg->dev,
>> +"exit hibernation failed.\n");
> 
>  Again, why duplicate the innermost *if*?
Again the reason is that combination of inner and outside ifs would give 
as a situation when core would not be hibernated but driver would try to 
exit from host or device hibernation.

> 
>>   +  }
>> +}
>> +
>>  /* Exit Partial Power Down when driver is removed. */
>>  if (hsotg->in_ppd) {
>>  ret = dwc2_exit_partial_power_down(hsotg, 0, true);
> 
> MBR, Sergei
> 
Regards,
Artur


Re: [PATCH 10/15] usb: dwc2: Allow exit hibernation in urb enqueue

2021-04-15 Thread Artur Petrosyan
Hi Sergei,

On 4/15/2021 13:12, Sergei Shtylyov wrote:
> On 15.04.2021 8:40, Artur Petrosyan wrote:
> 
>> When core is in hibernation state and an external
>> hub is connected, upper layer sends URB enqueue request,
>> which results in port reset issue.
>>
>> - Added exit from hibernation state to avoid port
>> reset issue and process upper layer request properly.
>>
>> Signed-off-by: Artur Petrosyan 
>> ---
>>drivers/usb/dwc2/hcd.c | 17 +
>>1 file changed, 17 insertions(+)
>>
>> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
>> index cc9ad6cf02d9..3b03b2d73aaa 100644
>> --- a/drivers/usb/dwc2/hcd.c
>> +++ b/drivers/usb/dwc2/hcd.c
>> @@ -4631,12 +4631,29 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd 
>> *hcd, struct urb *urb,
>>  struct dwc2_qh *qh;
>>  bool qh_allocated = false;
>>  struct dwc2_qtd *qtd;
>> +struct dwc2_gregs_backup *gr;
>> +
>> +gr = >gr_backup;
>>
>>  if (dbg_urb(urb)) {
>>  dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
>>  dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
>>  }
>>
>> +if (hsotg->hibernated) {
>> +if (gr->gotgctl & GOTGCTL_CURMODE_HOST) {
>> +retval = dwc2_exit_hibernation(hsotg, 0, 0, 1);
>> +if (retval)
>> +dev_err(hsotg->dev,
>> +"exit hibernation failed.\n");
>> +} else {
>> +retval = dwc2_exit_hibernation(hsotg, 0, 0, 0);
>> +if (retval)
>> +dev_err(hsotg->dev,
>> +"exit hibernation failed.\n");
> 
>  Why not put these identical *if*s outside the the outer *if*?
> 
Well the reason that the conditions are implemented like they are, is 
that the inner if checks whether core operates in host mode or device 
mode and the outside if checks if the core is hibernated or not.

So now imagine that the ifs are combined and core is not hibernated but 
the operational mode of the driver is let's say gadget. If the case is 
such then the driver will try to exit from gadget hibernation because of 
the else condition as the if condition will be false again because core 
is not hibernated. As a result if we combine the outside and inner ifs 
then it will try to exit from gadget hibernation but core is not 
hibernated and that would be an issue.


> 
>> +}
>> +}
>> +
>>  if (hsotg->in_ppd) {
>>  retval = dwc2_exit_partial_power_down(hsotg, 0, true);
>>  if (retval)
> 
> MBR, Sergei
> 

Regards,
Artur


[PATCH 15/15] usb: dwc2: Get rid of useless error checks in suspend interrupt

2021-04-14 Thread Artur Petrosyan
Squashed from Douglas Anderson's suggested commit
"usb: dwc2: Get rid of useless error checks for
hibernation/partial power down"

 - After this commit there should never be any
case where dwc2_enter_partial_power_down() and
dwc2_enter_hibernation() are called when
'params.power_down' is not correct.  Get rid of
the pile of error checking.

- As part of this cleanup some of the error messages
not to have __func__ in them.  That's not needed
for dev_err() calls since they already have the
device name as part of the message.

Signed-off-by: Artur Petrosyan 
Signed-off-by: Douglas Anderson 
---
 drivers/usb/dwc2/core.c  |  3 ---
 drivers/usb/dwc2/core_intr.c | 18 +++---
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 576c262dba55..6f70ab9577b4 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -391,9 +391,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg 
*hsotg)
  */
 int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host)
 {
-   if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION)
-   return -ENOTSUPP;
-
if (is_host)
return dwc2_host_enter_hibernation(hsotg);
else
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 470458ac664b..a5ab03808da6 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -535,13 +535,10 @@ static void dwc2_handle_usb_suspend_intr(struct 
dwc2_hsotg *hsotg)
switch (hsotg->params.power_down) {
case DWC2_POWER_DOWN_PARAM_PARTIAL:
ret = dwc2_enter_partial_power_down(hsotg);
-   if (ret) {
-   if (ret != -ENOTSUPP)
-   dev_err(hsotg->dev,
-   "%s: enter 
partial_power_down failed\n",
-   __func__);
-   goto skip_power_saving;
-   }
+   if (ret)
+   dev_err(hsotg->dev,
+   "enter partial_power_down 
failed\n");
+
udelay(100);
 
/* Ask phy to be suspended */
@@ -550,10 +547,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg 
*hsotg)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
ret = dwc2_enter_hibernation(hsotg, 0);
-   if (ret && ret != -ENOTSUPP)
+   if (ret)
dev_err(hsotg->dev,
-   "%s: enter hibernation 
failed\n",
-   __func__);
+   "enter hibernation failed\n");
break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
@@ -562,7 +558,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg 
*hsotg)
 */
dwc2_gadget_enter_clock_gating(hsotg);
}
-skip_power_saving:
+
/*
 * Change to L2 (suspend) state before releasing
 * spinlock
-- 
2.25.1



[PATCH 14/15] usb: dwc2: Update dwc2_handle_usb_suspend_intr function.

2021-04-14 Thread Artur Petrosyan
To avoid working in two modes (partial power down
and hibernation) changed conditions for entering
partial power down or hibernation.

Instead of checking hw_params.power_optimized and
hw_params.hibernation now checking power_down
param which already set to one of the options
(Hibernation or Partial Power Down) based on
OTG_EN_PWROPT.

Signed-off-by: Artur Petrosyan 
Signed-off-by: Minas Harutyunyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index f8963c0cf6af..470458ac664b 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -532,7 +532,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg 
*hsotg)
return;
}
if (dsts & DSTS_SUSPSTS) {
-   if (hsotg->hw_params.power_optimized) {
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
ret = dwc2_enter_partial_power_down(hsotg);
if (ret) {
if (ret != -ENOTSUPP)
@@ -541,21 +542,22 @@ static void dwc2_handle_usb_suspend_intr(struct 
dwc2_hsotg *hsotg)
__func__);
goto skip_power_saving;
}
-
udelay(100);
 
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy))
usb_phy_set_suspend(hsotg->uphy, true);
-   } else if (hsotg->hw_params.hibernation) {
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
ret = dwc2_enter_hibernation(hsotg, 0);
if (ret && ret != -ENOTSUPP)
dev_err(hsotg->dev,
"%s: enter hibernation 
failed\n",
__func__);
-   } else {
+   break;
+   case DWC2_POWER_DOWN_PARAM_NONE:
/*
-* If not hibernation nor partial power down 
are supported,
+* If neither hibernation nor partial power 
down are supported,
 * clock gating is used to save power.
 */
dwc2_gadget_enter_clock_gating(hsotg);
-- 
2.25.1



[PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive

2021-04-14 Thread Artur Petrosyan
When dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.

In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()"
function. If core is in hibernation, then checking the
operational mode of the driver. To check whether dwc2 core
is operating in host mode or device mode there is one way
which is retrieving the backup value of "gotgctl" and compare
the "CurMod" value. If previously core entered hibernation
in host mode then the exit is performed for host if not then
exit is performed for device mode. The introduced checking
is because in hibernation state all registers are not
accessible.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/platform.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index f8b819cfa80e..2ae4748ed5ec 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -316,8 +316,24 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
 static int dwc2_driver_remove(struct platform_device *dev)
 {
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
+   struct dwc2_gregs_backup *gr;
int ret = 0;
 
+   /* Exit Hibernation when driver is removed. */
+   if (hsotg->hibernated) {
+   if (gr->gotgctl & GOTGCTL_CURMODE_HOST) {
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   } else {
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   }
+   }
+
/* Exit Partial Power Down when driver is removed. */
if (hsotg->in_ppd) {
ret = dwc2_exit_partial_power_down(hsotg, 0, true);
-- 
2.25.1



[PATCH 12/15] usb: dwc2: Add hibernation exiting flow by system resume

2021-04-14 Thread Artur Petrosyan
Adds a new flow of exiting hibernation when PC is resumed
from suspend state.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index db8eb1940d17..c92307775863 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4470,6 +4470,16 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   if (ret)
+   dev_err(hsotg->dev, "exit hibernation failed.\n");
+
+   /*
+* Set HW accessible bit before powering on the controller
+* since an interrupt may rise.
+*/
+   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
-- 
2.25.1



[PATCH 11/15] usb: dwc2: Add hibernation entering flow by system suspend

2021-04-14 Thread Artur Petrosyan
Adds a new flow of entering hibernation when PC is
hibernated or suspended.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 3b03b2d73aaa..db8eb1940d17 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4387,6 +4387,16 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   /* Enter hibernation */
+   spin_unlock_irqrestore(>lock, flags);
+   ret = dwc2_enter_hibernation(hsotg, 1);
+   if (ret)
+   dev_err(hsotg->dev, "enter hibernation failed\n");
+   spin_lock_irqsave(>lock, flags);
+
+   /* After entering suspend, hardware is not accessible */
+   clear_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
-- 
2.25.1



[PATCH 10/15] usb: dwc2: Allow exit hibernation in urb enqueue

2021-04-14 Thread Artur Petrosyan
When core is in hibernation state and an external
hub is connected, upper layer sends URB enqueue request,
which results in port reset issue.

- Added exit from hibernation state to avoid port
reset issue and process upper layer request properly.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index cc9ad6cf02d9..3b03b2d73aaa 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4631,12 +4631,29 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, 
struct urb *urb,
struct dwc2_qh *qh;
bool qh_allocated = false;
struct dwc2_qtd *qtd;
+   struct dwc2_gregs_backup *gr;
+
+   gr = >gr_backup;
 
if (dbg_urb(urb)) {
dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
}
 
+   if (hsotg->hibernated) {
+   if (gr->gotgctl & GOTGCTL_CURMODE_HOST) {
+   retval = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   if (retval)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   } else {
+   retval = dwc2_exit_hibernation(hsotg, 0, 0, 0);
+   if (retval)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   }
+   }
+
if (hsotg->in_ppd) {
retval = dwc2_exit_partial_power_down(hsotg, 0, true);
if (retval)
-- 
2.25.1



[PATCH 09/15] usb: dwc2: Move exit hibernation to dwc2_port_resume() function

2021-04-14 Thread Artur Petrosyan
This move is done to call hibernation exit handler in
"dwc2_port_resume()" function when core receives port resume.
Otherwise it could be confusing to exit hibernation in
"dwc2_hcd_hub_control()" function but other power saving modes
in "dwc2_port_resume()" function.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 43a2298b7d42..cc9ad6cf02d9 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3383,6 +3383,11 @@ int dwc2_port_resume(struct dwc2_hsotg *hsotg)
"exit partial_power_down failed.\n");
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   /* Exit host hibernation. */
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
+   if (ret)
+   dev_err(hsotg->dev, "exit hibernation failed.\n");
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
@@ -3446,12 +3451,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
 
-   if (hsotg->bus_suspended) {
-   if (hsotg->hibernated)
-   dwc2_exit_hibernation(hsotg, 0, 0, 1);
-   else
-   dwc2_port_resume(hsotg);
-   }
+   if (hsotg->bus_suspended)
+   retval = dwc2_port_resume(hsotg);
break;
 
case USB_PORT_FEAT_POWER:
-- 
2.25.1



[PATCH 08/15] usb: dwc2: Move enter hibernation to dwc2_port_suspend() function

2021-04-14 Thread Artur Petrosyan
This move is done to call enter hibernation handler in
"dwc2_port_suspend()" function when core receives port suspend.
Otherwise it could be confusing to enter to hibernation in
"dwc2_hcd_hub_control()" function but other power saving modes
in "dwc2_port_suspend()" function.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 18 ++
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index ff945c40ef8a..43a2298b7d42 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3321,6 +3321,18 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
"enter partial_power_down failed.\n");
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   /*
+* Perform spin unlock and lock because in
+* "dwc2_host_enter_hibernation()" function there is a spinlock
+* logic which prevents servicing of any IRQ during entering
+* hibernation.
+*/
+   spin_unlock_irqrestore(>lock, flags);
+   ret = dwc2_enter_hibernation(hsotg, 1);
+   if (ret)
+   dev_err(hsotg->dev, "enter hibernation failed.\n");
+   spin_lock_irqsave(>lock, flags);
+   break;
case DWC2_POWER_DOWN_PARAM_NONE:
/*
 * If not hibernation nor partial power down are supported,
@@ -3650,10 +3662,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
"SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
if (windex != hsotg->otg_port)
goto error;
-   if (hsotg->params.power_down == 
DWC2_POWER_DOWN_PARAM_HIBERNATION)
-   dwc2_enter_hibernation(hsotg, 1);
-   else
-   dwc2_port_suspend(hsotg, windex);
+   if (!hsotg->bus_suspended)
+   retval = dwc2_port_suspend(hsotg, windex);
break;
 
case USB_PORT_FEAT_POWER:
-- 
2.25.1



[PATCH 07/15] usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.

2021-04-14 Thread Artur Petrosyan
When hibernation exit is performed the dwc2_hib_restore_common()
function is called. In that function we wait until GINTSTS_RESTOREDONE
bit is set. However, after the setting of that bit we get a lot of
(dwc2_hsotg_irq:) interrupts which indicates that (GINTSTS.RstrDoneInt)
restore done interrupt is asserted.

To avoid restore done interrupt storm after restore is generated
clear GINTSTS_RESTOREDONE bit in GINTSTS register.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index eccd96fa164e..576c262dba55 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -299,6 +299,12 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int 
rem_wakeup,
__func__);
} else {
dev_dbg(hsotg->dev, "restore done  generated here\n");
+
+   /*
+* To avoid restore done interrupt storm after restore is
+* generated clear GINTSTS_RESTOREDONE bit.
+*/
+   dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTSTS);
}
 }
 
-- 
2.25.1



[PATCH 06/15] usb: dwc2: Clear fifo_map when resetting core.

2021-04-14 Thread Artur Petrosyan
Switching from device mode to host mode by disconnecting
device cable core enters and exits form hibernation.
However, the fifo map remains not cleared. It results
to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/
gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2])
if in host mode we disconnect the micro a to b host
cable. Because core reset occurs.

To avoid the WARNING, fifo_map should be cleared
in dwc2_core_reset() function by taking into account configs.
fifo_map must be cleared only if driver is configured in
"CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE"
mode.

- Added "static inline void dwc2_clear_fifo_map()" helper
function to clear fifo_map with peripheral or dual role mode.

- Added a dummy version of "dwc2_clear_fifo_map()" helper
for host-only mode.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.c | 16 
 drivers/usb/dwc2/core.h |  3 +++
 2 files changed, 19 insertions(+)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index cb65f7f60573..eccd96fa164e 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -470,6 +470,22 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool 
skip_wait)
dwc2_writel(hsotg, greset, GRSTCTL);
}
 
+   /*
+* Switching from device mode to host mode by disconnecting
+* device cable core enters and exits form hibernation.
+* However, the fifo map remains not cleared. It results
+* to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/
+* gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2])
+* if in host mode we disconnect the micro a to b host
+* cable. Because core reset occurs.
+* To avoid the WARNING, fifo_map should be cleared
+* in dwc2_core_reset() function by taking into account configs.
+* fifo_map must be cleared only if driver is configured in
+* "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE"
+* mode.
+*/
+   dwc2_clear_fifo_map(hsotg);
+
/* Wait for AHB master IDLE state */
if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 1)) {
dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL 
GRSTCTL_AHBIDLE\n",
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 8c12b3061f7f..e1f432095565 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1423,6 +1423,8 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg 
*hsotg);
 int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
 void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
 void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg);
+static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg)
+{ hsotg->fifo_map = 0; }
 #else
 static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
 { return 0; }
@@ -1467,6 +1469,7 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct 
dwc2_hsotg *hsotg)
 { return 0; }
 static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
 static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) {}
 #endif
 
 #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
-- 
2.25.1



[PATCH 05/15] usb: dwc2: Allow exiting hibernation from gpwrdn rst detect

2021-04-14 Thread Artur Petrosyan
When device cable is disconnected core receives suspend
interrupt and enters hibernation. After entering
into hibernation GPWRDN_RST_DET and GPWRDN_STS_CHGINT
interrupts are asserted.

Allowed exit from gadget hibernation from
GPWRDN_RST_DET by checking only linestate.

Changed the return type of "dwc2_handle_gpwrdn_intr()"
function from void to int because exit from hibernation
functions have a return value.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 23 ++-
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 27d729fad227..f8963c0cf6af 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -751,10 +751,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct 
dwc2_hsotg *hsotg,
  * The GPWRDN interrupts are those that occur in both Host and
  * Device mode while core is in hibernated state.
  */
-static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
+static int dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
 {
u32 gpwrdn;
int linestate;
+   int ret = 0;
 
gpwrdn = dwc2_readl(hsotg, GPWRDN);
/* clear all interrupt */
@@ -778,17 +779,27 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg 
*hsotg)
if (hsotg->hw_params.hibernation &&
hsotg->hibernated) {
if (gpwrdn & GPWRDN_IDSTS) {
-   dwc2_exit_hibernation(hsotg, 0, 0, 0);
+   ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
call_gadget(hsotg, resume);
} else {
-   dwc2_exit_hibernation(hsotg, 1, 0, 1);
+   ret = dwc2_exit_hibernation(hsotg, 1, 0, 1);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
}
}
} else if ((gpwrdn & GPWRDN_RST_DET) &&
   (gpwrdn & GPWRDN_RST_DET_MSK)) {
dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__);
-   if (!linestate && (gpwrdn & GPWRDN_BSESSVLD))
-   dwc2_exit_hibernation(hsotg, 0, 1, 0);
+   if (!linestate) {
+   ret = dwc2_exit_hibernation(hsotg, 0, 1, 0);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit hibernation failed.\n");
+   }
} else if ((gpwrdn & GPWRDN_STS_CHGINT) &&
   (gpwrdn & GPWRDN_STS_CHGINT_MSK)) {
dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__);
@@ -800,6 +811,8 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg 
*hsotg)
 */
dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn);
}
+
+   return ret;
 }
 
 /*
-- 
2.25.1



[PATCH 04/15] usb: dwc2: Fix hibernation between host and device modes.

2021-04-14 Thread Artur Petrosyan
When core is in hibernation in host mode and a device cable
was connected then driver exited from device hibernation.
However, registers saved for host mode and when exited from
device hibernation register restore would be done for device
register which was wrong because there was no device registers
stored to restore.

- Added dwc_handle_gpwrdn_disc_det() function which handles
  gpwrdn disconnect detect flow and exits hibernation
  without restoring the registers.
- Updated exiting from hibernation in GPWRDN_STS_CHGINT with
  calling dwc_handle_gpwrdn_disc_det() function. Here no register
  is restored which is the solution described above.

Fixes: 65c9c4c6b01f ("usb: dwc2: Add dwc2_handle_gpwrdn_intr() handler")
Signed-off-by: Artur Petrosyan 
Signed-off-by: Minas Harutyunyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 154 +++
 1 file changed, 83 insertions(+), 71 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 550c52c1a0c7..27d729fad227 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -680,6 +680,71 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
return 0;
 }
 
+/**
+ * dwc_handle_gpwrdn_disc_det() - Handles the gpwrdn disconnect detect.
+ * Exits hibernation without restoring registers.
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @gpwrdn: GPWRDN register
+ */
+static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg,
+ u32 gpwrdn)
+{
+   u32 gpwrdn_tmp;
+
+   /* Switch-on voltage to the core */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Reset core */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Disable Power Down Clamp */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Deassert reset core */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+   udelay(5);
+
+   /* Disable PMU interrupt */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+
+   /* De-assert Wakeup Logic */
+   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
+   gpwrdn_tmp &= ~GPWRDN_PMUACTV;
+   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
+
+   hsotg->hibernated = 0;
+   hsotg->bus_suspended = 0;
+
+   if (gpwrdn & GPWRDN_IDSTS) {
+   hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+   dwc2_core_init(hsotg, false);
+   dwc2_enable_global_interrupts(hsotg);
+   dwc2_hsotg_core_init_disconnected(hsotg, false);
+   dwc2_hsotg_core_connect(hsotg);
+   } else {
+   hsotg->op_state = OTG_STATE_A_HOST;
+
+   /* Initialize the Core for Host mode */
+   dwc2_core_init(hsotg, false);
+   dwc2_enable_global_interrupts(hsotg);
+   dwc2_hcd_start(hsotg);
+   }
+}
+
 /*
  * GPWRDN interrupt handler.
  *
@@ -701,64 +766,14 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg 
*hsotg)
 
if ((gpwrdn & GPWRDN_DISCONN_DET) &&
(gpwrdn & GPWRDN_DISCONN_DET_MSK) && !linestate) {
-   u32 gpwrdn_tmp;
-
dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);
-
-   /* Switch-on voltage to the core */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Reset core */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Disable Power Down Clamp */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Deassert reset core */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-   udelay(10);
-
-   /* Disable PMU interrupt */
-   gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
-   gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
-   dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
-

[PATCH 03/15] usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.

2021-04-14 Thread Artur Petrosyan
Added setting "port_connect_status_change" flag to "1" in order
to re-enumerate, because after exit from hibernation port
connection status is not detected.

Fixes: c5c403dc4336 ("usb: dwc2: Add host/device hibernation functions")
Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index cda3f931195d..ff945c40ef8a 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5650,7 +5650,15 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, 
int rem_wakeup,
return ret;
}
 
-   dwc2_hcd_rem_wakeup(hsotg);
+   if (rem_wakeup) {
+   dwc2_hcd_rem_wakeup(hsotg);
+   /*
+* Change "port_connect_status_change" flag to re-enumerate,
+* because after exit from hibernation port connection status
+* is not detected.
+*/
+   hsotg->flags.b.port_connect_status_change = 1;
+   }
 
hsotg->hibernated = 0;
hsotg->bus_suspended = 0;
-- 
2.25.1



[PATCH 01/15] usb: dwc2: Update exit hibernation when port reset is asserted

2021-04-14 Thread Artur Petrosyan
No need to check for "DWC2_POWER_DOWN_PARAM_HIBERNATION" param
as "hsotg->hibernated" flag is already enough for exiting from
hibernation mode.

- Removes checking of "DWC2_POWER_DOWN_PARAM_HIBERNATION" param.

- For code readability Hibernation exit code moved after
debug message print.

- Added "dwc2_exit_hibernation()" function error checking.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 04a1b53d65af..cda3f931195d 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3668,9 +3668,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
break;
 
case USB_PORT_FEAT_RESET:
-   if (hsotg->params.power_down == 
DWC2_POWER_DOWN_PARAM_HIBERNATION &&
-   hsotg->hibernated)
-   dwc2_exit_hibernation(hsotg, 0, 1, 1);
+   dev_dbg(hsotg->dev,
+   "SetPortFeature - USB_PORT_FEAT_RESET\n");
+
+   hprt0 = dwc2_read_hprt0(hsotg);
+
+   if (hsotg->hibernated) {
+   retval = dwc2_exit_hibernation(hsotg, 0, 1, 1);
+   if (retval)
+   dev_err(hsotg->dev,
+   "exit hibernation failed\n");
+   }
 
if (hsotg->in_ppd) {
retval = dwc2_exit_partial_power_down(hsotg, 1,
@@ -3684,9 +3692,6 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, 
u16 typereq,
DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
dwc2_host_exit_clock_gating(hsotg, 0);
 
-   hprt0 = dwc2_read_hprt0(hsotg);
-   dev_dbg(hsotg->dev,
-   "SetPortFeature - USB_PORT_FEAT_RESET\n");
pcgctl = dwc2_readl(hsotg, PCGCTL);
pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
dwc2_writel(hsotg, pcgctl, PCGCTL);
-- 
2.25.1



[PATCH 02/15] usb: dwc2: Reset DEVADDR after exiting gadget hibernation.

2021-04-14 Thread Artur Petrosyan
Initially resetting device address was done in dwc2_hsotg_irq()
interrupt handler. However, when core is hibernated USB RESET
is not handled in dwc2_hsotg_irq() handler, instead USB RESET
interrupt is handled in dwc2_handle_gpwrdn_intr() handler.

- Added reset device address to zero when core exits from gadget
  hibernation.

Signed-off-by: Artur Petrosyan 
Signed-off-by: Minas Harutyunyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/gadget.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 2f50f3e62caa..e6bb1bdb2760 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -5305,6 +5305,10 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg 
*hsotg,
dwc2_writel(hsotg, dr->dcfg, DCFG);
dwc2_writel(hsotg, dr->dctl, DCTL);
 
+   /* On USB Reset, reset device address to zero */
+   if (reset)
+   dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK);
+
/* De-assert Wakeup Logic */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PMUACTV;
-- 
2.25.1



Re: [PATCH v2 00/12] usb: dwc2: Add clock gating support.

2021-04-13 Thread Artur Petrosyan
Hi Greg,

On 4/13/2021 11:35, Artur Petrosyan wrote:
> This patch set adds clock gating power saving support for
> dwc2 core.
> It adds support for the following cases described by programming guide.
>1. Enter to clock gating from USB_SUSPEND interrupt.
>2. Clock gating entering flow by system suspend.
>3. Clock gating exiting flow by system resume.
>4. Exit clock gating from wakeup interrupt.
>5. Exit clock gating from session request interrupt.
>6. Exit clock gating when port reset is asserted.
> 
> Additional cases to exit form clock gating were needed which are not
> described in clock gating programming guide.
>1. Added clock gating exit flow before removing driver
>2. Exit clock gating in urb enqueue.
> 
> It updates the implementation of dwc2 entering and exiting clock
> gating when a port is suspended or resumed.
> 
> The patch set also adds the implementation of function handlers
> for entering and exiting host or device clock gating.
> 
> NOTE: This is the third patch set in the power saving mode fixes
> series.
> This patch set is part of multiple series and is continuation
> of the "usb: dwc2: Fix and improve power saving modes" patch set.
> (Patch set link: https://marc.info/?l=linux-usb=160379622403975=2).
> The patches that were included in the "usb: dwc2:
> Fix and improve power saving modes" which was submitted
> earlier was too large and needed to be split up into
> smaller patch sets.
> 
> Changes since V1:
> Re sending the patch set as v1 because vger.kernel.org rejected
> the cover letter. With error code "550 5.7.1 Content-Policy"
> No changes in the patches or the source code.
> 
> 
> Artur Petrosyan (12):
>usb: dwc2: Add device clock gating support functions
>usb: dwc2: Add host clock gating support functions
>usb: dwc2: Allow entering clock gating from USB_SUSPEND interrupt
>usb: dwc2: Add exit clock gating from wakeup interrupt
>usb: dwc2: Add exit clock gating from session request interrupt
>usb: dwc2: Add exit clock gating when port reset is asserted
>usb: dwc2: Update enter clock gating when port is suspended
>usb: dwc2: Update exit clock gating when port is resumed
>usb: dwc2: Allow exit clock gating in urb enqueue
>usb: dwc2: Add clock gating entering flow by system suspend
>usb: dwc2: Add clock gating exiting flow by system resume
>usb: dwc2: Add exit clock gating before removing driver
> 
>   drivers/usb/dwc2/core.h  |  15 ++-
>   drivers/usb/dwc2/core_intr.c |  62 
>   drivers/usb/dwc2/gadget.c|  71 ++
>   drivers/usb/dwc2/hcd.c   | 177 +++
>   drivers/usb/dwc2/platform.c  |   9 ++
>   5 files changed, 272 insertions(+), 62 deletions(-)
> 
> 
> base-commit: 9bc46a12c53d8268392774172742aa9e5dd6953d
> 
This cover letter for the clock gating patches is being rejected by 
"vger.kernel.org". I have tried to send one more time as v2 but again it 
is rejected.
The error message is "vger.kernel.org
Remote Server returned '554 5.7.1 

[PATCH v2 12/12] usb: dwc2: Add exit clock gating before removing driver

2021-04-13 Thread Artur Petrosyan
When dwc2 core is in clock gating mode loading driver
again causes driver fail. Because in that mode
registers are not accessible.

Added a flow of exiting clock gating mode
to avoid the driver reload failure.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/platform.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index b28b8cd45799..f8b819cfa80e 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -326,6 +326,15 @@ static int dwc2_driver_remove(struct platform_device *dev)
"exit partial_power_down failed\n");
}
 
+   /* Exit clock gating when driver is removed. */
+   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
+   hsotg->bus_suspended) {
+   if (dwc2_is_device_mode(hsotg))
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
+   else
+   dwc2_host_exit_clock_gating(hsotg, 0);
+   }
+
dwc2_debugfs_exit(hsotg);
if (hsotg->hcd_enabled)
dwc2_hcd_remove(hsotg);
-- 
2.25.1



[PATCH v2 11/12] usb: dwc2: Add clock gating exiting flow by system resume

2021-04-13 Thread Artur Petrosyan
If not hibernation nor partial power down are supported,
port resume is done using the clock gating programming flow.

Adds a new flow of exiting clock gating when PC is
resumed.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 22 ++
 1 file changed, 22 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 09dcd37b9ef8..04a1b53d65af 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4445,6 +4445,28 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
+   /*
+* If not hibernation nor partial power down are supported,
+* port resume is done using the clock gating programming flow.
+*/
+   spin_unlock_irqrestore(>lock, flags);
+   dwc2_host_exit_clock_gating(hsotg, 0);
+
+   /*
+* Initialize the Core for Host mode, as after system resume
+* the global interrupts are disabled.
+*/
+   dwc2_core_init(hsotg, false);
+   dwc2_enable_global_interrupts(hsotg);
+   dwc2_hcd_reinit(hsotg);
+   spin_lock_irqsave(>lock, flags);
+
+   /*
+* Set HW accessible bit before powering on the controller
+* since an interrupt may rise.
+*/
+   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
default:
hsotg->lx_state = DWC2_L0;
goto unlock;
-- 
2.25.1



[PATCH v2 09/12] usb: dwc2: Allow exit clock gating in urb enqueue

2021-04-13 Thread Artur Petrosyan
When core is in clock gating state and an external
hub is connected, upper layer sends URB enqueue request,
which results in port reset issue.

Added exit from clock gating state to avoid port
reset issue and process upper layer request properly.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 8a42675ab94e..31d6a1b87228 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4597,6 +4597,14 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, 
struct urb *urb,
"exit partial_power_down failed\n");
}
 
+   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
+   hsotg->bus_suspended) {
+   if (dwc2_is_device_mode(hsotg))
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
+   else
+   dwc2_host_exit_clock_gating(hsotg, 0);
+   }
+
if (!ep)
return -EINVAL;
 
-- 
2.25.1



[PATCH v2 10/12] usb: dwc2: Add clock gating entering flow by system suspend

2021-04-13 Thread Artur Petrosyan
If not hibernation nor partial power down are supported,
clock gating is used to save power.

Adds a new flow of entering clock gating when PC is
suspended.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 31d6a1b87228..09dcd37b9ef8 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4372,6 +4372,15 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
+   /*
+* If not hibernation nor partial power down are supported,
+* clock gating is used to save power.
+*/
+   dwc2_host_enter_clock_gating(hsotg);
+
+   /* After entering suspend, hardware is not accessible */
+   clear_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
default:
goto skip_power_saving;
}
-- 
2.25.1



[PATCH v2 05/12] usb: dwc2: Add exit clock gating from session request interrupt

2021-04-13 Thread Artur Petrosyan
Added clock gating exit flow from session
request interrupt handler according programming guide.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/core_intr.c | 19 +--
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index c764407e7633..550c52c1a0c7 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -316,12 +316,19 @@ static void dwc2_handle_session_req_intr(struct 
dwc2_hsotg *hsotg)
hsotg->lx_state);
 
if (dwc2_is_device_mode(hsotg)) {
-   if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
-   ret = dwc2_exit_partial_power_down(hsotg, 0,
-  true);
-   if (ret)
-   dev_err(hsotg->dev,
-   "exit power_down failed\n");
+   if (hsotg->lx_state == DWC2_L2) {
+   if (hsotg->in_ppd) {
+   ret = dwc2_exit_partial_power_down(hsotg, 0,
+  true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit power_down failed\n");
+   }
+
+   /* Exit gadget mode clock gating. */
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
}
 
/*
-- 
2.25.1



[PATCH v2 08/12] usb: dwc2: Update exit clock gating when port is resumed

2021-04-13 Thread Artur Petrosyan
Updates the implementation of exiting clock gating mode
when core receives port resume.
Instead of setting the required bit fields of the registers
inline, called the "dwc2_host_exit_clock_gating()" function.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 29 -
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index e1225fe6c61a..8a42675ab94e 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3359,8 +3359,6 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
 int dwc2_port_resume(struct dwc2_hsotg *hsotg)
 {
unsigned long flags;
-   u32 hprt0;
-   u32 pcgctl;
int ret = 0;
 
spin_lock_irqsave(>lock, flags);
@@ -3374,33 +3372,14 @@ int dwc2_port_resume(struct dwc2_hsotg *hsotg)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
-   default:
/*
-* If power_down is supported, Phy clock is already resumed
-* after registers restore.
+* If not hibernation nor partial power down are supported,
+* port resume is done using the clock gating programming flow.
 */
-   if (!hsotg->params.power_down) {
-   pcgctl = dwc2_readl(hsotg, PCGCTL);
-   pcgctl &= ~PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgctl, PCGCTL);
-   spin_unlock_irqrestore(>lock, flags);
-   msleep(20);
-   spin_lock_irqsave(>lock, flags);
-   }
-
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 |= HPRT0_RES;
-   hprt0 &= ~HPRT0_SUSP;
-   dwc2_writel(hsotg, hprt0, HPRT0);
spin_unlock_irqrestore(>lock, flags);
-
-   msleep(USB_RESUME_TIMEOUT);
-
+   dwc2_host_exit_clock_gating(hsotg, 0);
spin_lock_irqsave(>lock, flags);
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
-   dwc2_writel(hsotg, hprt0, HPRT0);
-   hsotg->bus_suspended = false;
+   break;
}
 
spin_unlock_irqrestore(>lock, flags);
-- 
2.25.1



[PATCH v2 06/12] usb: dwc2: Add exit clock gating when port reset is asserted

2021-04-13 Thread Artur Petrosyan
Adds clock gating exit flow when set port feature
reset is received in suspended state.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index f1c24c15d185..27f030d5de54 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3712,6 +3712,10 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
"exit partial_power_down 
failed\n");
}
 
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_host_exit_clock_gating(hsotg, 0);
+
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_RESET\n");
-- 
2.25.1



[PATCH v2 07/12] usb: dwc2: Update enter clock gating when port is suspended

2021-04-13 Thread Artur Petrosyan
Updates the implementation of entering clock gating mode
when core receives port suspend.
Instead of setting the required bit fields of the registers
inline, called the "dwc2_host_enter_clock_gating()" function.

Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 19 ---
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 27f030d5de54..e1225fe6c61a 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3298,7 +3298,6 @@ static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg 
*hsotg)
 int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 {
unsigned long flags;
-   u32 hprt0;
u32 pcgctl;
u32 gotgctl;
int ret = 0;
@@ -3323,22 +3322,12 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
-   default:
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 |= HPRT0_SUSP;
-   dwc2_writel(hsotg, hprt0, HPRT0);
-   hsotg->bus_suspended = true;
/*
-* If power_down is supported, Phy clock will be suspended
-* after registers are backuped.
+* If not hibernation nor partial power down are supported,
+* clock gating is used to save power.
 */
-   if (!hsotg->params.power_down) {
-   /* Suspend the Phy Clock */
-   pcgctl = dwc2_readl(hsotg, PCGCTL);
-   pcgctl |= PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgctl, PCGCTL);
-   udelay(10);
-   }
+   dwc2_host_enter_clock_gating(hsotg);
+   break;
}
 
/* For HNP the bus must be suspended for at least 200ms */
-- 
2.25.1



[PATCH v2 04/12] usb: dwc2: Add exit clock gating from wakeup interrupt

2021-04-13 Thread Artur Petrosyan
Added exit from clock gating mode when wakeup interrupt
is detected. To exit from the clock gating
in device mode "dwc2_gadget_exit_clock_gating()"
function is used with rem_wakeup parameter 0. To exit
clock gating in host mode "dwc2_host_exit_clock_gating()"
with rem_wakeup parameter 1.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 33 ++---
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index ab7fe303c0f9..c764407e7633 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -415,17 +415,24 @@ static void dwc2_handle_wakeup_detected_intr(struct 
dwc2_hsotg *hsotg)
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
dwc2_readl(hsotg, DSTS));
-   if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
-   u32 dctl = dwc2_readl(hsotg, DCTL);
-   /* Clear Remote Wakeup Signaling */
-   dctl &= ~DCTL_RMTWKUPSIG;
-   dwc2_writel(hsotg, dctl, DCTL);
-   ret = dwc2_exit_partial_power_down(hsotg, 1,
-  true);
-   if (ret)
-   dev_err(hsotg->dev,
-   "exit partial_power_down failed\n");
-   call_gadget(hsotg, resume);
+   if (hsotg->lx_state == DWC2_L2) {
+   if (hsotg->in_ppd) {
+   u32 dctl = dwc2_readl(hsotg, DCTL);
+   /* Clear Remote Wakeup Signaling */
+   dctl &= ~DCTL_RMTWKUPSIG;
+   dwc2_writel(hsotg, dctl, DCTL);
+   ret = dwc2_exit_partial_power_down(hsotg, 1,
+  true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down 
failed\n");
+   call_gadget(hsotg, resume);
+   }
+
+   /* Exit gadget mode clock gating. */
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
} else {
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
@@ -440,6 +447,10 @@ static void dwc2_handle_wakeup_detected_intr(struct 
dwc2_hsotg *hsotg)
"exit partial_power_down 
failed\n");
}
 
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_host_exit_clock_gating(hsotg, 1);
+
/*
 * If we've got this quirk then the PHY is stuck upon
 * wakeup.  Assert reset.  This will propagate out and
-- 
2.25.1



[PATCH v2 03/12] usb: dwc2: Allow entering clock gating from USB_SUSPEND interrupt

2021-04-13 Thread Artur Petrosyan
If core doesn't support hibernation or partial power
down power saving options, power can still be saved
using clock gating on all the clocks.

- Added entering clock gating state from USB_SUSPEND
  interrupt.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 8c0152b514be..ab7fe303c0f9 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -529,14 +529,18 @@ static void dwc2_handle_usb_suspend_intr(struct 
dwc2_hsotg *hsotg)
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy))
usb_phy_set_suspend(hsotg->uphy, true);
-   }
-
-   if (hsotg->hw_params.hibernation) {
+   } else if (hsotg->hw_params.hibernation) {
ret = dwc2_enter_hibernation(hsotg, 0);
if (ret && ret != -ENOTSUPP)
dev_err(hsotg->dev,
"%s: enter hibernation 
failed\n",
__func__);
+   } else {
+   /*
+* If not hibernation nor partial power down 
are supported,
+* clock gating is used to save power.
+*/
+   dwc2_gadget_enter_clock_gating(hsotg);
}
 skip_power_saving:
/*
-- 
2.25.1



[PATCH v2 02/12] usb: dwc2: Add host clock gating support functions

2021-04-13 Thread Artur Petrosyan
Added host clock gating support functions according
programming guide.

Added function names:
dwc2_host_enter_clock_gating()
dwc2_host_exit_clock_gating()

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.h |  5 +++
 drivers/usb/dwc2/hcd.c  | 86 +
 2 files changed, 91 insertions(+)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index e5597796dca4..8c12b3061f7f 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1486,6 +1486,8 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
 int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg);
 int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
  int rem_wakeup, bool restore);
+void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg);
+void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup);
 bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
 static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
 { schedule_work(>phy_reset_work); }
@@ -1521,6 +1523,9 @@ static inline int 
dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
 static inline int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
int rem_wakeup, bool 
restore)
 { return 0; }
+static inline void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg,
+  int rem_wakeup) {}
 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) {}
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index f096006df96f..f1c24c15d185 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5821,3 +5821,89 @@ int dwc2_host_exit_partial_power_down(struct dwc2_hsotg 
*hsotg,
dev_dbg(hsotg->dev, "Exiting host partial power down completed.\n");
return ret;
 }
+
+/**
+ * dwc2_host_enter_clock_gating() - Put controller in clock gating.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * This function is for entering Host mode clock gating.
+ */
+void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg)
+{
+   u32 hprt0;
+   u32 pcgctl;
+
+   dev_dbg(hsotg->dev, "Entering host clock gating.\n");
+
+   /* Put this port in suspend mode. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_SUSP;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+
+   /* Set the Phy Clock bit as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Set the Gate hclk as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_GATEHCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   hsotg->bus_suspended = true;
+   hsotg->lx_state = DWC2_L2;
+}
+
+/**
+ * dwc2_host_exit_clock_gating() - Exit controller from clock gating.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: indicates whether resume is initiated by remote wakeup
+ *
+ * This function is for exiting Host mode clock gating.
+ */
+void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup)
+{
+   u32 hprt0;
+   u32 pcgctl;
+
+   dev_dbg(hsotg->dev, "Exiting host clock gating.\n");
+
+   /* Clear the Gate hclk. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl &= ~PCGCTL_GATEHCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Phy Clock bit. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl &= ~PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Drive resume signaling and exit suspend mode on the port. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_RES;
+   hprt0 &= ~HPRT0_SUSP;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+   udelay(5);
+
+   if (!rem_wakeup) {
+   /* In case of port resume need to wait for 40 ms */
+   msleep(USB_RESUME_TIMEOUT);
+
+   /* Stop driveing resume signaling on the port. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 &= ~HPRT0_RES;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+
+   hsotg->bus_suspended = false;
+   hsotg->lx_state = DWC2_L0;
+   } else {
+   mod_timer(>wkp_timer,
+ jiffies + msecs_to_jiffies(71));
+   }
+}
-- 
2.25.1



[PATCH v2 01/12] usb: dwc2: Add device clock gating support functions

2021-04-13 Thread Artur Petrosyan
Added device clock gating support functions according
programming guide.

Moved "bus_suspended" flag to "dwc2_hsotg" struct because
we need to set that flag while entering to clock gating
in case when the driver is built in peripheral mode.

Added function names:
dwc2_gadget_enter_clock_gating()
dwc2_gadget_exit_clock_gating()

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.h   | 10 --
 drivers/usb/dwc2/gadget.c | 71 +++
 2 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 5a7850482e57..e5597796dca4 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -866,6 +866,7 @@ struct dwc2_hregs_backup {
  * @ll_hw_enabled: Status of low-level hardware resources.
  * @hibernated:True if core is hibernated
  * @in_ppd:True if core is partial power down mode.
+ * @bus_suspended: True if bus is suspended
  * @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.
@@ -1023,7 +1024,6 @@ struct dwc2_hregs_backup {
  * a pointer to an array of register definitions, the
  * array size and the base address where the register bank
  * is to be found.
- * @bus_suspended: True if bus is suspended
  * @last_frame_num:Number of last frame. Range from 0 to  32768
  * @frame_num_array:Used only  if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is
  * defined, for missed SOFs tracking. Array holds that
@@ -1062,6 +1062,7 @@ struct dwc2_hsotg {
unsigned int ll_hw_enabled:1;
unsigned int hibernated:1;
unsigned int in_ppd:1;
+   bool bus_suspended;
unsigned int reset_phy_on_wake:1;
unsigned int need_phy_for_wake:1;
unsigned int phy_off_for_suspend:1;
@@ -1145,7 +1146,6 @@ struct dwc2_hsotg {
unsigned long hs_periodic_bitmap[
DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)];
u16 periodic_qh_count;
-   bool bus_suspended;
bool new_connection;
 
u16 last_frame_num;
@@ -1415,6 +1415,9 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
 int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg);
 int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
bool restore);
+void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg);
+void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
+  int rem_wakeup);
 int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
@@ -1453,6 +1456,9 @@ static inline int 
dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
 static inline int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
  bool restore)
 { return 0; }
+static inline void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
+int rem_wakeup) {}
 static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
 { return 0; }
 static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index e08baee4987b..2f50f3e62caa 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -5483,3 +5483,74 @@ int dwc2_gadget_exit_partial_power_down(struct 
dwc2_hsotg *hsotg,
dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n");
return ret;
 }
+
+/**
+ * dwc2_gadget_enter_clock_gating() - Put controller in clock gating.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * Return: non-zero if failed to enter device partial power down.
+ *
+ * This function is for entering device mode clock gating.
+ */
+void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg)
+{
+   u32 pcgctl;
+
+   dev_dbg(hsotg->dev, "Entering device clock gating.\n");
+
+   /* Set the Phy Clock bit as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Set the Gate hclk as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_GATEHCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   hsotg->lx_state = DWC2_L2;
+   hsotg->bus_suspended = true;
+}
+
+/*
+ * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating.
+ *
+ 

[PATCH 12/12] usb: dwc2: Add exit clock gating before removing driver

2021-04-13 Thread Artur Petrosyan
When dwc2 core is in clock gating mode loading driver
again causes driver fail. Because in that mode
registers are not accessible.

Added a flow of exiting clock gating mode
to avoid the driver reload failure.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/platform.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index b28b8cd45799..f8b819cfa80e 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -326,6 +326,15 @@ static int dwc2_driver_remove(struct platform_device *dev)
"exit partial_power_down failed\n");
}
 
+   /* Exit clock gating when driver is removed. */
+   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
+   hsotg->bus_suspended) {
+   if (dwc2_is_device_mode(hsotg))
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
+   else
+   dwc2_host_exit_clock_gating(hsotg, 0);
+   }
+
dwc2_debugfs_exit(hsotg);
if (hsotg->hcd_enabled)
dwc2_hcd_remove(hsotg);
-- 
2.25.1



[PATCH 11/12] usb: dwc2: Add clock gating exiting flow by system resume

2021-04-13 Thread Artur Petrosyan
If not hibernation nor partial power down are supported,
port resume is done using the clock gating programming flow.

Adds a new flow of exiting clock gating when PC is
resumed.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 22 ++
 1 file changed, 22 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 09dcd37b9ef8..04a1b53d65af 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4445,6 +4445,28 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
+   /*
+* If not hibernation nor partial power down are supported,
+* port resume is done using the clock gating programming flow.
+*/
+   spin_unlock_irqrestore(>lock, flags);
+   dwc2_host_exit_clock_gating(hsotg, 0);
+
+   /*
+* Initialize the Core for Host mode, as after system resume
+* the global interrupts are disabled.
+*/
+   dwc2_core_init(hsotg, false);
+   dwc2_enable_global_interrupts(hsotg);
+   dwc2_hcd_reinit(hsotg);
+   spin_lock_irqsave(>lock, flags);
+
+   /*
+* Set HW accessible bit before powering on the controller
+* since an interrupt may rise.
+*/
+   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
default:
hsotg->lx_state = DWC2_L0;
goto unlock;
-- 
2.25.1



[PATCH 09/12] usb: dwc2: Allow exit clock gating in urb enqueue

2021-04-13 Thread Artur Petrosyan
When core is in clock gating state and an external
hub is connected, upper layer sends URB enqueue request,
which results in port reset issue.

Added exit from clock gating state to avoid port
reset issue and process upper layer request properly.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 8a42675ab94e..31d6a1b87228 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4597,6 +4597,14 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, 
struct urb *urb,
"exit partial_power_down failed\n");
}
 
+   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
+   hsotg->bus_suspended) {
+   if (dwc2_is_device_mode(hsotg))
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
+   else
+   dwc2_host_exit_clock_gating(hsotg, 0);
+   }
+
if (!ep)
return -EINVAL;
 
-- 
2.25.1



[PATCH 10/12] usb: dwc2: Add clock gating entering flow by system suspend

2021-04-13 Thread Artur Petrosyan
If not hibernation nor partial power down are supported,
clock gating is used to save power.

Adds a new flow of entering clock gating when PC is
suspended.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 31d6a1b87228..09dcd37b9ef8 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4372,6 +4372,15 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
+   /*
+* If not hibernation nor partial power down are supported,
+* clock gating is used to save power.
+*/
+   dwc2_host_enter_clock_gating(hsotg);
+
+   /* After entering suspend, hardware is not accessible */
+   clear_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
default:
goto skip_power_saving;
}
-- 
2.25.1



[PATCH 08/12] usb: dwc2: Update exit clock gating when port is resumed

2021-04-13 Thread Artur Petrosyan
Updates the implementation of exiting clock gating mode
when core receives port resume.
Instead of setting the required bit fields of the registers
inline, called the "dwc2_host_exit_clock_gating()" function.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 29 -
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index e1225fe6c61a..8a42675ab94e 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3359,8 +3359,6 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
 int dwc2_port_resume(struct dwc2_hsotg *hsotg)
 {
unsigned long flags;
-   u32 hprt0;
-   u32 pcgctl;
int ret = 0;
 
spin_lock_irqsave(>lock, flags);
@@ -3374,33 +3372,14 @@ int dwc2_port_resume(struct dwc2_hsotg *hsotg)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
-   default:
/*
-* If power_down is supported, Phy clock is already resumed
-* after registers restore.
+* If not hibernation nor partial power down are supported,
+* port resume is done using the clock gating programming flow.
 */
-   if (!hsotg->params.power_down) {
-   pcgctl = dwc2_readl(hsotg, PCGCTL);
-   pcgctl &= ~PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgctl, PCGCTL);
-   spin_unlock_irqrestore(>lock, flags);
-   msleep(20);
-   spin_lock_irqsave(>lock, flags);
-   }
-
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 |= HPRT0_RES;
-   hprt0 &= ~HPRT0_SUSP;
-   dwc2_writel(hsotg, hprt0, HPRT0);
spin_unlock_irqrestore(>lock, flags);
-
-   msleep(USB_RESUME_TIMEOUT);
-
+   dwc2_host_exit_clock_gating(hsotg, 0);
spin_lock_irqsave(>lock, flags);
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
-   dwc2_writel(hsotg, hprt0, HPRT0);
-   hsotg->bus_suspended = false;
+   break;
}
 
spin_unlock_irqrestore(>lock, flags);
-- 
2.25.1



[PATCH 07/12] usb: dwc2: Update enter clock gating when port is suspended

2021-04-13 Thread Artur Petrosyan
Updates the implementation of entering clock gating mode
when core receives port suspend.
Instead of setting the required bit fields of the registers
inline, called the "dwc2_host_enter_clock_gating()" function.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 19 ---
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 27f030d5de54..e1225fe6c61a 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3298,7 +3298,6 @@ static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg 
*hsotg)
 int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 {
unsigned long flags;
-   u32 hprt0;
u32 pcgctl;
u32 gotgctl;
int ret = 0;
@@ -3323,22 +3322,12 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
break;
case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
-   default:
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 |= HPRT0_SUSP;
-   dwc2_writel(hsotg, hprt0, HPRT0);
-   hsotg->bus_suspended = true;
/*
-* If power_down is supported, Phy clock will be suspended
-* after registers are backuped.
+* If not hibernation nor partial power down are supported,
+* clock gating is used to save power.
 */
-   if (!hsotg->params.power_down) {
-   /* Suspend the Phy Clock */
-   pcgctl = dwc2_readl(hsotg, PCGCTL);
-   pcgctl |= PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgctl, PCGCTL);
-   udelay(10);
-   }
+   dwc2_host_enter_clock_gating(hsotg);
+   break;
}
 
/* For HNP the bus must be suspended for at least 200ms */
-- 
2.25.1



[PATCH 06/12] usb: dwc2: Add exit clock gating when port reset is asserted

2021-04-13 Thread Artur Petrosyan
Adds clock gating exit flow when set port feature
reset is received in suspended state.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index f1c24c15d185..27f030d5de54 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3712,6 +3712,10 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
"exit partial_power_down 
failed\n");
}
 
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_host_exit_clock_gating(hsotg, 0);
+
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_RESET\n");
-- 
2.25.1



[PATCH 04/12] usb: dwc2: Add exit clock gating from wakeup interrupt

2021-04-13 Thread Artur Petrosyan
Added exit from clock gating mode when wakeup interrupt
is detected. To exit from the clock gating
in device mode "dwc2_gadget_exit_clock_gating()"
function is used with rem_wakeup parameter 0. To exit
clock gating in host mode "dwc2_host_exit_clock_gating()"
with rem_wakeup parameter 1.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 33 ++---
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index ab7fe303c0f9..c764407e7633 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -415,17 +415,24 @@ static void dwc2_handle_wakeup_detected_intr(struct 
dwc2_hsotg *hsotg)
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
dwc2_readl(hsotg, DSTS));
-   if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
-   u32 dctl = dwc2_readl(hsotg, DCTL);
-   /* Clear Remote Wakeup Signaling */
-   dctl &= ~DCTL_RMTWKUPSIG;
-   dwc2_writel(hsotg, dctl, DCTL);
-   ret = dwc2_exit_partial_power_down(hsotg, 1,
-  true);
-   if (ret)
-   dev_err(hsotg->dev,
-   "exit partial_power_down failed\n");
-   call_gadget(hsotg, resume);
+   if (hsotg->lx_state == DWC2_L2) {
+   if (hsotg->in_ppd) {
+   u32 dctl = dwc2_readl(hsotg, DCTL);
+   /* Clear Remote Wakeup Signaling */
+   dctl &= ~DCTL_RMTWKUPSIG;
+   dwc2_writel(hsotg, dctl, DCTL);
+   ret = dwc2_exit_partial_power_down(hsotg, 1,
+  true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down 
failed\n");
+   call_gadget(hsotg, resume);
+   }
+
+   /* Exit gadget mode clock gating. */
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
} else {
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
@@ -440,6 +447,10 @@ static void dwc2_handle_wakeup_detected_intr(struct 
dwc2_hsotg *hsotg)
"exit partial_power_down 
failed\n");
}
 
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_host_exit_clock_gating(hsotg, 1);
+
/*
 * If we've got this quirk then the PHY is stuck upon
 * wakeup.  Assert reset.  This will propagate out and
-- 
2.25.1



[PATCH 02/12] usb: dwc2: Add host clock gating support functions

2021-04-13 Thread Artur Petrosyan
Added host clock gating support functions according
programming guide.

Added function names:
dwc2_host_enter_clock_gating()
dwc2_host_exit_clock_gating()

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.h |  5 +++
 drivers/usb/dwc2/hcd.c  | 86 +
 2 files changed, 91 insertions(+)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index e5597796dca4..8c12b3061f7f 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1486,6 +1486,8 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
 int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg);
 int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
  int rem_wakeup, bool restore);
+void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg);
+void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup);
 bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
 static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
 { schedule_work(>phy_reset_work); }
@@ -1521,6 +1523,9 @@ static inline int 
dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
 static inline int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
int rem_wakeup, bool 
restore)
 { return 0; }
+static inline void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg,
+  int rem_wakeup) {}
 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) {}
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index f096006df96f..f1c24c15d185 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5821,3 +5821,89 @@ int dwc2_host_exit_partial_power_down(struct dwc2_hsotg 
*hsotg,
dev_dbg(hsotg->dev, "Exiting host partial power down completed.\n");
return ret;
 }
+
+/**
+ * dwc2_host_enter_clock_gating() - Put controller in clock gating.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * This function is for entering Host mode clock gating.
+ */
+void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg)
+{
+   u32 hprt0;
+   u32 pcgctl;
+
+   dev_dbg(hsotg->dev, "Entering host clock gating.\n");
+
+   /* Put this port in suspend mode. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_SUSP;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+
+   /* Set the Phy Clock bit as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Set the Gate hclk as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_GATEHCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   hsotg->bus_suspended = true;
+   hsotg->lx_state = DWC2_L2;
+}
+
+/**
+ * dwc2_host_exit_clock_gating() - Exit controller from clock gating.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: indicates whether resume is initiated by remote wakeup
+ *
+ * This function is for exiting Host mode clock gating.
+ */
+void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup)
+{
+   u32 hprt0;
+   u32 pcgctl;
+
+   dev_dbg(hsotg->dev, "Exiting host clock gating.\n");
+
+   /* Clear the Gate hclk. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl &= ~PCGCTL_GATEHCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Phy Clock bit. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl &= ~PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Drive resume signaling and exit suspend mode on the port. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_RES;
+   hprt0 &= ~HPRT0_SUSP;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+   udelay(5);
+
+   if (!rem_wakeup) {
+   /* In case of port resume need to wait for 40 ms */
+   msleep(USB_RESUME_TIMEOUT);
+
+   /* Stop driveing resume signaling on the port. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 &= ~HPRT0_RES;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+
+   hsotg->bus_suspended = false;
+   hsotg->lx_state = DWC2_L0;
+   } else {
+   mod_timer(>wkp_timer,
+ jiffies + msecs_to_jiffies(71));
+   }
+}
-- 
2.25.1



[PATCH 03/12] usb: dwc2: Allow entering clock gating from USB_SUSPEND interrupt

2021-04-13 Thread Artur Petrosyan
If core doesn't support hibernation or partial power
down power saving options, power can still be saved
using clock gating on all the clocks.

- Added entering clock gating state from USB_SUSPEND
  interrupt.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 8c0152b514be..ab7fe303c0f9 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -529,14 +529,18 @@ static void dwc2_handle_usb_suspend_intr(struct 
dwc2_hsotg *hsotg)
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy))
usb_phy_set_suspend(hsotg->uphy, true);
-   }
-
-   if (hsotg->hw_params.hibernation) {
+   } else if (hsotg->hw_params.hibernation) {
ret = dwc2_enter_hibernation(hsotg, 0);
if (ret && ret != -ENOTSUPP)
dev_err(hsotg->dev,
"%s: enter hibernation 
failed\n",
__func__);
+   } else {
+   /*
+* If not hibernation nor partial power down 
are supported,
+* clock gating is used to save power.
+*/
+   dwc2_gadget_enter_clock_gating(hsotg);
}
 skip_power_saving:
/*
-- 
2.25.1



[PATCH 01/12] usb: dwc2: Add device clock gating support functions

2021-04-13 Thread Artur Petrosyan
Added device clock gating support functions according
programming guide.

Moved "bus_suspended" flag to "dwc2_hsotg" struct because
we need to set that flag while entering to clock gating
in case when the driver is built in peripheral mode.

Added function names:
dwc2_gadget_enter_clock_gating()
dwc2_gadget_exit_clock_gating()

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.h   | 10 --
 drivers/usb/dwc2/gadget.c | 71 +++
 2 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 5a7850482e57..e5597796dca4 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -866,6 +866,7 @@ struct dwc2_hregs_backup {
  * @ll_hw_enabled: Status of low-level hardware resources.
  * @hibernated:True if core is hibernated
  * @in_ppd:True if core is partial power down mode.
+ * @bus_suspended: True if bus is suspended
  * @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.
@@ -1023,7 +1024,6 @@ struct dwc2_hregs_backup {
  * a pointer to an array of register definitions, the
  * array size and the base address where the register bank
  * is to be found.
- * @bus_suspended: True if bus is suspended
  * @last_frame_num:Number of last frame. Range from 0 to  32768
  * @frame_num_array:Used only  if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is
  * defined, for missed SOFs tracking. Array holds that
@@ -1062,6 +1062,7 @@ struct dwc2_hsotg {
unsigned int ll_hw_enabled:1;
unsigned int hibernated:1;
unsigned int in_ppd:1;
+   bool bus_suspended;
unsigned int reset_phy_on_wake:1;
unsigned int need_phy_for_wake:1;
unsigned int phy_off_for_suspend:1;
@@ -1145,7 +1146,6 @@ struct dwc2_hsotg {
unsigned long hs_periodic_bitmap[
DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)];
u16 periodic_qh_count;
-   bool bus_suspended;
bool new_connection;
 
u16 last_frame_num;
@@ -1415,6 +1415,9 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
 int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg);
 int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
bool restore);
+void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg);
+void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
+  int rem_wakeup);
 int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
@@ -1453,6 +1456,9 @@ static inline int 
dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
 static inline int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
  bool restore)
 { return 0; }
+static inline void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
+int rem_wakeup) {}
 static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
 { return 0; }
 static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index e08baee4987b..2f50f3e62caa 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -5483,3 +5483,74 @@ int dwc2_gadget_exit_partial_power_down(struct 
dwc2_hsotg *hsotg,
dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n");
return ret;
 }
+
+/**
+ * dwc2_gadget_enter_clock_gating() - Put controller in clock gating.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * Return: non-zero if failed to enter device partial power down.
+ *
+ * This function is for entering device mode clock gating.
+ */
+void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg)
+{
+   u32 pcgctl;
+
+   dev_dbg(hsotg->dev, "Entering device clock gating.\n");
+
+   /* Set the Phy Clock bit as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   /* Set the Gate hclk as suspend is received. */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_GATEHCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(5);
+
+   hsotg->lx_state = DWC2_L2;
+   hsotg->bus_suspended = true;
+}
+
+/*
+ * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating.
+ *
+ 

[PATCH 05/12] usb: dwc2: Add exit clock gating from session request interrupt

2021-04-13 Thread Artur Petrosyan
Added clock gating exit flow from session
request interrupt handler according programming guide.

Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/core_intr.c | 19 +--
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index c764407e7633..550c52c1a0c7 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -316,12 +316,19 @@ static void dwc2_handle_session_req_intr(struct 
dwc2_hsotg *hsotg)
hsotg->lx_state);
 
if (dwc2_is_device_mode(hsotg)) {
-   if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
-   ret = dwc2_exit_partial_power_down(hsotg, 0,
-  true);
-   if (ret)
-   dev_err(hsotg->dev,
-   "exit power_down failed\n");
+   if (hsotg->lx_state == DWC2_L2) {
+   if (hsotg->in_ppd) {
+   ret = dwc2_exit_partial_power_down(hsotg, 0,
+  true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit power_down failed\n");
+   }
+
+   /* Exit gadget mode clock gating. */
+   if (hsotg->params.power_down ==
+   DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)
+   dwc2_gadget_exit_clock_gating(hsotg, 0);
}
 
/*
-- 
2.25.1



Re: [PATCH v2 00/14] usb: dwc2: Fix Partial Power down issues.

2021-04-08 Thread Artur Petrosyan
Hi Greg,

On 4/8/2021 13:17, Artur Petrosyan wrote:
> Hi Greg,
> 
> On 4/8/2021 11:28, Artur Petrosyan wrote:
>> This patch set fixes and improves the Partial Power Down mode for
>> dwc2 core.
>> It adds support for the following cases
>>   1. Entering and exiting partial power down when a port is
>>  suspended, resumed, port reset is asserted.
>>   2. Exiting the partial power down mode before removing driver.
>>   3. Exiting partial power down in wakeup detected interrupt handler.
>>   4. Exiting from partial power down mode when connector ID.
>>  status changes to "connId B
>>
>> It updates and fixes the implementation of dwc2 entering and
>> exiting partial power down mode when the system (PC) is suspended.
>>
>> The patch set also improves the implementation of function handlers
>> for entering and exiting host or device partial power down.
>>
>> NOTE: This is the second patch set in the power saving mode fixes
>> series.
>> This patch set is part of multiple series and is continuation
>> of the "usb: dwc2: Fix and improve power saving modes" patch set.
>> (Patch set link: 
>> https://urldefense.com/v3/__https://marc.info/?l=linux-usb=160379622403975=2__;!!A4F2R9G_pg!IJ-Xl1ZwQU2kmqHB3ITyWyno9BgpWUsC647AqK7GIlgzJu9BzT6VN7jt--__fGdMtgWF69M$
>>  ).
>> The patches that were included in the "usb: dwc2:
>> Fix and improve power saving modes" which was submitted
>> earlier was too large and needed to be split up into
>> smaller patch sets.
>>
>> Changes since V1:
>> No changes in the patches or the source code.
>> Sending the second version of the patch set because the first version
>> was not received by vger.kernel.org.
>>
>>
>>
>> Artur Petrosyan (14):
>> usb: dwc2: Add device partial power down functions
>> usb: dwc2: Add host partial power down functions
>> usb: dwc2: Update enter and exit partial power down functions
>> usb: dwc2: Add partial power down exit flow in wakeup intr.
>> usb: dwc2: Update port suspend/resume function definitions.
>> usb: dwc2: Add enter partial power down when port is suspended
>> usb: dwc2: Add exit partial power down when port is resumed
>> usb: dwc2: Add exit partial power down when port reset is asserted
>> usb: dwc2: Add part. power down exit from
>>   dwc2_conn_id_status_change().
>> usb: dwc2: Allow exit partial power down in urb enqueue
>> usb: dwc2: Fix session request interrupt handler
>> usb: dwc2: Update partial power down entering by system suspend
>> usb: dwc2: Fix partial power down exiting by system resume
>> usb: dwc2: Add exit partial power down before removing driver
>>
>>drivers/usb/dwc2/core.c  | 113 ++---
>>drivers/usb/dwc2/core.h  |  27 ++-
>>drivers/usb/dwc2/core_intr.c |  46 ++--
>>drivers/usb/dwc2/gadget.c| 148 ++-
>>drivers/usb/dwc2/hcd.c   | 458 +--
>>drivers/usb/dwc2/hw.h|   1 +
>>drivers/usb/dwc2/platform.c  |  11 +-
>>7 files changed, 558 insertions(+), 246 deletions(-)
>>
>>
>> base-commit: e9fcb07704fcef6fa6d0333fd2b3a62442eaf45b
>>
> 
> Re sending as a "v2" did not work :(.
> The patches are not in lore again.
> 
> Could the issue be with a comma in the end of To: or Cc: list?
> Let me remove the comma in the end of those lists and try sending as "v3".
> 
> Regards,
> Artur
> 

I just removed the comma in the end of those lists and resent the patch 
set as a "v3" and they are already seen in lore.
There is one strange thing though on lore. Some patch titles are not 
fully visible.

For sure the issue was comma in the end of To: or Cc: lists.
Not working example.
To: Greg Kroah-Hartman , 
linux-...@vger.kernel.org, linux-kernel@vger.kernel.org,

Working example.
To: Greg Kroah-Hartman , 
linux-...@vger.kernel.org, linux-kernel@vger.kernel.org

If the comma is at least in the end of one of those lists (To: or Cc:) 
vger.kernel.org mailing server will not accept them.

Regards,
Artur


[PATCH v3 14/14] usb: dwc2: Add exit partial power down before removing driver

2021-04-08 Thread Artur Petrosyan
When dwc2 core is in partial power down mode
loading driver again causes driver fail. Because in
that mode registers are not accessible.

Added a flow of exiting the partial power down mode
to avoid the driver reload failure.

Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/platform.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 5f18acac7406..b28b8cd45799 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -316,6 +316,15 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
 static int dwc2_driver_remove(struct platform_device *dev)
 {
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
+   int ret = 0;
+
+   /* Exit Partial Power Down when driver is removed. */
+   if (hsotg->in_ppd) {
+   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down failed\n");
+   }
 
dwc2_debugfs_exit(hsotg);
if (hsotg->hcd_enabled)
@@ -334,7 +343,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
reset_control_assert(hsotg->reset);
reset_control_assert(hsotg->reset_ecc);
 
-   return 0;
+   return ret;
 }
 
 /**
-- 
2.25.1



[PATCH v3 13/14] usb: dwc2: Fix partial power down exiting by system resume

2021-04-08 Thread Artur Petrosyan
Fixes the implementation of exiting from partial power down
power saving mode when PC is resumed.

Added port connection status checking which prevents exiting from
Partial Power Down mode from _dwc2_hcd_resume() if not in Partial
Power Down mode.

Rearranged the implementation to get rid of many "if"
statements.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Cc: 
Fixes: 6f6d70597c15 ("usb: dwc2: bus suspend/resume for hosts with 
DWC2_POWER_DOWN_PARAM_NONE")
Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 90 +-
 1 file changed, 46 insertions(+), 44 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 34030bafdff4..f096006df96f 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4427,7 +4427,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
 {
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
-   u32 pcgctl;
+   u32 hprt0;
int ret = 0;
 
spin_lock_irqsave(>lock, flags);
@@ -4438,11 +4438,40 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
if (hsotg->lx_state != DWC2_L2)
goto unlock;
 
-   if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) {
+   hprt0 = dwc2_read_hprt0(hsotg);
+
+   /*
+* Added port connection status checking which prevents exiting from
+* Partial Power Down mode from _dwc2_hcd_resume() if not in Partial
+* Power Down mode.
+*/
+   if (hprt0 & HPRT0_CONNSTS) {
+   hsotg->lx_state = DWC2_L0;
+   goto unlock;
+   }
+
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
+   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down failed\n");
+   /*
+* Set HW accessible bit before powering on the controller
+* since an interrupt may rise.
+*/
+   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   case DWC2_POWER_DOWN_PARAM_NONE:
+   default:
hsotg->lx_state = DWC2_L0;
goto unlock;
}
 
+   /* Change Root port status, as port status change occurred after 
resume.*/
+   hsotg->flags.b.port_suspend_change = 1;
+
/*
 * Enable power if not already done.
 * This must not be spinlocked since duration
@@ -4454,52 +4483,25 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
spin_lock_irqsave(>lock, flags);
}
 
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
-   /*
-* Set HW accessible bit before powering on the controller
-* since an interrupt may rise.
-*/
-   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
-
-
-   /* Exit partial_power_down */
-   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
-   if (ret && (ret != -ENOTSUPP))
-   dev_err(hsotg->dev, "exit partial_power_down failed\n");
-   } else {
-   pcgctl = readl(hsotg->regs + PCGCTL);
-   pcgctl &= ~PCGCTL_STOPPCLK;
-   writel(pcgctl, hsotg->regs + PCGCTL);
-   }
-
-   hsotg->lx_state = DWC2_L0;
-
+   /* Enable external vbus supply after resuming the port. */
spin_unlock_irqrestore(>lock, flags);
+   dwc2_vbus_supply_init(hsotg);
 
-   if (hsotg->bus_suspended) {
-   spin_lock_irqsave(>lock, flags);
-   hsotg->flags.b.port_suspend_change = 1;
-   spin_unlock_irqrestore(>lock, flags);
-   dwc2_port_resume(hsotg);
-   } else {
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
-   dwc2_vbus_supply_init(hsotg);
-
-   /* Wait for controller to correctly update D+/D- level 
*/
-   usleep_range(3000, 5000);
-   }
+   /* Wait for controller to correctly update D+/D- level */
+   usleep_range(3000, 5000);
+   spin_lock_irqsave(>lock, flags);
 
-   /*
-* Clear Port Enable and Port Status changes.
-* Enable Port Power.
-*/
-   dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET |
-   HPRT0_ENACHG, HPRT0);
-   /* Wait for controller to de

[PATCH v3 12/14] usb: dwc2: Update partial power down entering by system suspend

2021-04-08 Thread Artur Petrosyan
With current implementation the port power is being disabled,
which is not required by the programming guide. Also, if there
is a system which works only in "DWC2_POWER_DOWN_PARAM_NONE"
(clock gating) mode the current implementation does not set
Gate hclk bit in pcgctl register.

Rearranges and updates the implementation of entering to partial
power down power saving mode when PC is suspended to get
rid of many "if" statements and removes disabling of port power.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 53 ++
 1 file changed, 18 insertions(+), 35 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index cb52bc41bfb8..34030bafdff4 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4367,8 +4367,6 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
int ret = 0;
-   u32 hprt0;
-   u32 pcgctl;
 
spin_lock_irqsave(>lock, flags);
 
@@ -4384,47 +4382,32 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
if (hsotg->op_state == OTG_STATE_B_PERIPHERAL)
goto unlock;
 
-   if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL ||
-   hsotg->flags.b.port_connect_status == 0)
+   if (hsotg->bus_suspended)
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);
-   if (hprt0 & HPRT0_CONNSTS) {
-   hprt0 |= HPRT0_SUSP;
-   if (hsotg->params.power_down == 
DWC2_POWER_DOWN_PARAM_PARTIAL)
-   hprt0 &= ~HPRT0_PWR;
-   dwc2_writel(hsotg, hprt0, HPRT0);
-   }
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
-   spin_unlock_irqrestore(>lock, flags);
-   dwc2_vbus_supply_exit(hsotg);
-   spin_lock_irqsave(>lock, flags);
-   } else {
-   pcgctl = readl(hsotg->regs + PCGCTL);
-   pcgctl |= PCGCTL_STOPPCLK;
-   writel(pcgctl, hsotg->regs + PCGCTL);
-   }
-   }
+   if (hsotg->flags.b.port_connect_status == 0)
+   goto skip_power_saving;
 
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
/* Enter partial_power_down */
ret = dwc2_enter_partial_power_down(hsotg);
-   if (ret) {
-   if (ret != -ENOTSUPP)
-   dev_err(hsotg->dev,
-   "enter partial_power_down failed\n");
-   goto skip_power_saving;
-   }
-
-   /* After entering partial_power_down, hardware is no more 
accessible */
+   if (ret)
+   dev_err(hsotg->dev,
+   "enter partial_power_down failed\n");
+   /* After entering suspend, hardware is not accessible */
clear_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   case DWC2_POWER_DOWN_PARAM_NONE:
+   default:
+   goto skip_power_saving;
}
 
+   spin_unlock_irqrestore(>lock, flags);
+   dwc2_vbus_supply_exit(hsotg);
+   spin_lock_irqsave(>lock, flags);
+
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy)) {
spin_unlock_irqrestore(>lock, flags);
-- 
2.25.1



[PATCH v3 11/14] usb: dwc2: Fix session request interrupt handler

2021-04-08 Thread Artur Petrosyan
According to programming guide in host mode, port
power must be turned on in session request
interrupt handlers.

Cc: 
Fixes: 21795c826a45 ("usb: dwc2: exit hibernation on session request")
Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 0a7f9330907f..8c0152b514be 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -307,6 +307,7 @@ static void dwc2_handle_conn_id_status_change_intr(struct 
dwc2_hsotg *hsotg)
 static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
 {
int ret;
+   u32 hprt0;
 
/* Clear interrupt */
dwc2_writel(hsotg, GINTSTS_SESSREQINT, GINTSTS);
@@ -328,6 +329,13 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg 
*hsotg)
 * established
 */
dwc2_hsotg_disconnect(hsotg);
+   } else {
+   /* Turn on the port power bit. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_PWR;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+   /* Connect hcd after port power is set. */
+   dwc2_hcd_connect(hsotg);
}
 }
 
-- 
2.25.1



[PATCH v3 10/14] usb: dwc2: Allow exit partial power down in urb enqueue

2021-04-08 Thread Artur Petrosyan
When core is in partial power down state and an external
hub is connected, upper layer sends URB enqueue request,
which results in port reset issue.

Added exit from partial power down state to avoid port
reset issue and process upper layer request correctly.

Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 9529e9839961..cb52bc41bfb8 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4633,6 +4633,13 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, 
struct urb *urb,
dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
}
 
+   if (hsotg->in_ppd) {
+   retval = dwc2_exit_partial_power_down(hsotg, 0, true);
+   if (retval)
+   dev_err(hsotg->dev,
+   "exit partial_power_down failed\n");
+   }
+
if (!ep)
return -EINVAL;
 
-- 
2.25.1



[PATCH v3 09/14] usb: dwc2: Add part. power down exit from dwc2_conn_id_status_change().

2021-04-08 Thread Artur Petrosyan
Before changing to connector B exiting from Partial
Power Down is required.

- Added exiting from Partial Power Down mode when
  connector ID status changes to "connId B".
  Because if connector ID status changed to B connector
  while core was in partial power down mode, HANG would
  accrue from a soft reset.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/hcd.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 7c7496719152..9529e9839961 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3206,6 +3206,15 @@ static void dwc2_conn_id_status_change(struct 
work_struct *work)
if (count > 250)
dev_err(hsotg->dev,
"Connection id status change timed out\n");
+
+   /*
+* Exit Partial Power Down without restoring registers.
+* No need to check the return value as registers
+* are not being restored.
+*/
+   if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2)
+   dwc2_exit_partial_power_down(hsotg, 0, false);
+
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg);
-- 
2.25.1



[PATCH v3 08/14] usb: dwc2: Add exit partial power down when port reset is asserted

2021-04-08 Thread Artur Petrosyan
Adds Partial Power Down exiting flow when set port feature
reset is received in suspended state.

Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 720354df014b..7c7496719152 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3694,6 +3694,15 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
if (hsotg->params.power_down == 
DWC2_POWER_DOWN_PARAM_HIBERNATION &&
hsotg->hibernated)
dwc2_exit_hibernation(hsotg, 0, 1, 1);
+
+   if (hsotg->in_ppd) {
+   retval = dwc2_exit_partial_power_down(hsotg, 1,
+ true);
+   if (retval)
+   dev_err(hsotg->dev,
+   "exit partial_power_down 
failed\n");
+   }
+
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_RESET\n");
-- 
2.25.1



[PATCH v3 07/14] usb: dwc2: Add exit partial power down when port is resumed

2021-04-08 Thread Artur Petrosyan
Added flow of exiting Partial Power Down in
"dwc2_port_resume()" function when core receives resume.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/core.h |  5 ++--
 drivers/usb/dwc2/hcd.c  | 61 ++---
 2 files changed, 42 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 76807abd753b..5a7850482e57 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1471,7 +1471,7 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool 
force);
 void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
 int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
 int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
-void dwc2_port_resume(struct dwc2_hsotg *hsotg);
+int dwc2_port_resume(struct dwc2_hsotg *hsotg);
 int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
 int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
 int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
@@ -1497,7 +1497,8 @@ static inline int dwc2_core_init(struct dwc2_hsotg 
*hsotg, bool initial_setup)
 { return 0; }
 static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 { return 0; }
-static inline void dwc2_port_resume(struct dwc2_hsotg *hsotg) {}
+static inline int dwc2_port_resume(struct dwc2_hsotg *hsotg)
+{ return 0; }
 static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 { return 0; }
 static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index e7fb0d5940bc..720354df014b 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3353,44 +3353,61 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
  *
  * @hsotg: Programming view of the DWC_otg controller
  *
+ * Return: non-zero if failed to exit suspend mode for host.
+ *
  * This function is for exiting Host mode suspend.
  * Must NOT be called with interrupt disabled or spinlock held.
  */
-void dwc2_port_resume(struct dwc2_hsotg *hsotg)
+int dwc2_port_resume(struct dwc2_hsotg *hsotg)
 {
unsigned long flags;
u32 hprt0;
u32 pcgctl;
+   int ret = 0;
 
spin_lock_irqsave(>lock, flags);
 
-   /*
-* If power_down is supported, Phy clock is already resumed
-* after registers restore.
-*/
-   if (!hsotg->params.power_down) {
-   pcgctl = dwc2_readl(hsotg, PCGCTL);
-   pcgctl &= ~PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
+   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down failed.\n");
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   case DWC2_POWER_DOWN_PARAM_NONE:
+   default:
+   /*
+* If power_down is supported, Phy clock is already resumed
+* after registers restore.
+*/
+   if (!hsotg->params.power_down) {
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl &= ~PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   spin_unlock_irqrestore(>lock, flags);
+   msleep(20);
+   spin_lock_irqsave(>lock, flags);
+   }
+
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_RES;
+   hprt0 &= ~HPRT0_SUSP;
+   dwc2_writel(hsotg, hprt0, HPRT0);
spin_unlock_irqrestore(>lock, flags);
-   msleep(20);
+
+   msleep(USB_RESUME_TIMEOUT);
+
spin_lock_irqsave(>lock, flags);
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
+   dwc2_writel(hsotg, hprt0, HPRT0);
+   hsotg->bus_suspended = false;
}
 
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 |= HPRT0_RES;
-   hprt0 &= ~HPRT0_SUSP;
-   dwc2_writel(hsotg, hprt0, HPRT0);
spin_unlock_irqrestore(>lock, flags);
 
-   msleep(USB_RESUME_TIMEOUT);
-
-   spin_lock_irqsave(>lock, flags);
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
-   dwc2_writel(hsotg, hprt0, HPRT0);
-   hsotg->bus_suspended = false;
-   spin_unlock_irqrestore(>lock, flags);
+   return ret;
 }
 
 /* Handles hub class-specific requests */
-- 
2.25.1



[PATCH v3 06/14] usb: dwc2: Add enter partial power down when port is suspended

2021-04-08 Thread Artur Petrosyan
Adds flow of entering Partial Power Down in
"dwc2_port_suspend()" function when core receives suspend.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/core.h |  5 +++--
 drivers/usb/dwc2/hcd.c  | 48 ++---
 2 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index b7d99cf9e84c..76807abd753b 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1470,7 +1470,7 @@ void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
 void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
 void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
 int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
-void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
+int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
 void dwc2_port_resume(struct dwc2_hsotg *hsotg);
 int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
 int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
@@ -1495,7 +1495,8 @@ static inline void dwc2_hcd_start(struct dwc2_hsotg 
*hsotg) {}
 static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
 static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
 { return 0; }
-static inline void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) {}
+static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
+{ return 0; }
 static inline void dwc2_port_resume(struct dwc2_hsotg *hsotg) {}
 static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 { return 0; }
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index f4247a66c2b2..e7fb0d5940bc 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3281,15 +3281,18 @@ static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg 
*hsotg)
  * @hsotg: Programming view of the DWC_otg controller
  * @windex: The control request wIndex field
  *
+ * Return: non-zero if failed to enter suspend mode for host.
+ *
  * This function is for entering Host mode suspend.
  * Must NOT be called with interrupt disabled or spinlock held.
  */
-void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
+int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 {
unsigned long flags;
u32 hprt0;
u32 pcgctl;
u32 gotgctl;
+   int ret = 0;
 
dev_dbg(hsotg->dev, "%s()\n", __func__);
 
@@ -3302,22 +3305,31 @@ void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
hsotg->op_state = OTG_STATE_A_SUSPEND;
}
 
-   hprt0 = dwc2_read_hprt0(hsotg);
-   hprt0 |= HPRT0_SUSP;
-   dwc2_writel(hsotg, hprt0, HPRT0);
-
-   hsotg->bus_suspended = true;
-
-   /*
-* If power_down is supported, Phy clock will be suspended
-* after registers are backuped.
-*/
-   if (!hsotg->params.power_down) {
-   /* Suspend the Phy Clock */
-   pcgctl = dwc2_readl(hsotg, PCGCTL);
-   pcgctl |= PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgctl, PCGCTL);
-   udelay(10);
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
+   ret = dwc2_enter_partial_power_down(hsotg);
+   if (ret)
+   dev_err(hsotg->dev,
+   "enter partial_power_down failed.\n");
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   case DWC2_POWER_DOWN_PARAM_NONE:
+   default:
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_SUSP;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+   hsotg->bus_suspended = true;
+   /*
+* If power_down is supported, Phy clock will be suspended
+* after registers are backuped.
+*/
+   if (!hsotg->params.power_down) {
+   /* Suspend the Phy Clock */
+   pcgctl = dwc2_readl(hsotg, PCGCTL);
+   pcgctl |= PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgctl, PCGCTL);
+   udelay(10);
+   }
}
 
/* For HNP the bus must be suspended for at least 200ms */
@@ -3332,6 +3344,8 @@ void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 
windex)
} else {
spin_unlock_irqrestore(>lock, flags);
}
+
+   return ret;
 }
 
 /**
-- 
2.25.1



[PATCH v3 05/14] usb: dwc2: Update port suspend/resume function definitions.

2021-04-08 Thread Artur Petrosyan
Earlier "dwc2_port_suspend()" and "dwc2_port_resume()" functions
were implemented without proper description and host or device mode
difference.

- Added "dwc2_port_suspend" and "dwc2_port_resume" functions to
  "core.h" header file.

- Updated function description in documentation.

Signed-off-by: Artur Petrosyan 
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/core.h |  4 
 drivers/usb/dwc2/hcd.c  | 25 +++--
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 39037709a2ad..b7d99cf9e84c 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1470,6 +1470,8 @@ void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
 void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
 void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
 int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
+void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
+void dwc2_port_resume(struct dwc2_hsotg *hsotg);
 int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
 int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
 int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
@@ -1493,6 +1495,8 @@ static inline void dwc2_hcd_start(struct dwc2_hsotg 
*hsotg) {}
 static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
 static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
 { return 0; }
+static inline void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) {}
+static inline void dwc2_port_resume(struct dwc2_hsotg *hsotg) {}
 static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 { return 0; }
 static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index dd0362e07444..f4247a66c2b2 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -56,8 +56,6 @@
 #include "core.h"
 #include "hcd.h"
 
-static void dwc2_port_resume(struct dwc2_hsotg *hsotg);
-
 /*
  * =
  *  Host Core Layer Functions
@@ -3277,8 +3275,16 @@ static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg 
*hsotg)
return hcd->self.b_hnp_enable;
 }
 
-/* Must NOT be called with interrupt disabled or spinlock held */
-static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
+/**
+ * dwc2_port_suspend() - Put controller in suspend mode for host.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @windex: The control request wIndex field
+ *
+ * This function is for entering Host mode suspend.
+ * Must NOT be called with interrupt disabled or spinlock held.
+ */
+void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 {
unsigned long flags;
u32 hprt0;
@@ -3328,8 +3334,15 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, 
u16 windex)
}
 }
 
-/* Must NOT be called with interrupt disabled or spinlock held */
-static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
+/**
+ * dwc2_port_resume() - Exit controller from suspend mode for host.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * This function is for exiting Host mode suspend.
+ * Must NOT be called with interrupt disabled or spinlock held.
+ */
+void dwc2_port_resume(struct dwc2_hsotg *hsotg)
 {
unsigned long flags;
u32 hprt0;
-- 
2.25.1



[PATCH v3 04/14] usb: dwc2: Add partial power down exit flow in wakeup intr.

2021-04-08 Thread Artur Petrosyan
According to programming guide added host partial power
down exit flow in wakeup detected interrupt handler.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core_intr.c | 17 -
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 1fb957ce6c25..0a7f9330907f 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -423,15 +423,14 @@ static void dwc2_handle_wakeup_detected_intr(struct 
dwc2_hsotg *hsotg)
hsotg->lx_state = DWC2_L0;
}
} else {
-   if (hsotg->params.power_down)
-   return;
-
-   if (hsotg->lx_state != DWC2_L1) {
-   u32 pcgcctl = dwc2_readl(hsotg, PCGCTL);
-
-   /* Restart the Phy Clock */
-   pcgcctl &= ~PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgcctl, PCGCTL);
+   if (hsotg->lx_state == DWC2_L2) {
+   if (hsotg->in_ppd) {
+   ret = dwc2_exit_partial_power_down(hsotg, 1,
+  true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down 
failed\n");
+   }
 
/*
 * If we've got this quirk then the PHY is stuck upon
-- 
2.25.1



[PATCH v3 03/14] usb: dwc2: Update enter and exit partial power down functions

2021-04-08 Thread Artur Petrosyan
These are wrapper functions which are calling device or host
enter/exit partial power down functions.

This change is done because we need to separate device and
host partial power down functions as the programming flow
has a lot of difference between host and device. With this
update during partial power down exit driver relies on
backup value of "GOTGCTL_CURMODE_HOST" to determine the
mode of core before entering to PPD.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.c  | 113 ++-
 drivers/usb/dwc2/core.h  |   3 +-
 drivers/usb/dwc2/core_intr.c |  21 ---
 drivers/usb/dwc2/gadget.c|  20 ---
 drivers/usb/dwc2/hcd.c   |   2 +-
 drivers/usb/dwc2/hw.h|   1 +
 6 files changed, 45 insertions(+), 115 deletions(-)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index fec17a2d2447..cb65f7f60573 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -131,54 +131,26 @@ int dwc2_restore_global_registers(struct dwc2_hsotg 
*hsotg)
  * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
  *
  * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: indicates whether resume is initiated by Reset.
  * @restore: Controller registers need to be restored
  */
-int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
+int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup,
+bool restore)
 {
-   u32 pcgcctl;
-   int ret = 0;
-
-   if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
-   return -ENOTSUPP;
-
-   pcgcctl = dwc2_readl(hsotg, PCGCTL);
-   pcgcctl &= ~PCGCTL_STOPPCLK;
-   dwc2_writel(hsotg, pcgcctl, PCGCTL);
-
-   pcgcctl = dwc2_readl(hsotg, PCGCTL);
-   pcgcctl &= ~PCGCTL_PWRCLMP;
-   dwc2_writel(hsotg, pcgcctl, PCGCTL);
-
-   pcgcctl = dwc2_readl(hsotg, PCGCTL);
-   pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
-   dwc2_writel(hsotg, pcgcctl, PCGCTL);
+   struct dwc2_gregs_backup *gr;
 
-   udelay(100);
-   if (restore) {
-   ret = dwc2_restore_global_registers(hsotg);
-   if (ret) {
-   dev_err(hsotg->dev, "%s: failed to restore registers\n",
-   __func__);
-   return ret;
-   }
-   if (dwc2_is_host_mode(hsotg)) {
-   ret = dwc2_restore_host_registers(hsotg);
-   if (ret) {
-   dev_err(hsotg->dev, "%s: failed to restore host 
registers\n",
-   __func__);
-   return ret;
-   }
-   } else {
-   ret = dwc2_restore_device_registers(hsotg, 0);
-   if (ret) {
-   dev_err(hsotg->dev, "%s: failed to restore 
device registers\n",
-   __func__);
-   return ret;
-   }
-   }
-   }
+   gr = >gr_backup;
 
-   return ret;
+   /*
+* Restore host or device regisers with the same mode core enterted
+* to partial power down by checking "GOTGCTL_CURMODE_HOST" backup
+* value of the "gotgctl" register.
+*/
+   if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
+   return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup,
+restore);
+   else
+   return dwc2_gadget_exit_partial_power_down(hsotg, restore);
 }
 
 /**
@@ -188,57 +160,10 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg 
*hsotg, bool restore)
  */
 int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
 {
-   u32 pcgcctl;
-   int ret = 0;
-
-   if (!hsotg->params.power_down)
-   return -ENOTSUPP;
-
-   /* Backup all registers */
-   ret = dwc2_backup_global_registers(hsotg);
-   if (ret) {
-   dev_err(hsotg->dev, "%s: failed to backup global registers\n",
-   __func__);
-   return ret;
-   }
-
-   if (dwc2_is_host_mode(hsotg)) {
-   ret = dwc2_backup_host_registers(hsotg);
-   if (ret) {
-   dev_err(hsotg->dev, "%s: failed to backup host 
registers\n",
-   __func__);
-   return ret;
-   }
-   } else {
-   ret = dwc2_backup_device_registers(hsotg);
-   if (ret) {
-   dev_err(hsotg->dev, "%s: failed to backup device 
registers\n",
-   __func__);
-   return ret;
-   

[PATCH v3 02/14] usb: dwc2: Add host partial power down functions

2021-04-08 Thread Artur Petrosyan
For host mode Partial Power Down entering and exiting
separate functions are needed to implement the logic.
Earlier the logic was implemented in one function. Which was
confusing the readability. Also both host and device implementations
were in the same function.

- Added host partial power down functions which must be called
by dwc2_enter_partial_power_down()/dwc2_exit_partial_power_down()
functions.

Added function names:
dwc2_host_enter_partial_power_down()
dwc2_host_exit_partial_power_down()

NOTE: There is a checkpatch "CHECK" warning on "udelay(100)".
The delay is needed to properly exit gadget Partial Power Down
A delay less than 100 doesn't work.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.h |   8 ++
 drivers/usb/dwc2/hcd.c  | 160 
 2 files changed, 168 insertions(+)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index ed54d834138d..1a97df8bf5cb 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1474,6 +1474,9 @@ 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);
+int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg);
+int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
+ int rem_wakeup, bool restore);
 bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
 static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
 { schedule_work(>phy_reset_work); }
@@ -1500,6 +1503,11 @@ 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 int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
+{ return 0; }
+static inline int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
+   int rem_wakeup, bool 
restore)
+{ 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) {}
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 1a9789ec5847..35e617be4bc3 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5607,3 +5607,163 @@ bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
/* No reason to keep the PHY powered, so allow poweroff */
return true;
 }
+
+/**
+ * dwc2_host_enter_partial_power_down() - Put controller in partial
+ * power down.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * Return: non-zero if failed to enter host partial power down.
+ *
+ * This function is for entering Host mode partial power down.
+ */
+int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
+{
+   u32 pcgcctl;
+   u32 hprt0;
+   int ret = 0;
+
+   dev_dbg(hsotg->dev, "Entering host partial power down started.\n");
+
+   /* Put this port in suspend mode. */
+   hprt0 = dwc2_read_hprt0(hsotg);
+   hprt0 |= HPRT0_SUSP;
+   dwc2_writel(hsotg, hprt0, HPRT0);
+   udelay(5);
+
+   /* Wait for the HPRT0.PrtSusp register field to be set */
+   if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000))
+   dev_warn(hsotg->dev, "Suspend wasn't generated\n");
+
+   /* Backup all registers */
+   ret = dwc2_backup_global_registers(hsotg);
+   if (ret) {
+   dev_err(hsotg->dev, "%s: failed to backup global registers\n",
+   __func__);
+   return ret;
+   }
+
+   ret = dwc2_backup_host_registers(hsotg);
+   if (ret) {
+   dev_err(hsotg->dev, "%s: failed to backup host registers\n",
+   __func__);
+   return ret;
+   }
+
+   /*
+* Clear any pending interrupts since dwc2 will not be able to
+* clear them after entering partial_power_down.
+*/
+   dwc2_writel(hsotg, 0x, GINTSTS);
+
+   /* Put the controller in low power state */
+   pcgcctl = dwc2_readl(hsotg, PCGCTL);
+
+   pcgcctl |= PCGCTL_PWRCLMP;
+   dwc2_writel(hsotg, pcgcctl, PCGCTL);
+   udelay(5);
+
+   pcgcctl |= PCGCTL_RSTPDWNMODULE;
+   dwc2_writel(hsotg, pcgcctl, PCGCTL);
+   udelay(5);
+
+   pcgcctl |= PCGCTL_STOPPCLK;
+   dwc2_writel(hsotg, pcgcctl, PCGCTL);
+
+   /* Set in_ppd flag to 1 as here core enters suspend. */
+   hsotg->in_ppd = 1;
+   hsotg->lx_state = DWC2_L2;
+   hsotg->bus_suspended = true;
+
+   dev_dbg(hsotg->dev, "Entering host partial power down completed.\n");
+
+  

[PATCH v3 01/14] usb: dwc2: Add device partial power down functions

2021-04-08 Thread Artur Petrosyan
For device mode Partial Power Down entering and exiting
separate functions are needed to implement the logic.
Earlier the logic was implemented in one function. Which was
confusing the readability. Also both host and device implementations
were in the same function.

- Added device partial power down functions which must be called
by dwc2_enter_partial_power_down()/dwc2_exit_partial_power_down()
functions.

- Added "in_ppd" flag in "dwc2_hsotg" struct to indicate the
core state after entering into partial power down mode.

Added function names:
dwc2_gadget_enter_partial_power_down()
dwc2_gadget_exit_partial_power_down()

NOTE: There is a checkpatch "CHECK" warning on "udelay(100)".
The delay is needed to properly exit gadget Partial Power Down
A delay less than 100 doesn't work.

Signed-off-by: Artur Petrosyan 
Acked-by: Minas Harutyunyan 
---
 drivers/usb/dwc2/core.h   |  10 +++
 drivers/usb/dwc2/gadget.c | 128 ++
 2 files changed, 138 insertions(+)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index d0ebe721fb98..ed54d834138d 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -865,6 +865,7 @@ struct dwc2_hregs_backup {
  * @gadget_enabled:Peripheral mode sub-driver initialization indicator.
  * @ll_hw_enabled: Status of low-level hardware resources.
  * @hibernated:True if core is hibernated
+ * @in_ppd:True if core is partial power down mode.
  * @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.
@@ -1060,6 +1061,7 @@ struct dwc2_hsotg {
unsigned int gadget_enabled:1;
unsigned int ll_hw_enabled:1;
unsigned int hibernated:1;
+   unsigned int in_ppd:1;
unsigned int reset_phy_on_wake:1;
unsigned int need_phy_for_wake:1;
unsigned int phy_off_for_suspend:1;
@@ -1409,6 +1411,9 @@ int dwc2_restore_device_registers(struct dwc2_hsotg 
*hsotg, int remote_wakeup);
 int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg);
 int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
 int rem_wakeup, int reset);
+int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg);
+int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
+   bool restore);
 int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
@@ -1442,6 +1447,11 @@ static inline int dwc2_gadget_enter_hibernation(struct 
dwc2_hsotg *hsotg)
 static inline int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
   int rem_wakeup, int reset)
 { return 0; }
+static inline int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg 
*hsotg)
+{ return 0; }
+static inline int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
+ bool restore)
+{ return 0; }
 static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
 { return 0; }
 static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index ad4c94366dad..98a2a63c67ae 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -5351,3 +5351,131 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg 
*hsotg,
 
return ret;
 }
+
+/**
+ * dwc2_gadget_enter_partial_power_down() - Put controller in partial
+ * power down.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * Return: non-zero if failed to enter device partial power down.
+ *
+ * This function is for entering device mode partial power down.
+ */
+int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
+{
+   u32 pcgcctl;
+   int ret = 0;
+
+   dev_dbg(hsotg->dev, "Entering device partial power down started.\n");
+
+   /* Backup all registers */
+   ret = dwc2_backup_global_registers(hsotg);
+   if (ret) {
+   dev_err(hsotg->dev, "%s: failed to backup global registers\n",
+   __func__);
+   return ret;
+   }
+
+   ret = dwc2_backup_device_registers(hsotg);
+   if (ret) {
+   dev_err(hsotg->dev, "%s: failed to backup device registers\n",
+   __func__);
+   return ret;
+   }
+
+   /*
+* Clear any pending interrupts since dwc2 will not be able to
+* clear them after entering partial_power_down.
+*/
+   dwc2_writel(hsotg, 0x, GINTSTS);
+
+   /* Put the controller in low power state */
+   pcgcctl = dwc2_readl(hsotg, PCGCTL);
+
+   pcgcctl |

[PATCH v3 00/14] usb: dwc2: Fix Partial Power down issues.

2021-04-08 Thread Artur Petrosyan
This patch set fixes and improves the Partial Power Down mode for
dwc2 core.
It adds support for the following cases
1. Entering and exiting partial power down when a port is
   suspended, resumed, port reset is asserted.
2. Exiting the partial power down mode before removing driver.
3. Exiting partial power down in wakeup detected interrupt handler.
4. Exiting from partial power down mode when connector ID.
   status changes to "connId B

It updates and fixes the implementation of dwc2 entering and
exiting partial power down mode when the system (PC) is suspended.

The patch set also improves the implementation of function handlers
for entering and exiting host or device partial power down.

NOTE: This is the second patch set in the power saving mode fixes
series.
This patch set is part of multiple series and is continuation
of the "usb: dwc2: Fix and improve power saving modes" patch set.
(Patch set link: https://marc.info/?l=linux-usb=160379622403975=2).
The patches that were included in the "usb: dwc2:
Fix and improve power saving modes" which was submitted
earlier was too large and needed to be split up into
smaller patch sets.

Changes since V2:
No changes in the patches or the source code.
Assuming that the issue due to which the patches are not reaching to
vger.kernel.org is a comma in the end of To: or Cc: lists removed
commas in the end of those lists in each email of patches.


Artur Petrosyan (14):
  usb: dwc2: Add device partial power down functions
  usb: dwc2: Add host partial power down functions
  usb: dwc2: Update enter and exit partial power down functions
  usb: dwc2: Add partial power down exit flow in wakeup intr.
  usb: dwc2: Update port suspend/resume function definitions.
  usb: dwc2: Add enter partial power down when port is suspended
  usb: dwc2: Add exit partial power down when port is resumed
  usb: dwc2: Add exit partial power down when port reset is asserted
  usb: dwc2: Add part. power down exit from
dwc2_conn_id_status_change().
  usb: dwc2: Allow exit partial power down in urb enqueue
  usb: dwc2: Fix session request interrupt handler
  usb: dwc2: Update partial power down entering by system suspend
  usb: dwc2: Fix partial power down exiting by system resume
  usb: dwc2: Add exit partial power down before removing driver

 drivers/usb/dwc2/core.c  | 113 ++---
 drivers/usb/dwc2/core.h  |  27 ++-
 drivers/usb/dwc2/core_intr.c |  46 ++--
 drivers/usb/dwc2/gadget.c| 148 ++-
 drivers/usb/dwc2/hcd.c   | 458 +--
 drivers/usb/dwc2/hw.h|   1 +
 drivers/usb/dwc2/platform.c  |  11 +-
 7 files changed, 558 insertions(+), 246 deletions(-)


base-commit: e9fcb07704fcef6fa6d0333fd2b3a62442eaf45b
-- 
2.25.1



Re: [PATCH v2 00/14] usb: dwc2: Fix Partial Power down issues.

2021-04-08 Thread Artur Petrosyan
Hi Greg,

On 4/8/2021 11:28, Artur Petrosyan wrote:
> This patch set fixes and improves the Partial Power Down mode for
> dwc2 core.
> It adds support for the following cases
>  1. Entering and exiting partial power down when a port is
> suspended, resumed, port reset is asserted.
>  2. Exiting the partial power down mode before removing driver.
>  3. Exiting partial power down in wakeup detected interrupt handler.
>  4. Exiting from partial power down mode when connector ID.
> status changes to "connId B
> 
> It updates and fixes the implementation of dwc2 entering and
> exiting partial power down mode when the system (PC) is suspended.
> 
> The patch set also improves the implementation of function handlers
> for entering and exiting host or device partial power down.
> 
> NOTE: This is the second patch set in the power saving mode fixes
> series.
> This patch set is part of multiple series and is continuation
> of the "usb: dwc2: Fix and improve power saving modes" patch set.
> (Patch set link: https://marc.info/?l=linux-usb=160379622403975=2).
> The patches that were included in the "usb: dwc2:
> Fix and improve power saving modes" which was submitted
> earlier was too large and needed to be split up into
> smaller patch sets.
> 
> Changes since V1:
> No changes in the patches or the source code.
> Sending the second version of the patch set because the first version
> was not received by vger.kernel.org.
> 
> 
> 
> Artur Petrosyan (14):
>usb: dwc2: Add device partial power down functions
>usb: dwc2: Add host partial power down functions
>usb: dwc2: Update enter and exit partial power down functions
>usb: dwc2: Add partial power down exit flow in wakeup intr.
>usb: dwc2: Update port suspend/resume function definitions.
>usb: dwc2: Add enter partial power down when port is suspended
>usb: dwc2: Add exit partial power down when port is resumed
>usb: dwc2: Add exit partial power down when port reset is asserted
>usb: dwc2: Add part. power down exit from
>  dwc2_conn_id_status_change().
>usb: dwc2: Allow exit partial power down in urb enqueue
>usb: dwc2: Fix session request interrupt handler
>usb: dwc2: Update partial power down entering by system suspend
>usb: dwc2: Fix partial power down exiting by system resume
>usb: dwc2: Add exit partial power down before removing driver
> 
>   drivers/usb/dwc2/core.c  | 113 ++---
>   drivers/usb/dwc2/core.h  |  27 ++-
>   drivers/usb/dwc2/core_intr.c |  46 ++--
>   drivers/usb/dwc2/gadget.c| 148 ++-
>   drivers/usb/dwc2/hcd.c   | 458 +--
>   drivers/usb/dwc2/hw.h|   1 +
>   drivers/usb/dwc2/platform.c  |  11 +-
>   7 files changed, 558 insertions(+), 246 deletions(-)
> 
> 
> base-commit: e9fcb07704fcef6fa6d0333fd2b3a62442eaf45b
> 

Re sending as a "v2" did not work :(.
The patches are not in lore again.

Could the issue be with a comma in the end of To: or Cc: list?
Let me remove the comma in the end of those lists and try sending as "v3".

Regards,
Artur



[PATCH v2 13/14] usb: dwc2: Fix partial power down exiting by system resume

2021-04-08 Thread Artur Petrosyan
Fixes the implementation of exiting from partial power down
power saving mode when PC is resumed.

Added port connection status checking which prevents exiting from
Partial Power Down mode from _dwc2_hcd_resume() if not in Partial
Power Down mode.

Rearranged the implementation to get rid of many "if"
statements.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Cc: 
Fixes: 6f6d70597c15 ("usb: dwc2: bus suspend/resume for hosts with 
DWC2_POWER_DOWN_PARAM_NONE")
Signed-off-by: Artur Petrosyan 
---
 Changes in v2:
 - None

 drivers/usb/dwc2/hcd.c | 90 +-
 1 file changed, 46 insertions(+), 44 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 34030bafdff4..f096006df96f 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4427,7 +4427,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
 {
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
-   u32 pcgctl;
+   u32 hprt0;
int ret = 0;
 
spin_lock_irqsave(>lock, flags);
@@ -4438,11 +4438,40 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
if (hsotg->lx_state != DWC2_L2)
goto unlock;
 
-   if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) {
+   hprt0 = dwc2_read_hprt0(hsotg);
+
+   /*
+* Added port connection status checking which prevents exiting from
+* Partial Power Down mode from _dwc2_hcd_resume() if not in Partial
+* Power Down mode.
+*/
+   if (hprt0 & HPRT0_CONNSTS) {
+   hsotg->lx_state = DWC2_L0;
+   goto unlock;
+   }
+
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
+   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down failed\n");
+   /*
+* Set HW accessible bit before powering on the controller
+* since an interrupt may rise.
+*/
+   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   case DWC2_POWER_DOWN_PARAM_NONE:
+   default:
hsotg->lx_state = DWC2_L0;
goto unlock;
}
 
+   /* Change Root port status, as port status change occurred after 
resume.*/
+   hsotg->flags.b.port_suspend_change = 1;
+
/*
 * Enable power if not already done.
 * This must not be spinlocked since duration
@@ -4454,52 +4483,25 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
spin_lock_irqsave(>lock, flags);
}
 
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
-   /*
-* Set HW accessible bit before powering on the controller
-* since an interrupt may rise.
-*/
-   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
-
-
-   /* Exit partial_power_down */
-   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
-   if (ret && (ret != -ENOTSUPP))
-   dev_err(hsotg->dev, "exit partial_power_down failed\n");
-   } else {
-   pcgctl = readl(hsotg->regs + PCGCTL);
-   pcgctl &= ~PCGCTL_STOPPCLK;
-   writel(pcgctl, hsotg->regs + PCGCTL);
-   }
-
-   hsotg->lx_state = DWC2_L0;
-
+   /* Enable external vbus supply after resuming the port. */
spin_unlock_irqrestore(>lock, flags);
+   dwc2_vbus_supply_init(hsotg);
 
-   if (hsotg->bus_suspended) {
-   spin_lock_irqsave(>lock, flags);
-   hsotg->flags.b.port_suspend_change = 1;
-   spin_unlock_irqrestore(>lock, flags);
-   dwc2_port_resume(hsotg);
-   } else {
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
-   dwc2_vbus_supply_init(hsotg);
-
-   /* Wait for controller to correctly update D+/D- level 
*/
-   usleep_range(3000, 5000);
-   }
+   /* Wait for controller to correctly update D+/D- level */
+   usleep_range(3000, 5000);
+   spin_lock_irqsave(>lock, flags);
 
-   /*
-* Clear Port Enable and Port Status changes.
-* Enable Port Power.
-*/
-   dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET |
-   HPRT0_ENACHG, HPRT0);
-   /* Wait for controller to detect Por

[PATCH v2 00/14] usb: dwc2: Fix Partial Power down issues.

2021-04-08 Thread Artur Petrosyan
This patch set fixes and improves the Partial Power Down mode for
dwc2 core.
It adds support for the following cases
1. Entering and exiting partial power down when a port is
   suspended, resumed, port reset is asserted.
2. Exiting the partial power down mode before removing driver.
3. Exiting partial power down in wakeup detected interrupt handler.
4. Exiting from partial power down mode when connector ID.
   status changes to "connId B

It updates and fixes the implementation of dwc2 entering and
exiting partial power down mode when the system (PC) is suspended.

The patch set also improves the implementation of function handlers
for entering and exiting host or device partial power down.

NOTE: This is the second patch set in the power saving mode fixes
series.
This patch set is part of multiple series and is continuation
of the "usb: dwc2: Fix and improve power saving modes" patch set.
(Patch set link: https://marc.info/?l=linux-usb=160379622403975=2).
The patches that were included in the "usb: dwc2:
Fix and improve power saving modes" which was submitted
earlier was too large and needed to be split up into
smaller patch sets.

Changes since V1:
No changes in the patches or the source code.
Sending the second version of the patch set because the first version
was not received by vger.kernel.org.



Artur Petrosyan (14):
  usb: dwc2: Add device partial power down functions
  usb: dwc2: Add host partial power down functions
  usb: dwc2: Update enter and exit partial power down functions
  usb: dwc2: Add partial power down exit flow in wakeup intr.
  usb: dwc2: Update port suspend/resume function definitions.
  usb: dwc2: Add enter partial power down when port is suspended
  usb: dwc2: Add exit partial power down when port is resumed
  usb: dwc2: Add exit partial power down when port reset is asserted
  usb: dwc2: Add part. power down exit from
dwc2_conn_id_status_change().
  usb: dwc2: Allow exit partial power down in urb enqueue
  usb: dwc2: Fix session request interrupt handler
  usb: dwc2: Update partial power down entering by system suspend
  usb: dwc2: Fix partial power down exiting by system resume
  usb: dwc2: Add exit partial power down before removing driver

 drivers/usb/dwc2/core.c  | 113 ++---
 drivers/usb/dwc2/core.h  |  27 ++-
 drivers/usb/dwc2/core_intr.c |  46 ++--
 drivers/usb/dwc2/gadget.c| 148 ++-
 drivers/usb/dwc2/hcd.c   | 458 +--
 drivers/usb/dwc2/hw.h|   1 +
 drivers/usb/dwc2/platform.c  |  11 +-
 7 files changed, 558 insertions(+), 246 deletions(-)


base-commit: e9fcb07704fcef6fa6d0333fd2b3a62442eaf45b
-- 
2.25.1



Re: [PATCH 00/14] usb: dwc2: Fix Partial Power down issues.

2021-04-07 Thread Artur Petrosyan
Hi Greg,

On 4/7/2021 14:00, Artur Petrosyan wrote:
> This patch set fixes and improves the Partial Power Down mode for
> dwc2 core.
> It adds support for the following cases
>  1. Entering and exiting partial power down when a port is
> suspended, resumed, port reset is asserted.
>  2. Exiting the partial power down mode before removing driver.
>  3. Exiting partial power down in wakeup detected interrupt handler.
>  4. Exiting from partial power down mode when connector ID.
> status changes to "connId B
> 
> It updates and fixes the implementation of dwc2 entering and
> exiting partial power down mode when the system (PC) is suspended.
> 
> The patch set also improves the implementation of function handlers
> for entering and exiting host or device partial power down.
> 
> NOTE: This is the second patch set in the power saving mode fixes
> series.
> This patch set is part of multiple series and is continuation
> of the "usb: dwc2: Fix and improve power saving modes" patch set.
> (Patch set link: https://marc.info/?l=linux-usb=160379622403975=2).
> The patches that were included in the "usb: dwc2:
> Fix and improve power saving modes" which was submitted
> earlier was too large and needed to be split up into
> smaller patch sets.
> 
> 
> Artur Petrosyan (14):
>usb: dwc2: Add device partial power down functions
>usb: dwc2: Add host partial power down functions
>usb: dwc2: Update enter and exit partial power down functions
>usb: dwc2: Add partial power down exit flow in wakeup intr.
>usb: dwc2: Update port suspend/resume function definitions.
>usb: dwc2: Add enter partial power down when port is suspended
>usb: dwc2: Add exit partial power down when port is resumed
>usb: dwc2: Add exit partial power down when port reset is asserted
>usb: dwc2: Add part. power down exit from
>  dwc2_conn_id_status_change().
>usb: dwc2: Allow exit partial power down in urb enqueue
>usb: dwc2: Fix session request interrupt handler
>usb: dwc2: Update partial power down entering by system suspend
>usb: dwc2: Fix partial power down exiting by system resume
>usb: dwc2: Add exit partial power down before removing driver
> 
>   drivers/usb/dwc2/core.c  | 113 ++---
>   drivers/usb/dwc2/core.h  |  27 ++-
>   drivers/usb/dwc2/core_intr.c |  46 ++--
>   drivers/usb/dwc2/gadget.c| 148 ++-
>   drivers/usb/dwc2/hcd.c   | 458 +--
>   drivers/usb/dwc2/hw.h|   1 +
>   drivers/usb/dwc2/platform.c  |  11 +-
>   7 files changed, 558 insertions(+), 246 deletions(-)
> 
> 
> base-commit: e9fcb07704fcef6fa6d0333fd2b3a62442eaf45b
> 
I have submitted this patch set yesterday. It contains 14 patches. But 
only 2 of those patches were received by LKML only the cover letter and 
the 13th patch. 
(https://lore.kernel.org/linux-usb/cover.1617782102.git.arthur.petros...@synopsys.com/T/#t)

I checked here at Synopsys, Minas did receive all the patches as his 
email is in To list. Could this be an issue of vger.kernel.org mailing 
server?

Because I checked every local possibility that could result to such 
behavior. The patch 13 which was received by LKML has the similar 
content as the other patches.

The mailing tool that was used is ssmtp, checked all the configurations 
everything is fine.

Could you please suggest what should I do in this situation?

Regards,
Artur






[PATCH 13/14] usb: dwc2: Fix partial power down exiting by system resume

2021-04-07 Thread Artur Petrosyan
Fixes the implementation of exiting from partial power down
power saving mode when PC is resumed.

Added port connection status checking which prevents exiting from
Partial Power Down mode from _dwc2_hcd_resume() if not in Partial
Power Down mode.

Rearranged the implementation to get rid of many "if"
statements.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Cc: 
Fixes: 6f6d70597c15 ("usb: dwc2: bus suspend/resume for hosts with 
DWC2_POWER_DOWN_PARAM_NONE")
Signed-off-by: Artur Petrosyan 
---
 drivers/usb/dwc2/hcd.c | 90 +-
 1 file changed, 46 insertions(+), 44 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 34030bafdff4..f096006df96f 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4427,7 +4427,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
 {
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
-   u32 pcgctl;
+   u32 hprt0;
int ret = 0;
 
spin_lock_irqsave(>lock, flags);
@@ -4438,11 +4438,40 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
if (hsotg->lx_state != DWC2_L2)
goto unlock;
 
-   if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) {
+   hprt0 = dwc2_read_hprt0(hsotg);
+
+   /*
+* Added port connection status checking which prevents exiting from
+* Partial Power Down mode from _dwc2_hcd_resume() if not in Partial
+* Power Down mode.
+*/
+   if (hprt0 & HPRT0_CONNSTS) {
+   hsotg->lx_state = DWC2_L0;
+   goto unlock;
+   }
+
+   switch (hsotg->params.power_down) {
+   case DWC2_POWER_DOWN_PARAM_PARTIAL:
+   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
+   if (ret)
+   dev_err(hsotg->dev,
+   "exit partial_power_down failed\n");
+   /*
+* Set HW accessible bit before powering on the controller
+* since an interrupt may rise.
+*/
+   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
+   break;
+   case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+   case DWC2_POWER_DOWN_PARAM_NONE:
+   default:
hsotg->lx_state = DWC2_L0;
goto unlock;
}
 
+   /* Change Root port status, as port status change occurred after 
resume.*/
+   hsotg->flags.b.port_suspend_change = 1;
+
/*
 * Enable power if not already done.
 * This must not be spinlocked since duration
@@ -4454,52 +4483,25 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
spin_lock_irqsave(>lock, flags);
}
 
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
-   /*
-* Set HW accessible bit before powering on the controller
-* since an interrupt may rise.
-*/
-   set_bit(HCD_FLAG_HW_ACCESSIBLE, >flags);
-
-
-   /* Exit partial_power_down */
-   ret = dwc2_exit_partial_power_down(hsotg, 0, true);
-   if (ret && (ret != -ENOTSUPP))
-   dev_err(hsotg->dev, "exit partial_power_down failed\n");
-   } else {
-   pcgctl = readl(hsotg->regs + PCGCTL);
-   pcgctl &= ~PCGCTL_STOPPCLK;
-   writel(pcgctl, hsotg->regs + PCGCTL);
-   }
-
-   hsotg->lx_state = DWC2_L0;
-
+   /* Enable external vbus supply after resuming the port. */
spin_unlock_irqrestore(>lock, flags);
+   dwc2_vbus_supply_init(hsotg);
 
-   if (hsotg->bus_suspended) {
-   spin_lock_irqsave(>lock, flags);
-   hsotg->flags.b.port_suspend_change = 1;
-   spin_unlock_irqrestore(>lock, flags);
-   dwc2_port_resume(hsotg);
-   } else {
-   if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
-   dwc2_vbus_supply_init(hsotg);
-
-   /* Wait for controller to correctly update D+/D- level 
*/
-   usleep_range(3000, 5000);
-   }
+   /* Wait for controller to correctly update D+/D- level */
+   usleep_range(3000, 5000);
+   spin_lock_irqsave(>lock, flags);
 
-   /*
-* Clear Port Enable and Port Status changes.
-* Enable Port Power.
-*/
-   dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET |
-   HPRT0_ENACHG, HPRT0);
-   /* Wait for controller to detect Port Connect */
-   u

[PATCH 00/14] usb: dwc2: Fix Partial Power down issues.

2021-04-07 Thread Artur Petrosyan
This patch set fixes and improves the Partial Power Down mode for
dwc2 core.
It adds support for the following cases
1. Entering and exiting partial power down when a port is
   suspended, resumed, port reset is asserted.
2. Exiting the partial power down mode before removing driver.
3. Exiting partial power down in wakeup detected interrupt handler.
4. Exiting from partial power down mode when connector ID.
   status changes to "connId B

It updates and fixes the implementation of dwc2 entering and
exiting partial power down mode when the system (PC) is suspended.

The patch set also improves the implementation of function handlers
for entering and exiting host or device partial power down.

NOTE: This is the second patch set in the power saving mode fixes
series.
This patch set is part of multiple series and is continuation
of the "usb: dwc2: Fix and improve power saving modes" patch set.
(Patch set link: https://marc.info/?l=linux-usb=160379622403975=2).
The patches that were included in the "usb: dwc2:
Fix and improve power saving modes" which was submitted
earlier was too large and needed to be split up into
smaller patch sets. 


Artur Petrosyan (14):
  usb: dwc2: Add device partial power down functions
  usb: dwc2: Add host partial power down functions
  usb: dwc2: Update enter and exit partial power down functions
  usb: dwc2: Add partial power down exit flow in wakeup intr.
  usb: dwc2: Update port suspend/resume function definitions.
  usb: dwc2: Add enter partial power down when port is suspended
  usb: dwc2: Add exit partial power down when port is resumed
  usb: dwc2: Add exit partial power down when port reset is asserted
  usb: dwc2: Add part. power down exit from
dwc2_conn_id_status_change().
  usb: dwc2: Allow exit partial power down in urb enqueue
  usb: dwc2: Fix session request interrupt handler
  usb: dwc2: Update partial power down entering by system suspend
  usb: dwc2: Fix partial power down exiting by system resume
  usb: dwc2: Add exit partial power down before removing driver

 drivers/usb/dwc2/core.c  | 113 ++---
 drivers/usb/dwc2/core.h  |  27 ++-
 drivers/usb/dwc2/core_intr.c |  46 ++--
 drivers/usb/dwc2/gadget.c| 148 ++-
 drivers/usb/dwc2/hcd.c   | 458 +--
 drivers/usb/dwc2/hw.h|   1 +
 drivers/usb/dwc2/platform.c  |  11 +-
 7 files changed, 558 insertions(+), 246 deletions(-)


base-commit: e9fcb07704fcef6fa6d0333fd2b3a62442eaf45b
-- 
2.25.1



Re: [RFC PATCH] usb: dwc2: Try usb_get_phy_by_phandle instead of usb_get_phy

2020-12-29 Thread Artur Petrosyan
Hi Jules,

On 12/26/2020 17:45, Jules Maselbas wrote:
> Hi Artur,
> 
> On Fri, Dec 25, 2020 at 11:41:04AM +0000, Artur Petrosyan wrote:
>>> @@ -251,7 +251,12 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg 
>>> *hsotg)
>>> }
>>>
>>> if (!hsotg->phy) {
>>> -   hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
>>> +   if (hsotg->dev->of_node)
>>> +   i = of_property_match_string(hsotg->dev->of_node, 
>>> "phy-names", "usb2-phy");
>>
>> According the device tree you have provided the value of "i" will always
>> be "0".
> Yes
> 
>>> +   if (hsotg->dev->of_node && i >= 0)
>>> +   hsotg->uphy = devm_usb_get_phy_by_phandle(hsotg->dev, 
>>> "phys", i);
>>
>> Why do you use the value of "i" while in "<_phy0>" you have only one
>> phy. If you had several phy-names and the value of "i" gets more than 0,
>> then based on your usb_phy0 "devm_usb_get_phy_by_phandle" function will
>> return error. So, maybe it would be more correct (based on your device
>> tree), to use below command
>> hsotg->uphy = devm_usb_get_phy_by_phandle(hsotg->dev, "phys", 0);
> Yes I could use 0 instead of i, but I would like this to work not only
> for my case where the "usb2-phy" phandle comes first.
> 
> I've tried to follow what's done in phy-core.c, as done by the function
> phy_get. Where it first call "of_property_match_string" and then get the
> phy with the matched index.
> 
> I don't see how, in my case, the function "devm_usb_get_phy_by_phandle" can
> be called with i greater than 0, and returning an error.

I have noticed that there might be no need to check for "i >= 0" at all 
because "of_parse_phandle()" function has a check for index to not be 
less then 0.

> 
> Best,
> Jules
> 

Regards,
Artur


Re: [RFC PATCH] usb: dwc2: Try usb_get_phy_by_phandle instead of usb_get_phy

2020-12-25 Thread Artur Petrosyan
Hi Jules,

On 12/16/2020 20:59, Jules Maselbas wrote:
> On probe the dwc2 driver tries two path to get an usb phy, first calling
> devm_phy_get() and secondly with devm_usb_get_phy().
> 
> However the current implementation of devm_phy_get() never return a valid
> phy for usb-nop-xceiv. And the current implementation of devm_usb_get_phy
> only check for phy that's has already been registered.
> 
> During boot, I see the dwc2 driver being probed before the usb-nop-xceiv
> probe, this means that during the dwc2 probe the function devm_usb_get_phy
> never finds the a phy (because it hasn't been registered yet) but never
> cause the dwc2 probe to defer.
> 
> I tried to follow what is done by dwc3_core_get_phy(): if the current
> device has an of_node then try to get the usb_phy by phandle instead of
> using devm_usb_get_phy(). This way when the probe order is not good the
> devm_usb_get_phy_by_phandle() function will return -EPROBE_DEFER.
> 
> Signed-off-by: Jules Maselbas 
> --- 8< ---
> 
> A snippet of the device-tree source I am using:
>   {
>  phys = <_phy0>;
>  phy-names = "usb2-phy";
>  };
>  _phy0 {
>  #phy-cells = <0>;
>  compatible = "usb-nop-xceiv";
>  reset-gpios = < 0 GPIO_ACTIVE_LOW>;
>  };
> ---
>   drivers/usb/dwc2/platform.c | 7 ++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
> index db9fd4bd1a38..b58ce996add7 100644
> --- a/drivers/usb/dwc2/platform.c
> +++ b/drivers/usb/dwc2/platform.c
> @@ -251,7 +251,12 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg 
> *hsotg)
>   }
>   
>   if (!hsotg->phy) {
> - hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
> + if (hsotg->dev->of_node)
> + i = of_property_match_string(hsotg->dev->of_node, 
> "phy-names", "usb2-phy");

According the device tree you have provided the value of "i" will always 
be "0".

> + if (hsotg->dev->of_node && i >= 0)
> + hsotg->uphy = devm_usb_get_phy_by_phandle(hsotg->dev, 
> "phys", i);

Why do you use the value of "i" while in "<_phy0>" you have only one 
phy. If you had several phy-names and the value of "i" gets more than 0, 
then based on your usb_phy0 "devm_usb_get_phy_by_phandle" function will 
return error. So, maybe it would be more correct (based on your device 
tree), to use below command
hsotg->uphy = devm_usb_get_phy_by_phandle(hsotg->dev, "phys", 0);

> + else
> + hsotg->uphy = devm_usb_get_phy(hsotg->dev, 
> USB_PHY_TYPE_USB2);
>   if (IS_ERR(hsotg->uphy)) {
>   ret = PTR_ERR(hsotg->uphy);
>   switch (ret) {
> 

Regards,
Artur


Re: [PATCH] usb: dwc2: Remove redundant null check before clk_prepare_enable/clk_disable_unprepare

2020-12-07 Thread Artur Petrosyan
On 12/4/2020 12:36, Xu Wang wrote:
> Because clk_prepare_enable() and clk_disable_unprepare() already checked
> NULL clock parameter, so the additional checks are unnecessary, just
> remove them.
> 
> Signed-off-by: Xu Wang 

Reviewed-by: Artur Petrosyan 

> ---
>   drivers/usb/dwc2/platform.c | 11 ---
>   1 file changed, 4 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
> index 5f18acac7406..ba2b491c7f82 100644
> --- a/drivers/usb/dwc2/platform.c
> +++ b/drivers/usb/dwc2/platform.c
> @@ -143,11 +143,9 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg 
> *hsotg)
>   if (ret)
>   return ret;
>   
> - if (hsotg->clk) {
> - ret = clk_prepare_enable(hsotg->clk);
> - if (ret)
> - return ret;
> - }
> + ret = clk_prepare_enable(hsotg->clk);
> + if (ret)
> + return ret;
>   
>   if (hsotg->uphy) {
>   ret = usb_phy_init(hsotg->uphy);
> @@ -195,8 +193,7 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg 
> *hsotg)
>   if (ret)
>   return ret;
>   
> - if (hsotg->clk)
> - clk_disable_unprepare(hsotg->clk);
> + clk_disable_unprepare(hsotg->clk);
>   
>   return 0;
>   }
> 


Re: [PATCH v2 0/5] USB: dwc2: Allow wakeup from suspend; enable for rk3288-veyron

2019-04-19 Thread Artur Petrosyan
Hi Doug,

On 4/19/2019 15:43, Artur Petrosyan wrote:
> Hi,
> 
> On 4/18/2019 19:55, Doug Anderson wrote:
>> Hi,
>>
>> On Thu, Apr 18, 2019 at 5:41 AM Minas Harutyunyan
>>  wrote:
>>> Did you consider/reviewed patch series from Artur Petrosyan "[PATCH
>>> 00/14] usb: dwc2: Fix and improve power saving modes" (submitted on
>>> April 12) which fixing partial power down and hibernation flows for both
>>> modes: host and device?
>>> I suspect that this both patch series can be in conflict.
>>
>> No, I wasn't aware of them.  I'd like to try them out, but it looks
>> like it's currently impossible because they're not archived anywhere
>> that I can find.
>>
>> 1. LKML wasn't copied, so I can't find them on lore.kernel.org.  It is
>> suggested to CC LKML on all patches.
>>
>> 2. The Linux USB patchwork only has the cover letter plus the first 6
>> patches.  See 
>> <https://urldefense.proofpoint.com/v2/url?u=https-3A__patchwork.kernel.org_cover_10898333_=DwIBaQ=DPL6_X_6JkXFx7AXWqB0tg=9hPBFKCJ_nBjJhGVrrlYOeOQjP_HlVzYqrC_D7niMJI=rJbofHXqjP3sUBgEikaZ89fRWtsquvhFUkhSPguCiWw=_CrI0uolquXIYC5SuoZ1vBs7BM19VfCceI96qZm9kAY=>
>>
>> 3. Searching my own archives I only see the cover letter plus the
>> first 6 patches.
>>
>> Maybe you have some other pointer to how I can retrieve them?  I guess
>> I could try the first 6 patches without the later 8 but I'd rather get
>> the whole set...
>>
>>
>> -Doug
>>
> 
> 
> I have resend the patch set. You can find it with cover letter
> "[PATCH v1 00/14] usb: dwc2: Fix and improve power saving modes."
> 
> Let me know if you need any help.
> 

I am so sorry to inform you that the patches have not reached to LKML.
Looks like there is a problem with the kernel mailing list servers or 
our local servers.
Will try to fix this as soon as possible and let you know about it.

-- 
Regards,
Artur


Re: [PATCH] usb: dwc2: Disable power down feature on Samsung SoCs

2018-12-14 Thread Artur Petrosyan
Hi Marek,

On 12/6/2018 18:20, Marek Szyprowski wrote:
> Hi Artur,
> 
> On 2018-12-04 15:28, Artur Petrosyan wrote:
>> On 11/20/2018 19:38, Marek Szyprowski wrote:
>>> Power down feature of DWC2 module integrated in Samsung SoCs doesn't work
>>> properly or needs some additional handling in PHY or SoC glue layer, so
>>> disable it for now. Without disabling power down, DWC2 causes random memory
>>> trashes and fails enumeration if there is no USB link to host on driver
>>> probe.
>>>
>>> Fixes: 03ea6d6e9e1ff1 ("usb: dwc2: Enable power down")
>>> Signed-off-by: Marek Szyprowski 
>>> ---
>>>drivers/usb/dwc2/params.c | 10 +-
>>>1 file changed, 9 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
>>> index 7c1b6938f212..266157ae179a 100644
>>> --- a/drivers/usb/dwc2/params.c
>>> +++ b/drivers/usb/dwc2/params.c
>>> @@ -71,6 +71,13 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
>>> p->power_down = false;
>>>}
>>>
>>> +static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
>>> +{
>>> +   struct dwc2_core_params *p = >params;
>>> +
>>> +   p->power_down = 0;
>>> +}
>>> +
>>>static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
>>>{
>>> struct dwc2_core_params *p = >params;
>>> @@ -151,7 +158,8 @@ const struct of_device_id dwc2_of_match_table[] = {
>>> { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
>>> { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
>>> { .compatible = "snps,dwc2" },
>>> -   { .compatible = "samsung,s3c6400-hsotg" },
>>> +   { .compatible = "samsung,s3c6400-hsotg",
>>> + .data = dwc2_set_s3c6400_params },
>>> { .compatible = "amlogic,meson8-usb",
>>>   .data = dwc2_set_amlogic_params },
>>> { .compatible = "amlogic,meson8b-usb",
>>>
>> Could you please provide dmesg logs with verbose Debug enabled
>> configuration and the register dump.
>> So that we can see what the issue is related to.
> 
> I'm not sure if this helps much. The problem happens if usb cable is not
> connected on boot. Then, when I connect and disconnect USB cable,
> strange memory trashes happens. From brief tests, the trashing doesn't
> happen when debug messages are enabled, so it is related to timings.
> IMHO the simplest fix for now is to disable powerdown on Samsung SoCs.
> 
> Here is the initialization related part (booted without usb cable
> connected):
> 
> # dmesg | grep dwc
> [    2.261821] dwc2 1248.hsotg: Linked as a consumer to regulator.15
> [    2.266410] dwc2 1248.hsotg: Linked as a consumer to regulator.12
> [    2.273996] dwc2 1248.hsotg: dwc2_check_params: Invalid parameter
> besl=1
> [    2.279405] dwc2 1248.hsotg: dwc2_check_params: Invalid parameter
> g_np_tx_fifo_size=1024
> [    2.287882] dwc2 1248.hsotg: NonPeriodic TXFIFO size: 768
> [    2.287894] dwc2 1248.hsotg: RXFIFO size: 2048
> [    2.288003] dwc2 1248.hsotg: EPs: 16, dedicated fifos, 7808
> entries in SPRAM
> [    2.296631] dwc2 1248.hsotg: DCFG=0x0820, DCTL=0x,
> DIEPMSK=
> [    2.303044] dwc2 1248.hsotg: GAHBCFG=0x, GHWCFG1=0x
> [    2.309437] dwc2 1248.hsotg: GRXFSIZ=0x1f00, GNPTXFSIZ=0x03001f00
> [    2.316258] dwc2 1248.hsotg: DPTx[1] FSize=768, StAddr=0x2200
> [    2.322630] dwc2 1248.hsotg: DPTx[2] FSize=768, StAddr=0x2500
> [    2.329099] dwc2 1248.hsotg: DPTx[3] FSize=768, StAddr=0x2800
> [    2.335521] dwc2 1248.hsotg: DPTx[4] FSize=768, StAddr=0x2b00
> [    2.341900] dwc2 1248.hsotg: DPTx[5] FSize=768, StAddr=0x2e00
> [    2.348366] dwc2 1248.hsotg: DPTx[6] FSize=768, StAddr=0x3100
> [    2.354802] dwc2 1248.hsotg: DPTx[7] FSize=768, StAddr=0x3400
> [    2.361169] dwc2 1248.hsotg: DPTx[8] FSize=768, StAddr=0x3700
> [    2.367637] dwc2 1248.hsotg: DPTx[9] FSize=768, StAddr=0x3a00
> [    2.374059] dwc2 1248.hsotg: DPTx[10] FSize=768, StAddr=0x3d00
> [    2.380526] dwc2 1248.hsotg: DPTx[11] FSize=768, StAddr=0x4000
> [    2.387079] dwc2 1248.hsotg: DPTx[12] FSize=768, StAddr=0x4300
> [    2.393589] dwc2 1248.hsotg: DPTx[13] FSize=768, StAddr=0x4600
> [    2.400055] dwc2 1248.hsotg: DPTx[14] FSize=768, StAddr=0x4900
> [    2.406611] dwc2 1248.hsotg: DPTx[15]

Re: [PATCH] usb: dwc2: Disable power down feature on Samsung SoCs

2018-12-04 Thread Artur Petrosyan
Hi Marek,

On 11/20/2018 19:38, Marek Szyprowski wrote:
> Power down feature of DWC2 module integrated in Samsung SoCs doesn't work
> properly or needs some additional handling in PHY or SoC glue layer, so
> disable it for now. Without disabling power down, DWC2 causes random memory
> trashes and fails enumeration if there is no USB link to host on driver
> probe.
> 
> Fixes: 03ea6d6e9e1ff1 ("usb: dwc2: Enable power down")
> Signed-off-by: Marek Szyprowski 
> ---
>   drivers/usb/dwc2/params.c | 10 +-
>   1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
> index 7c1b6938f212..266157ae179a 100644
> --- a/drivers/usb/dwc2/params.c
> +++ b/drivers/usb/dwc2/params.c
> @@ -71,6 +71,13 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
>   p->power_down = false;
>   }
>   
> +static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
> +{
> + struct dwc2_core_params *p = >params;
> +
> + p->power_down = 0;
> +}
> +
>   static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
>   {
>   struct dwc2_core_params *p = >params;
> @@ -151,7 +158,8 @@ const struct of_device_id dwc2_of_match_table[] = {
>   { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
>   { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
>   { .compatible = "snps,dwc2" },
> - { .compatible = "samsung,s3c6400-hsotg" },
> + { .compatible = "samsung,s3c6400-hsotg",
> +   .data = dwc2_set_s3c6400_params },
>   { .compatible = "amlogic,meson8-usb",
> .data = dwc2_set_amlogic_params },
>   { .compatible = "amlogic,meson8b-usb",
> 

Could you please provide dmesg logs with verbose Debug enabled 
configuration and the register dump.
So that we can see what the issue is related to.

Regards,
Artur


Re: [PATCH] usb: dwc2: Disable power down feature on Samsung SoCs

2018-12-04 Thread Artur Petrosyan
Hi Marek,

On 11/20/2018 19:38, Marek Szyprowski wrote:
> Power down feature of DWC2 module integrated in Samsung SoCs doesn't work
> properly or needs some additional handling in PHY or SoC glue layer, so
> disable it for now. Without disabling power down, DWC2 causes random memory
> trashes and fails enumeration if there is no USB link to host on driver
> probe.
> 
> Fixes: 03ea6d6e9e1ff1 ("usb: dwc2: Enable power down")
> Signed-off-by: Marek Szyprowski 
> ---
>   drivers/usb/dwc2/params.c | 10 +-
>   1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
> index 7c1b6938f212..266157ae179a 100644
> --- a/drivers/usb/dwc2/params.c
> +++ b/drivers/usb/dwc2/params.c
> @@ -71,6 +71,13 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
>   p->power_down = false;
>   }
>   
> +static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
> +{
> + struct dwc2_core_params *p = >params;
> +
> + p->power_down = 0;
> +}
> +
>   static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
>   {
>   struct dwc2_core_params *p = >params;
> @@ -151,7 +158,8 @@ const struct of_device_id dwc2_of_match_table[] = {
>   { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
>   { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
>   { .compatible = "snps,dwc2" },
> - { .compatible = "samsung,s3c6400-hsotg" },
> + { .compatible = "samsung,s3c6400-hsotg",
> +   .data = dwc2_set_s3c6400_params },
>   { .compatible = "amlogic,meson8-usb",
> .data = dwc2_set_amlogic_params },
>   { .compatible = "amlogic,meson8b-usb",
> 

Could you please provide dmesg logs with verbose Debug enabled 
configuration and the register dump.
So that we can see what the issue is related to.

Regards,
Artur


Re: [PATCH] usb: dwc2: Fix HiKey regression caused by power_down feature

2018-09-27 Thread Artur Petrosyan
Hi John,

On 9/25/2018 21:59, John Stultz wrote:
> On Tue, Sep 25, 2018 at 3:04 AM, Artur Petrosyan
>  wrote:
>> Just a clarification by this commit "[PATCH] usb: dwc2: Fix HiKey
>> regression caused by power_down feature"
>> https://urldefense.proofpoint.com/v2/url?u=https-3A__marc.info_-3Fl-3Dlinux-2Dusb-26m-3D152669095513248-26w-3D2=DwIBaQ=DPL6_X_6JkXFx7AXWqB0tg=9hPBFKCJ_nBjJhGVrrlYOeOQjP_HlVzYqrC_D7niMJI=0lMkv7adFVwkzyaUzD6-pUG0iwg4fd6b1-aHQgbqvSI=m8SZvo3J_Za08sMbo-S9EkhoA06YnzEN-SRm-uTPnbg=
>>
>> the power_down is disabled setting "p->power_down = false;" in
>> "dwc2_set_his_params" function.
>>
>> Could you please clarify that the testes done for those 3 patches were
>> done enabling "p->power_down = true;" in "dwc2_set_his_params" function.
> 
> So if I remove the "power_down = true" initialization, USB does not
> seem to function.
> 
> If I boot w/ the gadget port removed, the USB host ports do work, but
> plugging in the gadget cable results in a bunch of:
> dwc2 f72c.usb: Waiting for Host Mode, Mode=Peripheral
> messages.
> 
> If I boot w/ the gadget port plugged in, USB gadget mode doesn't seem
> to function at all, and when I remove the gadget cable nothing
> happens, it doesn't switch to host mode.
> 
> thanks
> -john
> 

We would like to buy the HiKey board to perform testes.
We found this HiKey LeMaker to have USB 2.0 ports
https://www.ebay.com/itm/HiKey-LeMaker-version-2GB-Kirin-620-SoC-8-core-ARM-Cortex-A53-CPU-ARM-Mali-450/263958047308?hash=item3d75202a4c:g:aGsAAOSwOkxbqqot
on ebay.

Could you please confirm that it is the right board to test the issues 
you mention.

Regards,
Artur


Re: [PATCH] usb: dwc2: Fix HiKey regression caused by power_down feature

2018-09-27 Thread Artur Petrosyan
Hi John,

On 9/25/2018 21:59, John Stultz wrote:
> On Tue, Sep 25, 2018 at 3:04 AM, Artur Petrosyan
>  wrote:
>> Just a clarification by this commit "[PATCH] usb: dwc2: Fix HiKey
>> regression caused by power_down feature"
>> https://urldefense.proofpoint.com/v2/url?u=https-3A__marc.info_-3Fl-3Dlinux-2Dusb-26m-3D152669095513248-26w-3D2=DwIBaQ=DPL6_X_6JkXFx7AXWqB0tg=9hPBFKCJ_nBjJhGVrrlYOeOQjP_HlVzYqrC_D7niMJI=0lMkv7adFVwkzyaUzD6-pUG0iwg4fd6b1-aHQgbqvSI=m8SZvo3J_Za08sMbo-S9EkhoA06YnzEN-SRm-uTPnbg=
>>
>> the power_down is disabled setting "p->power_down = false;" in
>> "dwc2_set_his_params" function.
>>
>> Could you please clarify that the testes done for those 3 patches were
>> done enabling "p->power_down = true;" in "dwc2_set_his_params" function.
> 
> So if I remove the "power_down = true" initialization, USB does not
> seem to function.
> 
> If I boot w/ the gadget port removed, the USB host ports do work, but
> plugging in the gadget cable results in a bunch of:
> dwc2 f72c.usb: Waiting for Host Mode, Mode=Peripheral
> messages.
> 
> If I boot w/ the gadget port plugged in, USB gadget mode doesn't seem
> to function at all, and when I remove the gadget cable nothing
> happens, it doesn't switch to host mode.
> 
> thanks
> -john
> 

We would like to buy the HiKey board to perform testes.
We found this HiKey LeMaker to have USB 2.0 ports
https://www.ebay.com/itm/HiKey-LeMaker-version-2GB-Kirin-620-SoC-8-core-ARM-Cortex-A53-CPU-ARM-Mali-450/263958047308?hash=item3d75202a4c:g:aGsAAOSwOkxbqqot
on ebay.

Could you please confirm that it is the right board to test the issues 
you mention.

Regards,
Artur