usb: dwc2: Update enter and exit partial power down functions
authorArtur Petrosyan <Arthur.Petrosyan@synopsys.com>
Thu, 8 Apr 2021 09:44:45 +0000 (13:44 +0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 9 Apr 2021 13:16:38 +0000 (15:16 +0200)
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.

Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
Link: https://lore.kernel.org/r/20210408094446.6491BA022E@mailhost.synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hw.h

index fec17a2d2447dd5a863bf37fc940832737501c0c..cb65f7f6057315f71235f6e3b3ff9e4569ecfa2b 100644 (file)
@@ -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 = &hsotg->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;
-               }
-       }
-
-       /*
-        * Clear any pending interrupts since dwc2 will not be able to
-        * clear them after entering partial_power_down.
-        */
-       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
-
-       /* Put the controller in low power state */
-       pcgcctl = dwc2_readl(hsotg, PCGCTL);
-
-       pcgcctl |= PCGCTL_PWRCLMP;
-       dwc2_writel(hsotg, pcgcctl, PCGCTL);
-       ndelay(20);
-
-       pcgcctl |= PCGCTL_RSTPDWNMODULE;
-       dwc2_writel(hsotg, pcgcctl, PCGCTL);
-       ndelay(20);
-
-       pcgcctl |= PCGCTL_STOPPCLK;
-       dwc2_writel(hsotg, pcgcctl, PCGCTL);
-
-       return ret;
+       if (dwc2_is_host_mode(hsotg))
+               return dwc2_host_enter_partial_power_down(hsotg);
+       else
+               return dwc2_gadget_enter_partial_power_down(hsotg);
 }
 
 /**
index 1a97df8bf5cb9f4f05843821fa514e27084d3fa9..39037709a2ad524f0ba4e889b8b89b5370e819b8 100644 (file)
@@ -1303,7 +1303,8 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg)
  */
 int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait);
 int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg);
-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);
 int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host);
 int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
                int reset, int is_host);
index 55f1d14fc4148f0ffe25207aa0f0e90b5396a88e..1fb957ce6c25935be4a011a2227a137042bfb487 100644 (file)
@@ -315,9 +315,10 @@ 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) {
-                       ret = dwc2_exit_partial_power_down(hsotg, true);
-                       if (ret && (ret != -ENOTSUPP))
+               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");
                }
@@ -406,18 +407,16 @@ 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) {
+               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, true);
-                       if (ret && (ret != -ENOTSUPP))
-                               dev_err(hsotg->dev, "exit power_down failed\n");
-
-                       /* Change to L0 state */
-                       hsotg->lx_state = DWC2_L0;
+                       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);
                } else {
                        /* Change to L0 state */
index 98a2a63c67aea80ffb30fb57fd81e0a90368d194..e08baee4987b74befab68316541d70dba8197cdb 100644 (file)
@@ -3689,10 +3689,10 @@ irq_retry:
                dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS);
 
                /* This event must be used only if controller is suspended */
-               if (hsotg->lx_state == DWC2_L2) {
-                       dwc2_exit_partial_power_down(hsotg, true);
-                       hsotg->lx_state = DWC2_L0;
-               }
+               if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2)
+                       dwc2_exit_partial_power_down(hsotg, 0, true);
+
+               hsotg->lx_state = DWC2_L0;
        }
 
        if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
@@ -4615,11 +4615,15 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
        spin_lock_irqsave(&hsotg->lock, flags);
 
        /*
-        * If controller is hibernated, it must exit from power_down
-        * before being initialized / de-initialized
+        * If controller is in partial power down state, it must exit from
+        * that state before being initialized / de-initialized
         */
-       if (hsotg->lx_state == DWC2_L2)
-               dwc2_exit_partial_power_down(hsotg, false);
+       if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd)
+               /*
+                * No need to check the return value as
+                * registers are not being restored.
+                */
+               dwc2_exit_partial_power_down(hsotg, 0, false);
 
        if (is_active) {
                hsotg->op_state = OTG_STATE_B_PERIPHERAL;
index 35e617be4bc3d54693033151fa4967ac1e6df721..dd0362e074442eba07186523ce6014f6e5880c5a 100644 (file)
@@ -4418,7 +4418,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
 
 
                /* Exit partial_power_down */
-               ret = dwc2_exit_partial_power_down(hsotg, true);
+               ret = dwc2_exit_partial_power_down(hsotg, 0, true);
                if (ret && (ret != -ENOTSUPP))
                        dev_err(hsotg->dev, "exit partial_power_down failed\n");
        } else {
index c3d6dde2aca45cd28ae5a67b3a358e9a8e5fa05b..6b16fbf98bc6ec0183147c1325450c018776f634 100644 (file)
@@ -44,6 +44,7 @@
 #define GOTGCTL_CHIRPEN                        BIT(27)
 #define GOTGCTL_MULT_VALID_BC_MASK     (0x1f << 22)
 #define GOTGCTL_MULT_VALID_BC_SHIFT    22
+#define GOTGCTL_CURMODE_HOST           BIT(21)
 #define GOTGCTL_OTGVER                 BIT(20)
 #define GOTGCTL_BSESVLD                        BIT(19)
 #define GOTGCTL_ASESVLD                        BIT(18)