xref: /linux/drivers/usb/dwc2/core.c (revision 365b7673c34fed58b0a04ee4a7a51102c65ccd2e)
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