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 <mvardan@xxxxxxxxxxxx> Signed-off-by: John Youn <johnyoun@xxxxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html