xref: /linux/drivers/usb/dwc2/core.c (revision 41ba9b9b95beb8bb101a40c6badbbe49da6af9cd)
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  */
67d17ee77bSGregory Herrero static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
68d17ee77bSGregory Herrero {
69d17ee77bSGregory Herrero 	struct dwc2_gregs_backup *gr;
70d17ee77bSGregory Herrero 	int i;
71d17ee77bSGregory Herrero 
72d17ee77bSGregory Herrero 	/* Backup global regs */
73cc1e204cSMian Yousaf Kaukab 	gr = &hsotg->gr_backup;
74d17ee77bSGregory Herrero 
7595c8bc36SAntti Seppälä 	gr->gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
7695c8bc36SAntti Seppälä 	gr->gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
7795c8bc36SAntti Seppälä 	gr->gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
7895c8bc36SAntti Seppälä 	gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
7995c8bc36SAntti Seppälä 	gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
8095c8bc36SAntti Seppälä 	gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
8195c8bc36SAntti Seppälä 	gr->hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
8295c8bc36SAntti Seppälä 	gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
83600a490eSRazmik Karapetyan 	gr->pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
84d17ee77bSGregory Herrero 	for (i = 0; i < MAX_EPS_CHANNELS; i++)
8595c8bc36SAntti Seppälä 		gr->dtxfsiz[i] = dwc2_readl(hsotg->regs + DPTXFSIZN(i));
86d17ee77bSGregory Herrero 
87cc1e204cSMian Yousaf Kaukab 	gr->valid = true;
88d17ee77bSGregory Herrero 	return 0;
89d17ee77bSGregory Herrero }
90d17ee77bSGregory Herrero 
91d17ee77bSGregory Herrero /**
92d17ee77bSGregory Herrero  * dwc2_restore_global_registers() - Restore controller global registers.
93d17ee77bSGregory Herrero  * When resuming usb bus, device registers needs to be restored
94d17ee77bSGregory Herrero  * if controller power were disabled.
95d17ee77bSGregory Herrero  *
96d17ee77bSGregory Herrero  * @hsotg: Programming view of the DWC_otg controller
97d17ee77bSGregory Herrero  */
98d17ee77bSGregory Herrero static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
99d17ee77bSGregory Herrero {
100d17ee77bSGregory Herrero 	struct dwc2_gregs_backup *gr;
101d17ee77bSGregory Herrero 	int i;
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->hptxfsiz, hsotg->regs + HPTXFSIZ);
12295c8bc36SAntti Seppälä 	dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
123600a490eSRazmik Karapetyan 	dwc2_writel(gr->pcgcctl1, hsotg->regs + PCGCCTL1);
124d17ee77bSGregory Herrero 	for (i = 0; i < MAX_EPS_CHANNELS; i++)
12595c8bc36SAntti Seppälä 		dwc2_writel(gr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
126d17ee77bSGregory Herrero 
127d17ee77bSGregory Herrero 	return 0;
128d17ee77bSGregory Herrero }
129d17ee77bSGregory Herrero 
130d17ee77bSGregory Herrero /**
131*41ba9b9bSVardan 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  */
136*41ba9b9bSVardan 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 
141*41ba9b9bSVardan Mikayelyan 	if (!hsotg->params.power_down)
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 {
172d17ee77bSGregory Herrero 			ret = dwc2_restore_device_registers(hsotg);
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 /**
185*41ba9b9bSVardan 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  */
189*41ba9b9bSVardan Mikayelyan int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
190d17ee77bSGregory Herrero {
191d17ee77bSGregory Herrero 	u32 pcgcctl;
192d17ee77bSGregory Herrero 	int ret = 0;
193d17ee77bSGregory Herrero 
194*41ba9b9bSVardan 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
223*41ba9b9bSVardan 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 /**
245fef6bc37SJohn Youn  * dwc2_wait_for_mode() - Waits for the controller mode.
246fef6bc37SJohn Youn  * @hsotg:	Programming view of the DWC_otg controller.
247fef6bc37SJohn Youn  * @host_mode:	If true, waits for host mode, otherwise device mode.
248fef6bc37SJohn Youn  */
249fef6bc37SJohn Youn static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg,
250fef6bc37SJohn Youn 			       bool host_mode)
251fef6bc37SJohn Youn {
252fef6bc37SJohn Youn 	ktime_t start;
253fef6bc37SJohn Youn 	ktime_t end;
254fef6bc37SJohn Youn 	unsigned int timeout = 110;
255fef6bc37SJohn Youn 
256fef6bc37SJohn Youn 	dev_vdbg(hsotg->dev, "Waiting for %s mode\n",
257fef6bc37SJohn Youn 		 host_mode ? "host" : "device");
258fef6bc37SJohn Youn 
259fef6bc37SJohn Youn 	start = ktime_get();
260fef6bc37SJohn Youn 
261fef6bc37SJohn Youn 	while (1) {
262fef6bc37SJohn Youn 		s64 ms;
263fef6bc37SJohn Youn 
264fef6bc37SJohn Youn 		if (dwc2_is_host_mode(hsotg) == host_mode) {
265fef6bc37SJohn Youn 			dev_vdbg(hsotg->dev, "%s mode set\n",
266fef6bc37SJohn Youn 				 host_mode ? "Host" : "Device");
267fef6bc37SJohn Youn 			break;
268fef6bc37SJohn Youn 		}
269fef6bc37SJohn Youn 
270fef6bc37SJohn Youn 		end = ktime_get();
271fef6bc37SJohn Youn 		ms = ktime_to_ms(ktime_sub(end, start));
272fef6bc37SJohn Youn 
273fef6bc37SJohn Youn 		if (ms >= (s64)timeout) {
274fef6bc37SJohn Youn 			dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n",
275fef6bc37SJohn Youn 				 __func__, host_mode ? "host" : "device");
276fef6bc37SJohn Youn 			break;
277fef6bc37SJohn Youn 		}
278fef6bc37SJohn Youn 
279fef6bc37SJohn Youn 		usleep_range(1000, 2000);
280fef6bc37SJohn Youn 	}
281fef6bc37SJohn Youn }
282fef6bc37SJohn Youn 
283fef6bc37SJohn Youn /**
284fef6bc37SJohn Youn  * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce
285fef6bc37SJohn Youn  * filter is enabled.
286fef6bc37SJohn Youn  */
287fef6bc37SJohn Youn static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
288fef6bc37SJohn Youn {
289fef6bc37SJohn Youn 	u32 gsnpsid;
290fef6bc37SJohn Youn 	u32 ghwcfg4;
291fef6bc37SJohn Youn 
292fef6bc37SJohn Youn 	if (!dwc2_hw_is_otg(hsotg))
293fef6bc37SJohn Youn 		return false;
294fef6bc37SJohn Youn 
295fef6bc37SJohn Youn 	/* Check if core configuration includes the IDDIG filter. */
296fef6bc37SJohn Youn 	ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
297fef6bc37SJohn Youn 	if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
298fef6bc37SJohn Youn 		return false;
299fef6bc37SJohn Youn 
300fef6bc37SJohn Youn 	/*
301fef6bc37SJohn Youn 	 * Check if the IDDIG debounce filter is bypassed. Available
302fef6bc37SJohn Youn 	 * in core version >= 3.10a.
303fef6bc37SJohn Youn 	 */
304fef6bc37SJohn Youn 	gsnpsid = dwc2_readl(hsotg->regs + GSNPSID);
305fef6bc37SJohn Youn 	if (gsnpsid >= DWC2_CORE_REV_3_10a) {
306fef6bc37SJohn Youn 		u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
307fef6bc37SJohn Youn 
308fef6bc37SJohn Youn 		if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
309fef6bc37SJohn Youn 			return false;
310fef6bc37SJohn Youn 	}
311fef6bc37SJohn Youn 
312fef6bc37SJohn Youn 	return true;
313fef6bc37SJohn Youn }
314fef6bc37SJohn Youn 
315197ba5f4SPaul Zimmerman /*
316197ba5f4SPaul Zimmerman  * Do core a soft reset of the core.  Be careful with this because it
317197ba5f4SPaul Zimmerman  * resets all the internal state machines of the core.
318197ba5f4SPaul Zimmerman  */
3196e6360b6SJohn Stultz int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
320197ba5f4SPaul Zimmerman {
321197ba5f4SPaul Zimmerman 	u32 greset;
322fef6bc37SJohn Youn 	bool wait_for_host_mode = false;
323197ba5f4SPaul Zimmerman 
324197ba5f4SPaul Zimmerman 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
325197ba5f4SPaul Zimmerman 
326fef6bc37SJohn Youn 	/*
327fef6bc37SJohn Youn 	 * If the current mode is host, either due to the force mode
328fef6bc37SJohn Youn 	 * bit being set (which persists after core reset) or the
329fef6bc37SJohn Youn 	 * connector id pin, a core soft reset will temporarily reset
330fef6bc37SJohn Youn 	 * the mode to device. A delay from the IDDIG debounce filter
331fef6bc37SJohn Youn 	 * will occur before going back to host mode.
332fef6bc37SJohn Youn 	 *
333fef6bc37SJohn Youn 	 * Determine whether we will go back into host mode after a
334fef6bc37SJohn Youn 	 * reset and account for this delay after the reset.
335fef6bc37SJohn Youn 	 */
336fef6bc37SJohn Youn 	if (dwc2_iddig_filter_enabled(hsotg)) {
337fef6bc37SJohn Youn 		u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
338fef6bc37SJohn Youn 		u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
339fef6bc37SJohn Youn 
340fef6bc37SJohn Youn 		if (!(gotgctl & GOTGCTL_CONID_B) ||
341fef6bc37SJohn Youn 		    (gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
342fef6bc37SJohn Youn 			wait_for_host_mode = true;
343fef6bc37SJohn Youn 		}
344fef6bc37SJohn Youn 	}
345fef6bc37SJohn Youn 
346197ba5f4SPaul Zimmerman 	/* Core Soft Reset */
347b8ccc593SJohn Youn 	greset = dwc2_readl(hsotg->regs + GRSTCTL);
348197ba5f4SPaul Zimmerman 	greset |= GRSTCTL_CSFTRST;
34995c8bc36SAntti Seppälä 	dwc2_writel(greset, hsotg->regs + GRSTCTL);
35079d6b8c5SSevak Arakelyan 
35179d6b8c5SSevak Arakelyan 	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
35279d6b8c5SSevak Arakelyan 		dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
35379d6b8c5SSevak Arakelyan 			 __func__);
354197ba5f4SPaul Zimmerman 		return -EBUSY;
355197ba5f4SPaul Zimmerman 	}
356197ba5f4SPaul Zimmerman 
357b8ccc593SJohn Youn 	/* Wait for AHB master IDLE state */
35879d6b8c5SSevak Arakelyan 	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
35979d6b8c5SSevak Arakelyan 		dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
36079d6b8c5SSevak Arakelyan 			 __func__);
361b8ccc593SJohn Youn 		return -EBUSY;
362b8ccc593SJohn Youn 	}
363b8ccc593SJohn Youn 
3646e6360b6SJohn Stultz 	if (wait_for_host_mode && !skip_wait)
365fef6bc37SJohn Youn 		dwc2_wait_for_mode(hsotg, true);
366fef6bc37SJohn Youn 
367b5d308abSJohn Youn 	return 0;
368b5d308abSJohn Youn }
369b5d308abSJohn Youn 
370b5d308abSJohn Youn /*
37109c96980SJohn Youn  * Force the mode of the controller.
37209c96980SJohn Youn  *
37309c96980SJohn Youn  * Forcing the mode is needed for two cases:
37409c96980SJohn Youn  *
37509c96980SJohn Youn  * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the
37609c96980SJohn Youn  * controller to stay in a particular mode regardless of ID pin
37709c96980SJohn Youn  * changes. We do this usually after a core reset.
37809c96980SJohn Youn  *
37909c96980SJohn Youn  * 2) During probe we want to read reset values of the hw
38009c96980SJohn Youn  * configuration registers that are only available in either host or
38109c96980SJohn Youn  * device mode. We may need to force the mode if the current mode does
38209c96980SJohn Youn  * not allow us to access the register in the mode that we want.
38309c96980SJohn Youn  *
38409c96980SJohn Youn  * In either case it only makes sense to force the mode if the
38509c96980SJohn Youn  * controller hardware is OTG capable.
38609c96980SJohn Youn  *
38709c96980SJohn Youn  * Checks are done in this function to determine whether doing a force
38809c96980SJohn Youn  * would be valid or not.
38909c96980SJohn Youn  *
3902938fc63SJohn Youn  * If a force is done, it requires a IDDIG debounce filter delay if
3912938fc63SJohn Youn  * the filter is configured and enabled. We poll the current mode of
3922938fc63SJohn Youn  * the controller to account for this delay.
39309c96980SJohn Youn  */
39409c96980SJohn Youn static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
39509c96980SJohn Youn {
39609c96980SJohn Youn 	u32 gusbcfg;
39709c96980SJohn Youn 	u32 set;
39809c96980SJohn Youn 	u32 clear;
39909c96980SJohn Youn 
40009c96980SJohn Youn 	dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device");
40109c96980SJohn Youn 
40209c96980SJohn Youn 	/*
40309c96980SJohn Youn 	 * Force mode has no effect if the hardware is not OTG.
40409c96980SJohn Youn 	 */
40509c96980SJohn Youn 	if (!dwc2_hw_is_otg(hsotg))
40609c96980SJohn Youn 		return false;
40709c96980SJohn Youn 
40809c96980SJohn Youn 	/*
40909c96980SJohn Youn 	 * If dr_mode is either peripheral or host only, there is no
41009c96980SJohn Youn 	 * need to ever force the mode to the opposite mode.
41109c96980SJohn Youn 	 */
41209c96980SJohn Youn 	if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
41309c96980SJohn Youn 		return false;
41409c96980SJohn Youn 
41509c96980SJohn Youn 	if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
41609c96980SJohn Youn 		return false;
41709c96980SJohn Youn 
41809c96980SJohn Youn 	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
41909c96980SJohn Youn 
42009c96980SJohn Youn 	set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
42109c96980SJohn Youn 	clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
42209c96980SJohn Youn 
42309c96980SJohn Youn 	gusbcfg &= ~clear;
42409c96980SJohn Youn 	gusbcfg |= set;
42509c96980SJohn Youn 	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
42609c96980SJohn Youn 
4272938fc63SJohn Youn 	dwc2_wait_for_mode(hsotg, host);
42809c96980SJohn Youn 	return true;
42909c96980SJohn Youn }
43009c96980SJohn Youn 
4312938fc63SJohn Youn /**
4322938fc63SJohn Youn  * dwc2_clear_force_mode() - Clears the force mode bits.
4332938fc63SJohn Youn  *
4342938fc63SJohn Youn  * After clearing the bits, wait up to 100 ms to account for any
4352938fc63SJohn Youn  * potential IDDIG filter delay. We can't know if we expect this delay
4362938fc63SJohn Youn  * or not because the value of the connector ID status is affected by
4372938fc63SJohn Youn  * the force mode. We only need to call this once during probe if
4382938fc63SJohn Youn  * dr_mode == OTG.
43909c96980SJohn Youn  */
440323230efSJohn Youn void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
44109c96980SJohn Youn {
44209c96980SJohn Youn 	u32 gusbcfg;
44309c96980SJohn Youn 
44409c96980SJohn Youn 	gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
44509c96980SJohn Youn 	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
44609c96980SJohn Youn 	gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
44709c96980SJohn Youn 	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
44809c96980SJohn Youn 
4492938fc63SJohn Youn 	if (dwc2_iddig_filter_enabled(hsotg))
450d3fe81d2SNicholas Mc Guire 		msleep(100);
45109c96980SJohn Youn }
45209c96980SJohn Youn 
45309c96980SJohn Youn /*
45409c96980SJohn Youn  * Sets or clears force mode based on the dr_mode parameter.
45509c96980SJohn Youn  */
45609c96980SJohn Youn void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
45709c96980SJohn Youn {
458a07ce8d3SHeiko Stuebner 	bool ret;
459a07ce8d3SHeiko Stuebner 
46009c96980SJohn Youn 	switch (hsotg->dr_mode) {
46109c96980SJohn Youn 	case USB_DR_MODE_HOST:
462a07ce8d3SHeiko Stuebner 		ret = dwc2_force_mode(hsotg, true);
463a07ce8d3SHeiko Stuebner 		/*
464a07ce8d3SHeiko Stuebner 		 * NOTE: This is required for some rockchip soc based
465a07ce8d3SHeiko Stuebner 		 * platforms on their host-only dwc2.
466a07ce8d3SHeiko Stuebner 		 */
467a07ce8d3SHeiko Stuebner 		if (!ret)
468a07ce8d3SHeiko Stuebner 			msleep(50);
469a07ce8d3SHeiko Stuebner 
47009c96980SJohn Youn 		break;
47109c96980SJohn Youn 	case USB_DR_MODE_PERIPHERAL:
47209c96980SJohn Youn 		dwc2_force_mode(hsotg, false);
47309c96980SJohn Youn 		break;
47409c96980SJohn Youn 	case USB_DR_MODE_OTG:
47509c96980SJohn Youn 		dwc2_clear_force_mode(hsotg);
47609c96980SJohn Youn 		break;
47709c96980SJohn Youn 	default:
47809c96980SJohn Youn 		dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n",
47909c96980SJohn Youn 			 __func__, hsotg->dr_mode);
48009c96980SJohn Youn 		break;
48109c96980SJohn Youn 	}
48209c96980SJohn Youn }
48309c96980SJohn Youn 
48409c96980SJohn Youn /*
485b5d308abSJohn Youn  * Do core a soft reset of the core.  Be careful with this because it
486b5d308abSJohn Youn  * resets all the internal state machines of the core.
487b5d308abSJohn Youn  *
488b5d308abSJohn Youn  * Additionally this will apply force mode as per the hsotg->dr_mode
489b5d308abSJohn Youn  * parameter.
490b5d308abSJohn Youn  */
491b5d308abSJohn Youn int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
492b5d308abSJohn Youn {
493b5d308abSJohn Youn 	int retval;
494b5d308abSJohn Youn 
4956e6360b6SJohn Stultz 	retval = dwc2_core_reset(hsotg, false);
496b5d308abSJohn Youn 	if (retval)
497b5d308abSJohn Youn 		return retval;
498b5d308abSJohn Youn 
49909c96980SJohn Youn 	dwc2_force_dr_mode(hsotg);
500197ba5f4SPaul Zimmerman 	return 0;
501197ba5f4SPaul Zimmerman }
502197ba5f4SPaul Zimmerman 
50366e77a24SRazmik Karapetyan /*
50466e77a24SRazmik Karapetyan  * dwc2_enable_acg - enable active clock gating feature
50566e77a24SRazmik Karapetyan  */
50666e77a24SRazmik Karapetyan void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
50766e77a24SRazmik Karapetyan {
50866e77a24SRazmik Karapetyan 	if (hsotg->params.acg_enable) {
50966e77a24SRazmik Karapetyan 		u32 pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
51066e77a24SRazmik Karapetyan 
51166e77a24SRazmik Karapetyan 		dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
51266e77a24SRazmik Karapetyan 		pcgcctl1 |= PCGCCTL1_GATEEN;
51366e77a24SRazmik Karapetyan 		dwc2_writel(pcgcctl1, hsotg->regs + PCGCCTL1);
51466e77a24SRazmik Karapetyan 	}
51566e77a24SRazmik Karapetyan }
51666e77a24SRazmik Karapetyan 
517197ba5f4SPaul Zimmerman /**
518197ba5f4SPaul Zimmerman  * dwc2_dump_host_registers() - Prints the host registers
519197ba5f4SPaul Zimmerman  *
520197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
521197ba5f4SPaul Zimmerman  *
522197ba5f4SPaul Zimmerman  * NOTE: This function will be removed once the peripheral controller code
523197ba5f4SPaul Zimmerman  * is integrated and the driver is stable
524197ba5f4SPaul Zimmerman  */
525197ba5f4SPaul Zimmerman void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
526197ba5f4SPaul Zimmerman {
527197ba5f4SPaul Zimmerman #ifdef DEBUG
528197ba5f4SPaul Zimmerman 	u32 __iomem *addr;
529197ba5f4SPaul Zimmerman 	int i;
530197ba5f4SPaul Zimmerman 
531197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "Host Global Registers\n");
532197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HCFG;
533197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HCFG	 @0x%08lX : 0x%08X\n",
53495c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
535197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HFIR;
536197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HFIR	 @0x%08lX : 0x%08X\n",
53795c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
538197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HFNUM;
539197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HFNUM	 @0x%08lX : 0x%08X\n",
54095c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
541197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HPTXSTS;
542197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HPTXSTS	 @0x%08lX : 0x%08X\n",
54395c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
544197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HAINT;
545197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HAINT	 @0x%08lX : 0x%08X\n",
54695c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
547197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HAINTMSK;
548197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HAINTMSK	 @0x%08lX : 0x%08X\n",
54995c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
55095832c00SJohn Youn 	if (hsotg->params.dma_desc_enable) {
551197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HFLBADDR;
552197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
55395c8bc36SAntti Seppälä 			(unsigned long)addr, dwc2_readl(addr));
554197ba5f4SPaul Zimmerman 	}
555197ba5f4SPaul Zimmerman 
556197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HPRT0;
557197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HPRT0	 @0x%08lX : 0x%08X\n",
55895c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
559197ba5f4SPaul Zimmerman 
560bea8e86cSJohn Youn 	for (i = 0; i < hsotg->params.host_channels; i++) {
561197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
562197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCCHAR(i);
563197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCCHAR	 @0x%08lX : 0x%08X\n",
56495c8bc36SAntti Seppälä 			(unsigned long)addr, dwc2_readl(addr));
565197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCSPLT(i);
566197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCSPLT	 @0x%08lX : 0x%08X\n",
56795c8bc36SAntti Seppälä 			(unsigned long)addr, dwc2_readl(addr));
568197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCINT(i);
569197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCINT	 @0x%08lX : 0x%08X\n",
57095c8bc36SAntti Seppälä 			(unsigned long)addr, dwc2_readl(addr));
571197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCINTMSK(i);
572197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCINTMSK	 @0x%08lX : 0x%08X\n",
57395c8bc36SAntti Seppälä 			(unsigned long)addr, dwc2_readl(addr));
574197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCTSIZ(i);
575197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCTSIZ	 @0x%08lX : 0x%08X\n",
57695c8bc36SAntti Seppälä 			(unsigned long)addr, dwc2_readl(addr));
577197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCDMA(i);
578197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCDMA	 @0x%08lX : 0x%08X\n",
57995c8bc36SAntti Seppälä 			(unsigned long)addr, dwc2_readl(addr));
58095832c00SJohn Youn 		if (hsotg->params.dma_desc_enable) {
581197ba5f4SPaul Zimmerman 			addr = hsotg->regs + HCDMAB(i);
582197ba5f4SPaul Zimmerman 			dev_dbg(hsotg->dev, "HCDMAB	 @0x%08lX : 0x%08X\n",
58395c8bc36SAntti Seppälä 				(unsigned long)addr, dwc2_readl(addr));
584197ba5f4SPaul Zimmerman 		}
585197ba5f4SPaul Zimmerman 	}
586197ba5f4SPaul Zimmerman #endif
587197ba5f4SPaul Zimmerman }
588197ba5f4SPaul Zimmerman 
589197ba5f4SPaul Zimmerman /**
590197ba5f4SPaul Zimmerman  * dwc2_dump_global_registers() - Prints the core global registers
591197ba5f4SPaul Zimmerman  *
592197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
593197ba5f4SPaul Zimmerman  *
594197ba5f4SPaul Zimmerman  * NOTE: This function will be removed once the peripheral controller code
595197ba5f4SPaul Zimmerman  * is integrated and the driver is stable
596197ba5f4SPaul Zimmerman  */
597197ba5f4SPaul Zimmerman void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
598197ba5f4SPaul Zimmerman {
599197ba5f4SPaul Zimmerman #ifdef DEBUG
600197ba5f4SPaul Zimmerman 	u32 __iomem *addr;
601197ba5f4SPaul Zimmerman 
602197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "Core Global Registers\n");
603197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GOTGCTL;
604197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GOTGCTL	 @0x%08lX : 0x%08X\n",
60595c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
606197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GOTGINT;
607197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GOTGINT	 @0x%08lX : 0x%08X\n",
60895c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
609197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GAHBCFG;
610197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GAHBCFG	 @0x%08lX : 0x%08X\n",
61195c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
612197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GUSBCFG;
613197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GUSBCFG	 @0x%08lX : 0x%08X\n",
61495c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
615197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GRSTCTL;
616197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GRSTCTL	 @0x%08lX : 0x%08X\n",
61795c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
618197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GINTSTS;
619197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GINTSTS	 @0x%08lX : 0x%08X\n",
62095c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
621197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GINTMSK;
622197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GINTMSK	 @0x%08lX : 0x%08X\n",
62395c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
624197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GRXSTSR;
625197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GRXSTSR	 @0x%08lX : 0x%08X\n",
62695c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
627197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GRXFSIZ;
628197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GRXFSIZ	 @0x%08lX : 0x%08X\n",
62995c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
630197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GNPTXFSIZ;
631197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GNPTXFSIZ	 @0x%08lX : 0x%08X\n",
63295c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
633197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GNPTXSTS;
634197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GNPTXSTS	 @0x%08lX : 0x%08X\n",
63595c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
636197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GI2CCTL;
637197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GI2CCTL	 @0x%08lX : 0x%08X\n",
63895c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
639197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GPVNDCTL;
640197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GPVNDCTL	 @0x%08lX : 0x%08X\n",
64195c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
642197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GGPIO;
643197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GGPIO	 @0x%08lX : 0x%08X\n",
64495c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
645197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GUID;
646197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GUID	 @0x%08lX : 0x%08X\n",
64795c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
648197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GSNPSID;
649197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GSNPSID	 @0x%08lX : 0x%08X\n",
65095c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
651197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG1;
652197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG1	 @0x%08lX : 0x%08X\n",
65395c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
654197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG2;
655197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG2	 @0x%08lX : 0x%08X\n",
65695c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
657197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG3;
658197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG3	 @0x%08lX : 0x%08X\n",
65995c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
660197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG4;
661197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG4	 @0x%08lX : 0x%08X\n",
66295c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
663197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GLPMCFG;
664197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GLPMCFG	 @0x%08lX : 0x%08X\n",
66595c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
666197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GPWRDN;
667197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GPWRDN	 @0x%08lX : 0x%08X\n",
66895c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
669197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GDFIFOCFG;
670197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GDFIFOCFG	 @0x%08lX : 0x%08X\n",
67195c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
672197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HPTXFSIZ;
673197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HPTXFSIZ	 @0x%08lX : 0x%08X\n",
67495c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
675197ba5f4SPaul Zimmerman 
676197ba5f4SPaul Zimmerman 	addr = hsotg->regs + PCGCTL;
677197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "PCGCTL	 @0x%08lX : 0x%08X\n",
67895c8bc36SAntti Seppälä 		(unsigned long)addr, dwc2_readl(addr));
679197ba5f4SPaul Zimmerman #endif
680197ba5f4SPaul Zimmerman }
681197ba5f4SPaul Zimmerman 
682197ba5f4SPaul Zimmerman /**
683197ba5f4SPaul Zimmerman  * dwc2_flush_tx_fifo() - Flushes a Tx FIFO
684197ba5f4SPaul Zimmerman  *
685197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
686197ba5f4SPaul Zimmerman  * @num:   Tx FIFO to flush
687197ba5f4SPaul Zimmerman  */
688197ba5f4SPaul Zimmerman void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
689197ba5f4SPaul Zimmerman {
690197ba5f4SPaul Zimmerman 	u32 greset;
691197ba5f4SPaul Zimmerman 
692197ba5f4SPaul Zimmerman 	dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
693197ba5f4SPaul Zimmerman 
6948f55fd60SMinas Harutyunyan 	/* Wait for AHB master IDLE state */
6958f55fd60SMinas Harutyunyan 	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
6968f55fd60SMinas Harutyunyan 		dev_warn(hsotg->dev, "%s:  HANG! AHB Idle GRSCTL\n",
6978f55fd60SMinas Harutyunyan 			 __func__);
6988f55fd60SMinas Harutyunyan 
699197ba5f4SPaul Zimmerman 	greset = GRSTCTL_TXFFLSH;
700197ba5f4SPaul Zimmerman 	greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
70195c8bc36SAntti Seppälä 	dwc2_writel(greset, hsotg->regs + GRSTCTL);
702197ba5f4SPaul Zimmerman 
70379d6b8c5SSevak Arakelyan 	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
70479d6b8c5SSevak Arakelyan 		dev_warn(hsotg->dev, "%s:  HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
70579d6b8c5SSevak Arakelyan 			 __func__);
706197ba5f4SPaul Zimmerman 
707197ba5f4SPaul Zimmerman 	/* Wait for at least 3 PHY Clocks */
708197ba5f4SPaul Zimmerman 	udelay(1);
709197ba5f4SPaul Zimmerman }
710197ba5f4SPaul Zimmerman 
711197ba5f4SPaul Zimmerman /**
712197ba5f4SPaul Zimmerman  * dwc2_flush_rx_fifo() - Flushes the Rx FIFO
713197ba5f4SPaul Zimmerman  *
714197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
715197ba5f4SPaul Zimmerman  */
716197ba5f4SPaul Zimmerman void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
717197ba5f4SPaul Zimmerman {
718197ba5f4SPaul Zimmerman 	u32 greset;
719197ba5f4SPaul Zimmerman 
720197ba5f4SPaul Zimmerman 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
721197ba5f4SPaul Zimmerman 
7228f55fd60SMinas Harutyunyan 	/* Wait for AHB master IDLE state */
7238f55fd60SMinas Harutyunyan 	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
7248f55fd60SMinas Harutyunyan 		dev_warn(hsotg->dev, "%s:  HANG! AHB Idle GRSCTL\n",
7258f55fd60SMinas Harutyunyan 			 __func__);
7268f55fd60SMinas Harutyunyan 
727197ba5f4SPaul Zimmerman 	greset = GRSTCTL_RXFFLSH;
72895c8bc36SAntti Seppälä 	dwc2_writel(greset, hsotg->regs + GRSTCTL);
729197ba5f4SPaul Zimmerman 
73079d6b8c5SSevak Arakelyan 	/* Wait for RxFIFO flush done */
73179d6b8c5SSevak Arakelyan 	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
73279d6b8c5SSevak Arakelyan 		dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n",
73379d6b8c5SSevak Arakelyan 			 __func__);
734197ba5f4SPaul Zimmerman 
735197ba5f4SPaul Zimmerman 	/* Wait for at least 3 PHY Clocks */
736197ba5f4SPaul Zimmerman 	udelay(1);
737197ba5f4SPaul Zimmerman }
738197ba5f4SPaul Zimmerman 
73909c96980SJohn Youn /*
74009c96980SJohn Youn  * Forces either host or device mode if the controller is not
74109c96980SJohn Youn  * currently in that mode.
74209c96980SJohn Youn  *
74309c96980SJohn Youn  * Returns true if the mode was forced.
74409c96980SJohn Youn  */
745323230efSJohn Youn bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host)
74609c96980SJohn Youn {
74709c96980SJohn Youn 	if (host && dwc2_is_host_mode(hsotg))
74809c96980SJohn Youn 		return false;
74909c96980SJohn Youn 	else if (!host && dwc2_is_device_mode(hsotg))
75009c96980SJohn Youn 		return false;
75109c96980SJohn Youn 
75209c96980SJohn Youn 	return dwc2_force_mode(hsotg, host);
75309c96980SJohn Youn }
75409c96980SJohn Youn 
755197ba5f4SPaul Zimmerman bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
756197ba5f4SPaul Zimmerman {
75795c8bc36SAntti Seppälä 	if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff)
758197ba5f4SPaul Zimmerman 		return false;
759197ba5f4SPaul Zimmerman 	else
760197ba5f4SPaul Zimmerman 		return true;
761197ba5f4SPaul Zimmerman }
762197ba5f4SPaul Zimmerman 
763197ba5f4SPaul Zimmerman /**
764197ba5f4SPaul Zimmerman  * dwc2_enable_global_interrupts() - Enables the controller's Global
765197ba5f4SPaul Zimmerman  * Interrupt in the AHB Config register
766197ba5f4SPaul Zimmerman  *
767197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
768197ba5f4SPaul Zimmerman  */
769197ba5f4SPaul Zimmerman void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
770197ba5f4SPaul Zimmerman {
77195c8bc36SAntti Seppälä 	u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
772197ba5f4SPaul Zimmerman 
773197ba5f4SPaul Zimmerman 	ahbcfg |= GAHBCFG_GLBL_INTR_EN;
77495c8bc36SAntti Seppälä 	dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
775197ba5f4SPaul Zimmerman }
776197ba5f4SPaul Zimmerman 
777197ba5f4SPaul Zimmerman /**
778197ba5f4SPaul Zimmerman  * dwc2_disable_global_interrupts() - Disables the controller's Global
779197ba5f4SPaul Zimmerman  * Interrupt in the AHB Config register
780197ba5f4SPaul Zimmerman  *
781197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
782197ba5f4SPaul Zimmerman  */
783197ba5f4SPaul Zimmerman void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
784197ba5f4SPaul Zimmerman {
78595c8bc36SAntti Seppälä 	u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
786197ba5f4SPaul Zimmerman 
787197ba5f4SPaul Zimmerman 	ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
78895c8bc36SAntti Seppälä 	dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
789197ba5f4SPaul Zimmerman }
790197ba5f4SPaul Zimmerman 
7916bea9620SJohn Youn /* Returns the controller's GHWCFG2.OTG_MODE. */
7929da51974SJohn Youn unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg)
7936bea9620SJohn Youn {
7946bea9620SJohn Youn 	u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
7956bea9620SJohn Youn 
7966bea9620SJohn Youn 	return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
7976bea9620SJohn Youn 		GHWCFG2_OP_MODE_SHIFT;
7986bea9620SJohn Youn }
7996bea9620SJohn Youn 
8006bea9620SJohn Youn /* Returns true if the controller is capable of DRD. */
8016bea9620SJohn Youn bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg)
8026bea9620SJohn Youn {
8039da51974SJohn Youn 	unsigned int op_mode = dwc2_op_mode(hsotg);
8046bea9620SJohn Youn 
8056bea9620SJohn Youn 	return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) ||
8066bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) ||
8076bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE);
8086bea9620SJohn Youn }
8096bea9620SJohn Youn 
8106bea9620SJohn Youn /* Returns true if the controller is host-only. */
8116bea9620SJohn Youn bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg)
8126bea9620SJohn Youn {
8139da51974SJohn Youn 	unsigned int op_mode = dwc2_op_mode(hsotg);
8146bea9620SJohn Youn 
8156bea9620SJohn Youn 	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
8166bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
8176bea9620SJohn Youn }
8186bea9620SJohn Youn 
8196bea9620SJohn Youn /* Returns true if the controller is device-only. */
8206bea9620SJohn Youn bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
8216bea9620SJohn Youn {
8229da51974SJohn Youn 	unsigned int op_mode = dwc2_op_mode(hsotg);
8236bea9620SJohn Youn 
8246bea9620SJohn Youn 	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
8256bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
8266bea9620SJohn Youn }
8276bea9620SJohn Youn 
82879d6b8c5SSevak Arakelyan /**
82979d6b8c5SSevak Arakelyan  * dwc2_hsotg_wait_bit_set - Waits for bit to be set.
83079d6b8c5SSevak Arakelyan  * @hsotg: Programming view of DWC_otg controller.
83179d6b8c5SSevak Arakelyan  * @offset: Register's offset where bit/bits must be set.
83279d6b8c5SSevak Arakelyan  * @mask: Mask of the bit/bits which must be set.
83379d6b8c5SSevak Arakelyan  * @timeout: Timeout to wait.
83479d6b8c5SSevak Arakelyan  *
83579d6b8c5SSevak Arakelyan  * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
83679d6b8c5SSevak Arakelyan  */
83779d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
83879d6b8c5SSevak Arakelyan 			    u32 timeout)
83979d6b8c5SSevak Arakelyan {
84079d6b8c5SSevak Arakelyan 	u32 i;
84179d6b8c5SSevak Arakelyan 
84279d6b8c5SSevak Arakelyan 	for (i = 0; i < timeout; i++) {
84379d6b8c5SSevak Arakelyan 		if (dwc2_readl(hsotg->regs + offset) & mask)
84479d6b8c5SSevak Arakelyan 			return 0;
84579d6b8c5SSevak Arakelyan 		udelay(1);
84679d6b8c5SSevak Arakelyan 	}
84779d6b8c5SSevak Arakelyan 
84879d6b8c5SSevak Arakelyan 	return -ETIMEDOUT;
84979d6b8c5SSevak Arakelyan }
85079d6b8c5SSevak Arakelyan 
85179d6b8c5SSevak Arakelyan /**
85279d6b8c5SSevak Arakelyan  * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear.
85379d6b8c5SSevak Arakelyan  * @hsotg: Programming view of DWC_otg controller.
85479d6b8c5SSevak Arakelyan  * @offset: Register's offset where bit/bits must be set.
85579d6b8c5SSevak Arakelyan  * @mask: Mask of the bit/bits which must be set.
85679d6b8c5SSevak Arakelyan  * @timeout: Timeout to wait.
85779d6b8c5SSevak Arakelyan  *
85879d6b8c5SSevak Arakelyan  * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
85979d6b8c5SSevak Arakelyan  */
86079d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
86179d6b8c5SSevak Arakelyan 			      u32 timeout)
86279d6b8c5SSevak Arakelyan {
86379d6b8c5SSevak Arakelyan 	u32 i;
86479d6b8c5SSevak Arakelyan 
86579d6b8c5SSevak Arakelyan 	for (i = 0; i < timeout; i++) {
86679d6b8c5SSevak Arakelyan 		if (!(dwc2_readl(hsotg->regs + offset) & mask))
86779d6b8c5SSevak Arakelyan 			return 0;
86879d6b8c5SSevak Arakelyan 		udelay(1);
86979d6b8c5SSevak Arakelyan 	}
87079d6b8c5SSevak Arakelyan 
87179d6b8c5SSevak Arakelyan 	return -ETIMEDOUT;
87279d6b8c5SSevak Arakelyan }
87379d6b8c5SSevak Arakelyan 
874197ba5f4SPaul Zimmerman MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
875197ba5f4SPaul Zimmerman MODULE_AUTHOR("Synopsys, Inc.");
876197ba5f4SPaul Zimmerman MODULE_LICENSE("Dual BSD/GPL");
877