15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2197ba5f4SPaul Zimmerman /* 3197ba5f4SPaul Zimmerman * core.c - DesignWare HS OTG Controller common routines 4197ba5f4SPaul Zimmerman * 5197ba5f4SPaul Zimmerman * Copyright (C) 2004-2013 Synopsys, Inc. 6197ba5f4SPaul Zimmerman * 7197ba5f4SPaul Zimmerman * Redistribution and use in source and binary forms, with or without 8197ba5f4SPaul Zimmerman * modification, are permitted provided that the following conditions 9197ba5f4SPaul Zimmerman * are met: 10197ba5f4SPaul Zimmerman * 1. Redistributions of source code must retain the above copyright 11197ba5f4SPaul Zimmerman * notice, this list of conditions, and the following disclaimer, 12197ba5f4SPaul Zimmerman * without modification. 13197ba5f4SPaul Zimmerman * 2. Redistributions in binary form must reproduce the above copyright 14197ba5f4SPaul Zimmerman * notice, this list of conditions and the following disclaimer in the 15197ba5f4SPaul Zimmerman * documentation and/or other materials provided with the distribution. 16197ba5f4SPaul Zimmerman * 3. The names of the above-listed copyright holders may not be used 17197ba5f4SPaul Zimmerman * to endorse or promote products derived from this software without 18197ba5f4SPaul Zimmerman * specific prior written permission. 19197ba5f4SPaul Zimmerman * 20197ba5f4SPaul Zimmerman * ALTERNATIVELY, this software may be distributed under the terms of the 21197ba5f4SPaul Zimmerman * GNU General Public License ("GPL") as published by the Free Software 22197ba5f4SPaul Zimmerman * Foundation; either version 2 of the License, or (at your option) any 23197ba5f4SPaul Zimmerman * later version. 24197ba5f4SPaul Zimmerman * 25197ba5f4SPaul Zimmerman * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 26197ba5f4SPaul Zimmerman * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 27197ba5f4SPaul Zimmerman * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28197ba5f4SPaul Zimmerman * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 29197ba5f4SPaul Zimmerman * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30197ba5f4SPaul Zimmerman * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31197ba5f4SPaul Zimmerman * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32197ba5f4SPaul Zimmerman * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33197ba5f4SPaul Zimmerman * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34197ba5f4SPaul Zimmerman * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35197ba5f4SPaul Zimmerman * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36197ba5f4SPaul Zimmerman */ 37197ba5f4SPaul Zimmerman 38197ba5f4SPaul Zimmerman /* 39197ba5f4SPaul Zimmerman * The Core code provides basic services for accessing and managing the 40197ba5f4SPaul Zimmerman * DWC_otg hardware. These services are used by both the Host Controller 41197ba5f4SPaul Zimmerman * Driver and the Peripheral Controller Driver. 42197ba5f4SPaul Zimmerman */ 43197ba5f4SPaul Zimmerman #include <linux/kernel.h> 44197ba5f4SPaul Zimmerman #include <linux/module.h> 45197ba5f4SPaul Zimmerman #include <linux/moduleparam.h> 46197ba5f4SPaul Zimmerman #include <linux/spinlock.h> 47197ba5f4SPaul Zimmerman #include <linux/interrupt.h> 48197ba5f4SPaul Zimmerman #include <linux/dma-mapping.h> 49197ba5f4SPaul Zimmerman #include <linux/delay.h> 50197ba5f4SPaul Zimmerman #include <linux/io.h> 51197ba5f4SPaul Zimmerman #include <linux/slab.h> 52197ba5f4SPaul Zimmerman #include <linux/usb.h> 53197ba5f4SPaul Zimmerman 54197ba5f4SPaul Zimmerman #include <linux/usb/hcd.h> 55197ba5f4SPaul Zimmerman #include <linux/usb/ch11.h> 56197ba5f4SPaul Zimmerman 57197ba5f4SPaul Zimmerman #include "core.h" 58197ba5f4SPaul Zimmerman #include "hcd.h" 59197ba5f4SPaul Zimmerman 60d17ee77bSGregory Herrero /** 61d17ee77bSGregory Herrero * dwc2_backup_global_registers() - Backup global controller registers. 62d17ee77bSGregory Herrero * When suspending usb bus, registers needs to be backuped 63d17ee77bSGregory Herrero * if controller power is disabled once suspended. 64d17ee77bSGregory Herrero * 65d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 66d17ee77bSGregory Herrero */ 67c5c403dcSVardan Mikayelyan int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) 68d17ee77bSGregory Herrero { 69d17ee77bSGregory Herrero struct dwc2_gregs_backup *gr; 70af7c2bd3SVardan Mikayelyan 71af7c2bd3SVardan Mikayelyan dev_dbg(hsotg->dev, "%s\n", __func__); 72d17ee77bSGregory Herrero 73d17ee77bSGregory Herrero /* Backup global regs */ 74cc1e204cSMian Yousaf Kaukab gr = &hsotg->gr_backup; 75d17ee77bSGregory Herrero 7695c8bc36SAntti Seppälä gr->gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); 7795c8bc36SAntti Seppälä gr->gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 7895c8bc36SAntti Seppälä gr->gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG); 7995c8bc36SAntti Seppälä gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 8095c8bc36SAntti Seppälä gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ); 8195c8bc36SAntti Seppälä gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); 8295c8bc36SAntti Seppälä gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG); 83600a490eSRazmik Karapetyan gr->pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1); 8466a36096SVardan Mikayelyan gr->glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG); 8566a36096SVardan Mikayelyan gr->gi2cctl = dwc2_readl(hsotg->regs + GI2CCTL); 8666a36096SVardan Mikayelyan gr->pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); 87d17ee77bSGregory Herrero 88cc1e204cSMian Yousaf Kaukab gr->valid = true; 89d17ee77bSGregory Herrero return 0; 90d17ee77bSGregory Herrero } 91d17ee77bSGregory Herrero 92d17ee77bSGregory Herrero /** 93d17ee77bSGregory Herrero * dwc2_restore_global_registers() - Restore controller global registers. 94d17ee77bSGregory Herrero * When resuming usb bus, device registers needs to be restored 95d17ee77bSGregory Herrero * if controller power were disabled. 96d17ee77bSGregory Herrero * 97d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 98d17ee77bSGregory Herrero */ 99c5c403dcSVardan Mikayelyan int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) 100d17ee77bSGregory Herrero { 101d17ee77bSGregory Herrero struct dwc2_gregs_backup *gr; 102d17ee77bSGregory Herrero 103d17ee77bSGregory Herrero dev_dbg(hsotg->dev, "%s\n", __func__); 104d17ee77bSGregory Herrero 105d17ee77bSGregory Herrero /* Restore global regs */ 106cc1e204cSMian Yousaf Kaukab gr = &hsotg->gr_backup; 107cc1e204cSMian Yousaf Kaukab if (!gr->valid) { 108d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: no global registers to restore\n", 109d17ee77bSGregory Herrero __func__); 110d17ee77bSGregory Herrero return -EINVAL; 111d17ee77bSGregory Herrero } 112cc1e204cSMian Yousaf Kaukab gr->valid = false; 113d17ee77bSGregory Herrero 11495c8bc36SAntti Seppälä dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 11595c8bc36SAntti Seppälä dwc2_writel(gr->gotgctl, hsotg->regs + GOTGCTL); 11695c8bc36SAntti Seppälä dwc2_writel(gr->gintmsk, hsotg->regs + GINTMSK); 11795c8bc36SAntti Seppälä dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG); 11895c8bc36SAntti Seppälä dwc2_writel(gr->gahbcfg, hsotg->regs + GAHBCFG); 11995c8bc36SAntti Seppälä dwc2_writel(gr->grxfsiz, hsotg->regs + GRXFSIZ); 12095c8bc36SAntti Seppälä dwc2_writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ); 12195c8bc36SAntti Seppälä dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG); 122600a490eSRazmik Karapetyan dwc2_writel(gr->pcgcctl1, hsotg->regs + PCGCCTL1); 12366a36096SVardan Mikayelyan dwc2_writel(gr->glpmcfg, hsotg->regs + GLPMCFG); 12466a36096SVardan Mikayelyan dwc2_writel(gr->pcgcctl, hsotg->regs + PCGCTL); 12566a36096SVardan Mikayelyan dwc2_writel(gr->gi2cctl, hsotg->regs + GI2CCTL); 126d17ee77bSGregory Herrero 127d17ee77bSGregory Herrero return 0; 128d17ee77bSGregory Herrero } 129d17ee77bSGregory Herrero 130d17ee77bSGregory Herrero /** 13141ba9b9bSVardan Mikayelyan * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. 132d17ee77bSGregory Herrero * 133d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 134d17ee77bSGregory Herrero * @restore: Controller registers need to be restored 135d17ee77bSGregory Herrero */ 13641ba9b9bSVardan Mikayelyan int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) 137d17ee77bSGregory Herrero { 138d17ee77bSGregory Herrero u32 pcgcctl; 139d17ee77bSGregory Herrero int ret = 0; 140d17ee77bSGregory Herrero 141631a2310SVardan Mikayelyan if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) 142285046aaSGregory Herrero return -ENOTSUPP; 143285046aaSGregory Herrero 14495c8bc36SAntti Seppälä pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); 145d17ee77bSGregory Herrero pcgcctl &= ~PCGCTL_STOPPCLK; 14695c8bc36SAntti Seppälä dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 147d17ee77bSGregory Herrero 14895c8bc36SAntti Seppälä pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); 149d17ee77bSGregory Herrero pcgcctl &= ~PCGCTL_PWRCLMP; 15095c8bc36SAntti Seppälä dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 151d17ee77bSGregory Herrero 15295c8bc36SAntti Seppälä pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); 153d17ee77bSGregory Herrero pcgcctl &= ~PCGCTL_RSTPDWNMODULE; 15495c8bc36SAntti Seppälä dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 155d17ee77bSGregory Herrero 156d17ee77bSGregory Herrero udelay(100); 157d17ee77bSGregory Herrero if (restore) { 158d17ee77bSGregory Herrero ret = dwc2_restore_global_registers(hsotg); 159d17ee77bSGregory Herrero if (ret) { 160d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: failed to restore registers\n", 161d17ee77bSGregory Herrero __func__); 162d17ee77bSGregory Herrero return ret; 163d17ee77bSGregory Herrero } 164d17ee77bSGregory Herrero if (dwc2_is_host_mode(hsotg)) { 165d17ee77bSGregory Herrero ret = dwc2_restore_host_registers(hsotg); 166d17ee77bSGregory Herrero if (ret) { 167d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: failed to restore host registers\n", 168d17ee77bSGregory Herrero __func__); 169d17ee77bSGregory Herrero return ret; 170d17ee77bSGregory Herrero } 171d17ee77bSGregory Herrero } else { 1729a5d2816SVardan Mikayelyan ret = dwc2_restore_device_registers(hsotg, 0); 173d17ee77bSGregory Herrero if (ret) { 174d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: failed to restore device registers\n", 175d17ee77bSGregory Herrero __func__); 176d17ee77bSGregory Herrero return ret; 177d17ee77bSGregory Herrero } 178d17ee77bSGregory Herrero } 179d17ee77bSGregory Herrero } 180d17ee77bSGregory Herrero 181d17ee77bSGregory Herrero return ret; 182d17ee77bSGregory Herrero } 183d17ee77bSGregory Herrero 184d17ee77bSGregory Herrero /** 18541ba9b9bSVardan Mikayelyan * dwc2_enter_partial_power_down() - Put controller in Partial Power Down. 186d17ee77bSGregory Herrero * 187d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 188d17ee77bSGregory Herrero */ 18941ba9b9bSVardan Mikayelyan int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) 190d17ee77bSGregory Herrero { 191d17ee77bSGregory Herrero u32 pcgcctl; 192d17ee77bSGregory Herrero int ret = 0; 193d17ee77bSGregory Herrero 19441ba9b9bSVardan Mikayelyan if (!hsotg->params.power_down) 195285046aaSGregory Herrero return -ENOTSUPP; 196285046aaSGregory Herrero 197d17ee77bSGregory Herrero /* Backup all registers */ 198d17ee77bSGregory Herrero ret = dwc2_backup_global_registers(hsotg); 199d17ee77bSGregory Herrero if (ret) { 200d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: failed to backup global registers\n", 201d17ee77bSGregory Herrero __func__); 202d17ee77bSGregory Herrero return ret; 203d17ee77bSGregory Herrero } 204d17ee77bSGregory Herrero 205d17ee77bSGregory Herrero if (dwc2_is_host_mode(hsotg)) { 206d17ee77bSGregory Herrero ret = dwc2_backup_host_registers(hsotg); 207d17ee77bSGregory Herrero if (ret) { 208d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: failed to backup host registers\n", 209d17ee77bSGregory Herrero __func__); 210d17ee77bSGregory Herrero return ret; 211d17ee77bSGregory Herrero } 212d17ee77bSGregory Herrero } else { 213d17ee77bSGregory Herrero ret = dwc2_backup_device_registers(hsotg); 214d17ee77bSGregory Herrero if (ret) { 215d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: failed to backup device registers\n", 216d17ee77bSGregory Herrero __func__); 217d17ee77bSGregory Herrero return ret; 218d17ee77bSGregory Herrero } 219d17ee77bSGregory Herrero } 220d17ee77bSGregory Herrero 221cad73da2SGregory Herrero /* 222cad73da2SGregory Herrero * Clear any pending interrupts since dwc2 will not be able to 22341ba9b9bSVardan Mikayelyan * clear them after entering partial_power_down. 224cad73da2SGregory Herrero */ 225cad73da2SGregory Herrero dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 226cad73da2SGregory Herrero 227d17ee77bSGregory Herrero /* Put the controller in low power state */ 22895c8bc36SAntti Seppälä pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); 229d17ee77bSGregory Herrero 230d17ee77bSGregory Herrero pcgcctl |= PCGCTL_PWRCLMP; 23195c8bc36SAntti Seppälä dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 232d17ee77bSGregory Herrero ndelay(20); 233d17ee77bSGregory Herrero 234d17ee77bSGregory Herrero pcgcctl |= PCGCTL_RSTPDWNMODULE; 23595c8bc36SAntti Seppälä dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 236d17ee77bSGregory Herrero ndelay(20); 237d17ee77bSGregory Herrero 238d17ee77bSGregory Herrero pcgcctl |= PCGCTL_STOPPCLK; 23995c8bc36SAntti Seppälä dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 240d17ee77bSGregory Herrero 241d17ee77bSGregory Herrero return ret; 242d17ee77bSGregory Herrero } 243d17ee77bSGregory Herrero 244fef6bc37SJohn Youn /** 24594d2666cSVardan Mikayelyan * dwc2_restore_essential_regs() - Restore essiential regs of core. 24694d2666cSVardan Mikayelyan * 24794d2666cSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 24894d2666cSVardan Mikayelyan * @rmode: Restore mode, enabled in case of remote-wakeup. 24994d2666cSVardan Mikayelyan * @is_host: Host or device mode. 25094d2666cSVardan Mikayelyan */ 25194d2666cSVardan Mikayelyan static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode, 25294d2666cSVardan Mikayelyan int is_host) 25394d2666cSVardan Mikayelyan { 25494d2666cSVardan Mikayelyan u32 pcgcctl; 25594d2666cSVardan Mikayelyan struct dwc2_gregs_backup *gr; 25694d2666cSVardan Mikayelyan struct dwc2_dregs_backup *dr; 25794d2666cSVardan Mikayelyan struct dwc2_hregs_backup *hr; 25894d2666cSVardan Mikayelyan 25994d2666cSVardan Mikayelyan gr = &hsotg->gr_backup; 26094d2666cSVardan Mikayelyan dr = &hsotg->dr_backup; 26194d2666cSVardan Mikayelyan hr = &hsotg->hr_backup; 26294d2666cSVardan Mikayelyan 26394d2666cSVardan Mikayelyan dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__); 26494d2666cSVardan Mikayelyan 26594d2666cSVardan Mikayelyan /* Load restore values for [31:14] bits */ 26694d2666cSVardan Mikayelyan pcgcctl = (gr->pcgcctl & 0xffffc000); 26794d2666cSVardan Mikayelyan /* If High Speed */ 26894d2666cSVardan Mikayelyan if (is_host) { 26994d2666cSVardan Mikayelyan if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK)) 27094d2666cSVardan Mikayelyan pcgcctl |= BIT(17); 27194d2666cSVardan Mikayelyan } else { 27294d2666cSVardan Mikayelyan if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK)) 27394d2666cSVardan Mikayelyan pcgcctl |= BIT(17); 27494d2666cSVardan Mikayelyan } 27594d2666cSVardan Mikayelyan dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 27694d2666cSVardan Mikayelyan 27794d2666cSVardan Mikayelyan /* Umnask global Interrupt in GAHBCFG and restore it */ 27894d2666cSVardan Mikayelyan dwc2_writel(gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG); 27994d2666cSVardan Mikayelyan 28094d2666cSVardan Mikayelyan /* Clear all pending interupts */ 28194d2666cSVardan Mikayelyan dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); 28294d2666cSVardan Mikayelyan 28394d2666cSVardan Mikayelyan /* Unmask restore done interrupt */ 28494d2666cSVardan Mikayelyan dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTMSK); 28594d2666cSVardan Mikayelyan 28694d2666cSVardan Mikayelyan /* Restore GUSBCFG and HCFG/DCFG */ 28794d2666cSVardan Mikayelyan dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG); 28894d2666cSVardan Mikayelyan 28994d2666cSVardan Mikayelyan if (is_host) { 29094d2666cSVardan Mikayelyan dwc2_writel(hr->hcfg, hsotg->regs + HCFG); 29194d2666cSVardan Mikayelyan if (rmode) 29294d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_RESTOREMODE; 29394d2666cSVardan Mikayelyan dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 29494d2666cSVardan Mikayelyan udelay(10); 29594d2666cSVardan Mikayelyan 29694d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_ESS_REG_RESTORED; 29794d2666cSVardan Mikayelyan dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 29894d2666cSVardan Mikayelyan udelay(10); 29994d2666cSVardan Mikayelyan } else { 30094d2666cSVardan Mikayelyan dwc2_writel(dr->dcfg, hsotg->regs + DCFG); 30194d2666cSVardan Mikayelyan if (!rmode) 30294d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE; 30394d2666cSVardan Mikayelyan dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 30494d2666cSVardan Mikayelyan udelay(10); 30594d2666cSVardan Mikayelyan 30694d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_ESS_REG_RESTORED; 30794d2666cSVardan Mikayelyan dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); 30894d2666cSVardan Mikayelyan udelay(10); 30994d2666cSVardan Mikayelyan } 31094d2666cSVardan Mikayelyan } 31194d2666cSVardan Mikayelyan 31294d2666cSVardan Mikayelyan /** 31394d2666cSVardan Mikayelyan * dwc2_hib_restore_common() - Common part of restore routine. 31494d2666cSVardan Mikayelyan * 31594d2666cSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 31694d2666cSVardan Mikayelyan * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 31794d2666cSVardan Mikayelyan * @is_host: Host or device mode. 31894d2666cSVardan Mikayelyan */ 31994d2666cSVardan Mikayelyan void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, 32094d2666cSVardan Mikayelyan int is_host) 32194d2666cSVardan Mikayelyan { 32294d2666cSVardan Mikayelyan u32 gpwrdn; 32394d2666cSVardan Mikayelyan 32494d2666cSVardan Mikayelyan /* Switch-on voltage to the core */ 32594d2666cSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 32694d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PWRDNSWTCH; 32794d2666cSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 32894d2666cSVardan Mikayelyan udelay(10); 32994d2666cSVardan Mikayelyan 33094d2666cSVardan Mikayelyan /* Reset core */ 33194d2666cSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 33294d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PWRDNRSTN; 33394d2666cSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 33494d2666cSVardan Mikayelyan udelay(10); 33594d2666cSVardan Mikayelyan 33694d2666cSVardan Mikayelyan /* Enable restore from PMU */ 33794d2666cSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 33894d2666cSVardan Mikayelyan gpwrdn |= GPWRDN_RESTORE; 33994d2666cSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 34094d2666cSVardan Mikayelyan udelay(10); 34194d2666cSVardan Mikayelyan 34294d2666cSVardan Mikayelyan /* Disable Power Down Clamp */ 34394d2666cSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 34494d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PWRDNCLMP; 34594d2666cSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 34694d2666cSVardan Mikayelyan udelay(50); 34794d2666cSVardan Mikayelyan 34894d2666cSVardan Mikayelyan if (!is_host && rem_wakeup) 34994d2666cSVardan Mikayelyan udelay(70); 35094d2666cSVardan Mikayelyan 35194d2666cSVardan Mikayelyan /* Deassert reset core */ 35294d2666cSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 35394d2666cSVardan Mikayelyan gpwrdn |= GPWRDN_PWRDNRSTN; 35494d2666cSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 35594d2666cSVardan Mikayelyan udelay(10); 35694d2666cSVardan Mikayelyan 35794d2666cSVardan Mikayelyan /* Disable PMU interrupt */ 35894d2666cSVardan Mikayelyan gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); 35994d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PMUINTSEL; 36094d2666cSVardan Mikayelyan dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); 36194d2666cSVardan Mikayelyan udelay(10); 36294d2666cSVardan Mikayelyan 36394d2666cSVardan Mikayelyan /* Set Restore Essential Regs bit in PCGCCTL register */ 36494d2666cSVardan Mikayelyan dwc2_restore_essential_regs(hsotg, rem_wakeup, is_host); 36594d2666cSVardan Mikayelyan 36694d2666cSVardan Mikayelyan /* 36794d2666cSVardan Mikayelyan * Wait For Restore_done Interrupt. This mechanism of polling the 36894d2666cSVardan Mikayelyan * interrupt is introduced to avoid any possible race conditions 36994d2666cSVardan Mikayelyan */ 37094d2666cSVardan Mikayelyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE, 37194d2666cSVardan Mikayelyan 20000)) { 37294d2666cSVardan Mikayelyan dev_dbg(hsotg->dev, 37394d2666cSVardan Mikayelyan "%s: Restore Done wan't generated here\n", 37494d2666cSVardan Mikayelyan __func__); 37594d2666cSVardan Mikayelyan } else { 37694d2666cSVardan Mikayelyan dev_dbg(hsotg->dev, "restore done generated here\n"); 37794d2666cSVardan Mikayelyan } 37894d2666cSVardan Mikayelyan } 37994d2666cSVardan Mikayelyan 38094d2666cSVardan Mikayelyan /** 381fef6bc37SJohn Youn * dwc2_wait_for_mode() - Waits for the controller mode. 382fef6bc37SJohn Youn * @hsotg: Programming view of the DWC_otg controller. 383fef6bc37SJohn Youn * @host_mode: If true, waits for host mode, otherwise device mode. 384fef6bc37SJohn Youn */ 385fef6bc37SJohn Youn static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg, 386fef6bc37SJohn Youn bool host_mode) 387fef6bc37SJohn Youn { 388fef6bc37SJohn Youn ktime_t start; 389fef6bc37SJohn Youn ktime_t end; 390fef6bc37SJohn Youn unsigned int timeout = 110; 391fef6bc37SJohn Youn 392fef6bc37SJohn Youn dev_vdbg(hsotg->dev, "Waiting for %s mode\n", 393fef6bc37SJohn Youn host_mode ? "host" : "device"); 394fef6bc37SJohn Youn 395fef6bc37SJohn Youn start = ktime_get(); 396fef6bc37SJohn Youn 397fef6bc37SJohn Youn while (1) { 398fef6bc37SJohn Youn s64 ms; 399fef6bc37SJohn Youn 400fef6bc37SJohn Youn if (dwc2_is_host_mode(hsotg) == host_mode) { 401fef6bc37SJohn Youn dev_vdbg(hsotg->dev, "%s mode set\n", 402fef6bc37SJohn Youn host_mode ? "Host" : "Device"); 403fef6bc37SJohn Youn break; 404fef6bc37SJohn Youn } 405fef6bc37SJohn Youn 406fef6bc37SJohn Youn end = ktime_get(); 407fef6bc37SJohn Youn ms = ktime_to_ms(ktime_sub(end, start)); 408fef6bc37SJohn Youn 409fef6bc37SJohn Youn if (ms >= (s64)timeout) { 410fef6bc37SJohn Youn dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n", 411fef6bc37SJohn Youn __func__, host_mode ? "host" : "device"); 412fef6bc37SJohn Youn break; 413fef6bc37SJohn Youn } 414fef6bc37SJohn Youn 415fef6bc37SJohn Youn usleep_range(1000, 2000); 416fef6bc37SJohn Youn } 417fef6bc37SJohn Youn } 418fef6bc37SJohn Youn 419fef6bc37SJohn Youn /** 420fef6bc37SJohn Youn * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce 421fef6bc37SJohn Youn * filter is enabled. 422fef6bc37SJohn Youn */ 423fef6bc37SJohn Youn static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) 424fef6bc37SJohn Youn { 425fef6bc37SJohn Youn u32 gsnpsid; 426fef6bc37SJohn Youn u32 ghwcfg4; 427fef6bc37SJohn Youn 428fef6bc37SJohn Youn if (!dwc2_hw_is_otg(hsotg)) 429fef6bc37SJohn Youn return false; 430fef6bc37SJohn Youn 431fef6bc37SJohn Youn /* Check if core configuration includes the IDDIG filter. */ 432fef6bc37SJohn Youn ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4); 433fef6bc37SJohn Youn if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN)) 434fef6bc37SJohn Youn return false; 435fef6bc37SJohn Youn 436fef6bc37SJohn Youn /* 437fef6bc37SJohn Youn * Check if the IDDIG debounce filter is bypassed. Available 438fef6bc37SJohn Youn * in core version >= 3.10a. 439fef6bc37SJohn Youn */ 440fef6bc37SJohn Youn gsnpsid = dwc2_readl(hsotg->regs + GSNPSID); 441fef6bc37SJohn Youn if (gsnpsid >= DWC2_CORE_REV_3_10a) { 442fef6bc37SJohn Youn u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); 443fef6bc37SJohn Youn 444fef6bc37SJohn Youn if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS) 445fef6bc37SJohn Youn return false; 446fef6bc37SJohn Youn } 447fef6bc37SJohn Youn 448fef6bc37SJohn Youn return true; 449fef6bc37SJohn Youn } 450fef6bc37SJohn Youn 451197ba5f4SPaul Zimmerman /* 452624815ceSVardan Mikayelyan * dwc2_enter_hibernation() - Common function to enter hibernation. 453624815ceSVardan Mikayelyan * 454624815ceSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 455624815ceSVardan Mikayelyan * @is_host: True if core is in host mode. 456624815ceSVardan Mikayelyan * 457624815ceSVardan Mikayelyan * Return: 0 if successful, negative error code otherwise 458624815ceSVardan Mikayelyan */ 459624815ceSVardan Mikayelyan int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host) 460624815ceSVardan Mikayelyan { 461624815ceSVardan Mikayelyan if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION) 462624815ceSVardan Mikayelyan return -ENOTSUPP; 463624815ceSVardan Mikayelyan 464624815ceSVardan Mikayelyan if (is_host) 465624815ceSVardan Mikayelyan return dwc2_host_enter_hibernation(hsotg); 466624815ceSVardan Mikayelyan else 467624815ceSVardan Mikayelyan return dwc2_gadget_enter_hibernation(hsotg); 468624815ceSVardan Mikayelyan } 469624815ceSVardan Mikayelyan 470624815ceSVardan Mikayelyan /* 471624815ceSVardan Mikayelyan * dwc2_exit_hibernation() - Common function to exit from hibernation. 472624815ceSVardan Mikayelyan * 473624815ceSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 474624815ceSVardan Mikayelyan * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 475624815ceSVardan Mikayelyan * @reset: Enabled in case of restore with reset. 476624815ceSVardan Mikayelyan * @is_host: True if core is in host mode. 477624815ceSVardan Mikayelyan * 478624815ceSVardan Mikayelyan * Return: 0 if successful, negative error code otherwise 479624815ceSVardan Mikayelyan */ 480624815ceSVardan Mikayelyan int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, 481624815ceSVardan Mikayelyan int reset, int is_host) 482624815ceSVardan Mikayelyan { 483624815ceSVardan Mikayelyan if (is_host) 484624815ceSVardan Mikayelyan return dwc2_host_exit_hibernation(hsotg, rem_wakeup, reset); 485624815ceSVardan Mikayelyan else 486624815ceSVardan Mikayelyan return dwc2_gadget_exit_hibernation(hsotg, rem_wakeup, reset); 487624815ceSVardan Mikayelyan } 488624815ceSVardan Mikayelyan 489624815ceSVardan Mikayelyan /* 490197ba5f4SPaul Zimmerman * Do core a soft reset of the core. Be careful with this because it 491197ba5f4SPaul Zimmerman * resets all the internal state machines of the core. 492197ba5f4SPaul Zimmerman */ 4936e6360b6SJohn Stultz int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) 494197ba5f4SPaul Zimmerman { 495197ba5f4SPaul Zimmerman u32 greset; 496fef6bc37SJohn Youn bool wait_for_host_mode = false; 497197ba5f4SPaul Zimmerman 498197ba5f4SPaul Zimmerman dev_vdbg(hsotg->dev, "%s()\n", __func__); 499197ba5f4SPaul Zimmerman 500fef6bc37SJohn Youn /* 501fef6bc37SJohn Youn * If the current mode is host, either due to the force mode 502fef6bc37SJohn Youn * bit being set (which persists after core reset) or the 503fef6bc37SJohn Youn * connector id pin, a core soft reset will temporarily reset 504fef6bc37SJohn Youn * the mode to device. A delay from the IDDIG debounce filter 505fef6bc37SJohn Youn * will occur before going back to host mode. 506fef6bc37SJohn Youn * 507fef6bc37SJohn Youn * Determine whether we will go back into host mode after a 508fef6bc37SJohn Youn * reset and account for this delay after the reset. 509fef6bc37SJohn Youn */ 510fef6bc37SJohn Youn if (dwc2_iddig_filter_enabled(hsotg)) { 511fef6bc37SJohn Youn u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); 512fef6bc37SJohn Youn u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 513fef6bc37SJohn Youn 514fef6bc37SJohn Youn if (!(gotgctl & GOTGCTL_CONID_B) || 515fef6bc37SJohn Youn (gusbcfg & GUSBCFG_FORCEHOSTMODE)) { 516fef6bc37SJohn Youn wait_for_host_mode = true; 517fef6bc37SJohn Youn } 518fef6bc37SJohn Youn } 519fef6bc37SJohn Youn 520197ba5f4SPaul Zimmerman /* Core Soft Reset */ 521b8ccc593SJohn Youn greset = dwc2_readl(hsotg->regs + GRSTCTL); 522197ba5f4SPaul Zimmerman greset |= GRSTCTL_CSFTRST; 52395c8bc36SAntti Seppälä dwc2_writel(greset, hsotg->regs + GRSTCTL); 52479d6b8c5SSevak Arakelyan 52579d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) { 52679d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n", 52779d6b8c5SSevak Arakelyan __func__); 528197ba5f4SPaul Zimmerman return -EBUSY; 529197ba5f4SPaul Zimmerman } 530197ba5f4SPaul Zimmerman 531b8ccc593SJohn Youn /* Wait for AHB master IDLE state */ 53279d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) { 53379d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n", 53479d6b8c5SSevak Arakelyan __func__); 535b8ccc593SJohn Youn return -EBUSY; 536b8ccc593SJohn Youn } 537b8ccc593SJohn Youn 5386e6360b6SJohn Stultz if (wait_for_host_mode && !skip_wait) 539fef6bc37SJohn Youn dwc2_wait_for_mode(hsotg, true); 540fef6bc37SJohn Youn 541b5d308abSJohn Youn return 0; 542b5d308abSJohn Youn } 543b5d308abSJohn Youn 54413b1f8e2SVardan Mikayelyan /** 54513b1f8e2SVardan Mikayelyan * dwc2_force_mode() - Force the mode of the controller. 54609c96980SJohn Youn * 54709c96980SJohn Youn * Forcing the mode is needed for two cases: 54809c96980SJohn Youn * 54909c96980SJohn Youn * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the 55009c96980SJohn Youn * controller to stay in a particular mode regardless of ID pin 55113b1f8e2SVardan Mikayelyan * changes. We do this once during probe. 55209c96980SJohn Youn * 55309c96980SJohn Youn * 2) During probe we want to read reset values of the hw 55409c96980SJohn Youn * configuration registers that are only available in either host or 55509c96980SJohn Youn * device mode. We may need to force the mode if the current mode does 55609c96980SJohn Youn * not allow us to access the register in the mode that we want. 55709c96980SJohn Youn * 55809c96980SJohn Youn * In either case it only makes sense to force the mode if the 55909c96980SJohn Youn * controller hardware is OTG capable. 56009c96980SJohn Youn * 56109c96980SJohn Youn * Checks are done in this function to determine whether doing a force 56209c96980SJohn Youn * would be valid or not. 56309c96980SJohn Youn * 5642938fc63SJohn Youn * If a force is done, it requires a IDDIG debounce filter delay if 5652938fc63SJohn Youn * the filter is configured and enabled. We poll the current mode of 5662938fc63SJohn Youn * the controller to account for this delay. 56709c96980SJohn Youn */ 56813b1f8e2SVardan Mikayelyan void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) 56909c96980SJohn Youn { 57009c96980SJohn Youn u32 gusbcfg; 57109c96980SJohn Youn u32 set; 57209c96980SJohn Youn u32 clear; 57309c96980SJohn Youn 57409c96980SJohn Youn dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device"); 57509c96980SJohn Youn 57609c96980SJohn Youn /* 57709c96980SJohn Youn * Force mode has no effect if the hardware is not OTG. 57809c96980SJohn Youn */ 57909c96980SJohn Youn if (!dwc2_hw_is_otg(hsotg)) 58013b1f8e2SVardan Mikayelyan return; 58109c96980SJohn Youn 58209c96980SJohn Youn /* 58309c96980SJohn Youn * If dr_mode is either peripheral or host only, there is no 58409c96980SJohn Youn * need to ever force the mode to the opposite mode. 58509c96980SJohn Youn */ 58609c96980SJohn Youn if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) 58713b1f8e2SVardan Mikayelyan return; 58809c96980SJohn Youn 58909c96980SJohn Youn if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST)) 59013b1f8e2SVardan Mikayelyan return; 59109c96980SJohn Youn 59209c96980SJohn Youn gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 59309c96980SJohn Youn 59409c96980SJohn Youn set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE; 59509c96980SJohn Youn clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE; 59609c96980SJohn Youn 59709c96980SJohn Youn gusbcfg &= ~clear; 59809c96980SJohn Youn gusbcfg |= set; 59909c96980SJohn Youn dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); 60009c96980SJohn Youn 6012938fc63SJohn Youn dwc2_wait_for_mode(hsotg, host); 60213b1f8e2SVardan Mikayelyan return; 60309c96980SJohn Youn } 60409c96980SJohn Youn 6052938fc63SJohn Youn /** 6062938fc63SJohn Youn * dwc2_clear_force_mode() - Clears the force mode bits. 6072938fc63SJohn Youn * 6082938fc63SJohn Youn * After clearing the bits, wait up to 100 ms to account for any 6092938fc63SJohn Youn * potential IDDIG filter delay. We can't know if we expect this delay 6102938fc63SJohn Youn * or not because the value of the connector ID status is affected by 6112938fc63SJohn Youn * the force mode. We only need to call this once during probe if 6122938fc63SJohn Youn * dr_mode == OTG. 61309c96980SJohn Youn */ 614*365b7673SGrigor Tovmasyan static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) 61509c96980SJohn Youn { 61609c96980SJohn Youn u32 gusbcfg; 61709c96980SJohn Youn 61813b1f8e2SVardan Mikayelyan if (!dwc2_hw_is_otg(hsotg)) 61913b1f8e2SVardan Mikayelyan return; 62013b1f8e2SVardan Mikayelyan 62113b1f8e2SVardan Mikayelyan dev_dbg(hsotg->dev, "Clearing force mode bits\n"); 62213b1f8e2SVardan Mikayelyan 62309c96980SJohn Youn gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); 62409c96980SJohn Youn gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; 62509c96980SJohn Youn gusbcfg &= ~GUSBCFG_FORCEDEVMODE; 62609c96980SJohn Youn dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); 62709c96980SJohn Youn 6282938fc63SJohn Youn if (dwc2_iddig_filter_enabled(hsotg)) 629d3fe81d2SNicholas Mc Guire msleep(100); 63009c96980SJohn Youn } 63109c96980SJohn Youn 63209c96980SJohn Youn /* 63309c96980SJohn Youn * Sets or clears force mode based on the dr_mode parameter. 63409c96980SJohn Youn */ 63509c96980SJohn Youn void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) 63609c96980SJohn Youn { 63709c96980SJohn Youn switch (hsotg->dr_mode) { 63809c96980SJohn Youn case USB_DR_MODE_HOST: 639a07ce8d3SHeiko Stuebner /* 640a07ce8d3SHeiko Stuebner * NOTE: This is required for some rockchip soc based 641a07ce8d3SHeiko Stuebner * platforms on their host-only dwc2. 642a07ce8d3SHeiko Stuebner */ 64313b1f8e2SVardan Mikayelyan if (!dwc2_hw_is_otg(hsotg)) 644a07ce8d3SHeiko Stuebner msleep(50); 645a07ce8d3SHeiko Stuebner 64609c96980SJohn Youn break; 64709c96980SJohn Youn case USB_DR_MODE_PERIPHERAL: 64809c96980SJohn Youn dwc2_force_mode(hsotg, false); 64909c96980SJohn Youn break; 65009c96980SJohn Youn case USB_DR_MODE_OTG: 65109c96980SJohn Youn dwc2_clear_force_mode(hsotg); 65209c96980SJohn Youn break; 65309c96980SJohn Youn default: 65409c96980SJohn Youn dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n", 65509c96980SJohn Youn __func__, hsotg->dr_mode); 65609c96980SJohn Youn break; 65709c96980SJohn Youn } 65809c96980SJohn Youn } 65909c96980SJohn Youn 66009c96980SJohn Youn /* 66166e77a24SRazmik Karapetyan * dwc2_enable_acg - enable active clock gating feature 66266e77a24SRazmik Karapetyan */ 66366e77a24SRazmik Karapetyan void dwc2_enable_acg(struct dwc2_hsotg *hsotg) 66466e77a24SRazmik Karapetyan { 66566e77a24SRazmik Karapetyan if (hsotg->params.acg_enable) { 66666e77a24SRazmik Karapetyan u32 pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1); 66766e77a24SRazmik Karapetyan 66866e77a24SRazmik Karapetyan dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n"); 66966e77a24SRazmik Karapetyan pcgcctl1 |= PCGCCTL1_GATEEN; 67066e77a24SRazmik Karapetyan dwc2_writel(pcgcctl1, hsotg->regs + PCGCCTL1); 67166e77a24SRazmik Karapetyan } 67266e77a24SRazmik Karapetyan } 67366e77a24SRazmik Karapetyan 674197ba5f4SPaul Zimmerman /** 675197ba5f4SPaul Zimmerman * dwc2_dump_host_registers() - Prints the host registers 676197ba5f4SPaul Zimmerman * 677197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 678197ba5f4SPaul Zimmerman * 679197ba5f4SPaul Zimmerman * NOTE: This function will be removed once the peripheral controller code 680197ba5f4SPaul Zimmerman * is integrated and the driver is stable 681197ba5f4SPaul Zimmerman */ 682197ba5f4SPaul Zimmerman void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) 683197ba5f4SPaul Zimmerman { 684197ba5f4SPaul Zimmerman #ifdef DEBUG 685197ba5f4SPaul Zimmerman u32 __iomem *addr; 686197ba5f4SPaul Zimmerman int i; 687197ba5f4SPaul Zimmerman 688197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "Host Global Registers\n"); 689197ba5f4SPaul Zimmerman addr = hsotg->regs + HCFG; 690197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n", 69195c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 692197ba5f4SPaul Zimmerman addr = hsotg->regs + HFIR; 693197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n", 69495c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 695197ba5f4SPaul Zimmerman addr = hsotg->regs + HFNUM; 696197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n", 69795c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 698197ba5f4SPaul Zimmerman addr = hsotg->regs + HPTXSTS; 699197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n", 70095c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 701197ba5f4SPaul Zimmerman addr = hsotg->regs + HAINT; 702197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n", 70395c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 704197ba5f4SPaul Zimmerman addr = hsotg->regs + HAINTMSK; 705197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n", 70695c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 70795832c00SJohn Youn if (hsotg->params.dma_desc_enable) { 708197ba5f4SPaul Zimmerman addr = hsotg->regs + HFLBADDR; 709197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", 71095c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 711197ba5f4SPaul Zimmerman } 712197ba5f4SPaul Zimmerman 713197ba5f4SPaul Zimmerman addr = hsotg->regs + HPRT0; 714197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n", 71595c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 716197ba5f4SPaul Zimmerman 717bea8e86cSJohn Youn for (i = 0; i < hsotg->params.host_channels; i++) { 718197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i); 719197ba5f4SPaul Zimmerman addr = hsotg->regs + HCCHAR(i); 720197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n", 72195c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 722197ba5f4SPaul Zimmerman addr = hsotg->regs + HCSPLT(i); 723197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n", 72495c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 725197ba5f4SPaul Zimmerman addr = hsotg->regs + HCINT(i); 726197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n", 72795c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 728197ba5f4SPaul Zimmerman addr = hsotg->regs + HCINTMSK(i); 729197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n", 73095c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 731197ba5f4SPaul Zimmerman addr = hsotg->regs + HCTSIZ(i); 732197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n", 73395c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 734197ba5f4SPaul Zimmerman addr = hsotg->regs + HCDMA(i); 735197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n", 73695c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 73795832c00SJohn Youn if (hsotg->params.dma_desc_enable) { 738197ba5f4SPaul Zimmerman addr = hsotg->regs + HCDMAB(i); 739197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n", 74095c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 741197ba5f4SPaul Zimmerman } 742197ba5f4SPaul Zimmerman } 743197ba5f4SPaul Zimmerman #endif 744197ba5f4SPaul Zimmerman } 745197ba5f4SPaul Zimmerman 746197ba5f4SPaul Zimmerman /** 747197ba5f4SPaul Zimmerman * dwc2_dump_global_registers() - Prints the core global registers 748197ba5f4SPaul Zimmerman * 749197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 750197ba5f4SPaul Zimmerman * 751197ba5f4SPaul Zimmerman * NOTE: This function will be removed once the peripheral controller code 752197ba5f4SPaul Zimmerman * is integrated and the driver is stable 753197ba5f4SPaul Zimmerman */ 754197ba5f4SPaul Zimmerman void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg) 755197ba5f4SPaul Zimmerman { 756197ba5f4SPaul Zimmerman #ifdef DEBUG 757197ba5f4SPaul Zimmerman u32 __iomem *addr; 758197ba5f4SPaul Zimmerman 759197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "Core Global Registers\n"); 760197ba5f4SPaul Zimmerman addr = hsotg->regs + GOTGCTL; 761197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n", 76295c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 763197ba5f4SPaul Zimmerman addr = hsotg->regs + GOTGINT; 764197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n", 76595c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 766197ba5f4SPaul Zimmerman addr = hsotg->regs + GAHBCFG; 767197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n", 76895c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 769197ba5f4SPaul Zimmerman addr = hsotg->regs + GUSBCFG; 770197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n", 77195c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 772197ba5f4SPaul Zimmerman addr = hsotg->regs + GRSTCTL; 773197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n", 77495c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 775197ba5f4SPaul Zimmerman addr = hsotg->regs + GINTSTS; 776197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n", 77795c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 778197ba5f4SPaul Zimmerman addr = hsotg->regs + GINTMSK; 779197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n", 78095c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 781197ba5f4SPaul Zimmerman addr = hsotg->regs + GRXSTSR; 782197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n", 78395c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 784197ba5f4SPaul Zimmerman addr = hsotg->regs + GRXFSIZ; 785197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n", 78695c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 787197ba5f4SPaul Zimmerman addr = hsotg->regs + GNPTXFSIZ; 788197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n", 78995c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 790197ba5f4SPaul Zimmerman addr = hsotg->regs + GNPTXSTS; 791197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n", 79295c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 793197ba5f4SPaul Zimmerman addr = hsotg->regs + GI2CCTL; 794197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n", 79595c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 796197ba5f4SPaul Zimmerman addr = hsotg->regs + GPVNDCTL; 797197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n", 79895c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 799197ba5f4SPaul Zimmerman addr = hsotg->regs + GGPIO; 800197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n", 80195c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 802197ba5f4SPaul Zimmerman addr = hsotg->regs + GUID; 803197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n", 80495c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 805197ba5f4SPaul Zimmerman addr = hsotg->regs + GSNPSID; 806197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n", 80795c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 808197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG1; 809197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n", 81095c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 811197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG2; 812197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n", 81395c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 814197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG3; 815197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n", 81695c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 817197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG4; 818197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n", 81995c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 820197ba5f4SPaul Zimmerman addr = hsotg->regs + GLPMCFG; 821197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n", 82295c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 823197ba5f4SPaul Zimmerman addr = hsotg->regs + GPWRDN; 824197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n", 82595c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 826197ba5f4SPaul Zimmerman addr = hsotg->regs + GDFIFOCFG; 827197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n", 82895c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 829197ba5f4SPaul Zimmerman addr = hsotg->regs + HPTXFSIZ; 830197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n", 83195c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 832197ba5f4SPaul Zimmerman 833197ba5f4SPaul Zimmerman addr = hsotg->regs + PCGCTL; 834197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n", 83595c8bc36SAntti Seppälä (unsigned long)addr, dwc2_readl(addr)); 836197ba5f4SPaul Zimmerman #endif 837197ba5f4SPaul Zimmerman } 838197ba5f4SPaul Zimmerman 839197ba5f4SPaul Zimmerman /** 840197ba5f4SPaul Zimmerman * dwc2_flush_tx_fifo() - Flushes a Tx FIFO 841197ba5f4SPaul Zimmerman * 842197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 843197ba5f4SPaul Zimmerman * @num: Tx FIFO to flush 844197ba5f4SPaul Zimmerman */ 845197ba5f4SPaul Zimmerman void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num) 846197ba5f4SPaul Zimmerman { 847197ba5f4SPaul Zimmerman u32 greset; 848197ba5f4SPaul Zimmerman 849197ba5f4SPaul Zimmerman dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num); 850197ba5f4SPaul Zimmerman 8518f55fd60SMinas Harutyunyan /* Wait for AHB master IDLE state */ 8528f55fd60SMinas Harutyunyan if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 8538f55fd60SMinas Harutyunyan dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 8548f55fd60SMinas Harutyunyan __func__); 8558f55fd60SMinas Harutyunyan 856197ba5f4SPaul Zimmerman greset = GRSTCTL_TXFFLSH; 857197ba5f4SPaul Zimmerman greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK; 85895c8bc36SAntti Seppälä dwc2_writel(greset, hsotg->regs + GRSTCTL); 859197ba5f4SPaul Zimmerman 86079d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000)) 86179d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n", 86279d6b8c5SSevak Arakelyan __func__); 863197ba5f4SPaul Zimmerman 864197ba5f4SPaul Zimmerman /* Wait for at least 3 PHY Clocks */ 865197ba5f4SPaul Zimmerman udelay(1); 866197ba5f4SPaul Zimmerman } 867197ba5f4SPaul Zimmerman 868197ba5f4SPaul Zimmerman /** 869197ba5f4SPaul Zimmerman * dwc2_flush_rx_fifo() - Flushes the Rx FIFO 870197ba5f4SPaul Zimmerman * 871197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 872197ba5f4SPaul Zimmerman */ 873197ba5f4SPaul Zimmerman void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg) 874197ba5f4SPaul Zimmerman { 875197ba5f4SPaul Zimmerman u32 greset; 876197ba5f4SPaul Zimmerman 877197ba5f4SPaul Zimmerman dev_vdbg(hsotg->dev, "%s()\n", __func__); 878197ba5f4SPaul Zimmerman 8798f55fd60SMinas Harutyunyan /* Wait for AHB master IDLE state */ 8808f55fd60SMinas Harutyunyan if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 8818f55fd60SMinas Harutyunyan dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 8828f55fd60SMinas Harutyunyan __func__); 8838f55fd60SMinas Harutyunyan 884197ba5f4SPaul Zimmerman greset = GRSTCTL_RXFFLSH; 88595c8bc36SAntti Seppälä dwc2_writel(greset, hsotg->regs + GRSTCTL); 886197ba5f4SPaul Zimmerman 88779d6b8c5SSevak Arakelyan /* Wait for RxFIFO flush done */ 88879d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000)) 88979d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n", 89079d6b8c5SSevak Arakelyan __func__); 891197ba5f4SPaul Zimmerman 892197ba5f4SPaul Zimmerman /* Wait for at least 3 PHY Clocks */ 893197ba5f4SPaul Zimmerman udelay(1); 894197ba5f4SPaul Zimmerman } 895197ba5f4SPaul Zimmerman 896197ba5f4SPaul Zimmerman bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg) 897197ba5f4SPaul Zimmerman { 89895c8bc36SAntti Seppälä if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff) 899197ba5f4SPaul Zimmerman return false; 900197ba5f4SPaul Zimmerman else 901197ba5f4SPaul Zimmerman return true; 902197ba5f4SPaul Zimmerman } 903197ba5f4SPaul Zimmerman 904197ba5f4SPaul Zimmerman /** 905197ba5f4SPaul Zimmerman * dwc2_enable_global_interrupts() - Enables the controller's Global 906197ba5f4SPaul Zimmerman * Interrupt in the AHB Config register 907197ba5f4SPaul Zimmerman * 908197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 909197ba5f4SPaul Zimmerman */ 910197ba5f4SPaul Zimmerman void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg) 911197ba5f4SPaul Zimmerman { 91295c8bc36SAntti Seppälä u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG); 913197ba5f4SPaul Zimmerman 914197ba5f4SPaul Zimmerman ahbcfg |= GAHBCFG_GLBL_INTR_EN; 91595c8bc36SAntti Seppälä dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG); 916197ba5f4SPaul Zimmerman } 917197ba5f4SPaul Zimmerman 918197ba5f4SPaul Zimmerman /** 919197ba5f4SPaul Zimmerman * dwc2_disable_global_interrupts() - Disables the controller's Global 920197ba5f4SPaul Zimmerman * Interrupt in the AHB Config register 921197ba5f4SPaul Zimmerman * 922197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 923197ba5f4SPaul Zimmerman */ 924197ba5f4SPaul Zimmerman void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg) 925197ba5f4SPaul Zimmerman { 92695c8bc36SAntti Seppälä u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG); 927197ba5f4SPaul Zimmerman 928197ba5f4SPaul Zimmerman ahbcfg &= ~GAHBCFG_GLBL_INTR_EN; 92995c8bc36SAntti Seppälä dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG); 930197ba5f4SPaul Zimmerman } 931197ba5f4SPaul Zimmerman 9326bea9620SJohn Youn /* Returns the controller's GHWCFG2.OTG_MODE. */ 9339da51974SJohn Youn unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg) 9346bea9620SJohn Youn { 9356bea9620SJohn Youn u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2); 9366bea9620SJohn Youn 9376bea9620SJohn Youn return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >> 9386bea9620SJohn Youn GHWCFG2_OP_MODE_SHIFT; 9396bea9620SJohn Youn } 9406bea9620SJohn Youn 9416bea9620SJohn Youn /* Returns true if the controller is capable of DRD. */ 9426bea9620SJohn Youn bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) 9436bea9620SJohn Youn { 9449da51974SJohn Youn unsigned int op_mode = dwc2_op_mode(hsotg); 9456bea9620SJohn Youn 9466bea9620SJohn Youn return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) || 9476bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) || 9486bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE); 9496bea9620SJohn Youn } 9506bea9620SJohn Youn 9516bea9620SJohn Youn /* Returns true if the controller is host-only. */ 9526bea9620SJohn Youn bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) 9536bea9620SJohn Youn { 9549da51974SJohn Youn unsigned int op_mode = dwc2_op_mode(hsotg); 9556bea9620SJohn Youn 9566bea9620SJohn Youn return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) || 9576bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST); 9586bea9620SJohn Youn } 9596bea9620SJohn Youn 9606bea9620SJohn Youn /* Returns true if the controller is device-only. */ 9616bea9620SJohn Youn bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg) 9626bea9620SJohn Youn { 9639da51974SJohn Youn unsigned int op_mode = dwc2_op_mode(hsotg); 9646bea9620SJohn Youn 9656bea9620SJohn Youn return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || 9666bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE); 9676bea9620SJohn Youn } 9686bea9620SJohn Youn 96979d6b8c5SSevak Arakelyan /** 97079d6b8c5SSevak Arakelyan * dwc2_hsotg_wait_bit_set - Waits for bit to be set. 97179d6b8c5SSevak Arakelyan * @hsotg: Programming view of DWC_otg controller. 97279d6b8c5SSevak Arakelyan * @offset: Register's offset where bit/bits must be set. 97379d6b8c5SSevak Arakelyan * @mask: Mask of the bit/bits which must be set. 97479d6b8c5SSevak Arakelyan * @timeout: Timeout to wait. 97579d6b8c5SSevak Arakelyan * 97679d6b8c5SSevak Arakelyan * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 97779d6b8c5SSevak Arakelyan */ 97879d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 97979d6b8c5SSevak Arakelyan u32 timeout) 98079d6b8c5SSevak Arakelyan { 98179d6b8c5SSevak Arakelyan u32 i; 98279d6b8c5SSevak Arakelyan 98379d6b8c5SSevak Arakelyan for (i = 0; i < timeout; i++) { 98479d6b8c5SSevak Arakelyan if (dwc2_readl(hsotg->regs + offset) & mask) 98579d6b8c5SSevak Arakelyan return 0; 98679d6b8c5SSevak Arakelyan udelay(1); 98779d6b8c5SSevak Arakelyan } 98879d6b8c5SSevak Arakelyan 98979d6b8c5SSevak Arakelyan return -ETIMEDOUT; 99079d6b8c5SSevak Arakelyan } 99179d6b8c5SSevak Arakelyan 99279d6b8c5SSevak Arakelyan /** 99379d6b8c5SSevak Arakelyan * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear. 99479d6b8c5SSevak Arakelyan * @hsotg: Programming view of DWC_otg controller. 99579d6b8c5SSevak Arakelyan * @offset: Register's offset where bit/bits must be set. 99679d6b8c5SSevak Arakelyan * @mask: Mask of the bit/bits which must be set. 99779d6b8c5SSevak Arakelyan * @timeout: Timeout to wait. 99879d6b8c5SSevak Arakelyan * 99979d6b8c5SSevak Arakelyan * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 100079d6b8c5SSevak Arakelyan */ 100179d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 100279d6b8c5SSevak Arakelyan u32 timeout) 100379d6b8c5SSevak Arakelyan { 100479d6b8c5SSevak Arakelyan u32 i; 100579d6b8c5SSevak Arakelyan 100679d6b8c5SSevak Arakelyan for (i = 0; i < timeout; i++) { 100779d6b8c5SSevak Arakelyan if (!(dwc2_readl(hsotg->regs + offset) & mask)) 100879d6b8c5SSevak Arakelyan return 0; 100979d6b8c5SSevak Arakelyan udelay(1); 101079d6b8c5SSevak Arakelyan } 101179d6b8c5SSevak Arakelyan 101279d6b8c5SSevak Arakelyan return -ETIMEDOUT; 101379d6b8c5SSevak Arakelyan } 101479d6b8c5SSevak Arakelyan 1015197ba5f4SPaul Zimmerman MODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); 1016197ba5f4SPaul Zimmerman MODULE_AUTHOR("Synopsys, Inc."); 1017197ba5f4SPaul Zimmerman MODULE_LICENSE("Dual BSD/GPL"); 1018