xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 696c8b12)
172246da4SFelipe Balbi /**
272246da4SFelipe Balbi  * core.c - DesignWare USB3 DRD Controller Core file
372246da4SFelipe Balbi  *
472246da4SFelipe Balbi  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
572246da4SFelipe Balbi  *
672246da4SFelipe Balbi  * Authors: Felipe Balbi <balbi@ti.com>,
772246da4SFelipe Balbi  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
872246da4SFelipe Balbi  *
95945f789SFelipe Balbi  * This program is free software: you can redistribute it and/or modify
105945f789SFelipe Balbi  * it under the terms of the GNU General Public License version 2  of
115945f789SFelipe Balbi  * the License as published by the Free Software Foundation.
1272246da4SFelipe Balbi  *
135945f789SFelipe Balbi  * This program is distributed in the hope that it will be useful,
145945f789SFelipe Balbi  * but WITHOUT ANY WARRANTY; without even the implied warranty of
155945f789SFelipe Balbi  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165945f789SFelipe Balbi  * GNU General Public License for more details.
1772246da4SFelipe Balbi  *
185945f789SFelipe Balbi  * You should have received a copy of the GNU General Public License
195945f789SFelipe Balbi  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2072246da4SFelipe Balbi  */
2172246da4SFelipe Balbi 
22fa0ea13eSFelipe Balbi #include <linux/version.h>
23a72e658bSFelipe Balbi #include <linux/module.h>
2472246da4SFelipe Balbi #include <linux/kernel.h>
2572246da4SFelipe Balbi #include <linux/slab.h>
2672246da4SFelipe Balbi #include <linux/spinlock.h>
2772246da4SFelipe Balbi #include <linux/platform_device.h>
2872246da4SFelipe Balbi #include <linux/pm_runtime.h>
2972246da4SFelipe Balbi #include <linux/interrupt.h>
3072246da4SFelipe Balbi #include <linux/ioport.h>
3172246da4SFelipe Balbi #include <linux/io.h>
3272246da4SFelipe Balbi #include <linux/list.h>
3372246da4SFelipe Balbi #include <linux/delay.h>
3472246da4SFelipe Balbi #include <linux/dma-mapping.h>
35457e84b6SFelipe Balbi #include <linux/of.h>
36404905a6SHeikki Krogerus #include <linux/acpi.h>
376344475fSSekhar Nori #include <linux/pinctrl/consumer.h>
3872246da4SFelipe Balbi 
3972246da4SFelipe Balbi #include <linux/usb/ch9.h>
4072246da4SFelipe Balbi #include <linux/usb/gadget.h>
41f7e846f0SFelipe Balbi #include <linux/usb/of.h>
42a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
4372246da4SFelipe Balbi 
446462cbd5SFelipe Balbi #include "platform_data.h"
4572246da4SFelipe Balbi #include "core.h"
4672246da4SFelipe Balbi #include "gadget.h"
4772246da4SFelipe Balbi #include "io.h"
4872246da4SFelipe Balbi 
4972246da4SFelipe Balbi #include "debug.h"
5072246da4SFelipe Balbi 
518300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
528300dd23SFelipe Balbi 
533140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
543140e8cbSSebastian Andrzej Siewior {
553140e8cbSSebastian Andrzej Siewior 	u32 reg;
563140e8cbSSebastian Andrzej Siewior 
573140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
583140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
593140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
603140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
613140e8cbSSebastian Andrzej Siewior }
628300dd23SFelipe Balbi 
6372246da4SFelipe Balbi /**
6472246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
6572246da4SFelipe Balbi  * @dwc: pointer to our context structure
6672246da4SFelipe Balbi  */
6757303488SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc)
6872246da4SFelipe Balbi {
6972246da4SFelipe Balbi 	u32		reg;
70f59dcab1SFelipe Balbi 	int		retries = 1000;
7157303488SKishon Vijay Abraham I 	int		ret;
7272246da4SFelipe Balbi 
7351e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
7451e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
7557303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
7657303488SKishon Vijay Abraham I 	if (ret < 0)
7757303488SKishon Vijay Abraham I 		return ret;
7857303488SKishon Vijay Abraham I 
7957303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
8057303488SKishon Vijay Abraham I 	if (ret < 0) {
8157303488SKishon Vijay Abraham I 		phy_exit(dwc->usb2_generic_phy);
8257303488SKishon Vijay Abraham I 		return ret;
8357303488SKishon Vijay Abraham I 	}
8472246da4SFelipe Balbi 
85f59dcab1SFelipe Balbi 	/*
86f59dcab1SFelipe Balbi 	 * We're resetting only the device side because, if we're in host mode,
87f59dcab1SFelipe Balbi 	 * XHCI driver will reset the host block. If dwc3 was configured for
88f59dcab1SFelipe Balbi 	 * host-only mode, then we can return early.
89f59dcab1SFelipe Balbi 	 */
90f59dcab1SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_HOST)
9157303488SKishon Vijay Abraham I 		return 0;
92f59dcab1SFelipe Balbi 
93f59dcab1SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
94f59dcab1SFelipe Balbi 	reg |= DWC3_DCTL_CSFTRST;
95f59dcab1SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
96f59dcab1SFelipe Balbi 
97f59dcab1SFelipe Balbi 	do {
98f59dcab1SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
99f59dcab1SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
100f59dcab1SFelipe Balbi 			return 0;
101f59dcab1SFelipe Balbi 
102f59dcab1SFelipe Balbi 		udelay(1);
103f59dcab1SFelipe Balbi 	} while (--retries);
104f59dcab1SFelipe Balbi 
105f59dcab1SFelipe Balbi 	return -ETIMEDOUT;
10672246da4SFelipe Balbi }
10772246da4SFelipe Balbi 
10872246da4SFelipe Balbi /**
109c5cc74e8SHeikki Krogerus  * dwc3_soft_reset - Issue soft reset
110c5cc74e8SHeikki Krogerus  * @dwc: Pointer to our controller context structure
111c5cc74e8SHeikki Krogerus  */
112c5cc74e8SHeikki Krogerus static int dwc3_soft_reset(struct dwc3 *dwc)
113c5cc74e8SHeikki Krogerus {
114c5cc74e8SHeikki Krogerus 	unsigned long timeout;
115c5cc74e8SHeikki Krogerus 	u32 reg;
116c5cc74e8SHeikki Krogerus 
117c5cc74e8SHeikki Krogerus 	timeout = jiffies + msecs_to_jiffies(500);
118c5cc74e8SHeikki Krogerus 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
119c5cc74e8SHeikki Krogerus 	do {
120c5cc74e8SHeikki Krogerus 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
121c5cc74e8SHeikki Krogerus 		if (!(reg & DWC3_DCTL_CSFTRST))
122c5cc74e8SHeikki Krogerus 			break;
123c5cc74e8SHeikki Krogerus 
124c5cc74e8SHeikki Krogerus 		if (time_after(jiffies, timeout)) {
125c5cc74e8SHeikki Krogerus 			dev_err(dwc->dev, "Reset Timed Out\n");
126c5cc74e8SHeikki Krogerus 			return -ETIMEDOUT;
127c5cc74e8SHeikki Krogerus 		}
128c5cc74e8SHeikki Krogerus 
129c5cc74e8SHeikki Krogerus 		cpu_relax();
130c5cc74e8SHeikki Krogerus 	} while (true);
131c5cc74e8SHeikki Krogerus 
132c5cc74e8SHeikki Krogerus 	return 0;
133c5cc74e8SHeikki Krogerus }
134c5cc74e8SHeikki Krogerus 
135db2be4e9SNikhil Badola /*
136db2be4e9SNikhil Badola  * dwc3_frame_length_adjustment - Adjusts frame length if required
137db2be4e9SNikhil Badola  * @dwc3: Pointer to our controller context structure
138db2be4e9SNikhil Badola  * @fladj: Value of GFLADJ_30MHZ to adjust frame length
139db2be4e9SNikhil Badola  */
140db2be4e9SNikhil Badola static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
141db2be4e9SNikhil Badola {
142db2be4e9SNikhil Badola 	u32 reg;
143db2be4e9SNikhil Badola 	u32 dft;
144db2be4e9SNikhil Badola 
145db2be4e9SNikhil Badola 	if (dwc->revision < DWC3_REVISION_250A)
146db2be4e9SNikhil Badola 		return;
147db2be4e9SNikhil Badola 
148db2be4e9SNikhil Badola 	if (fladj == 0)
149db2be4e9SNikhil Badola 		return;
150db2be4e9SNikhil Badola 
151db2be4e9SNikhil Badola 	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
152db2be4e9SNikhil Badola 	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
153db2be4e9SNikhil Badola 	if (!dev_WARN_ONCE(dwc->dev, dft == fladj,
154db2be4e9SNikhil Badola 	    "request value same as default, ignoring\n")) {
155db2be4e9SNikhil Badola 		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
156db2be4e9SNikhil Badola 		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
157db2be4e9SNikhil Badola 		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
158db2be4e9SNikhil Badola 	}
159db2be4e9SNikhil Badola }
160db2be4e9SNikhil Badola 
161c5cc74e8SHeikki Krogerus /**
16272246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
16372246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
16472246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
16572246da4SFelipe Balbi  */
16672246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
16772246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
16872246da4SFelipe Balbi {
16972246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
17072246da4SFelipe Balbi }
17172246da4SFelipe Balbi 
17272246da4SFelipe Balbi /**
1731d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
17472246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
17572246da4SFelipe Balbi  * @length: size of the event buffer
17672246da4SFelipe Balbi  *
1771d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
17872246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
17972246da4SFelipe Balbi  */
18067d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
18167d0b500SFelipe Balbi 		unsigned length)
18272246da4SFelipe Balbi {
18372246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
18472246da4SFelipe Balbi 
185380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
18672246da4SFelipe Balbi 	if (!evt)
18772246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
18872246da4SFelipe Balbi 
18972246da4SFelipe Balbi 	evt->dwc	= dwc;
19072246da4SFelipe Balbi 	evt->length	= length;
19172246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
19272246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
193e32672f0SFelipe Balbi 	if (!evt->buf)
19472246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
19572246da4SFelipe Balbi 
19672246da4SFelipe Balbi 	return evt;
19772246da4SFelipe Balbi }
19872246da4SFelipe Balbi 
19972246da4SFelipe Balbi /**
20072246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
20172246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
20272246da4SFelipe Balbi  */
20372246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
20472246da4SFelipe Balbi {
20572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
20672246da4SFelipe Balbi 
207*696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
20864b6c8a7SAnton Tikhomirov 	if (evt)
20972246da4SFelipe Balbi 		dwc3_free_one_event_buffer(dwc, evt);
21072246da4SFelipe Balbi }
21172246da4SFelipe Balbi 
21272246da4SFelipe Balbi /**
21372246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
2141d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
21572246da4SFelipe Balbi  * @length: size of event buffer
21672246da4SFelipe Balbi  *
2171d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
21872246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
21972246da4SFelipe Balbi  */
22041ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
22172246da4SFelipe Balbi {
222660e9bdeSFelipe Balbi 	struct dwc3_event_buffer *evt;
22372246da4SFelipe Balbi 
22472246da4SFelipe Balbi 	evt = dwc3_alloc_one_event_buffer(dwc, length);
22572246da4SFelipe Balbi 	if (IS_ERR(evt)) {
22672246da4SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffer\n");
22772246da4SFelipe Balbi 		return PTR_ERR(evt);
22872246da4SFelipe Balbi 	}
229*696c8b12SFelipe Balbi 	dwc->ev_buf = evt;
23072246da4SFelipe Balbi 
23172246da4SFelipe Balbi 	return 0;
23272246da4SFelipe Balbi }
23372246da4SFelipe Balbi 
23472246da4SFelipe Balbi /**
23572246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
2361d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
23772246da4SFelipe Balbi  *
23872246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
23972246da4SFelipe Balbi  */
2407acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
24172246da4SFelipe Balbi {
24272246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
24372246da4SFelipe Balbi 
244*696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
2451407bf13SFelipe Balbi 	dwc3_trace(trace_dwc3_core,
2461407bf13SFelipe Balbi 			"Event buf %p dma %08llx length %d\n",
24772246da4SFelipe Balbi 			evt->buf, (unsigned long long) evt->dma,
24872246da4SFelipe Balbi 			evt->length);
24972246da4SFelipe Balbi 
2507acd85e0SPaul Zimmerman 	evt->lpos = 0;
2517acd85e0SPaul Zimmerman 
252660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
25372246da4SFelipe Balbi 			lower_32_bits(evt->dma));
254660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
25572246da4SFelipe Balbi 			upper_32_bits(evt->dma));
256660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
25768d6a01bSFelipe Balbi 			DWC3_GEVNTSIZ_SIZE(evt->length));
258660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
25972246da4SFelipe Balbi 
26072246da4SFelipe Balbi 	return 0;
26172246da4SFelipe Balbi }
26272246da4SFelipe Balbi 
26372246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
26472246da4SFelipe Balbi {
26572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
26672246da4SFelipe Balbi 
267*696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
2687acd85e0SPaul Zimmerman 
2697acd85e0SPaul Zimmerman 	evt->lpos = 0;
2707acd85e0SPaul Zimmerman 
271660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
272660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
273660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
27468d6a01bSFelipe Balbi 			| DWC3_GEVNTSIZ_SIZE(0));
275660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
27672246da4SFelipe Balbi }
27772246da4SFelipe Balbi 
2780ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
2790ffcaf37SFelipe Balbi {
2800ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
2810ffcaf37SFelipe Balbi 		return 0;
2820ffcaf37SFelipe Balbi 
2830ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
2840ffcaf37SFelipe Balbi 		return 0;
2850ffcaf37SFelipe Balbi 
2860ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
2870ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
2880ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
2890ffcaf37SFelipe Balbi 		return -ENOMEM;
2900ffcaf37SFelipe Balbi 
2910ffcaf37SFelipe Balbi 	return 0;
2920ffcaf37SFelipe Balbi }
2930ffcaf37SFelipe Balbi 
2940ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
2950ffcaf37SFelipe Balbi {
2960ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
2970ffcaf37SFelipe Balbi 	u32 param;
2980ffcaf37SFelipe Balbi 	int ret;
2990ffcaf37SFelipe Balbi 
3000ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3010ffcaf37SFelipe Balbi 		return 0;
3020ffcaf37SFelipe Balbi 
3030ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3040ffcaf37SFelipe Balbi 		return 0;
3050ffcaf37SFelipe Balbi 
3060ffcaf37SFelipe Balbi 	 /* should never fall here */
3070ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3080ffcaf37SFelipe Balbi 		return 0;
3090ffcaf37SFelipe Balbi 
3100ffcaf37SFelipe Balbi 	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
3110ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
3120ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
3130ffcaf37SFelipe Balbi 	if (dma_mapping_error(dwc->dev, scratch_addr)) {
3140ffcaf37SFelipe Balbi 		dev_err(dwc->dev, "failed to map scratch buffer\n");
3150ffcaf37SFelipe Balbi 		ret = -EFAULT;
3160ffcaf37SFelipe Balbi 		goto err0;
3170ffcaf37SFelipe Balbi 	}
3180ffcaf37SFelipe Balbi 
3190ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
3200ffcaf37SFelipe Balbi 
3210ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
3220ffcaf37SFelipe Balbi 
3230ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3240ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
3250ffcaf37SFelipe Balbi 	if (ret < 0)
3260ffcaf37SFelipe Balbi 		goto err1;
3270ffcaf37SFelipe Balbi 
3280ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
3290ffcaf37SFelipe Balbi 
3300ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3310ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
3320ffcaf37SFelipe Balbi 	if (ret < 0)
3330ffcaf37SFelipe Balbi 		goto err1;
3340ffcaf37SFelipe Balbi 
3350ffcaf37SFelipe Balbi 	return 0;
3360ffcaf37SFelipe Balbi 
3370ffcaf37SFelipe Balbi err1:
3380ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3390ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3400ffcaf37SFelipe Balbi 
3410ffcaf37SFelipe Balbi err0:
3420ffcaf37SFelipe Balbi 	return ret;
3430ffcaf37SFelipe Balbi }
3440ffcaf37SFelipe Balbi 
3450ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
3460ffcaf37SFelipe Balbi {
3470ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3480ffcaf37SFelipe Balbi 		return;
3490ffcaf37SFelipe Balbi 
3500ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3510ffcaf37SFelipe Balbi 		return;
3520ffcaf37SFelipe Balbi 
3530ffcaf37SFelipe Balbi 	 /* should never fall here */
3540ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3550ffcaf37SFelipe Balbi 		return;
3560ffcaf37SFelipe Balbi 
3570ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3580ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3590ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
3600ffcaf37SFelipe Balbi }
3610ffcaf37SFelipe Balbi 
362789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
363789451f6SFelipe Balbi {
364789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
365789451f6SFelipe Balbi 
366789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
367789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
368789451f6SFelipe Balbi 
36973815280SFelipe Balbi 	dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
370789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
371789451f6SFelipe Balbi }
372789451f6SFelipe Balbi 
37341ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
37426ceca97SFelipe Balbi {
37526ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
37626ceca97SFelipe Balbi 
37726ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
37826ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
37926ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
38026ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
38126ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
38226ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
38326ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
38426ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
38526ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
38626ceca97SFelipe Balbi }
38726ceca97SFelipe Balbi 
38872246da4SFelipe Balbi /**
389b5a65c40SHuang Rui  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
390b5a65c40SHuang Rui  * @dwc: Pointer to our controller context structure
39188bc9d19SHeikki Krogerus  *
39288bc9d19SHeikki Krogerus  * Returns 0 on success. The USB PHY interfaces are configured but not
39388bc9d19SHeikki Krogerus  * initialized. The PHY interfaces and the PHYs get initialized together with
39488bc9d19SHeikki Krogerus  * the core in dwc3_core_init.
395b5a65c40SHuang Rui  */
39688bc9d19SHeikki Krogerus static int dwc3_phy_setup(struct dwc3 *dwc)
397b5a65c40SHuang Rui {
398b5a65c40SHuang Rui 	u32 reg;
39988bc9d19SHeikki Krogerus 	int ret;
400b5a65c40SHuang Rui 
401b5a65c40SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
402b5a65c40SHuang Rui 
4032164a476SHuang Rui 	/*
4042164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
4052164a476SHuang Rui 	 * to '0' during coreConsultant configuration. So default value
4062164a476SHuang Rui 	 * will be '0' when the core is reset. Application needs to set it
4072164a476SHuang Rui 	 * to '1' after the core initialization is completed.
4082164a476SHuang Rui 	 */
4092164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
4102164a476SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
4112164a476SHuang Rui 
412b5a65c40SHuang Rui 	if (dwc->u2ss_inp3_quirk)
413b5a65c40SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
414b5a65c40SHuang Rui 
415df31f5b3SHuang Rui 	if (dwc->req_p1p2p3_quirk)
416df31f5b3SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
417df31f5b3SHuang Rui 
418a2a1d0f5SHuang Rui 	if (dwc->del_p1p2p3_quirk)
419a2a1d0f5SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
420a2a1d0f5SHuang Rui 
42141c06ffdSHuang Rui 	if (dwc->del_phy_power_chg_quirk)
42241c06ffdSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
42341c06ffdSHuang Rui 
424fb67afcaSHuang Rui 	if (dwc->lfps_filter_quirk)
425fb67afcaSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
426fb67afcaSHuang Rui 
42714f4ac53SHuang Rui 	if (dwc->rx_detect_poll_quirk)
42814f4ac53SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
42914f4ac53SHuang Rui 
4306b6a0c9aSHuang Rui 	if (dwc->tx_de_emphasis_quirk)
4316b6a0c9aSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
4326b6a0c9aSHuang Rui 
433cd72f890SFelipe Balbi 	if (dwc->dis_u3_susphy_quirk)
43459acfa20SHuang Rui 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
43559acfa20SHuang Rui 
436b5a65c40SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
437b5a65c40SHuang Rui 
4382164a476SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
4392164a476SHuang Rui 
4403e10a2ceSHeikki Krogerus 	/* Select the HS PHY interface */
4413e10a2ceSHeikki Krogerus 	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
4423e10a2ceSHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
44343cacb03SFelipe Balbi 		if (dwc->hsphy_interface &&
44443cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
4453e10a2ceSHeikki Krogerus 			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
44688bc9d19SHeikki Krogerus 			break;
44743cacb03SFelipe Balbi 		} else if (dwc->hsphy_interface &&
44843cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
4493e10a2ceSHeikki Krogerus 			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
45088bc9d19SHeikki Krogerus 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
4513e10a2ceSHeikki Krogerus 		} else {
45288bc9d19SHeikki Krogerus 			/* Relying on default value. */
45388bc9d19SHeikki Krogerus 			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
4543e10a2ceSHeikki Krogerus 				break;
4553e10a2ceSHeikki Krogerus 		}
4563e10a2ceSHeikki Krogerus 		/* FALLTHROUGH */
45788bc9d19SHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
45888bc9d19SHeikki Krogerus 		/* Making sure the interface and PHY are operational */
45988bc9d19SHeikki Krogerus 		ret = dwc3_soft_reset(dwc);
46088bc9d19SHeikki Krogerus 		if (ret)
46188bc9d19SHeikki Krogerus 			return ret;
46288bc9d19SHeikki Krogerus 
46388bc9d19SHeikki Krogerus 		udelay(1);
46488bc9d19SHeikki Krogerus 
46588bc9d19SHeikki Krogerus 		ret = dwc3_ulpi_init(dwc);
46688bc9d19SHeikki Krogerus 		if (ret)
46788bc9d19SHeikki Krogerus 			return ret;
46888bc9d19SHeikki Krogerus 		/* FALLTHROUGH */
4693e10a2ceSHeikki Krogerus 	default:
4703e10a2ceSHeikki Krogerus 		break;
4713e10a2ceSHeikki Krogerus 	}
4723e10a2ceSHeikki Krogerus 
4732164a476SHuang Rui 	/*
4742164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
4752164a476SHuang Rui 	 * '0' during coreConsultant configuration. So default value will
4762164a476SHuang Rui 	 * be '0' when the core is reset. Application needs to set it to
4772164a476SHuang Rui 	 * '1' after the core initialization is completed.
4782164a476SHuang Rui 	 */
4792164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
4802164a476SHuang Rui 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
4812164a476SHuang Rui 
482cd72f890SFelipe Balbi 	if (dwc->dis_u2_susphy_quirk)
4830effe0a3SHuang Rui 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
4840effe0a3SHuang Rui 
485ec791d14SJohn Youn 	if (dwc->dis_enblslpm_quirk)
486ec791d14SJohn Youn 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
487ec791d14SJohn Youn 
4882164a476SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
48988bc9d19SHeikki Krogerus 
49088bc9d19SHeikki Krogerus 	return 0;
491b5a65c40SHuang Rui }
492b5a65c40SHuang Rui 
493b5a65c40SHuang Rui /**
49472246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
49572246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
49672246da4SFelipe Balbi  *
49772246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
49872246da4SFelipe Balbi  */
49941ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
50072246da4SFelipe Balbi {
5010ffcaf37SFelipe Balbi 	u32			hwparams4 = dwc->hwparams.hwparams4;
50272246da4SFelipe Balbi 	u32			reg;
50372246da4SFelipe Balbi 	int			ret;
50472246da4SFelipe Balbi 
5057650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
5067650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
507690fb371SJohn Youn 	if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
508690fb371SJohn Youn 		/* Detected DWC_usb3 IP */
509690fb371SJohn Youn 		dwc->revision = reg;
510690fb371SJohn Youn 	} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
511690fb371SJohn Youn 		/* Detected DWC_usb31 IP */
512690fb371SJohn Youn 		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
513690fb371SJohn Youn 		dwc->revision |= DWC3_REVISION_IS_DWC31;
514690fb371SJohn Youn 	} else {
5157650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
5167650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
5177650bd74SSebastian Andrzej Siewior 		goto err0;
5187650bd74SSebastian Andrzej Siewior 	}
5197650bd74SSebastian Andrzej Siewior 
520fa0ea13eSFelipe Balbi 	/*
521fa0ea13eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
522fa0ea13eSFelipe Balbi 	 * out which kernel version a bug was found.
523fa0ea13eSFelipe Balbi 	 */
524fa0ea13eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
525fa0ea13eSFelipe Balbi 
5260e1e5c47SPaul Zimmerman 	/* Handle USB2.0-only core configuration */
5270e1e5c47SPaul Zimmerman 	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
5280e1e5c47SPaul Zimmerman 			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
5290e1e5c47SPaul Zimmerman 		if (dwc->maximum_speed == USB_SPEED_SUPER)
5300e1e5c47SPaul Zimmerman 			dwc->maximum_speed = USB_SPEED_HIGH;
5310e1e5c47SPaul Zimmerman 	}
5320e1e5c47SPaul Zimmerman 
53372246da4SFelipe Balbi 	/* issue device SoftReset too */
534c5cc74e8SHeikki Krogerus 	ret = dwc3_soft_reset(dwc);
535c5cc74e8SHeikki Krogerus 	if (ret)
53672246da4SFelipe Balbi 		goto err0;
53772246da4SFelipe Balbi 
53857303488SKishon Vijay Abraham I 	ret = dwc3_core_soft_reset(dwc);
53957303488SKishon Vijay Abraham I 	if (ret)
54057303488SKishon Vijay Abraham I 		goto err0;
54158a0f23fSPratyush Anand 
5424878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
5433e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
5444878a028SSebastian Andrzej Siewior 
545164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
5464878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
54732a4a135SFelipe Balbi 		/**
54832a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
54932a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
55032a4a135SFelipe Balbi 		 *
55132a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
55232a4a135SFelipe Balbi 		 * configurations.
55332a4a135SFelipe Balbi 		 *
55432a4a135SFelipe Balbi 		 * Refers to:
55532a4a135SFelipe Balbi 		 *
55632a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
55732a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
55832a4a135SFelipe Balbi 		 */
55932a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
56032a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
56132a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
56232a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
56332a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
56432a4a135SFelipe Balbi 		else
5654878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
5664878a028SSebastian Andrzej Siewior 		break;
5670ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
5680ffcaf37SFelipe Balbi 		/* enable hibernation here */
5690ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
5702eac3992SHuang Rui 
5712eac3992SHuang Rui 		/*
5722eac3992SHuang Rui 		 * REVISIT Enabling this bit so that host-mode hibernation
5732eac3992SHuang Rui 		 * will work. Device-mode hibernation is not yet implemented.
5742eac3992SHuang Rui 		 */
5752eac3992SHuang Rui 		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
5760ffcaf37SFelipe Balbi 		break;
5774878a028SSebastian Andrzej Siewior 	default:
5781407bf13SFelipe Balbi 		dwc3_trace(trace_dwc3_core, "No power optimization available\n");
5794878a028SSebastian Andrzej Siewior 	}
5804878a028SSebastian Andrzej Siewior 
581946bd579SHuang Rui 	/* check if current dwc3 is on simulation board */
582946bd579SHuang Rui 	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
5831407bf13SFelipe Balbi 		dwc3_trace(trace_dwc3_core,
5841407bf13SFelipe Balbi 				"running on FPGA platform\n");
585946bd579SHuang Rui 		dwc->is_fpga = true;
586946bd579SHuang Rui 	}
587946bd579SHuang Rui 
5883b81221aSHuang Rui 	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
5893b81221aSHuang Rui 			"disable_scramble cannot be used on non-FPGA builds\n");
5903b81221aSHuang Rui 
5913b81221aSHuang Rui 	if (dwc->disable_scramble_quirk && dwc->is_fpga)
5923b81221aSHuang Rui 		reg |= DWC3_GCTL_DISSCRAMBLE;
5933b81221aSHuang Rui 	else
5943b81221aSHuang Rui 		reg &= ~DWC3_GCTL_DISSCRAMBLE;
5953b81221aSHuang Rui 
5969a5b2f31SHuang Rui 	if (dwc->u2exit_lfps_quirk)
5979a5b2f31SHuang Rui 		reg |= DWC3_GCTL_U2EXIT_LFPS;
5989a5b2f31SHuang Rui 
5994878a028SSebastian Andrzej Siewior 	/*
6004878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
6011d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
6024878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
6031d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
6044878a028SSebastian Andrzej Siewior 	 */
6054878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
6064878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
6074878a028SSebastian Andrzej Siewior 
608789451f6SFelipe Balbi 	dwc3_core_num_eps(dwc);
609789451f6SFelipe Balbi 
6104878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
6114878a028SSebastian Andrzej Siewior 
6120ffcaf37SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
6130ffcaf37SFelipe Balbi 	if (ret)
6140ffcaf37SFelipe Balbi 		goto err1;
6150ffcaf37SFelipe Balbi 
6160ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
6170ffcaf37SFelipe Balbi 	if (ret)
6180ffcaf37SFelipe Balbi 		goto err2;
6190ffcaf37SFelipe Balbi 
62072246da4SFelipe Balbi 	return 0;
62172246da4SFelipe Balbi 
6220ffcaf37SFelipe Balbi err2:
6230ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
6240ffcaf37SFelipe Balbi 
6250ffcaf37SFelipe Balbi err1:
6260ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
6270ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
62857303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
62957303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
6300ffcaf37SFelipe Balbi 
63172246da4SFelipe Balbi err0:
63272246da4SFelipe Balbi 	return ret;
63372246da4SFelipe Balbi }
63472246da4SFelipe Balbi 
63572246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
63672246da4SFelipe Balbi {
6370ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
63801b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
63901b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
64057303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
64157303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
64272246da4SFelipe Balbi }
64372246da4SFelipe Balbi 
6443c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
64572246da4SFelipe Balbi {
6463c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
647941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
6483c9f94acSFelipe Balbi 	int ret;
64972246da4SFelipe Balbi 
6505088b6f5SKishon Vijay Abraham I 	if (node) {
6515088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
6525088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
653bb674907SFelipe Balbi 	} else {
654bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
655bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
6565088b6f5SKishon Vijay Abraham I 	}
6575088b6f5SKishon Vijay Abraham I 
658d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
659d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
660122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
661122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
662122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
663d105e7f8SFelipe Balbi 			return ret;
664122f06e6SKishon Vijay Abraham I 		} else {
66551e1e7bcSFelipe Balbi 			dev_err(dev, "no usb2 phy configured\n");
666122f06e6SKishon Vijay Abraham I 			return ret;
667122f06e6SKishon Vijay Abraham I 		}
66851e1e7bcSFelipe Balbi 	}
66951e1e7bcSFelipe Balbi 
670d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
671315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
672122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
673122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
674122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
675d105e7f8SFelipe Balbi 			return ret;
676122f06e6SKishon Vijay Abraham I 		} else {
67751e1e7bcSFelipe Balbi 			dev_err(dev, "no usb3 phy configured\n");
678122f06e6SKishon Vijay Abraham I 			return ret;
679122f06e6SKishon Vijay Abraham I 		}
68051e1e7bcSFelipe Balbi 	}
68151e1e7bcSFelipe Balbi 
68257303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
68357303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
68457303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
68557303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
68657303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
68757303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
68857303488SKishon Vijay Abraham I 			return ret;
68957303488SKishon Vijay Abraham I 		} else {
69057303488SKishon Vijay Abraham I 			dev_err(dev, "no usb2 phy configured\n");
69157303488SKishon Vijay Abraham I 			return ret;
69257303488SKishon Vijay Abraham I 		}
69357303488SKishon Vijay Abraham I 	}
69457303488SKishon Vijay Abraham I 
69557303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
69657303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
69757303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
69857303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
69957303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
70057303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
70157303488SKishon Vijay Abraham I 			return ret;
70257303488SKishon Vijay Abraham I 		} else {
70357303488SKishon Vijay Abraham I 			dev_err(dev, "no usb3 phy configured\n");
70457303488SKishon Vijay Abraham I 			return ret;
70557303488SKishon Vijay Abraham I 		}
70657303488SKishon Vijay Abraham I 	}
70757303488SKishon Vijay Abraham I 
7083c9f94acSFelipe Balbi 	return 0;
7093c9f94acSFelipe Balbi }
7103c9f94acSFelipe Balbi 
7115f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
7125f94adfeSFelipe Balbi {
7135f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
7145f94adfeSFelipe Balbi 	int ret;
7155f94adfeSFelipe Balbi 
7165f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
7175f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
7185f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
7195f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
7205f94adfeSFelipe Balbi 		if (ret) {
7215f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
7225f94adfeSFelipe Balbi 			return ret;
7235f94adfeSFelipe Balbi 		}
7245f94adfeSFelipe Balbi 		break;
7255f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
7265f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
7275f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
7285f94adfeSFelipe Balbi 		if (ret) {
7295f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
7305f94adfeSFelipe Balbi 			return ret;
7315f94adfeSFelipe Balbi 		}
7325f94adfeSFelipe Balbi 		break;
7335f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
7345f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
7355f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
7365f94adfeSFelipe Balbi 		if (ret) {
7375f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
7385f94adfeSFelipe Balbi 			return ret;
7395f94adfeSFelipe Balbi 		}
7405f94adfeSFelipe Balbi 
7415f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
7425f94adfeSFelipe Balbi 		if (ret) {
7435f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
7445f94adfeSFelipe Balbi 			return ret;
7455f94adfeSFelipe Balbi 		}
7465f94adfeSFelipe Balbi 		break;
7475f94adfeSFelipe Balbi 	default:
7485f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
7495f94adfeSFelipe Balbi 		return -EINVAL;
7505f94adfeSFelipe Balbi 	}
7515f94adfeSFelipe Balbi 
7525f94adfeSFelipe Balbi 	return 0;
7535f94adfeSFelipe Balbi }
7545f94adfeSFelipe Balbi 
7555f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
7565f94adfeSFelipe Balbi {
7575f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
7585f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
7595f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
7605f94adfeSFelipe Balbi 		break;
7615f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
7625f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
7635f94adfeSFelipe Balbi 		break;
7645f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
7655f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
7665f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
7675f94adfeSFelipe Balbi 		break;
7685f94adfeSFelipe Balbi 	default:
7695f94adfeSFelipe Balbi 		/* do nothing */
7705f94adfeSFelipe Balbi 		break;
7715f94adfeSFelipe Balbi 	}
7725f94adfeSFelipe Balbi }
7735f94adfeSFelipe Balbi 
7743c9f94acSFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
7753c9f94acSFelipe Balbi 
7763c9f94acSFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
7773c9f94acSFelipe Balbi {
7783c9f94acSFelipe Balbi 	struct device		*dev = &pdev->dev;
7793c9f94acSFelipe Balbi 	struct dwc3_platform_data *pdata = dev_get_platdata(dev);
7803c9f94acSFelipe Balbi 	struct resource		*res;
7813c9f94acSFelipe Balbi 	struct dwc3		*dwc;
78280caf7d2SHuang Rui 	u8			lpm_nyet_threshold;
7836b6a0c9aSHuang Rui 	u8			tx_de_emphasis;
784460d098cSHuang Rui 	u8			hird_threshold;
785db2be4e9SNikhil Badola 	u32			fladj = 0;
7863c9f94acSFelipe Balbi 
787b09e99eeSAndy Shevchenko 	int			ret;
7883c9f94acSFelipe Balbi 
7893c9f94acSFelipe Balbi 	void __iomem		*regs;
7903c9f94acSFelipe Balbi 	void			*mem;
7913c9f94acSFelipe Balbi 
7923c9f94acSFelipe Balbi 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
793734d5a53SJingoo Han 	if (!mem)
7943c9f94acSFelipe Balbi 		return -ENOMEM;
795734d5a53SJingoo Han 
7963c9f94acSFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
7973c9f94acSFelipe Balbi 	dwc->mem = mem;
7983c9f94acSFelipe Balbi 	dwc->dev = dev;
7993c9f94acSFelipe Balbi 
8003c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
8013c9f94acSFelipe Balbi 	if (!res) {
8023c9f94acSFelipe Balbi 		dev_err(dev, "missing IRQ\n");
8033c9f94acSFelipe Balbi 		return -ENODEV;
8043c9f94acSFelipe Balbi 	}
8053c9f94acSFelipe Balbi 	dwc->xhci_resources[1].start = res->start;
8063c9f94acSFelipe Balbi 	dwc->xhci_resources[1].end = res->end;
8073c9f94acSFelipe Balbi 	dwc->xhci_resources[1].flags = res->flags;
8083c9f94acSFelipe Balbi 	dwc->xhci_resources[1].name = res->name;
8093c9f94acSFelipe Balbi 
8103c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8113c9f94acSFelipe Balbi 	if (!res) {
8123c9f94acSFelipe Balbi 		dev_err(dev, "missing memory resource\n");
8133c9f94acSFelipe Balbi 		return -ENODEV;
8143c9f94acSFelipe Balbi 	}
8153c9f94acSFelipe Balbi 
816f32a5e23SVivek Gautam 	dwc->xhci_resources[0].start = res->start;
817f32a5e23SVivek Gautam 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
818f32a5e23SVivek Gautam 					DWC3_XHCI_REGS_END;
819f32a5e23SVivek Gautam 	dwc->xhci_resources[0].flags = res->flags;
820f32a5e23SVivek Gautam 	dwc->xhci_resources[0].name = res->name;
821f32a5e23SVivek Gautam 
822f32a5e23SVivek Gautam 	res->start += DWC3_GLOBALS_REGS_START;
823f32a5e23SVivek Gautam 
824f32a5e23SVivek Gautam 	/*
825f32a5e23SVivek Gautam 	 * Request memory region but exclude xHCI regs,
826f32a5e23SVivek Gautam 	 * since it will be requested by the xhci-plat driver.
827f32a5e23SVivek Gautam 	 */
828f32a5e23SVivek Gautam 	regs = devm_ioremap_resource(dev, res);
8293da1f6eeSFelipe Balbi 	if (IS_ERR(regs)) {
8303da1f6eeSFelipe Balbi 		ret = PTR_ERR(regs);
8313da1f6eeSFelipe Balbi 		goto err0;
8323da1f6eeSFelipe Balbi 	}
833f32a5e23SVivek Gautam 
834f32a5e23SVivek Gautam 	dwc->regs	= regs;
835f32a5e23SVivek Gautam 	dwc->regs_size	= resource_size(res);
836f32a5e23SVivek Gautam 
83780caf7d2SHuang Rui 	/* default to highest possible threshold */
83880caf7d2SHuang Rui 	lpm_nyet_threshold = 0xff;
83980caf7d2SHuang Rui 
8406b6a0c9aSHuang Rui 	/* default to -3.5dB de-emphasis */
8416b6a0c9aSHuang Rui 	tx_de_emphasis = 1;
8426b6a0c9aSHuang Rui 
843460d098cSHuang Rui 	/*
844460d098cSHuang Rui 	 * default to assert utmi_sleep_n and use maximum allowed HIRD
845460d098cSHuang Rui 	 * threshold value of 0b1100
846460d098cSHuang Rui 	 */
847460d098cSHuang Rui 	hird_threshold = 12;
848460d098cSHuang Rui 
84963863b98SHeikki Krogerus 	dwc->maximum_speed = usb_get_maximum_speed(dev);
85006e7114fSHeikki Krogerus 	dwc->dr_mode = usb_get_dr_mode(dev);
85163863b98SHeikki Krogerus 
8523d128919SHeikki Krogerus 	dwc->has_lpm_erratum = device_property_read_bool(dev,
85380caf7d2SHuang Rui 				"snps,has-lpm-erratum");
8543d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,lpm-nyet-threshold",
85580caf7d2SHuang Rui 				&lpm_nyet_threshold);
8563d128919SHeikki Krogerus 	dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
857460d098cSHuang Rui 				"snps,is-utmi-l1-suspend");
8583d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,hird-threshold",
859460d098cSHuang Rui 				&hird_threshold);
8603d128919SHeikki Krogerus 	dwc->usb3_lpm_capable = device_property_read_bool(dev,
861eac68e8fSRobert Baldyga 				"snps,usb3_lpm_capable");
8623c9f94acSFelipe Balbi 
8633d128919SHeikki Krogerus 	dwc->disable_scramble_quirk = device_property_read_bool(dev,
8643b81221aSHuang Rui 				"snps,disable_scramble_quirk");
8653d128919SHeikki Krogerus 	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
8669a5b2f31SHuang Rui 				"snps,u2exit_lfps_quirk");
8673d128919SHeikki Krogerus 	dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
868b5a65c40SHuang Rui 				"snps,u2ss_inp3_quirk");
8693d128919SHeikki Krogerus 	dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
870df31f5b3SHuang Rui 				"snps,req_p1p2p3_quirk");
8713d128919SHeikki Krogerus 	dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
872a2a1d0f5SHuang Rui 				"snps,del_p1p2p3_quirk");
8733d128919SHeikki Krogerus 	dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
87441c06ffdSHuang Rui 				"snps,del_phy_power_chg_quirk");
8753d128919SHeikki Krogerus 	dwc->lfps_filter_quirk = device_property_read_bool(dev,
876fb67afcaSHuang Rui 				"snps,lfps_filter_quirk");
8773d128919SHeikki Krogerus 	dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
87814f4ac53SHuang Rui 				"snps,rx_detect_poll_quirk");
8793d128919SHeikki Krogerus 	dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
88059acfa20SHuang Rui 				"snps,dis_u3_susphy_quirk");
8813d128919SHeikki Krogerus 	dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
8820effe0a3SHuang Rui 				"snps,dis_u2_susphy_quirk");
883ec791d14SJohn Youn 	dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
884ec791d14SJohn Youn 				"snps,dis_enblslpm_quirk");
8856b6a0c9aSHuang Rui 
8863d128919SHeikki Krogerus 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
8876b6a0c9aSHuang Rui 				"snps,tx_de_emphasis_quirk");
8883d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,tx_de_emphasis",
8896b6a0c9aSHuang Rui 				&tx_de_emphasis);
8903d128919SHeikki Krogerus 	device_property_read_string(dev, "snps,hsphy_interface",
8913e10a2ceSHeikki Krogerus 				    &dwc->hsphy_interface);
8923d128919SHeikki Krogerus 	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
893db2be4e9SNikhil Badola 				 &fladj);
8943d128919SHeikki Krogerus 
8953d128919SHeikki Krogerus 	if (pdata) {
8963c9f94acSFelipe Balbi 		dwc->maximum_speed = pdata->maximum_speed;
89780caf7d2SHuang Rui 		dwc->has_lpm_erratum = pdata->has_lpm_erratum;
89880caf7d2SHuang Rui 		if (pdata->lpm_nyet_threshold)
89980caf7d2SHuang Rui 			lpm_nyet_threshold = pdata->lpm_nyet_threshold;
900460d098cSHuang Rui 		dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
901460d098cSHuang Rui 		if (pdata->hird_threshold)
902460d098cSHuang Rui 			hird_threshold = pdata->hird_threshold;
9033c9f94acSFelipe Balbi 
904eac68e8fSRobert Baldyga 		dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
9053c9f94acSFelipe Balbi 		dwc->dr_mode = pdata->dr_mode;
9063b81221aSHuang Rui 
9073b81221aSHuang Rui 		dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
9089a5b2f31SHuang Rui 		dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
909b5a65c40SHuang Rui 		dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
910df31f5b3SHuang Rui 		dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
911a2a1d0f5SHuang Rui 		dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
91241c06ffdSHuang Rui 		dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
913fb67afcaSHuang Rui 		dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
91414f4ac53SHuang Rui 		dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
91559acfa20SHuang Rui 		dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
9160effe0a3SHuang Rui 		dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
917ec791d14SJohn Youn 		dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
9186b6a0c9aSHuang Rui 
9196b6a0c9aSHuang Rui 		dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
9206b6a0c9aSHuang Rui 		if (pdata->tx_de_emphasis)
9216b6a0c9aSHuang Rui 			tx_de_emphasis = pdata->tx_de_emphasis;
9223e10a2ceSHeikki Krogerus 
9233e10a2ceSHeikki Krogerus 		dwc->hsphy_interface = pdata->hsphy_interface;
924db2be4e9SNikhil Badola 		fladj = pdata->fladj_value;
9253c9f94acSFelipe Balbi 	}
9263c9f94acSFelipe Balbi 
92780caf7d2SHuang Rui 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
9286b6a0c9aSHuang Rui 	dwc->tx_de_emphasis = tx_de_emphasis;
92980caf7d2SHuang Rui 
930460d098cSHuang Rui 	dwc->hird_threshold = hird_threshold
931460d098cSHuang Rui 		| (dwc->is_utmi_l1_suspend << 4);
932460d098cSHuang Rui 
9336c89cce0SHeikki Krogerus 	platform_set_drvdata(pdev, dwc);
9342917e718SHeikki Krogerus 	dwc3_cache_hwparams(dwc);
9356c89cce0SHeikki Krogerus 
93688bc9d19SHeikki Krogerus 	ret = dwc3_phy_setup(dwc);
93788bc9d19SHeikki Krogerus 	if (ret)
93888bc9d19SHeikki Krogerus 		goto err0;
93945bb7de2SHeikki Krogerus 
9403c9f94acSFelipe Balbi 	ret = dwc3_core_get_phy(dwc);
9413c9f94acSFelipe Balbi 	if (ret)
9423da1f6eeSFelipe Balbi 		goto err0;
9433c9f94acSFelipe Balbi 
94472246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
94572246da4SFelipe Balbi 
94619bacdc9SHeikki Krogerus 	if (!dev->dma_mask) {
947ddff14f1SKishon Vijay Abraham I 		dev->dma_mask = dev->parent->dma_mask;
948ddff14f1SKishon Vijay Abraham I 		dev->dma_parms = dev->parent->dma_parms;
949ddff14f1SKishon Vijay Abraham I 		dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
95019bacdc9SHeikki Krogerus 	}
951ddff14f1SKishon Vijay Abraham I 
952802ca850SChanho Park 	pm_runtime_enable(dev);
953802ca850SChanho Park 	pm_runtime_get_sync(dev);
954802ca850SChanho Park 	pm_runtime_forbid(dev);
95572246da4SFelipe Balbi 
9563921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
9573921426bSFelipe Balbi 	if (ret) {
9583921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
9593921426bSFelipe Balbi 		ret = -ENOMEM;
9603da1f6eeSFelipe Balbi 		goto err1;
9613921426bSFelipe Balbi 	}
9623921426bSFelipe Balbi 
96332a4a135SFelipe Balbi 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
96432a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_HOST;
96532a4a135SFelipe Balbi 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
96632a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
96732a4a135SFelipe Balbi 
96832a4a135SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
96932a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_OTG;
97032a4a135SFelipe Balbi 
97172246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
97272246da4SFelipe Balbi 	if (ret) {
973802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
9743da1f6eeSFelipe Balbi 		goto err1;
97572246da4SFelipe Balbi 	}
97672246da4SFelipe Balbi 
97777966eb8SJohn Youn 	/* Check the maximum_speed parameter */
97877966eb8SJohn Youn 	switch (dwc->maximum_speed) {
97977966eb8SJohn Youn 	case USB_SPEED_LOW:
98077966eb8SJohn Youn 	case USB_SPEED_FULL:
98177966eb8SJohn Youn 	case USB_SPEED_HIGH:
98277966eb8SJohn Youn 	case USB_SPEED_SUPER:
98377966eb8SJohn Youn 	case USB_SPEED_SUPER_PLUS:
98477966eb8SJohn Youn 		break;
98577966eb8SJohn Youn 	default:
98677966eb8SJohn Youn 		dev_err(dev, "invalid maximum_speed parameter %d\n",
98777966eb8SJohn Youn 			dwc->maximum_speed);
98877966eb8SJohn Youn 		/* fall through */
98977966eb8SJohn Youn 	case USB_SPEED_UNKNOWN:
99077966eb8SJohn Youn 		/* default to superspeed */
9912c7f1bd9SJohn Youn 		dwc->maximum_speed = USB_SPEED_SUPER;
9922c7f1bd9SJohn Youn 
9932c7f1bd9SJohn Youn 		/*
9942c7f1bd9SJohn Youn 		 * default to superspeed plus if we are capable.
9952c7f1bd9SJohn Youn 		 */
9962c7f1bd9SJohn Youn 		if (dwc3_is_usb31(dwc) &&
9972c7f1bd9SJohn Youn 		    (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
9982c7f1bd9SJohn Youn 		     DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
9992c7f1bd9SJohn Youn 			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
100077966eb8SJohn Youn 
100177966eb8SJohn Youn 		break;
10022c7f1bd9SJohn Youn 	}
10032c7f1bd9SJohn Youn 
1004db2be4e9SNikhil Badola 	/* Adjust Frame Length */
1005db2be4e9SNikhil Badola 	dwc3_frame_length_adjustment(dwc, fladj);
1006db2be4e9SNikhil Badola 
10073088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
10083088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
100957303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb2_generic_phy);
101057303488SKishon Vijay Abraham I 	if (ret < 0)
10113da1f6eeSFelipe Balbi 		goto err2;
101257303488SKishon Vijay Abraham I 
101357303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb3_generic_phy);
101457303488SKishon Vijay Abraham I 	if (ret < 0)
10153da1f6eeSFelipe Balbi 		goto err3;
10163088f108SKishon Vijay Abraham I 
1017f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
1018f122d33eSFelipe Balbi 	if (ret) {
1019f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
10203da1f6eeSFelipe Balbi 		goto err4;
1021f122d33eSFelipe Balbi 	}
1022f122d33eSFelipe Balbi 
10235f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
10245f94adfeSFelipe Balbi 	if (ret)
10253da1f6eeSFelipe Balbi 		goto err5;
102672246da4SFelipe Balbi 
102772246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
102872246da4SFelipe Balbi 	if (ret) {
1029802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
10303da1f6eeSFelipe Balbi 		goto err6;
103172246da4SFelipe Balbi 	}
103272246da4SFelipe Balbi 
1033802ca850SChanho Park 	pm_runtime_allow(dev);
103472246da4SFelipe Balbi 
103572246da4SFelipe Balbi 	return 0;
103672246da4SFelipe Balbi 
10373da1f6eeSFelipe Balbi err6:
10385f94adfeSFelipe Balbi 	dwc3_core_exit_mode(dwc);
103972246da4SFelipe Balbi 
10403da1f6eeSFelipe Balbi err5:
1041f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
1042f122d33eSFelipe Balbi 
10433da1f6eeSFelipe Balbi err4:
104457303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
104557303488SKishon Vijay Abraham I 
10463da1f6eeSFelipe Balbi err3:
104757303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
104857303488SKishon Vijay Abraham I 
10493da1f6eeSFelipe Balbi err2:
1050501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
1051501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
105272246da4SFelipe Balbi 	dwc3_core_exit(dwc);
105372246da4SFelipe Balbi 
10543da1f6eeSFelipe Balbi err1:
10553921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
105688bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
10573921426bSFelipe Balbi 
10583da1f6eeSFelipe Balbi err0:
10593da1f6eeSFelipe Balbi 	/*
10603da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
10613da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
10623da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
10633da1f6eeSFelipe Balbi 	 */
10643da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
10653da1f6eeSFelipe Balbi 
106672246da4SFelipe Balbi 	return ret;
106772246da4SFelipe Balbi }
106872246da4SFelipe Balbi 
1069fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
107072246da4SFelipe Balbi {
107172246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
10723da1f6eeSFelipe Balbi 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
10733da1f6eeSFelipe Balbi 
10743da1f6eeSFelipe Balbi 	/*
10753da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
10763da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
10773da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
10783da1f6eeSFelipe Balbi 	 */
10793da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
108072246da4SFelipe Balbi 
1081dc99f16fSFelipe Balbi 	dwc3_debugfs_exit(dwc);
1082dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
1083dc99f16fSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
1084dc99f16fSFelipe Balbi 	dwc3_free_event_buffers(dwc);
1085dc99f16fSFelipe Balbi 
10868ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
10878ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
108857303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
108957303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
10908ba007a9SKishon Vijay Abraham I 
109172246da4SFelipe Balbi 	dwc3_core_exit(dwc);
109288bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
109372246da4SFelipe Balbi 
10947415f17cSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
10957415f17cSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
10967415f17cSFelipe Balbi 
109772246da4SFelipe Balbi 	return 0;
109872246da4SFelipe Balbi }
109972246da4SFelipe Balbi 
11007415f17cSFelipe Balbi #ifdef CONFIG_PM_SLEEP
11017415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
11027415f17cSFelipe Balbi {
11037415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
11047415f17cSFelipe Balbi 	unsigned long	flags;
11057415f17cSFelipe Balbi 
11067415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
11077415f17cSFelipe Balbi 
1108a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
1109a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
1110a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
11117415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
11127415f17cSFelipe Balbi 		/* FALLTHROUGH */
1113a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
11147415f17cSFelipe Balbi 	default:
11150b0231aaSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
11167415f17cSFelipe Balbi 		break;
11177415f17cSFelipe Balbi 	}
11187415f17cSFelipe Balbi 
11197415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
11207415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
11217415f17cSFelipe Balbi 
11227415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
11237415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
112457303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
112557303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
11267415f17cSFelipe Balbi 
11276344475fSSekhar Nori 	pinctrl_pm_select_sleep_state(dev);
11286344475fSSekhar Nori 
11297415f17cSFelipe Balbi 	return 0;
11307415f17cSFelipe Balbi }
11317415f17cSFelipe Balbi 
11327415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
11337415f17cSFelipe Balbi {
11347415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
11357415f17cSFelipe Balbi 	unsigned long	flags;
113657303488SKishon Vijay Abraham I 	int		ret;
11377415f17cSFelipe Balbi 
11386344475fSSekhar Nori 	pinctrl_pm_select_default_state(dev);
11396344475fSSekhar Nori 
11407415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
11417415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
114257303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
114357303488SKishon Vijay Abraham I 	if (ret < 0)
114457303488SKishon Vijay Abraham I 		return ret;
114557303488SKishon Vijay Abraham I 
114657303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
114757303488SKishon Vijay Abraham I 	if (ret < 0)
114857303488SKishon Vijay Abraham I 		goto err_usb2phy_init;
11497415f17cSFelipe Balbi 
11507415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
11517415f17cSFelipe Balbi 
11520b0231aaSFelipe Balbi 	dwc3_event_buffers_setup(dwc);
11537415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
11547415f17cSFelipe Balbi 
1155a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
1156a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
1157a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
11587415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
11597415f17cSFelipe Balbi 		/* FALLTHROUGH */
1160a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
11617415f17cSFelipe Balbi 	default:
11627415f17cSFelipe Balbi 		/* do nothing */
11637415f17cSFelipe Balbi 		break;
11647415f17cSFelipe Balbi 	}
11657415f17cSFelipe Balbi 
11667415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
11677415f17cSFelipe Balbi 
11687415f17cSFelipe Balbi 	pm_runtime_disable(dev);
11697415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
11707415f17cSFelipe Balbi 	pm_runtime_enable(dev);
11717415f17cSFelipe Balbi 
11727415f17cSFelipe Balbi 	return 0;
117357303488SKishon Vijay Abraham I 
117457303488SKishon Vijay Abraham I err_usb2phy_init:
117557303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
117657303488SKishon Vijay Abraham I 
117757303488SKishon Vijay Abraham I 	return ret;
11787415f17cSFelipe Balbi }
11797415f17cSFelipe Balbi 
11807415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
11817415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
11827415f17cSFelipe Balbi };
11837415f17cSFelipe Balbi 
11847415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
11857415f17cSFelipe Balbi #else
11867415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
11877415f17cSFelipe Balbi #endif
11887415f17cSFelipe Balbi 
11895088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
11905088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
11915088b6f5SKishon Vijay Abraham I 	{
119222a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
119322a5aa17SFelipe Balbi 	},
119422a5aa17SFelipe Balbi 	{
11955088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
11965088b6f5SKishon Vijay Abraham I 	},
11975088b6f5SKishon Vijay Abraham I 	{ },
11985088b6f5SKishon Vijay Abraham I };
11995088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
12005088b6f5SKishon Vijay Abraham I #endif
12015088b6f5SKishon Vijay Abraham I 
1202404905a6SHeikki Krogerus #ifdef CONFIG_ACPI
1203404905a6SHeikki Krogerus 
1204404905a6SHeikki Krogerus #define ACPI_ID_INTEL_BSW	"808622B7"
1205404905a6SHeikki Krogerus 
1206404905a6SHeikki Krogerus static const struct acpi_device_id dwc3_acpi_match[] = {
1207404905a6SHeikki Krogerus 	{ ACPI_ID_INTEL_BSW, 0 },
1208404905a6SHeikki Krogerus 	{ },
1209404905a6SHeikki Krogerus };
1210404905a6SHeikki Krogerus MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
1211404905a6SHeikki Krogerus #endif
1212404905a6SHeikki Krogerus 
121372246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
121472246da4SFelipe Balbi 	.probe		= dwc3_probe,
12157690417dSBill Pemberton 	.remove		= dwc3_remove,
121672246da4SFelipe Balbi 	.driver		= {
121772246da4SFelipe Balbi 		.name	= "dwc3",
12185088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
1219404905a6SHeikki Krogerus 		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
12207415f17cSFelipe Balbi 		.pm	= DWC3_PM_OPS,
122172246da4SFelipe Balbi 	},
122272246da4SFelipe Balbi };
122372246da4SFelipe Balbi 
1224b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
1225b1116dccSTobias Klauser 
12267ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
122772246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
12285945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
122972246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
1230