xref: /linux/drivers/usb/dwc2/core.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
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 
8197ba5f4SPaul Zimmerman /*
9197ba5f4SPaul Zimmerman  * The Core code provides basic services for accessing and managing the
10197ba5f4SPaul Zimmerman  * DWC_otg hardware. These services are used by both the Host Controller
11197ba5f4SPaul Zimmerman  * Driver and the Peripheral Controller Driver.
12197ba5f4SPaul Zimmerman  */
13197ba5f4SPaul Zimmerman #include <linux/kernel.h>
14197ba5f4SPaul Zimmerman #include <linux/module.h>
15197ba5f4SPaul Zimmerman #include <linux/moduleparam.h>
16197ba5f4SPaul Zimmerman #include <linux/spinlock.h>
17197ba5f4SPaul Zimmerman #include <linux/interrupt.h>
18197ba5f4SPaul Zimmerman #include <linux/dma-mapping.h>
19197ba5f4SPaul Zimmerman #include <linux/delay.h>
20197ba5f4SPaul Zimmerman #include <linux/io.h>
21197ba5f4SPaul Zimmerman #include <linux/slab.h>
22197ba5f4SPaul Zimmerman #include <linux/usb.h>
23197ba5f4SPaul Zimmerman 
24197ba5f4SPaul Zimmerman #include <linux/usb/hcd.h>
25197ba5f4SPaul Zimmerman #include <linux/usb/ch11.h>
26197ba5f4SPaul Zimmerman 
27197ba5f4SPaul Zimmerman #include "core.h"
28197ba5f4SPaul Zimmerman #include "hcd.h"
29197ba5f4SPaul Zimmerman 
30d17ee77bSGregory Herrero /**
31d17ee77bSGregory Herrero  * dwc2_backup_global_registers() - Backup global controller registers.
32d17ee77bSGregory Herrero  * When suspending usb bus, registers needs to be backuped
33d17ee77bSGregory Herrero  * if controller power is disabled once suspended.
34d17ee77bSGregory Herrero  *
35d17ee77bSGregory Herrero  * @hsotg: Programming view of the DWC_otg controller
36d17ee77bSGregory Herrero  */
37c5c403dcSVardan Mikayelyan int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
38d17ee77bSGregory Herrero {
39d17ee77bSGregory Herrero 	struct dwc2_gregs_backup *gr;
40af7c2bd3SVardan Mikayelyan 
41af7c2bd3SVardan Mikayelyan 	dev_dbg(hsotg->dev, "%s\n", __func__);
42d17ee77bSGregory Herrero 
43d17ee77bSGregory Herrero 	/* Backup global regs */
44cc1e204cSMian Yousaf Kaukab 	gr = &hsotg->gr_backup;
45d17ee77bSGregory Herrero 
46f25c42b8SGevorg Sahakyan 	gr->gotgctl = dwc2_readl(hsotg, GOTGCTL);
47f25c42b8SGevorg Sahakyan 	gr->gintmsk = dwc2_readl(hsotg, GINTMSK);
48f25c42b8SGevorg Sahakyan 	gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG);
49f25c42b8SGevorg Sahakyan 	gr->gusbcfg = dwc2_readl(hsotg, GUSBCFG);
50f25c42b8SGevorg Sahakyan 	gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
51f25c42b8SGevorg Sahakyan 	gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
52f25c42b8SGevorg Sahakyan 	gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG);
53f25c42b8SGevorg Sahakyan 	gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1);
54f25c42b8SGevorg Sahakyan 	gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG);
55f25c42b8SGevorg Sahakyan 	gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL);
56f25c42b8SGevorg Sahakyan 	gr->pcgcctl = dwc2_readl(hsotg, PCGCTL);
57d17ee77bSGregory Herrero 
58cc1e204cSMian Yousaf Kaukab 	gr->valid = true;
59d17ee77bSGregory Herrero 	return 0;
60d17ee77bSGregory Herrero }
61d17ee77bSGregory Herrero 
62d17ee77bSGregory Herrero /**
63d17ee77bSGregory Herrero  * dwc2_restore_global_registers() - Restore controller global registers.
64d17ee77bSGregory Herrero  * When resuming usb bus, device registers needs to be restored
65d17ee77bSGregory Herrero  * if controller power were disabled.
66d17ee77bSGregory Herrero  *
67d17ee77bSGregory Herrero  * @hsotg: Programming view of the DWC_otg controller
68d17ee77bSGregory Herrero  */
69c5c403dcSVardan Mikayelyan int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
70d17ee77bSGregory Herrero {
71d17ee77bSGregory Herrero 	struct dwc2_gregs_backup *gr;
72d17ee77bSGregory Herrero 
73d17ee77bSGregory Herrero 	dev_dbg(hsotg->dev, "%s\n", __func__);
74d17ee77bSGregory Herrero 
75d17ee77bSGregory Herrero 	/* Restore global regs */
76cc1e204cSMian Yousaf Kaukab 	gr = &hsotg->gr_backup;
77cc1e204cSMian Yousaf Kaukab 	if (!gr->valid) {
78d17ee77bSGregory Herrero 		dev_err(hsotg->dev, "%s: no global registers to restore\n",
79d17ee77bSGregory Herrero 			__func__);
80d17ee77bSGregory Herrero 		return -EINVAL;
81d17ee77bSGregory Herrero 	}
82cc1e204cSMian Yousaf Kaukab 	gr->valid = false;
83d17ee77bSGregory Herrero 
84f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
85f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gotgctl, GOTGCTL);
86f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gintmsk, GINTMSK);
87f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
88f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG);
89f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ);
90f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ);
91f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG);
92f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1);
93f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG);
94f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->pcgcctl, PCGCTL);
95f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL);
96d17ee77bSGregory Herrero 
97d17ee77bSGregory Herrero 	return 0;
98d17ee77bSGregory Herrero }
99d17ee77bSGregory Herrero 
100d17ee77bSGregory Herrero /**
10141ba9b9bSVardan Mikayelyan  * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
102d17ee77bSGregory Herrero  *
103d17ee77bSGregory Herrero  * @hsotg: Programming view of the DWC_otg controller
104c9c394abSArtur Petrosyan  * @rem_wakeup: indicates whether resume is initiated by Reset.
105d17ee77bSGregory Herrero  * @restore: Controller registers need to be restored
106d17ee77bSGregory Herrero  */
107c9c394abSArtur Petrosyan int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup,
108c9c394abSArtur Petrosyan 				 bool restore)
109d17ee77bSGregory Herrero {
110c9c394abSArtur Petrosyan 	struct dwc2_gregs_backup *gr;
111d17ee77bSGregory Herrero 
112c9c394abSArtur Petrosyan 	gr = &hsotg->gr_backup;
113285046aaSGregory Herrero 
114c9c394abSArtur Petrosyan 	/*
115c9c394abSArtur Petrosyan 	 * Restore host or device regisers with the same mode core enterted
116c9c394abSArtur Petrosyan 	 * to partial power down by checking "GOTGCTL_CURMODE_HOST" backup
117c9c394abSArtur Petrosyan 	 * value of the "gotgctl" register.
118c9c394abSArtur Petrosyan 	 */
119c9c394abSArtur Petrosyan 	if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
120c9c394abSArtur Petrosyan 		return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup,
121c9c394abSArtur Petrosyan 							 restore);
122c9c394abSArtur Petrosyan 	else
123c9c394abSArtur Petrosyan 		return dwc2_gadget_exit_partial_power_down(hsotg, restore);
124d17ee77bSGregory Herrero }
125d17ee77bSGregory Herrero 
126d17ee77bSGregory Herrero /**
12741ba9b9bSVardan Mikayelyan  * dwc2_enter_partial_power_down() - Put controller in Partial Power Down.
128d17ee77bSGregory Herrero  *
129d17ee77bSGregory Herrero  * @hsotg: Programming view of the DWC_otg controller
130d17ee77bSGregory Herrero  */
13141ba9b9bSVardan Mikayelyan int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
132d17ee77bSGregory Herrero {
133c9c394abSArtur Petrosyan 	if (dwc2_is_host_mode(hsotg))
134c9c394abSArtur Petrosyan 		return dwc2_host_enter_partial_power_down(hsotg);
135c9c394abSArtur Petrosyan 	else
136c9c394abSArtur Petrosyan 		return dwc2_gadget_enter_partial_power_down(hsotg);
137d17ee77bSGregory Herrero }
138d17ee77bSGregory Herrero 
139fef6bc37SJohn Youn /**
14094d2666cSVardan Mikayelyan  * dwc2_restore_essential_regs() - Restore essiential regs of core.
14194d2666cSVardan Mikayelyan  *
14294d2666cSVardan Mikayelyan  * @hsotg: Programming view of the DWC_otg controller
14394d2666cSVardan Mikayelyan  * @rmode: Restore mode, enabled in case of remote-wakeup.
14494d2666cSVardan Mikayelyan  * @is_host: Host or device mode.
14594d2666cSVardan Mikayelyan  */
14694d2666cSVardan Mikayelyan static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode,
14794d2666cSVardan Mikayelyan 					int is_host)
14894d2666cSVardan Mikayelyan {
14994d2666cSVardan Mikayelyan 	u32 pcgcctl;
15094d2666cSVardan Mikayelyan 	struct dwc2_gregs_backup *gr;
15194d2666cSVardan Mikayelyan 	struct dwc2_dregs_backup *dr;
15294d2666cSVardan Mikayelyan 	struct dwc2_hregs_backup *hr;
15394d2666cSVardan Mikayelyan 
15494d2666cSVardan Mikayelyan 	gr = &hsotg->gr_backup;
15594d2666cSVardan Mikayelyan 	dr = &hsotg->dr_backup;
15694d2666cSVardan Mikayelyan 	hr = &hsotg->hr_backup;
15794d2666cSVardan Mikayelyan 
15894d2666cSVardan Mikayelyan 	dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__);
15994d2666cSVardan Mikayelyan 
16094d2666cSVardan Mikayelyan 	/* Load restore values for [31:14] bits */
16194d2666cSVardan Mikayelyan 	pcgcctl = (gr->pcgcctl & 0xffffc000);
16294d2666cSVardan Mikayelyan 	/* If High Speed */
16394d2666cSVardan Mikayelyan 	if (is_host) {
16494d2666cSVardan Mikayelyan 		if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK))
16594d2666cSVardan Mikayelyan 			pcgcctl |= BIT(17);
16694d2666cSVardan Mikayelyan 	} else {
16794d2666cSVardan Mikayelyan 		if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK))
16894d2666cSVardan Mikayelyan 			pcgcctl |= BIT(17);
16994d2666cSVardan Mikayelyan 	}
170f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, pcgcctl, PCGCTL);
17194d2666cSVardan Mikayelyan 
17294d2666cSVardan Mikayelyan 	/* Umnask global Interrupt in GAHBCFG and restore it */
173f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, GAHBCFG);
17494d2666cSVardan Mikayelyan 
17594d2666cSVardan Mikayelyan 	/* Clear all pending interupts */
176f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, 0xffffffff, GINTSTS);
17794d2666cSVardan Mikayelyan 
17894d2666cSVardan Mikayelyan 	/* Unmask restore done interrupt */
179f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTMSK);
18094d2666cSVardan Mikayelyan 
18194d2666cSVardan Mikayelyan 	/* Restore GUSBCFG and HCFG/DCFG */
182f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
18394d2666cSVardan Mikayelyan 
18494d2666cSVardan Mikayelyan 	if (is_host) {
185f25c42b8SGevorg Sahakyan 		dwc2_writel(hsotg, hr->hcfg, HCFG);
18694d2666cSVardan Mikayelyan 		if (rmode)
18794d2666cSVardan Mikayelyan 			pcgcctl |= PCGCTL_RESTOREMODE;
188f25c42b8SGevorg Sahakyan 		dwc2_writel(hsotg, pcgcctl, PCGCTL);
18994d2666cSVardan Mikayelyan 		udelay(10);
19094d2666cSVardan Mikayelyan 
19194d2666cSVardan Mikayelyan 		pcgcctl |= PCGCTL_ESS_REG_RESTORED;
192f25c42b8SGevorg Sahakyan 		dwc2_writel(hsotg, pcgcctl, PCGCTL);
19394d2666cSVardan Mikayelyan 		udelay(10);
19494d2666cSVardan Mikayelyan 	} else {
195f25c42b8SGevorg Sahakyan 		dwc2_writel(hsotg, dr->dcfg, DCFG);
19694d2666cSVardan Mikayelyan 		if (!rmode)
19794d2666cSVardan Mikayelyan 			pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE;
198f25c42b8SGevorg Sahakyan 		dwc2_writel(hsotg, pcgcctl, PCGCTL);
19994d2666cSVardan Mikayelyan 		udelay(10);
20094d2666cSVardan Mikayelyan 
20194d2666cSVardan Mikayelyan 		pcgcctl |= PCGCTL_ESS_REG_RESTORED;
202f25c42b8SGevorg Sahakyan 		dwc2_writel(hsotg, pcgcctl, PCGCTL);
20394d2666cSVardan Mikayelyan 		udelay(10);
20494d2666cSVardan Mikayelyan 	}
20594d2666cSVardan Mikayelyan }
20694d2666cSVardan Mikayelyan 
20794d2666cSVardan Mikayelyan /**
20894d2666cSVardan Mikayelyan  * dwc2_hib_restore_common() - Common part of restore routine.
20994d2666cSVardan Mikayelyan  *
21094d2666cSVardan Mikayelyan  * @hsotg: Programming view of the DWC_otg controller
21194d2666cSVardan Mikayelyan  * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup.
21294d2666cSVardan Mikayelyan  * @is_host: Host or device mode.
21394d2666cSVardan Mikayelyan  */
21494d2666cSVardan Mikayelyan void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
21594d2666cSVardan Mikayelyan 			     int is_host)
21694d2666cSVardan Mikayelyan {
21794d2666cSVardan Mikayelyan 	u32 gpwrdn;
21894d2666cSVardan Mikayelyan 
21994d2666cSVardan Mikayelyan 	/* Switch-on voltage to the core */
220f25c42b8SGevorg Sahakyan 	gpwrdn = dwc2_readl(hsotg, GPWRDN);
22194d2666cSVardan Mikayelyan 	gpwrdn &= ~GPWRDN_PWRDNSWTCH;
222f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
22394d2666cSVardan Mikayelyan 	udelay(10);
22494d2666cSVardan Mikayelyan 
22594d2666cSVardan Mikayelyan 	/* Reset core */
226f25c42b8SGevorg Sahakyan 	gpwrdn = dwc2_readl(hsotg, GPWRDN);
22794d2666cSVardan Mikayelyan 	gpwrdn &= ~GPWRDN_PWRDNRSTN;
228f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
22994d2666cSVardan Mikayelyan 	udelay(10);
23094d2666cSVardan Mikayelyan 
23194d2666cSVardan Mikayelyan 	/* Enable restore from PMU */
232f25c42b8SGevorg Sahakyan 	gpwrdn = dwc2_readl(hsotg, GPWRDN);
23394d2666cSVardan Mikayelyan 	gpwrdn |= GPWRDN_RESTORE;
234f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
23594d2666cSVardan Mikayelyan 	udelay(10);
23694d2666cSVardan Mikayelyan 
23794d2666cSVardan Mikayelyan 	/* Disable Power Down Clamp */
238f25c42b8SGevorg Sahakyan 	gpwrdn = dwc2_readl(hsotg, GPWRDN);
23994d2666cSVardan Mikayelyan 	gpwrdn &= ~GPWRDN_PWRDNCLMP;
240f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
24194d2666cSVardan Mikayelyan 	udelay(50);
24294d2666cSVardan Mikayelyan 
24394d2666cSVardan Mikayelyan 	if (!is_host && rem_wakeup)
24494d2666cSVardan Mikayelyan 		udelay(70);
24594d2666cSVardan Mikayelyan 
24694d2666cSVardan Mikayelyan 	/* Deassert reset core */
247f25c42b8SGevorg Sahakyan 	gpwrdn = dwc2_readl(hsotg, GPWRDN);
24894d2666cSVardan Mikayelyan 	gpwrdn |= GPWRDN_PWRDNRSTN;
249f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
25094d2666cSVardan Mikayelyan 	udelay(10);
25194d2666cSVardan Mikayelyan 
2524483ef3cSMinas Harutyunyan 	/* Reset ULPI latch */
2534483ef3cSMinas Harutyunyan 	gpwrdn = dwc2_readl(hsotg, GPWRDN);
2544483ef3cSMinas Harutyunyan 	gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY;
2554483ef3cSMinas Harutyunyan 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
2564483ef3cSMinas Harutyunyan 
25794d2666cSVardan Mikayelyan 	/* Disable PMU interrupt */
258f25c42b8SGevorg Sahakyan 	gpwrdn = dwc2_readl(hsotg, GPWRDN);
25994d2666cSVardan Mikayelyan 	gpwrdn &= ~GPWRDN_PMUINTSEL;
260f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gpwrdn, GPWRDN);
26194d2666cSVardan Mikayelyan 	udelay(10);
26294d2666cSVardan Mikayelyan 
26394d2666cSVardan Mikayelyan 	/* Set Restore Essential Regs bit in PCGCCTL register */
26494d2666cSVardan Mikayelyan 	dwc2_restore_essential_regs(hsotg, rem_wakeup, is_host);
26594d2666cSVardan Mikayelyan 
26694d2666cSVardan Mikayelyan 	/*
26794d2666cSVardan Mikayelyan 	 * Wait For Restore_done Interrupt. This mechanism of polling the
26894d2666cSVardan Mikayelyan 	 * interrupt is introduced to avoid any possible race conditions
26994d2666cSVardan Mikayelyan 	 */
27094d2666cSVardan Mikayelyan 	if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE,
27194d2666cSVardan Mikayelyan 				    20000)) {
27294d2666cSVardan Mikayelyan 		dev_dbg(hsotg->dev,
273a76cb3d9SColin Ian King 			"%s: Restore Done wasn't generated here\n",
27494d2666cSVardan Mikayelyan 			__func__);
27594d2666cSVardan Mikayelyan 	} else {
27694d2666cSVardan Mikayelyan 		dev_dbg(hsotg->dev, "restore done  generated here\n");
2775160d687SArtur Petrosyan 
2785160d687SArtur Petrosyan 		/*
2795160d687SArtur Petrosyan 		 * To avoid restore done interrupt storm after restore is
2805160d687SArtur Petrosyan 		 * generated clear GINTSTS_RESTOREDONE bit.
2815160d687SArtur Petrosyan 		 */
2825160d687SArtur Petrosyan 		dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTSTS);
28394d2666cSVardan Mikayelyan 	}
28494d2666cSVardan Mikayelyan }
28594d2666cSVardan Mikayelyan 
28694d2666cSVardan Mikayelyan /**
287fef6bc37SJohn Youn  * dwc2_wait_for_mode() - Waits for the controller mode.
288fef6bc37SJohn Youn  * @hsotg:	Programming view of the DWC_otg controller.
289fef6bc37SJohn Youn  * @host_mode:	If true, waits for host mode, otherwise device mode.
290fef6bc37SJohn Youn  */
291fef6bc37SJohn Youn static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg,
292fef6bc37SJohn Youn 			       bool host_mode)
293fef6bc37SJohn Youn {
294fef6bc37SJohn Youn 	ktime_t start;
295fef6bc37SJohn Youn 	ktime_t end;
296fef6bc37SJohn Youn 	unsigned int timeout = 110;
297fef6bc37SJohn Youn 
298fef6bc37SJohn Youn 	dev_vdbg(hsotg->dev, "Waiting for %s mode\n",
299fef6bc37SJohn Youn 		 host_mode ? "host" : "device");
300fef6bc37SJohn Youn 
301fef6bc37SJohn Youn 	start = ktime_get();
302fef6bc37SJohn Youn 
303fef6bc37SJohn Youn 	while (1) {
304fef6bc37SJohn Youn 		s64 ms;
305fef6bc37SJohn Youn 
306fef6bc37SJohn Youn 		if (dwc2_is_host_mode(hsotg) == host_mode) {
307fef6bc37SJohn Youn 			dev_vdbg(hsotg->dev, "%s mode set\n",
308fef6bc37SJohn Youn 				 host_mode ? "Host" : "Device");
309fef6bc37SJohn Youn 			break;
310fef6bc37SJohn Youn 		}
311fef6bc37SJohn Youn 
312fef6bc37SJohn Youn 		end = ktime_get();
313fef6bc37SJohn Youn 		ms = ktime_to_ms(ktime_sub(end, start));
314fef6bc37SJohn Youn 
315fef6bc37SJohn Youn 		if (ms >= (s64)timeout) {
316fef6bc37SJohn Youn 			dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n",
317fef6bc37SJohn Youn 				 __func__, host_mode ? "host" : "device");
318fef6bc37SJohn Youn 			break;
319fef6bc37SJohn Youn 		}
320fef6bc37SJohn Youn 
321fef6bc37SJohn Youn 		usleep_range(1000, 2000);
322fef6bc37SJohn Youn 	}
323fef6bc37SJohn Youn }
324fef6bc37SJohn Youn 
325fef6bc37SJohn Youn /**
326fef6bc37SJohn Youn  * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce
327fef6bc37SJohn Youn  * filter is enabled.
3286fb914d7SGrigor Tovmasyan  *
3296fb914d7SGrigor Tovmasyan  * @hsotg: Programming view of DWC_otg controller
330fef6bc37SJohn Youn  */
331fef6bc37SJohn Youn static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
332fef6bc37SJohn Youn {
333fef6bc37SJohn Youn 	u32 gsnpsid;
334fef6bc37SJohn Youn 	u32 ghwcfg4;
335fef6bc37SJohn Youn 
336fef6bc37SJohn Youn 	if (!dwc2_hw_is_otg(hsotg))
337fef6bc37SJohn Youn 		return false;
338fef6bc37SJohn Youn 
339fef6bc37SJohn Youn 	/* Check if core configuration includes the IDDIG filter. */
340f25c42b8SGevorg Sahakyan 	ghwcfg4 = dwc2_readl(hsotg, GHWCFG4);
341fef6bc37SJohn Youn 	if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
342fef6bc37SJohn Youn 		return false;
343fef6bc37SJohn Youn 
344fef6bc37SJohn Youn 	/*
345fef6bc37SJohn Youn 	 * Check if the IDDIG debounce filter is bypassed. Available
346fef6bc37SJohn Youn 	 * in core version >= 3.10a.
347fef6bc37SJohn Youn 	 */
348f25c42b8SGevorg Sahakyan 	gsnpsid = dwc2_readl(hsotg, GSNPSID);
349fef6bc37SJohn Youn 	if (gsnpsid >= DWC2_CORE_REV_3_10a) {
350f25c42b8SGevorg Sahakyan 		u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
351fef6bc37SJohn Youn 
352fef6bc37SJohn Youn 		if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
353fef6bc37SJohn Youn 			return false;
354fef6bc37SJohn Youn 	}
355fef6bc37SJohn Youn 
356fef6bc37SJohn Youn 	return true;
357fef6bc37SJohn Youn }
358fef6bc37SJohn Youn 
359197ba5f4SPaul Zimmerman /*
360624815ceSVardan Mikayelyan  * dwc2_enter_hibernation() - Common function to enter hibernation.
361624815ceSVardan Mikayelyan  *
362624815ceSVardan Mikayelyan  * @hsotg: Programming view of the DWC_otg controller
363624815ceSVardan Mikayelyan  * @is_host: True if core is in host mode.
364624815ceSVardan Mikayelyan  *
365624815ceSVardan Mikayelyan  * Return: 0 if successful, negative error code otherwise
366624815ceSVardan Mikayelyan  */
367624815ceSVardan Mikayelyan int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host)
368624815ceSVardan Mikayelyan {
369624815ceSVardan Mikayelyan 	if (is_host)
370624815ceSVardan Mikayelyan 		return dwc2_host_enter_hibernation(hsotg);
371624815ceSVardan Mikayelyan 	else
372624815ceSVardan Mikayelyan 		return dwc2_gadget_enter_hibernation(hsotg);
373624815ceSVardan Mikayelyan }
374624815ceSVardan Mikayelyan 
375624815ceSVardan Mikayelyan /*
376624815ceSVardan Mikayelyan  * dwc2_exit_hibernation() - Common function to exit from hibernation.
377624815ceSVardan Mikayelyan  *
378624815ceSVardan Mikayelyan  * @hsotg: Programming view of the DWC_otg controller
379624815ceSVardan Mikayelyan  * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup.
380624815ceSVardan Mikayelyan  * @reset: Enabled in case of restore with reset.
381624815ceSVardan Mikayelyan  * @is_host: True if core is in host mode.
382624815ceSVardan Mikayelyan  *
383624815ceSVardan Mikayelyan  * Return: 0 if successful, negative error code otherwise
384624815ceSVardan Mikayelyan  */
385624815ceSVardan Mikayelyan int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
386624815ceSVardan Mikayelyan 			  int reset, int is_host)
387624815ceSVardan Mikayelyan {
388624815ceSVardan Mikayelyan 	if (is_host)
389624815ceSVardan Mikayelyan 		return dwc2_host_exit_hibernation(hsotg, rem_wakeup, reset);
390624815ceSVardan Mikayelyan 	else
391624815ceSVardan Mikayelyan 		return dwc2_gadget_exit_hibernation(hsotg, rem_wakeup, reset);
392624815ceSVardan Mikayelyan }
393624815ceSVardan Mikayelyan 
394624815ceSVardan Mikayelyan /*
395197ba5f4SPaul Zimmerman  * Do core a soft reset of the core.  Be careful with this because it
396197ba5f4SPaul Zimmerman  * resets all the internal state machines of the core.
397197ba5f4SPaul Zimmerman  */
3986e6360b6SJohn Stultz int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
399197ba5f4SPaul Zimmerman {
400197ba5f4SPaul Zimmerman 	u32 greset;
401fef6bc37SJohn Youn 	bool wait_for_host_mode = false;
402197ba5f4SPaul Zimmerman 
403197ba5f4SPaul Zimmerman 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
404197ba5f4SPaul Zimmerman 
405fef6bc37SJohn Youn 	/*
406fef6bc37SJohn Youn 	 * If the current mode is host, either due to the force mode
407fef6bc37SJohn Youn 	 * bit being set (which persists after core reset) or the
408fef6bc37SJohn Youn 	 * connector id pin, a core soft reset will temporarily reset
409fef6bc37SJohn Youn 	 * the mode to device. A delay from the IDDIG debounce filter
410fef6bc37SJohn Youn 	 * will occur before going back to host mode.
411fef6bc37SJohn Youn 	 *
412fef6bc37SJohn Youn 	 * Determine whether we will go back into host mode after a
413fef6bc37SJohn Youn 	 * reset and account for this delay after the reset.
414fef6bc37SJohn Youn 	 */
415fef6bc37SJohn Youn 	if (dwc2_iddig_filter_enabled(hsotg)) {
416f25c42b8SGevorg Sahakyan 		u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
417f25c42b8SGevorg Sahakyan 		u32 gusbcfg = dwc2_readl(hsotg, GUSBCFG);
418fef6bc37SJohn Youn 
419fef6bc37SJohn Youn 		if (!(gotgctl & GOTGCTL_CONID_B) ||
420fef6bc37SJohn Youn 		    (gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
421fef6bc37SJohn Youn 			wait_for_host_mode = true;
422fef6bc37SJohn Youn 		}
423fef6bc37SJohn Youn 	}
424fef6bc37SJohn Youn 
425197ba5f4SPaul Zimmerman 	/* Core Soft Reset */
426f25c42b8SGevorg Sahakyan 	greset = dwc2_readl(hsotg, GRSTCTL);
427197ba5f4SPaul Zimmerman 	greset |= GRSTCTL_CSFTRST;
428f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, greset, GRSTCTL);
42979d6b8c5SSevak Arakelyan 
43065dc2e72SMinas Harutyunyan 	if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) <
43165dc2e72SMinas Harutyunyan 		(DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
43265dc2e72SMinas Harutyunyan 		if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL,
43365dc2e72SMinas Harutyunyan 					      GRSTCTL_CSFTRST, 10000)) {
43465dc2e72SMinas Harutyunyan 			dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n",
43579d6b8c5SSevak Arakelyan 				 __func__);
436197ba5f4SPaul Zimmerman 			return -EBUSY;
437197ba5f4SPaul Zimmerman 		}
43865dc2e72SMinas Harutyunyan 	} else {
43965dc2e72SMinas Harutyunyan 		if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL,
44065dc2e72SMinas Harutyunyan 					    GRSTCTL_CSFTRST_DONE, 10000)) {
44165dc2e72SMinas Harutyunyan 			dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n",
44265dc2e72SMinas Harutyunyan 				 __func__);
44365dc2e72SMinas Harutyunyan 			return -EBUSY;
44465dc2e72SMinas Harutyunyan 		}
44565dc2e72SMinas Harutyunyan 		greset = dwc2_readl(hsotg, GRSTCTL);
44665dc2e72SMinas Harutyunyan 		greset &= ~GRSTCTL_CSFTRST;
44765dc2e72SMinas Harutyunyan 		greset |= GRSTCTL_CSFTRST_DONE;
44865dc2e72SMinas Harutyunyan 		dwc2_writel(hsotg, greset, GRSTCTL);
44965dc2e72SMinas Harutyunyan 	}
450197ba5f4SPaul Zimmerman 
451238f65aeSArtur Petrosyan 	/*
452238f65aeSArtur Petrosyan 	 * Switching from device mode to host mode by disconnecting
453238f65aeSArtur Petrosyan 	 * device cable core enters and exits form hibernation.
454238f65aeSArtur Petrosyan 	 * However, the fifo map remains not cleared. It results
455238f65aeSArtur Petrosyan 	 * to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/
456238f65aeSArtur Petrosyan 	 * gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2])
457238f65aeSArtur Petrosyan 	 * if in host mode we disconnect the micro a to b host
458238f65aeSArtur Petrosyan 	 * cable. Because core reset occurs.
459238f65aeSArtur Petrosyan 	 * To avoid the WARNING, fifo_map should be cleared
460238f65aeSArtur Petrosyan 	 * in dwc2_core_reset() function by taking into account configs.
461238f65aeSArtur Petrosyan 	 * fifo_map must be cleared only if driver is configured in
462238f65aeSArtur Petrosyan 	 * "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE"
463238f65aeSArtur Petrosyan 	 * mode.
464238f65aeSArtur Petrosyan 	 */
465238f65aeSArtur Petrosyan 	dwc2_clear_fifo_map(hsotg);
466238f65aeSArtur Petrosyan 
467b8ccc593SJohn Youn 	/* Wait for AHB master IDLE state */
468dfc4fdebSMartin Blumenstingl 	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) {
46979d6b8c5SSevak Arakelyan 		dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
47079d6b8c5SSevak Arakelyan 			 __func__);
471b8ccc593SJohn Youn 		return -EBUSY;
472b8ccc593SJohn Youn 	}
473b8ccc593SJohn Youn 
4746e6360b6SJohn Stultz 	if (wait_for_host_mode && !skip_wait)
475fef6bc37SJohn Youn 		dwc2_wait_for_mode(hsotg, true);
476fef6bc37SJohn Youn 
477b5d308abSJohn Youn 	return 0;
478b5d308abSJohn Youn }
479b5d308abSJohn Youn 
48013b1f8e2SVardan Mikayelyan /**
48113b1f8e2SVardan Mikayelyan  * dwc2_force_mode() - Force the mode of the controller.
48209c96980SJohn Youn  *
48309c96980SJohn Youn  * Forcing the mode is needed for two cases:
48409c96980SJohn Youn  *
48509c96980SJohn Youn  * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the
48609c96980SJohn Youn  * controller to stay in a particular mode regardless of ID pin
48713b1f8e2SVardan Mikayelyan  * changes. We do this once during probe.
48809c96980SJohn Youn  *
48909c96980SJohn Youn  * 2) During probe we want to read reset values of the hw
49009c96980SJohn Youn  * configuration registers that are only available in either host or
49109c96980SJohn Youn  * device mode. We may need to force the mode if the current mode does
49209c96980SJohn Youn  * not allow us to access the register in the mode that we want.
49309c96980SJohn Youn  *
49409c96980SJohn Youn  * In either case it only makes sense to force the mode if the
49509c96980SJohn Youn  * controller hardware is OTG capable.
49609c96980SJohn Youn  *
49709c96980SJohn Youn  * Checks are done in this function to determine whether doing a force
49809c96980SJohn Youn  * would be valid or not.
49909c96980SJohn Youn  *
5002938fc63SJohn Youn  * If a force is done, it requires a IDDIG debounce filter delay if
5012938fc63SJohn Youn  * the filter is configured and enabled. We poll the current mode of
5022938fc63SJohn Youn  * the controller to account for this delay.
5036fb914d7SGrigor Tovmasyan  *
5046fb914d7SGrigor Tovmasyan  * @hsotg: Programming view of DWC_otg controller
5056fb914d7SGrigor Tovmasyan  * @host: Host mode flag
50609c96980SJohn Youn  */
50713b1f8e2SVardan Mikayelyan void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
50809c96980SJohn Youn {
50909c96980SJohn Youn 	u32 gusbcfg;
51009c96980SJohn Youn 	u32 set;
51109c96980SJohn Youn 	u32 clear;
51209c96980SJohn Youn 
51309c96980SJohn Youn 	dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device");
51409c96980SJohn Youn 
51509c96980SJohn Youn 	/*
51609c96980SJohn Youn 	 * Force mode has no effect if the hardware is not OTG.
51709c96980SJohn Youn 	 */
51809c96980SJohn Youn 	if (!dwc2_hw_is_otg(hsotg))
51913b1f8e2SVardan Mikayelyan 		return;
52009c96980SJohn Youn 
52109c96980SJohn Youn 	/*
52209c96980SJohn Youn 	 * If dr_mode is either peripheral or host only, there is no
52309c96980SJohn Youn 	 * need to ever force the mode to the opposite mode.
52409c96980SJohn Youn 	 */
52509c96980SJohn Youn 	if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
52613b1f8e2SVardan Mikayelyan 		return;
52709c96980SJohn Youn 
52809c96980SJohn Youn 	if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
52913b1f8e2SVardan Mikayelyan 		return;
53009c96980SJohn Youn 
531f25c42b8SGevorg Sahakyan 	gusbcfg = dwc2_readl(hsotg, GUSBCFG);
53209c96980SJohn Youn 
53309c96980SJohn Youn 	set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
53409c96980SJohn Youn 	clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
53509c96980SJohn Youn 
53609c96980SJohn Youn 	gusbcfg &= ~clear;
53709c96980SJohn Youn 	gusbcfg |= set;
538f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gusbcfg, GUSBCFG);
53909c96980SJohn Youn 
5402938fc63SJohn Youn 	dwc2_wait_for_mode(hsotg, host);
54113b1f8e2SVardan Mikayelyan 	return;
54209c96980SJohn Youn }
54309c96980SJohn Youn 
5442938fc63SJohn Youn /**
5452938fc63SJohn Youn  * dwc2_clear_force_mode() - Clears the force mode bits.
5462938fc63SJohn Youn  *
5472938fc63SJohn Youn  * After clearing the bits, wait up to 100 ms to account for any
5482938fc63SJohn Youn  * potential IDDIG filter delay. We can't know if we expect this delay
5492938fc63SJohn Youn  * or not because the value of the connector ID status is affected by
5502938fc63SJohn Youn  * the force mode. We only need to call this once during probe if
5512938fc63SJohn Youn  * dr_mode == OTG.
5526fb914d7SGrigor Tovmasyan  *
5536fb914d7SGrigor Tovmasyan  * @hsotg: Programming view of DWC_otg controller
55409c96980SJohn Youn  */
555365b7673SGrigor Tovmasyan static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
55609c96980SJohn Youn {
55709c96980SJohn Youn 	u32 gusbcfg;
55809c96980SJohn Youn 
55913b1f8e2SVardan Mikayelyan 	if (!dwc2_hw_is_otg(hsotg))
56013b1f8e2SVardan Mikayelyan 		return;
56113b1f8e2SVardan Mikayelyan 
56213b1f8e2SVardan Mikayelyan 	dev_dbg(hsotg->dev, "Clearing force mode bits\n");
56313b1f8e2SVardan Mikayelyan 
564f25c42b8SGevorg Sahakyan 	gusbcfg = dwc2_readl(hsotg, GUSBCFG);
56509c96980SJohn Youn 	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
56609c96980SJohn Youn 	gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
567f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, gusbcfg, GUSBCFG);
56809c96980SJohn Youn 
5692938fc63SJohn Youn 	if (dwc2_iddig_filter_enabled(hsotg))
570d3fe81d2SNicholas Mc Guire 		msleep(100);
57109c96980SJohn Youn }
57209c96980SJohn Youn 
57309c96980SJohn Youn /*
57409c96980SJohn Youn  * Sets or clears force mode based on the dr_mode parameter.
57509c96980SJohn Youn  */
57609c96980SJohn Youn void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
57709c96980SJohn Youn {
57809c96980SJohn Youn 	switch (hsotg->dr_mode) {
57909c96980SJohn Youn 	case USB_DR_MODE_HOST:
580a07ce8d3SHeiko Stuebner 		/*
581a07ce8d3SHeiko Stuebner 		 * NOTE: This is required for some rockchip soc based
582a07ce8d3SHeiko Stuebner 		 * platforms on their host-only dwc2.
583a07ce8d3SHeiko Stuebner 		 */
58413b1f8e2SVardan Mikayelyan 		if (!dwc2_hw_is_otg(hsotg))
585a07ce8d3SHeiko Stuebner 			msleep(50);
586a07ce8d3SHeiko Stuebner 
58709c96980SJohn Youn 		break;
58809c96980SJohn Youn 	case USB_DR_MODE_PERIPHERAL:
58909c96980SJohn Youn 		dwc2_force_mode(hsotg, false);
59009c96980SJohn Youn 		break;
59109c96980SJohn Youn 	case USB_DR_MODE_OTG:
59209c96980SJohn Youn 		dwc2_clear_force_mode(hsotg);
59309c96980SJohn Youn 		break;
59409c96980SJohn Youn 	default:
59509c96980SJohn Youn 		dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n",
59609c96980SJohn Youn 			 __func__, hsotg->dr_mode);
59709c96980SJohn Youn 		break;
59809c96980SJohn Youn 	}
59909c96980SJohn Youn }
60009c96980SJohn Youn 
60109c96980SJohn Youn /*
60266e77a24SRazmik Karapetyan  * dwc2_enable_acg - enable active clock gating feature
60366e77a24SRazmik Karapetyan  */
60466e77a24SRazmik Karapetyan void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
60566e77a24SRazmik Karapetyan {
60666e77a24SRazmik Karapetyan 	if (hsotg->params.acg_enable) {
607f25c42b8SGevorg Sahakyan 		u32 pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1);
60866e77a24SRazmik Karapetyan 
60966e77a24SRazmik Karapetyan 		dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
61066e77a24SRazmik Karapetyan 		pcgcctl1 |= PCGCCTL1_GATEEN;
611f25c42b8SGevorg Sahakyan 		dwc2_writel(hsotg, pcgcctl1, PCGCCTL1);
61266e77a24SRazmik Karapetyan 	}
61366e77a24SRazmik Karapetyan }
61466e77a24SRazmik Karapetyan 
615197ba5f4SPaul Zimmerman /**
616197ba5f4SPaul Zimmerman  * dwc2_dump_host_registers() - Prints the host registers
617197ba5f4SPaul Zimmerman  *
618197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
619197ba5f4SPaul Zimmerman  *
620197ba5f4SPaul Zimmerman  * NOTE: This function will be removed once the peripheral controller code
621197ba5f4SPaul Zimmerman  * is integrated and the driver is stable
622197ba5f4SPaul Zimmerman  */
623197ba5f4SPaul Zimmerman void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
624197ba5f4SPaul Zimmerman {
625197ba5f4SPaul Zimmerman #ifdef DEBUG
626197ba5f4SPaul Zimmerman 	u32 __iomem *addr;
627197ba5f4SPaul Zimmerman 	int i;
628197ba5f4SPaul Zimmerman 
629197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "Host Global Registers\n");
630197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HCFG;
631197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HCFG	 @0x%08lX : 0x%08X\n",
632f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HCFG));
633197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HFIR;
634197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HFIR	 @0x%08lX : 0x%08X\n",
635f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HFIR));
636197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HFNUM;
637197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HFNUM	 @0x%08lX : 0x%08X\n",
638f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HFNUM));
639197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HPTXSTS;
640197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HPTXSTS	 @0x%08lX : 0x%08X\n",
641f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HPTXSTS));
642197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HAINT;
643197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HAINT	 @0x%08lX : 0x%08X\n",
644f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HAINT));
645197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HAINTMSK;
646197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HAINTMSK	 @0x%08lX : 0x%08X\n",
647f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HAINTMSK));
64895832c00SJohn Youn 	if (hsotg->params.dma_desc_enable) {
649197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HFLBADDR;
650197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
651f25c42b8SGevorg Sahakyan 			(unsigned long)addr, dwc2_readl(hsotg, HFLBADDR));
652197ba5f4SPaul Zimmerman 	}
653197ba5f4SPaul Zimmerman 
654197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HPRT0;
655197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HPRT0	 @0x%08lX : 0x%08X\n",
656f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HPRT0));
657197ba5f4SPaul Zimmerman 
658bea8e86cSJohn Youn 	for (i = 0; i < hsotg->params.host_channels; i++) {
659197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
660197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCCHAR(i);
661197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCCHAR	 @0x%08lX : 0x%08X\n",
662f25c42b8SGevorg Sahakyan 			(unsigned long)addr, dwc2_readl(hsotg, HCCHAR(i)));
663197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCSPLT(i);
664197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCSPLT	 @0x%08lX : 0x%08X\n",
665f25c42b8SGevorg Sahakyan 			(unsigned long)addr, dwc2_readl(hsotg, HCSPLT(i)));
666197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCINT(i);
667197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCINT	 @0x%08lX : 0x%08X\n",
668f25c42b8SGevorg Sahakyan 			(unsigned long)addr, dwc2_readl(hsotg, HCINT(i)));
669197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCINTMSK(i);
670197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCINTMSK	 @0x%08lX : 0x%08X\n",
671f25c42b8SGevorg Sahakyan 			(unsigned long)addr, dwc2_readl(hsotg, HCINTMSK(i)));
672197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCTSIZ(i);
673197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCTSIZ	 @0x%08lX : 0x%08X\n",
674f25c42b8SGevorg Sahakyan 			(unsigned long)addr, dwc2_readl(hsotg, HCTSIZ(i)));
675197ba5f4SPaul Zimmerman 		addr = hsotg->regs + HCDMA(i);
676197ba5f4SPaul Zimmerman 		dev_dbg(hsotg->dev, "HCDMA	 @0x%08lX : 0x%08X\n",
677f25c42b8SGevorg Sahakyan 			(unsigned long)addr, dwc2_readl(hsotg, HCDMA(i)));
67895832c00SJohn Youn 		if (hsotg->params.dma_desc_enable) {
679197ba5f4SPaul Zimmerman 			addr = hsotg->regs + HCDMAB(i);
680197ba5f4SPaul Zimmerman 			dev_dbg(hsotg->dev, "HCDMAB	 @0x%08lX : 0x%08X\n",
681f25c42b8SGevorg Sahakyan 				(unsigned long)addr, dwc2_readl(hsotg,
682f25c42b8SGevorg Sahakyan 								HCDMAB(i)));
683197ba5f4SPaul Zimmerman 		}
684197ba5f4SPaul Zimmerman 	}
685197ba5f4SPaul Zimmerman #endif
686197ba5f4SPaul Zimmerman }
687197ba5f4SPaul Zimmerman 
688197ba5f4SPaul Zimmerman /**
689197ba5f4SPaul Zimmerman  * dwc2_dump_global_registers() - Prints the core global registers
690197ba5f4SPaul Zimmerman  *
691197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
692197ba5f4SPaul Zimmerman  *
693197ba5f4SPaul Zimmerman  * NOTE: This function will be removed once the peripheral controller code
694197ba5f4SPaul Zimmerman  * is integrated and the driver is stable
695197ba5f4SPaul Zimmerman  */
696197ba5f4SPaul Zimmerman void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
697197ba5f4SPaul Zimmerman {
698197ba5f4SPaul Zimmerman #ifdef DEBUG
699197ba5f4SPaul Zimmerman 	u32 __iomem *addr;
700197ba5f4SPaul Zimmerman 
701197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "Core Global Registers\n");
702197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GOTGCTL;
703197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GOTGCTL	 @0x%08lX : 0x%08X\n",
704f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GOTGCTL));
705197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GOTGINT;
706197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GOTGINT	 @0x%08lX : 0x%08X\n",
707f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GOTGINT));
708197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GAHBCFG;
709197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GAHBCFG	 @0x%08lX : 0x%08X\n",
710f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GAHBCFG));
711197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GUSBCFG;
712197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GUSBCFG	 @0x%08lX : 0x%08X\n",
713f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GUSBCFG));
714197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GRSTCTL;
715197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GRSTCTL	 @0x%08lX : 0x%08X\n",
716f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GRSTCTL));
717197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GINTSTS;
718197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GINTSTS	 @0x%08lX : 0x%08X\n",
719f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GINTSTS));
720197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GINTMSK;
721197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GINTMSK	 @0x%08lX : 0x%08X\n",
722f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GINTMSK));
723197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GRXSTSR;
724197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GRXSTSR	 @0x%08lX : 0x%08X\n",
725f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GRXSTSR));
726197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GRXFSIZ;
727197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GRXFSIZ	 @0x%08lX : 0x%08X\n",
728f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GRXFSIZ));
729197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GNPTXFSIZ;
730197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GNPTXFSIZ	 @0x%08lX : 0x%08X\n",
731f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GNPTXFSIZ));
732197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GNPTXSTS;
733197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GNPTXSTS	 @0x%08lX : 0x%08X\n",
734f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GNPTXSTS));
735197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GI2CCTL;
736197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GI2CCTL	 @0x%08lX : 0x%08X\n",
737f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GI2CCTL));
738197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GPVNDCTL;
739197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GPVNDCTL	 @0x%08lX : 0x%08X\n",
740f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GPVNDCTL));
741197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GGPIO;
742197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GGPIO	 @0x%08lX : 0x%08X\n",
743f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GGPIO));
744197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GUID;
745197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GUID	 @0x%08lX : 0x%08X\n",
746f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GUID));
747197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GSNPSID;
748197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GSNPSID	 @0x%08lX : 0x%08X\n",
749f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GSNPSID));
750197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG1;
751197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG1	 @0x%08lX : 0x%08X\n",
752f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GHWCFG1));
753197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG2;
754197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG2	 @0x%08lX : 0x%08X\n",
755f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GHWCFG2));
756197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG3;
757197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG3	 @0x%08lX : 0x%08X\n",
758f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GHWCFG3));
759197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GHWCFG4;
760197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GHWCFG4	 @0x%08lX : 0x%08X\n",
761f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GHWCFG4));
762197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GLPMCFG;
763197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GLPMCFG	 @0x%08lX : 0x%08X\n",
764f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GLPMCFG));
765197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GPWRDN;
766197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GPWRDN	 @0x%08lX : 0x%08X\n",
767f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GPWRDN));
768197ba5f4SPaul Zimmerman 	addr = hsotg->regs + GDFIFOCFG;
769197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "GDFIFOCFG	 @0x%08lX : 0x%08X\n",
770f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, GDFIFOCFG));
771197ba5f4SPaul Zimmerman 	addr = hsotg->regs + HPTXFSIZ;
772197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "HPTXFSIZ	 @0x%08lX : 0x%08X\n",
773f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, HPTXFSIZ));
774197ba5f4SPaul Zimmerman 
775197ba5f4SPaul Zimmerman 	addr = hsotg->regs + PCGCTL;
776197ba5f4SPaul Zimmerman 	dev_dbg(hsotg->dev, "PCGCTL	 @0x%08lX : 0x%08X\n",
777f25c42b8SGevorg Sahakyan 		(unsigned long)addr, dwc2_readl(hsotg, PCGCTL));
778197ba5f4SPaul Zimmerman #endif
779197ba5f4SPaul Zimmerman }
780197ba5f4SPaul Zimmerman 
781197ba5f4SPaul Zimmerman /**
782197ba5f4SPaul Zimmerman  * dwc2_flush_tx_fifo() - Flushes a Tx FIFO
783197ba5f4SPaul Zimmerman  *
784197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
785197ba5f4SPaul Zimmerman  * @num:   Tx FIFO to flush
786197ba5f4SPaul Zimmerman  */
787197ba5f4SPaul Zimmerman void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
788197ba5f4SPaul Zimmerman {
789197ba5f4SPaul Zimmerman 	u32 greset;
790197ba5f4SPaul Zimmerman 
791197ba5f4SPaul Zimmerman 	dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
792197ba5f4SPaul Zimmerman 
7938f55fd60SMinas Harutyunyan 	/* Wait for AHB master IDLE state */
7948f55fd60SMinas Harutyunyan 	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
7958f55fd60SMinas Harutyunyan 		dev_warn(hsotg->dev, "%s:  HANG! AHB Idle GRSCTL\n",
7968f55fd60SMinas Harutyunyan 			 __func__);
7978f55fd60SMinas Harutyunyan 
798197ba5f4SPaul Zimmerman 	greset = GRSTCTL_TXFFLSH;
799197ba5f4SPaul Zimmerman 	greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
800f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, greset, GRSTCTL);
801197ba5f4SPaul Zimmerman 
80279d6b8c5SSevak Arakelyan 	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
80379d6b8c5SSevak Arakelyan 		dev_warn(hsotg->dev, "%s:  HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
80479d6b8c5SSevak Arakelyan 			 __func__);
805197ba5f4SPaul Zimmerman 
806197ba5f4SPaul Zimmerman 	/* Wait for at least 3 PHY Clocks */
807197ba5f4SPaul Zimmerman 	udelay(1);
808197ba5f4SPaul Zimmerman }
809197ba5f4SPaul Zimmerman 
810197ba5f4SPaul Zimmerman /**
811197ba5f4SPaul Zimmerman  * dwc2_flush_rx_fifo() - Flushes the Rx FIFO
812197ba5f4SPaul Zimmerman  *
813197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
814197ba5f4SPaul Zimmerman  */
815197ba5f4SPaul Zimmerman void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
816197ba5f4SPaul Zimmerman {
817197ba5f4SPaul Zimmerman 	u32 greset;
818197ba5f4SPaul Zimmerman 
819197ba5f4SPaul Zimmerman 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
820197ba5f4SPaul Zimmerman 
8218f55fd60SMinas Harutyunyan 	/* Wait for AHB master IDLE state */
8228f55fd60SMinas Harutyunyan 	if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
8238f55fd60SMinas Harutyunyan 		dev_warn(hsotg->dev, "%s:  HANG! AHB Idle GRSCTL\n",
8248f55fd60SMinas Harutyunyan 			 __func__);
8258f55fd60SMinas Harutyunyan 
826197ba5f4SPaul Zimmerman 	greset = GRSTCTL_RXFFLSH;
827f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, greset, GRSTCTL);
828197ba5f4SPaul Zimmerman 
82979d6b8c5SSevak Arakelyan 	/* Wait for RxFIFO flush done */
83079d6b8c5SSevak Arakelyan 	if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
83179d6b8c5SSevak Arakelyan 		dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n",
83279d6b8c5SSevak Arakelyan 			 __func__);
833197ba5f4SPaul Zimmerman 
834197ba5f4SPaul Zimmerman 	/* Wait for at least 3 PHY Clocks */
835197ba5f4SPaul Zimmerman 	udelay(1);
836197ba5f4SPaul Zimmerman }
837197ba5f4SPaul Zimmerman 
838197ba5f4SPaul Zimmerman bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
839197ba5f4SPaul Zimmerman {
840f25c42b8SGevorg Sahakyan 	if (dwc2_readl(hsotg, GSNPSID) == 0xffffffff)
841197ba5f4SPaul Zimmerman 		return false;
842197ba5f4SPaul Zimmerman 	else
843197ba5f4SPaul Zimmerman 		return true;
844197ba5f4SPaul Zimmerman }
845197ba5f4SPaul Zimmerman 
846197ba5f4SPaul Zimmerman /**
847197ba5f4SPaul Zimmerman  * dwc2_enable_global_interrupts() - Enables the controller's Global
848197ba5f4SPaul Zimmerman  * Interrupt in the AHB Config register
849197ba5f4SPaul Zimmerman  *
850197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
851197ba5f4SPaul Zimmerman  */
852197ba5f4SPaul Zimmerman void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
853197ba5f4SPaul Zimmerman {
854f25c42b8SGevorg Sahakyan 	u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
855197ba5f4SPaul Zimmerman 
856197ba5f4SPaul Zimmerman 	ahbcfg |= GAHBCFG_GLBL_INTR_EN;
857f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, ahbcfg, GAHBCFG);
858197ba5f4SPaul Zimmerman }
859197ba5f4SPaul Zimmerman 
860197ba5f4SPaul Zimmerman /**
861197ba5f4SPaul Zimmerman  * dwc2_disable_global_interrupts() - Disables the controller's Global
862197ba5f4SPaul Zimmerman  * Interrupt in the AHB Config register
863197ba5f4SPaul Zimmerman  *
864197ba5f4SPaul Zimmerman  * @hsotg: Programming view of DWC_otg controller
865197ba5f4SPaul Zimmerman  */
866197ba5f4SPaul Zimmerman void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
867197ba5f4SPaul Zimmerman {
868f25c42b8SGevorg Sahakyan 	u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
869197ba5f4SPaul Zimmerman 
870197ba5f4SPaul Zimmerman 	ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
871f25c42b8SGevorg Sahakyan 	dwc2_writel(hsotg, ahbcfg, GAHBCFG);
872197ba5f4SPaul Zimmerman }
873197ba5f4SPaul Zimmerman 
8746bea9620SJohn Youn /* Returns the controller's GHWCFG2.OTG_MODE. */
8759da51974SJohn Youn unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg)
8766bea9620SJohn Youn {
877f25c42b8SGevorg Sahakyan 	u32 ghwcfg2 = dwc2_readl(hsotg, GHWCFG2);
8786bea9620SJohn Youn 
8796bea9620SJohn Youn 	return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
8806bea9620SJohn Youn 		GHWCFG2_OP_MODE_SHIFT;
8816bea9620SJohn Youn }
8826bea9620SJohn Youn 
8836bea9620SJohn Youn /* Returns true if the controller is capable of DRD. */
8846bea9620SJohn Youn bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg)
8856bea9620SJohn Youn {
8869da51974SJohn Youn 	unsigned int op_mode = dwc2_op_mode(hsotg);
8876bea9620SJohn Youn 
8886bea9620SJohn Youn 	return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) ||
8896bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) ||
8906bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE);
8916bea9620SJohn Youn }
8926bea9620SJohn Youn 
8936bea9620SJohn Youn /* Returns true if the controller is host-only. */
8946bea9620SJohn Youn bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg)
8956bea9620SJohn Youn {
8969da51974SJohn Youn 	unsigned int op_mode = dwc2_op_mode(hsotg);
8976bea9620SJohn Youn 
8986bea9620SJohn Youn 	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
8996bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST);
9006bea9620SJohn Youn }
9016bea9620SJohn Youn 
9026bea9620SJohn Youn /* Returns true if the controller is device-only. */
9036bea9620SJohn Youn bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
9046bea9620SJohn Youn {
9059da51974SJohn Youn 	unsigned int op_mode = dwc2_op_mode(hsotg);
9066bea9620SJohn Youn 
9076bea9620SJohn Youn 	return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
9086bea9620SJohn Youn 		(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
9096bea9620SJohn Youn }
9106bea9620SJohn Youn 
91179d6b8c5SSevak Arakelyan /**
91279d6b8c5SSevak Arakelyan  * dwc2_hsotg_wait_bit_set - Waits for bit to be set.
91379d6b8c5SSevak Arakelyan  * @hsotg: Programming view of DWC_otg controller.
91479d6b8c5SSevak Arakelyan  * @offset: Register's offset where bit/bits must be set.
91579d6b8c5SSevak Arakelyan  * @mask: Mask of the bit/bits which must be set.
91679d6b8c5SSevak Arakelyan  * @timeout: Timeout to wait.
91779d6b8c5SSevak Arakelyan  *
91879d6b8c5SSevak Arakelyan  * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
91979d6b8c5SSevak Arakelyan  */
92079d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
92179d6b8c5SSevak Arakelyan 			    u32 timeout)
92279d6b8c5SSevak Arakelyan {
92379d6b8c5SSevak Arakelyan 	u32 i;
92479d6b8c5SSevak Arakelyan 
92579d6b8c5SSevak Arakelyan 	for (i = 0; i < timeout; i++) {
926f25c42b8SGevorg Sahakyan 		if (dwc2_readl(hsotg, offset) & mask)
92779d6b8c5SSevak Arakelyan 			return 0;
92879d6b8c5SSevak Arakelyan 		udelay(1);
92979d6b8c5SSevak Arakelyan 	}
93079d6b8c5SSevak Arakelyan 
93179d6b8c5SSevak Arakelyan 	return -ETIMEDOUT;
93279d6b8c5SSevak Arakelyan }
93379d6b8c5SSevak Arakelyan 
93479d6b8c5SSevak Arakelyan /**
93579d6b8c5SSevak Arakelyan  * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear.
93679d6b8c5SSevak Arakelyan  * @hsotg: Programming view of DWC_otg controller.
93779d6b8c5SSevak Arakelyan  * @offset: Register's offset where bit/bits must be set.
93879d6b8c5SSevak Arakelyan  * @mask: Mask of the bit/bits which must be set.
93979d6b8c5SSevak Arakelyan  * @timeout: Timeout to wait.
94079d6b8c5SSevak Arakelyan  *
94179d6b8c5SSevak Arakelyan  * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
94279d6b8c5SSevak Arakelyan  */
94379d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
94479d6b8c5SSevak Arakelyan 			      u32 timeout)
94579d6b8c5SSevak Arakelyan {
94679d6b8c5SSevak Arakelyan 	u32 i;
94779d6b8c5SSevak Arakelyan 
94879d6b8c5SSevak Arakelyan 	for (i = 0; i < timeout; i++) {
949f25c42b8SGevorg Sahakyan 		if (!(dwc2_readl(hsotg, offset) & mask))
95079d6b8c5SSevak Arakelyan 			return 0;
95179d6b8c5SSevak Arakelyan 		udelay(1);
95279d6b8c5SSevak Arakelyan 	}
95379d6b8c5SSevak Arakelyan 
95479d6b8c5SSevak Arakelyan 	return -ETIMEDOUT;
95579d6b8c5SSevak Arakelyan }
95679d6b8c5SSevak Arakelyan 
957059d8d52SJules Maselbas /*
958059d8d52SJules Maselbas  * Initializes the FSLSPClkSel field of the HCFG register depending on the
959059d8d52SJules Maselbas  * PHY type
960059d8d52SJules Maselbas  */
961059d8d52SJules Maselbas void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
962059d8d52SJules Maselbas {
963059d8d52SJules Maselbas 	u32 hcfg, val;
964059d8d52SJules Maselbas 
965059d8d52SJules Maselbas 	if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
966059d8d52SJules Maselbas 	     hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
967059d8d52SJules Maselbas 	     hsotg->params.ulpi_fs_ls) ||
968059d8d52SJules Maselbas 	    hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) {
969059d8d52SJules Maselbas 		/* Full speed PHY */
970059d8d52SJules Maselbas 		val = HCFG_FSLSPCLKSEL_48_MHZ;
971059d8d52SJules Maselbas 	} else {
972059d8d52SJules Maselbas 		/* High speed PHY running at full speed or high speed */
973059d8d52SJules Maselbas 		val = HCFG_FSLSPCLKSEL_30_60_MHZ;
974059d8d52SJules Maselbas 	}
975059d8d52SJules Maselbas 
976059d8d52SJules Maselbas 	dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
977059d8d52SJules Maselbas 	hcfg = dwc2_readl(hsotg, HCFG);
978059d8d52SJules Maselbas 	hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
979059d8d52SJules Maselbas 	hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
980059d8d52SJules Maselbas 	dwc2_writel(hsotg, hcfg, HCFG);
981059d8d52SJules Maselbas }
982059d8d52SJules Maselbas 
983*f8453bbdSMinas Harutyunyan static void dwc2_set_clock_switch_timer(struct dwc2_hsotg *hsotg)
984*f8453bbdSMinas Harutyunyan {
985*f8453bbdSMinas Harutyunyan 	u32 grstctl, gsnpsid, val = 0;
986*f8453bbdSMinas Harutyunyan 
987*f8453bbdSMinas Harutyunyan 	gsnpsid = dwc2_readl(hsotg, GSNPSID);
988*f8453bbdSMinas Harutyunyan 
989*f8453bbdSMinas Harutyunyan 	/*
990*f8453bbdSMinas Harutyunyan 	 * Applicable only to HSOTG core v5.00a or higher.
991*f8453bbdSMinas Harutyunyan 	 * Not applicable to HS/FS IOT devices.
992*f8453bbdSMinas Harutyunyan 	 */
993*f8453bbdSMinas Harutyunyan 	if ((gsnpsid & ~DWC2_CORE_REV_MASK) != DWC2_OTG_ID ||
994*f8453bbdSMinas Harutyunyan 	    gsnpsid < DWC2_CORE_REV_5_00a)
995*f8453bbdSMinas Harutyunyan 		return;
996*f8453bbdSMinas Harutyunyan 
997*f8453bbdSMinas Harutyunyan 	if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI &&
998*f8453bbdSMinas Harutyunyan 	     hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) ||
999*f8453bbdSMinas Harutyunyan 	    (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
1000*f8453bbdSMinas Harutyunyan 	     hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) ||
1001*f8453bbdSMinas Harutyunyan 	    (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED &&
1002*f8453bbdSMinas Harutyunyan 	     hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED)) {
1003*f8453bbdSMinas Harutyunyan 		val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_DIS;
1004*f8453bbdSMinas Harutyunyan 	}
1005*f8453bbdSMinas Harutyunyan 
1006*f8453bbdSMinas Harutyunyan 	if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW &&
1007*f8453bbdSMinas Harutyunyan 	    hsotg->hw_params.hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED &&
1008*f8453bbdSMinas Harutyunyan 	    hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) {
1009*f8453bbdSMinas Harutyunyan 		val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_147;
1010*f8453bbdSMinas Harutyunyan 	}
1011*f8453bbdSMinas Harutyunyan 
1012*f8453bbdSMinas Harutyunyan 	grstctl = dwc2_readl(hsotg, GRSTCTL);
1013*f8453bbdSMinas Harutyunyan 	grstctl &= ~GRSTCTL_CLOCK_SWITH_TIMER_MASK;
1014*f8453bbdSMinas Harutyunyan 	grstctl |= GRSTCTL_CLOCK_SWITH_TIMER(val);
1015*f8453bbdSMinas Harutyunyan 	dwc2_writel(hsotg, grstctl, GRSTCTL);
1016*f8453bbdSMinas Harutyunyan }
1017*f8453bbdSMinas Harutyunyan 
1018059d8d52SJules Maselbas static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
1019059d8d52SJules Maselbas {
1020059d8d52SJules Maselbas 	u32 usbcfg, ggpio, i2cctl;
1021059d8d52SJules Maselbas 	int retval = 0;
1022059d8d52SJules Maselbas 
1023059d8d52SJules Maselbas 	/*
1024059d8d52SJules Maselbas 	 * core_init() is now called on every switch so only call the
1025059d8d52SJules Maselbas 	 * following for the first time through
1026059d8d52SJules Maselbas 	 */
1027059d8d52SJules Maselbas 	if (select_phy) {
1028059d8d52SJules Maselbas 		dev_dbg(hsotg->dev, "FS PHY selected\n");
1029059d8d52SJules Maselbas 
1030059d8d52SJules Maselbas 		usbcfg = dwc2_readl(hsotg, GUSBCFG);
1031059d8d52SJules Maselbas 		if (!(usbcfg & GUSBCFG_PHYSEL)) {
1032059d8d52SJules Maselbas 			usbcfg |= GUSBCFG_PHYSEL;
1033059d8d52SJules Maselbas 			dwc2_writel(hsotg, usbcfg, GUSBCFG);
1034059d8d52SJules Maselbas 
1035*f8453bbdSMinas Harutyunyan 			dwc2_set_clock_switch_timer(hsotg);
1036*f8453bbdSMinas Harutyunyan 
1037059d8d52SJules Maselbas 			/* Reset after a PHY select */
1038059d8d52SJules Maselbas 			retval = dwc2_core_reset(hsotg, false);
1039059d8d52SJules Maselbas 
1040059d8d52SJules Maselbas 			if (retval) {
1041059d8d52SJules Maselbas 				dev_err(hsotg->dev,
1042059d8d52SJules Maselbas 					"%s: Reset failed, aborting", __func__);
1043059d8d52SJules Maselbas 				return retval;
1044059d8d52SJules Maselbas 			}
1045059d8d52SJules Maselbas 		}
1046059d8d52SJules Maselbas 
1047059d8d52SJules Maselbas 		if (hsotg->params.activate_stm_fs_transceiver) {
1048059d8d52SJules Maselbas 			ggpio = dwc2_readl(hsotg, GGPIO);
1049059d8d52SJules Maselbas 			if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) {
1050059d8d52SJules Maselbas 				dev_dbg(hsotg->dev, "Activating transceiver\n");
1051059d8d52SJules Maselbas 				/*
1052059d8d52SJules Maselbas 				 * STM32F4x9 uses the GGPIO register as general
1053059d8d52SJules Maselbas 				 * core configuration register.
1054059d8d52SJules Maselbas 				 */
1055059d8d52SJules Maselbas 				ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN;
1056059d8d52SJules Maselbas 				dwc2_writel(hsotg, ggpio, GGPIO);
1057059d8d52SJules Maselbas 			}
1058059d8d52SJules Maselbas 		}
1059059d8d52SJules Maselbas 	}
1060059d8d52SJules Maselbas 
1061059d8d52SJules Maselbas 	/*
1062059d8d52SJules Maselbas 	 * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
1063059d8d52SJules Maselbas 	 * do this on HNP Dev/Host mode switches (done in dev_init and
1064059d8d52SJules Maselbas 	 * host_init).
1065059d8d52SJules Maselbas 	 */
1066059d8d52SJules Maselbas 	if (dwc2_is_host_mode(hsotg))
1067059d8d52SJules Maselbas 		dwc2_init_fs_ls_pclk_sel(hsotg);
1068059d8d52SJules Maselbas 
1069059d8d52SJules Maselbas 	if (hsotg->params.i2c_enable) {
1070059d8d52SJules Maselbas 		dev_dbg(hsotg->dev, "FS PHY enabling I2C\n");
1071059d8d52SJules Maselbas 
1072059d8d52SJules Maselbas 		/* Program GUSBCFG.OtgUtmiFsSel to I2C */
1073059d8d52SJules Maselbas 		usbcfg = dwc2_readl(hsotg, GUSBCFG);
1074059d8d52SJules Maselbas 		usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
1075059d8d52SJules Maselbas 		dwc2_writel(hsotg, usbcfg, GUSBCFG);
1076059d8d52SJules Maselbas 
1077059d8d52SJules Maselbas 		/* Program GI2CCTL.I2CEn */
1078059d8d52SJules Maselbas 		i2cctl = dwc2_readl(hsotg, GI2CCTL);
1079059d8d52SJules Maselbas 		i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
1080059d8d52SJules Maselbas 		i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
1081059d8d52SJules Maselbas 		i2cctl &= ~GI2CCTL_I2CEN;
1082059d8d52SJules Maselbas 		dwc2_writel(hsotg, i2cctl, GI2CCTL);
1083059d8d52SJules Maselbas 		i2cctl |= GI2CCTL_I2CEN;
1084059d8d52SJules Maselbas 		dwc2_writel(hsotg, i2cctl, GI2CCTL);
1085059d8d52SJules Maselbas 	}
1086059d8d52SJules Maselbas 
1087059d8d52SJules Maselbas 	return retval;
1088059d8d52SJules Maselbas }
1089059d8d52SJules Maselbas 
1090059d8d52SJules Maselbas static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
1091059d8d52SJules Maselbas {
1092059d8d52SJules Maselbas 	u32 usbcfg, usbcfg_old;
1093059d8d52SJules Maselbas 	int retval = 0;
1094059d8d52SJules Maselbas 
1095059d8d52SJules Maselbas 	if (!select_phy)
1096059d8d52SJules Maselbas 		return 0;
1097059d8d52SJules Maselbas 
1098059d8d52SJules Maselbas 	usbcfg = dwc2_readl(hsotg, GUSBCFG);
1099059d8d52SJules Maselbas 	usbcfg_old = usbcfg;
1100059d8d52SJules Maselbas 
1101059d8d52SJules Maselbas 	/*
1102059d8d52SJules Maselbas 	 * HS PHY parameters. These parameters are preserved during soft reset
1103059d8d52SJules Maselbas 	 * so only program the first time. Do a soft reset immediately after
1104059d8d52SJules Maselbas 	 * setting phyif.
1105059d8d52SJules Maselbas 	 */
1106059d8d52SJules Maselbas 	switch (hsotg->params.phy_type) {
1107059d8d52SJules Maselbas 	case DWC2_PHY_TYPE_PARAM_ULPI:
1108059d8d52SJules Maselbas 		/* ULPI interface */
1109059d8d52SJules Maselbas 		dev_dbg(hsotg->dev, "HS ULPI PHY selected\n");
1110059d8d52SJules Maselbas 		usbcfg |= GUSBCFG_ULPI_UTMI_SEL;
1111059d8d52SJules Maselbas 		usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
1112059d8d52SJules Maselbas 		if (hsotg->params.phy_ulpi_ddr)
1113059d8d52SJules Maselbas 			usbcfg |= GUSBCFG_DDRSEL;
1114059d8d52SJules Maselbas 
1115059d8d52SJules Maselbas 		/* Set external VBUS indicator as needed. */
1116059d8d52SJules Maselbas 		if (hsotg->params.oc_disable)
1117059d8d52SJules Maselbas 			usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND |
1118059d8d52SJules Maselbas 				   GUSBCFG_INDICATORPASSTHROUGH);
1119059d8d52SJules Maselbas 		break;
1120059d8d52SJules Maselbas 	case DWC2_PHY_TYPE_PARAM_UTMI:
1121059d8d52SJules Maselbas 		/* UTMI+ interface */
1122059d8d52SJules Maselbas 		dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n");
1123059d8d52SJules Maselbas 		usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
1124059d8d52SJules Maselbas 		if (hsotg->params.phy_utmi_width == 16)
1125059d8d52SJules Maselbas 			usbcfg |= GUSBCFG_PHYIF16;
1126059d8d52SJules Maselbas 		break;
1127059d8d52SJules Maselbas 	default:
1128059d8d52SJules Maselbas 		dev_err(hsotg->dev, "FS PHY selected at HS!\n");
1129059d8d52SJules Maselbas 		break;
1130059d8d52SJules Maselbas 	}
1131059d8d52SJules Maselbas 
1132059d8d52SJules Maselbas 	if (usbcfg != usbcfg_old) {
1133059d8d52SJules Maselbas 		dwc2_writel(hsotg, usbcfg, GUSBCFG);
1134059d8d52SJules Maselbas 
1135059d8d52SJules Maselbas 		/* Reset after setting the PHY parameters */
1136059d8d52SJules Maselbas 		retval = dwc2_core_reset(hsotg, false);
1137059d8d52SJules Maselbas 		if (retval) {
1138059d8d52SJules Maselbas 			dev_err(hsotg->dev,
1139059d8d52SJules Maselbas 				"%s: Reset failed, aborting", __func__);
1140059d8d52SJules Maselbas 			return retval;
1141059d8d52SJules Maselbas 		}
1142059d8d52SJules Maselbas 	}
1143059d8d52SJules Maselbas 
1144059d8d52SJules Maselbas 	return retval;
1145059d8d52SJules Maselbas }
1146059d8d52SJules Maselbas 
1147aafe9351SClément Lassieur static void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg)
1148aafe9351SClément Lassieur {
1149aafe9351SClément Lassieur 	u32 usbcfg;
1150aafe9351SClément Lassieur 
1151aafe9351SClément Lassieur 	if (hsotg->params.phy_type != DWC2_PHY_TYPE_PARAM_UTMI)
1152aafe9351SClément Lassieur 		return;
1153aafe9351SClément Lassieur 
1154aafe9351SClément Lassieur 	usbcfg = dwc2_readl(hsotg, GUSBCFG);
1155aafe9351SClément Lassieur 
1156aafe9351SClément Lassieur 	usbcfg &= ~GUSBCFG_USBTRDTIM_MASK;
1157aafe9351SClément Lassieur 	if (hsotg->params.phy_utmi_width == 16)
1158aafe9351SClément Lassieur 		usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT;
1159aafe9351SClément Lassieur 	else
1160aafe9351SClément Lassieur 		usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT;
1161aafe9351SClément Lassieur 
1162aafe9351SClément Lassieur 	dwc2_writel(hsotg, usbcfg, GUSBCFG);
1163aafe9351SClément Lassieur }
1164aafe9351SClément Lassieur 
1165059d8d52SJules Maselbas int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
1166059d8d52SJules Maselbas {
1167059d8d52SJules Maselbas 	u32 usbcfg;
1168d712b725S周琰杰 (Zhou Yanjie) 	u32 otgctl;
1169059d8d52SJules Maselbas 	int retval = 0;
1170059d8d52SJules Maselbas 
1171059d8d52SJules Maselbas 	if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL ||
1172059d8d52SJules Maselbas 	     hsotg->params.speed == DWC2_SPEED_PARAM_LOW) &&
1173059d8d52SJules Maselbas 	    hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) {
1174059d8d52SJules Maselbas 		/* If FS/LS mode with FS/LS PHY */
1175059d8d52SJules Maselbas 		retval = dwc2_fs_phy_init(hsotg, select_phy);
1176059d8d52SJules Maselbas 		if (retval)
1177059d8d52SJules Maselbas 			return retval;
1178059d8d52SJules Maselbas 	} else {
1179059d8d52SJules Maselbas 		/* High speed PHY */
1180059d8d52SJules Maselbas 		retval = dwc2_hs_phy_init(hsotg, select_phy);
1181059d8d52SJules Maselbas 		if (retval)
1182059d8d52SJules Maselbas 			return retval;
1183aafe9351SClément Lassieur 
1184aafe9351SClément Lassieur 		if (dwc2_is_device_mode(hsotg))
1185aafe9351SClément Lassieur 			dwc2_set_turnaround_time(hsotg);
1186059d8d52SJules Maselbas 	}
1187059d8d52SJules Maselbas 
1188059d8d52SJules Maselbas 	if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
1189059d8d52SJules Maselbas 	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
1190059d8d52SJules Maselbas 	    hsotg->params.ulpi_fs_ls) {
1191059d8d52SJules Maselbas 		dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
1192059d8d52SJules Maselbas 		usbcfg = dwc2_readl(hsotg, GUSBCFG);
1193059d8d52SJules Maselbas 		usbcfg |= GUSBCFG_ULPI_FS_LS;
1194059d8d52SJules Maselbas 		usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
1195059d8d52SJules Maselbas 		dwc2_writel(hsotg, usbcfg, GUSBCFG);
1196059d8d52SJules Maselbas 	} else {
1197059d8d52SJules Maselbas 		usbcfg = dwc2_readl(hsotg, GUSBCFG);
1198059d8d52SJules Maselbas 		usbcfg &= ~GUSBCFG_ULPI_FS_LS;
1199059d8d52SJules Maselbas 		usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
1200059d8d52SJules Maselbas 		dwc2_writel(hsotg, usbcfg, GUSBCFG);
1201059d8d52SJules Maselbas 	}
1202059d8d52SJules Maselbas 
1203d712b725S周琰杰 (Zhou Yanjie) 	if (!hsotg->params.activate_ingenic_overcurrent_detection) {
1204d712b725S周琰杰 (Zhou Yanjie) 		if (dwc2_is_host_mode(hsotg)) {
1205d712b725S周琰杰 (Zhou Yanjie) 			otgctl = readl(hsotg->regs + GOTGCTL);
1206d712b725S周琰杰 (Zhou Yanjie) 			otgctl |= GOTGCTL_VBVALOEN | GOTGCTL_VBVALOVAL;
1207d712b725S周琰杰 (Zhou Yanjie) 			writel(otgctl, hsotg->regs + GOTGCTL);
1208d712b725S周琰杰 (Zhou Yanjie) 		}
1209d712b725S周琰杰 (Zhou Yanjie) 	}
1210d712b725S周琰杰 (Zhou Yanjie) 
1211059d8d52SJules Maselbas 	return retval;
1212059d8d52SJules Maselbas }
1213059d8d52SJules Maselbas 
1214197ba5f4SPaul Zimmerman MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
1215197ba5f4SPaul Zimmerman MODULE_AUTHOR("Synopsys, Inc.");
1216197ba5f4SPaul Zimmerman MODULE_LICENSE("Dual BSD/GPL");
1217