Add common (host/device) helper functions, which will be called while
exiting from hibernation, from both sides.

dwc2_restore_essential_regs()
dwc2_hib_restore_common()

Signed-off-by: Vardan Mikayelyan <mvar...@synopsys.com>
Signed-off-by: John Youn <johny...@synopsys.com>
---
 drivers/usb/dwc2/core.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc2/core.h |   2 +
 2 files changed, 138 insertions(+)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 0e61511..f478cdd 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -239,6 +239,142 @@ int dwc2_enter_partial_power_down(struct dwc2_hsotg 
*hsotg)
 }
 
 /**
+ * dwc2_restore_essential_regs() - Restore essiential regs of core.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rmode: Restore mode, enabled in case of remote-wakeup.
+ */
+static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode)
+{
+       u32 pcgcctl;
+       struct dwc2_gregs_backup *gr;
+       struct dwc2_dregs_backup *dr;
+       struct dwc2_hregs_backup *hr;
+       int is_host = dwc2_is_host_mode(hsotg);
+
+       gr = &hsotg->gr_backup;
+       dr = &hsotg->dr_backup;
+       hr = &hsotg->hr_backup;
+
+       dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__);
+
+       /* Load restore values for [31:14] bits */
+       pcgcctl = (gr->pcgcctl & 0xffffc000) | 0x00020000;
+       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+
+       /* Umnask global Interrupt in GAHBCFG and restore it */
+       dwc2_writel(gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG);
+
+       /* Clear all pending interupts */
+       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+
+       /* Unmask restore done interrupt */
+       dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTMSK);
+
+       /* Restore GUSBCFG and HCFG/DCFG */
+       dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
+
+       if (is_host) {
+               dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
+               if (rmode)
+                       pcgcctl |= 0x200;
+               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               udelay(10);
+
+               pcgcctl = (gr->pcgcctl & 0xffffc000) | 0x00020000;
+               pcgcctl |= PCGCTL_ESS_REG_RESTORED;
+               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               udelay(10);
+       } else {
+               dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
+               if (!rmode)
+                       pcgcctl |= 0x208;
+               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               udelay(10);
+
+               pcgcctl |= PCGCTL_ESS_REG_RESTORED;
+               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               udelay(10);
+       }
+}
+
+/**
+ * dwc2_hib_restore_common() - Common part of restore routine.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup.
+ */
+void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup)
+{
+       u32 gpwrdn;
+       u32 gintsts;
+       int timeout;
+       int is_host = dwc2_is_host_mode(hsotg);
+
+       /* Switch-on voltage to the core */
+       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn &= ~GPWRDN_PWRDNSWTCH;
+       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       udelay(10);
+
+       /* Reset core */
+       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn &= ~GPWRDN_PWRDNRSTN;
+       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       udelay(10);
+
+       /* Enable restore from PMU */
+       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn |= GPWRDN_RESTORE;
+       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       udelay(10);
+
+       /* Disable Power Down Clamp */
+       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn &= ~GPWRDN_PWRDNCLMP;
+       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       udelay(10);
+
+       if (!is_host && rem_wakeup)
+               udelay(70);
+
+       /* Deassert reset core */
+       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn |= GPWRDN_PWRDNRSTN;
+       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       udelay(10);
+
+       /* Disable PMU interrupt */
+       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn &= ~GPWRDN_PMUINTSEL;
+       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+
+       /* Set Restore Essential Regs bit in PCGCCTL register */
+       dwc2_restore_essential_regs(hsotg, rem_wakeup);
+
+       /*
+        * Wait For Restore_done Interrupt. This mechanism of polling the
+        * interrupt is introduced to avoid any possible race conditions
+        */
+       timeout = 2000;
+       do {
+               gintsts = dwc2_readl(hsotg->regs + GINTSTS);
+               if (!(gintsts & GINTSTS_RESTOREDONE)) {
+                       udelay(10);
+                       continue;
+               }
+               dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTSTS);
+               dev_dbg(hsotg->dev,
+                       "%s: restore done generated here timeout = %d\n",
+                       __func__, timeout);
+               break;
+       } while (--timeout);
+
+       if (!timeout)
+               dev_dbg(hsotg->dev, "Restore Done wasn't generated here\n");
+}
+
+/**
  * dwc2_wait_for_mode() - Waits for the controller mode.
  * @hsotg:     Programming view of the DWC_otg controller.
  * @host_mode: If true, waits for host mode, otherwise device mode.
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 31ebdfa..950915b 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1130,6 +1130,8 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg 
*hsotg)
 void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
 void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
 
+void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup);
+
 /* This function should be called on every hardware interrupt. */
 irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to