xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 2c7f1bd9)
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;
7057303488SKishon Vijay Abraham I 	int		ret;
7172246da4SFelipe Balbi 
7272246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
7372246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
7472246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
7572246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
7672246da4SFelipe Balbi 
7772246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
7872246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
7972246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
8072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
8172246da4SFelipe Balbi 
8272246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
8372246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
8472246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
8572246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
8672246da4SFelipe Balbi 
8751e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
8851e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
8957303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
9057303488SKishon Vijay Abraham I 	if (ret < 0)
9157303488SKishon Vijay Abraham I 		return ret;
9257303488SKishon Vijay Abraham I 
9357303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
9457303488SKishon Vijay Abraham I 	if (ret < 0) {
9557303488SKishon Vijay Abraham I 		phy_exit(dwc->usb2_generic_phy);
9657303488SKishon Vijay Abraham I 		return ret;
9757303488SKishon Vijay Abraham I 	}
9872246da4SFelipe Balbi 	mdelay(100);
9972246da4SFelipe Balbi 
10072246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
10172246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
10272246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
10372246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
10472246da4SFelipe Balbi 
10572246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
10672246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
10772246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
10872246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
10972246da4SFelipe Balbi 
11045627ac6SPratyush Anand 	mdelay(100);
11145627ac6SPratyush Anand 
11272246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
11372246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
11472246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
11572246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
11657303488SKishon Vijay Abraham I 
11757303488SKishon Vijay Abraham I 	return 0;
11872246da4SFelipe Balbi }
11972246da4SFelipe Balbi 
12072246da4SFelipe Balbi /**
121c5cc74e8SHeikki Krogerus  * dwc3_soft_reset - Issue soft reset
122c5cc74e8SHeikki Krogerus  * @dwc: Pointer to our controller context structure
123c5cc74e8SHeikki Krogerus  */
124c5cc74e8SHeikki Krogerus static int dwc3_soft_reset(struct dwc3 *dwc)
125c5cc74e8SHeikki Krogerus {
126c5cc74e8SHeikki Krogerus 	unsigned long timeout;
127c5cc74e8SHeikki Krogerus 	u32 reg;
128c5cc74e8SHeikki Krogerus 
129c5cc74e8SHeikki Krogerus 	timeout = jiffies + msecs_to_jiffies(500);
130c5cc74e8SHeikki Krogerus 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
131c5cc74e8SHeikki Krogerus 	do {
132c5cc74e8SHeikki Krogerus 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
133c5cc74e8SHeikki Krogerus 		if (!(reg & DWC3_DCTL_CSFTRST))
134c5cc74e8SHeikki Krogerus 			break;
135c5cc74e8SHeikki Krogerus 
136c5cc74e8SHeikki Krogerus 		if (time_after(jiffies, timeout)) {
137c5cc74e8SHeikki Krogerus 			dev_err(dwc->dev, "Reset Timed Out\n");
138c5cc74e8SHeikki Krogerus 			return -ETIMEDOUT;
139c5cc74e8SHeikki Krogerus 		}
140c5cc74e8SHeikki Krogerus 
141c5cc74e8SHeikki Krogerus 		cpu_relax();
142c5cc74e8SHeikki Krogerus 	} while (true);
143c5cc74e8SHeikki Krogerus 
144c5cc74e8SHeikki Krogerus 	return 0;
145c5cc74e8SHeikki Krogerus }
146c5cc74e8SHeikki Krogerus 
147db2be4e9SNikhil Badola /*
148db2be4e9SNikhil Badola  * dwc3_frame_length_adjustment - Adjusts frame length if required
149db2be4e9SNikhil Badola  * @dwc3: Pointer to our controller context structure
150db2be4e9SNikhil Badola  * @fladj: Value of GFLADJ_30MHZ to adjust frame length
151db2be4e9SNikhil Badola  */
152db2be4e9SNikhil Badola static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
153db2be4e9SNikhil Badola {
154db2be4e9SNikhil Badola 	u32 reg;
155db2be4e9SNikhil Badola 	u32 dft;
156db2be4e9SNikhil Badola 
157db2be4e9SNikhil Badola 	if (dwc->revision < DWC3_REVISION_250A)
158db2be4e9SNikhil Badola 		return;
159db2be4e9SNikhil Badola 
160db2be4e9SNikhil Badola 	if (fladj == 0)
161db2be4e9SNikhil Badola 		return;
162db2be4e9SNikhil Badola 
163db2be4e9SNikhil Badola 	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
164db2be4e9SNikhil Badola 	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
165db2be4e9SNikhil Badola 	if (!dev_WARN_ONCE(dwc->dev, dft == fladj,
166db2be4e9SNikhil Badola 	    "request value same as default, ignoring\n")) {
167db2be4e9SNikhil Badola 		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
168db2be4e9SNikhil Badola 		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
169db2be4e9SNikhil Badola 		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
170db2be4e9SNikhil Badola 	}
171db2be4e9SNikhil Badola }
172db2be4e9SNikhil Badola 
173c5cc74e8SHeikki Krogerus /**
17472246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
17572246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
17672246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
17772246da4SFelipe Balbi  */
17872246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
17972246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
18072246da4SFelipe Balbi {
18172246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
18272246da4SFelipe Balbi }
18372246da4SFelipe Balbi 
18472246da4SFelipe Balbi /**
1851d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
18672246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
18772246da4SFelipe Balbi  * @length: size of the event buffer
18872246da4SFelipe Balbi  *
1891d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
19072246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
19172246da4SFelipe Balbi  */
19267d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
19367d0b500SFelipe Balbi 		unsigned length)
19472246da4SFelipe Balbi {
19572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
19672246da4SFelipe Balbi 
197380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
19872246da4SFelipe Balbi 	if (!evt)
19972246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
20072246da4SFelipe Balbi 
20172246da4SFelipe Balbi 	evt->dwc	= dwc;
20272246da4SFelipe Balbi 	evt->length	= length;
20372246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
20472246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
205e32672f0SFelipe Balbi 	if (!evt->buf)
20672246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
20772246da4SFelipe Balbi 
20872246da4SFelipe Balbi 	return evt;
20972246da4SFelipe Balbi }
21072246da4SFelipe Balbi 
21172246da4SFelipe Balbi /**
21272246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
21372246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
21472246da4SFelipe Balbi  */
21572246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
21672246da4SFelipe Balbi {
21772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
21872246da4SFelipe Balbi 	int i;
21972246da4SFelipe Balbi 
2209f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
22172246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
22264b6c8a7SAnton Tikhomirov 		if (evt)
22372246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
22472246da4SFelipe Balbi 	}
22572246da4SFelipe Balbi }
22672246da4SFelipe Balbi 
22772246da4SFelipe Balbi /**
22872246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
2291d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
23072246da4SFelipe Balbi  * @length: size of event buffer
23172246da4SFelipe Balbi  *
2321d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
23372246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
23472246da4SFelipe Balbi  */
23541ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
23672246da4SFelipe Balbi {
2379f622b2aSFelipe Balbi 	int			num;
23872246da4SFelipe Balbi 	int			i;
23972246da4SFelipe Balbi 
2409f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
2419f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
2429f622b2aSFelipe Balbi 
243380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
244380f0d28SFelipe Balbi 			GFP_KERNEL);
245734d5a53SJingoo Han 	if (!dwc->ev_buffs)
246457d3f21SFelipe Balbi 		return -ENOMEM;
247457d3f21SFelipe Balbi 
24872246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
24972246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
25072246da4SFelipe Balbi 
25172246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
25272246da4SFelipe Balbi 		if (IS_ERR(evt)) {
25372246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
25472246da4SFelipe Balbi 			return PTR_ERR(evt);
25572246da4SFelipe Balbi 		}
25672246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
25772246da4SFelipe Balbi 	}
25872246da4SFelipe Balbi 
25972246da4SFelipe Balbi 	return 0;
26072246da4SFelipe Balbi }
26172246da4SFelipe Balbi 
26272246da4SFelipe Balbi /**
26372246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
2641d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
26572246da4SFelipe Balbi  *
26672246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
26772246da4SFelipe Balbi  */
2687acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
26972246da4SFelipe Balbi {
27072246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
27172246da4SFelipe Balbi 	int				n;
27272246da4SFelipe Balbi 
2739f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
27472246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2751407bf13SFelipe Balbi 		dwc3_trace(trace_dwc3_core,
2761407bf13SFelipe Balbi 				"Event buf %p dma %08llx length %d\n",
27772246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
27872246da4SFelipe Balbi 				evt->length);
27972246da4SFelipe Balbi 
2807acd85e0SPaul Zimmerman 		evt->lpos = 0;
2817acd85e0SPaul Zimmerman 
28272246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
28372246da4SFelipe Balbi 				lower_32_bits(evt->dma));
28472246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
28572246da4SFelipe Balbi 				upper_32_bits(evt->dma));
28672246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
28768d6a01bSFelipe Balbi 				DWC3_GEVNTSIZ_SIZE(evt->length));
28872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
28972246da4SFelipe Balbi 	}
29072246da4SFelipe Balbi 
29172246da4SFelipe Balbi 	return 0;
29272246da4SFelipe Balbi }
29372246da4SFelipe Balbi 
29472246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
29572246da4SFelipe Balbi {
29672246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
29772246da4SFelipe Balbi 	int				n;
29872246da4SFelipe Balbi 
2999f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
30072246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
3017acd85e0SPaul Zimmerman 
3027acd85e0SPaul Zimmerman 		evt->lpos = 0;
3037acd85e0SPaul Zimmerman 
30472246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
30572246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
30668d6a01bSFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
30768d6a01bSFelipe Balbi 				| DWC3_GEVNTSIZ_SIZE(0));
30872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
30972246da4SFelipe Balbi 	}
31072246da4SFelipe Balbi }
31172246da4SFelipe Balbi 
3120ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
3130ffcaf37SFelipe Balbi {
3140ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3150ffcaf37SFelipe Balbi 		return 0;
3160ffcaf37SFelipe Balbi 
3170ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3180ffcaf37SFelipe Balbi 		return 0;
3190ffcaf37SFelipe Balbi 
3200ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
3210ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
3220ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
3230ffcaf37SFelipe Balbi 		return -ENOMEM;
3240ffcaf37SFelipe Balbi 
3250ffcaf37SFelipe Balbi 	return 0;
3260ffcaf37SFelipe Balbi }
3270ffcaf37SFelipe Balbi 
3280ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
3290ffcaf37SFelipe Balbi {
3300ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
3310ffcaf37SFelipe Balbi 	u32 param;
3320ffcaf37SFelipe Balbi 	int ret;
3330ffcaf37SFelipe Balbi 
3340ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3350ffcaf37SFelipe Balbi 		return 0;
3360ffcaf37SFelipe Balbi 
3370ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3380ffcaf37SFelipe Balbi 		return 0;
3390ffcaf37SFelipe Balbi 
3400ffcaf37SFelipe Balbi 	 /* should never fall here */
3410ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3420ffcaf37SFelipe Balbi 		return 0;
3430ffcaf37SFelipe Balbi 
3440ffcaf37SFelipe Balbi 	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
3450ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
3460ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
3470ffcaf37SFelipe Balbi 	if (dma_mapping_error(dwc->dev, scratch_addr)) {
3480ffcaf37SFelipe Balbi 		dev_err(dwc->dev, "failed to map scratch buffer\n");
3490ffcaf37SFelipe Balbi 		ret = -EFAULT;
3500ffcaf37SFelipe Balbi 		goto err0;
3510ffcaf37SFelipe Balbi 	}
3520ffcaf37SFelipe Balbi 
3530ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
3540ffcaf37SFelipe Balbi 
3550ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
3560ffcaf37SFelipe Balbi 
3570ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3580ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
3590ffcaf37SFelipe Balbi 	if (ret < 0)
3600ffcaf37SFelipe Balbi 		goto err1;
3610ffcaf37SFelipe Balbi 
3620ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
3630ffcaf37SFelipe Balbi 
3640ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3650ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
3660ffcaf37SFelipe Balbi 	if (ret < 0)
3670ffcaf37SFelipe Balbi 		goto err1;
3680ffcaf37SFelipe Balbi 
3690ffcaf37SFelipe Balbi 	return 0;
3700ffcaf37SFelipe Balbi 
3710ffcaf37SFelipe Balbi err1:
3720ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3730ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3740ffcaf37SFelipe Balbi 
3750ffcaf37SFelipe Balbi err0:
3760ffcaf37SFelipe Balbi 	return ret;
3770ffcaf37SFelipe Balbi }
3780ffcaf37SFelipe Balbi 
3790ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
3800ffcaf37SFelipe Balbi {
3810ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3820ffcaf37SFelipe Balbi 		return;
3830ffcaf37SFelipe Balbi 
3840ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3850ffcaf37SFelipe Balbi 		return;
3860ffcaf37SFelipe Balbi 
3870ffcaf37SFelipe Balbi 	 /* should never fall here */
3880ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3890ffcaf37SFelipe Balbi 		return;
3900ffcaf37SFelipe Balbi 
3910ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3920ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3930ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
3940ffcaf37SFelipe Balbi }
3950ffcaf37SFelipe Balbi 
396789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
397789451f6SFelipe Balbi {
398789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
399789451f6SFelipe Balbi 
400789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
401789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
402789451f6SFelipe Balbi 
40373815280SFelipe Balbi 	dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
404789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
405789451f6SFelipe Balbi }
406789451f6SFelipe Balbi 
40741ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
40826ceca97SFelipe Balbi {
40926ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
41026ceca97SFelipe Balbi 
41126ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
41226ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
41326ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
41426ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
41526ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
41626ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
41726ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
41826ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
41926ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
42026ceca97SFelipe Balbi }
42126ceca97SFelipe Balbi 
42272246da4SFelipe Balbi /**
423b5a65c40SHuang Rui  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
424b5a65c40SHuang Rui  * @dwc: Pointer to our controller context structure
42588bc9d19SHeikki Krogerus  *
42688bc9d19SHeikki Krogerus  * Returns 0 on success. The USB PHY interfaces are configured but not
42788bc9d19SHeikki Krogerus  * initialized. The PHY interfaces and the PHYs get initialized together with
42888bc9d19SHeikki Krogerus  * the core in dwc3_core_init.
429b5a65c40SHuang Rui  */
43088bc9d19SHeikki Krogerus static int dwc3_phy_setup(struct dwc3 *dwc)
431b5a65c40SHuang Rui {
432b5a65c40SHuang Rui 	u32 reg;
43388bc9d19SHeikki Krogerus 	int ret;
434b5a65c40SHuang Rui 
435b5a65c40SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
436b5a65c40SHuang Rui 
4372164a476SHuang Rui 	/*
4382164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
4392164a476SHuang Rui 	 * to '0' during coreConsultant configuration. So default value
4402164a476SHuang Rui 	 * will be '0' when the core is reset. Application needs to set it
4412164a476SHuang Rui 	 * to '1' after the core initialization is completed.
4422164a476SHuang Rui 	 */
4432164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
4442164a476SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
4452164a476SHuang Rui 
446b5a65c40SHuang Rui 	if (dwc->u2ss_inp3_quirk)
447b5a65c40SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
448b5a65c40SHuang Rui 
449df31f5b3SHuang Rui 	if (dwc->req_p1p2p3_quirk)
450df31f5b3SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
451df31f5b3SHuang Rui 
452a2a1d0f5SHuang Rui 	if (dwc->del_p1p2p3_quirk)
453a2a1d0f5SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
454a2a1d0f5SHuang Rui 
45541c06ffdSHuang Rui 	if (dwc->del_phy_power_chg_quirk)
45641c06ffdSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
45741c06ffdSHuang Rui 
458fb67afcaSHuang Rui 	if (dwc->lfps_filter_quirk)
459fb67afcaSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
460fb67afcaSHuang Rui 
46114f4ac53SHuang Rui 	if (dwc->rx_detect_poll_quirk)
46214f4ac53SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
46314f4ac53SHuang Rui 
4646b6a0c9aSHuang Rui 	if (dwc->tx_de_emphasis_quirk)
4656b6a0c9aSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
4666b6a0c9aSHuang Rui 
467cd72f890SFelipe Balbi 	if (dwc->dis_u3_susphy_quirk)
46859acfa20SHuang Rui 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
46959acfa20SHuang Rui 
470b5a65c40SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
471b5a65c40SHuang Rui 
4722164a476SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
4732164a476SHuang Rui 
4743e10a2ceSHeikki Krogerus 	/* Select the HS PHY interface */
4753e10a2ceSHeikki Krogerus 	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
4763e10a2ceSHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
47743cacb03SFelipe Balbi 		if (dwc->hsphy_interface &&
47843cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
4793e10a2ceSHeikki Krogerus 			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
48088bc9d19SHeikki Krogerus 			break;
48143cacb03SFelipe Balbi 		} else if (dwc->hsphy_interface &&
48243cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
4833e10a2ceSHeikki Krogerus 			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
48488bc9d19SHeikki Krogerus 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
4853e10a2ceSHeikki Krogerus 		} else {
48688bc9d19SHeikki Krogerus 			/* Relying on default value. */
48788bc9d19SHeikki Krogerus 			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
4883e10a2ceSHeikki Krogerus 				break;
4893e10a2ceSHeikki Krogerus 		}
4903e10a2ceSHeikki Krogerus 		/* FALLTHROUGH */
49188bc9d19SHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
49288bc9d19SHeikki Krogerus 		/* Making sure the interface and PHY are operational */
49388bc9d19SHeikki Krogerus 		ret = dwc3_soft_reset(dwc);
49488bc9d19SHeikki Krogerus 		if (ret)
49588bc9d19SHeikki Krogerus 			return ret;
49688bc9d19SHeikki Krogerus 
49788bc9d19SHeikki Krogerus 		udelay(1);
49888bc9d19SHeikki Krogerus 
49988bc9d19SHeikki Krogerus 		ret = dwc3_ulpi_init(dwc);
50088bc9d19SHeikki Krogerus 		if (ret)
50188bc9d19SHeikki Krogerus 			return ret;
50288bc9d19SHeikki Krogerus 		/* FALLTHROUGH */
5033e10a2ceSHeikki Krogerus 	default:
5043e10a2ceSHeikki Krogerus 		break;
5053e10a2ceSHeikki Krogerus 	}
5063e10a2ceSHeikki Krogerus 
5072164a476SHuang Rui 	/*
5082164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
5092164a476SHuang Rui 	 * '0' during coreConsultant configuration. So default value will
5102164a476SHuang Rui 	 * be '0' when the core is reset. Application needs to set it to
5112164a476SHuang Rui 	 * '1' after the core initialization is completed.
5122164a476SHuang Rui 	 */
5132164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
5142164a476SHuang Rui 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
5152164a476SHuang Rui 
516cd72f890SFelipe Balbi 	if (dwc->dis_u2_susphy_quirk)
5170effe0a3SHuang Rui 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
5180effe0a3SHuang Rui 
519ec791d14SJohn Youn 	if (dwc->dis_enblslpm_quirk)
520ec791d14SJohn Youn 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
521ec791d14SJohn Youn 
5222164a476SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
52388bc9d19SHeikki Krogerus 
52488bc9d19SHeikki Krogerus 	return 0;
525b5a65c40SHuang Rui }
526b5a65c40SHuang Rui 
527b5a65c40SHuang Rui /**
52872246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
52972246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
53072246da4SFelipe Balbi  *
53172246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
53272246da4SFelipe Balbi  */
53341ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
53472246da4SFelipe Balbi {
5350ffcaf37SFelipe Balbi 	u32			hwparams4 = dwc->hwparams.hwparams4;
53672246da4SFelipe Balbi 	u32			reg;
53772246da4SFelipe Balbi 	int			ret;
53872246da4SFelipe Balbi 
5397650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
5407650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
541690fb371SJohn Youn 	if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
542690fb371SJohn Youn 		/* Detected DWC_usb3 IP */
543690fb371SJohn Youn 		dwc->revision = reg;
544690fb371SJohn Youn 	} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
545690fb371SJohn Youn 		/* Detected DWC_usb31 IP */
546690fb371SJohn Youn 		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
547690fb371SJohn Youn 		dwc->revision |= DWC3_REVISION_IS_DWC31;
548690fb371SJohn Youn 	} else {
5497650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
5507650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
5517650bd74SSebastian Andrzej Siewior 		goto err0;
5527650bd74SSebastian Andrzej Siewior 	}
5537650bd74SSebastian Andrzej Siewior 
554fa0ea13eSFelipe Balbi 	/*
555fa0ea13eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
556fa0ea13eSFelipe Balbi 	 * out which kernel version a bug was found.
557fa0ea13eSFelipe Balbi 	 */
558fa0ea13eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
559fa0ea13eSFelipe Balbi 
5600e1e5c47SPaul Zimmerman 	/* Handle USB2.0-only core configuration */
5610e1e5c47SPaul Zimmerman 	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
5620e1e5c47SPaul Zimmerman 			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
5630e1e5c47SPaul Zimmerman 		if (dwc->maximum_speed == USB_SPEED_SUPER)
5640e1e5c47SPaul Zimmerman 			dwc->maximum_speed = USB_SPEED_HIGH;
5650e1e5c47SPaul Zimmerman 	}
5660e1e5c47SPaul Zimmerman 
56772246da4SFelipe Balbi 	/* issue device SoftReset too */
568c5cc74e8SHeikki Krogerus 	ret = dwc3_soft_reset(dwc);
569c5cc74e8SHeikki Krogerus 	if (ret)
57072246da4SFelipe Balbi 		goto err0;
57172246da4SFelipe Balbi 
57257303488SKishon Vijay Abraham I 	ret = dwc3_core_soft_reset(dwc);
57357303488SKishon Vijay Abraham I 	if (ret)
57457303488SKishon Vijay Abraham I 		goto err0;
57558a0f23fSPratyush Anand 
5764878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
5773e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
5784878a028SSebastian Andrzej Siewior 
579164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
5804878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
58132a4a135SFelipe Balbi 		/**
58232a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
58332a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
58432a4a135SFelipe Balbi 		 *
58532a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
58632a4a135SFelipe Balbi 		 * configurations.
58732a4a135SFelipe Balbi 		 *
58832a4a135SFelipe Balbi 		 * Refers to:
58932a4a135SFelipe Balbi 		 *
59032a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
59132a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
59232a4a135SFelipe Balbi 		 */
59332a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
59432a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
59532a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
59632a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
59732a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
59832a4a135SFelipe Balbi 		else
5994878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
6004878a028SSebastian Andrzej Siewior 		break;
6010ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
6020ffcaf37SFelipe Balbi 		/* enable hibernation here */
6030ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
6042eac3992SHuang Rui 
6052eac3992SHuang Rui 		/*
6062eac3992SHuang Rui 		 * REVISIT Enabling this bit so that host-mode hibernation
6072eac3992SHuang Rui 		 * will work. Device-mode hibernation is not yet implemented.
6082eac3992SHuang Rui 		 */
6092eac3992SHuang Rui 		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
6100ffcaf37SFelipe Balbi 		break;
6114878a028SSebastian Andrzej Siewior 	default:
6121407bf13SFelipe Balbi 		dwc3_trace(trace_dwc3_core, "No power optimization available\n");
6134878a028SSebastian Andrzej Siewior 	}
6144878a028SSebastian Andrzej Siewior 
615946bd579SHuang Rui 	/* check if current dwc3 is on simulation board */
616946bd579SHuang Rui 	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
6171407bf13SFelipe Balbi 		dwc3_trace(trace_dwc3_core,
6181407bf13SFelipe Balbi 				"running on FPGA platform\n");
619946bd579SHuang Rui 		dwc->is_fpga = true;
620946bd579SHuang Rui 	}
621946bd579SHuang Rui 
6223b81221aSHuang Rui 	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
6233b81221aSHuang Rui 			"disable_scramble cannot be used on non-FPGA builds\n");
6243b81221aSHuang Rui 
6253b81221aSHuang Rui 	if (dwc->disable_scramble_quirk && dwc->is_fpga)
6263b81221aSHuang Rui 		reg |= DWC3_GCTL_DISSCRAMBLE;
6273b81221aSHuang Rui 	else
6283b81221aSHuang Rui 		reg &= ~DWC3_GCTL_DISSCRAMBLE;
6293b81221aSHuang Rui 
6309a5b2f31SHuang Rui 	if (dwc->u2exit_lfps_quirk)
6319a5b2f31SHuang Rui 		reg |= DWC3_GCTL_U2EXIT_LFPS;
6329a5b2f31SHuang Rui 
6334878a028SSebastian Andrzej Siewior 	/*
6344878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
6351d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
6364878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
6371d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
6384878a028SSebastian Andrzej Siewior 	 */
6394878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
6404878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
6414878a028SSebastian Andrzej Siewior 
642789451f6SFelipe Balbi 	dwc3_core_num_eps(dwc);
643789451f6SFelipe Balbi 
6444878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
6454878a028SSebastian Andrzej Siewior 
6460ffcaf37SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
6470ffcaf37SFelipe Balbi 	if (ret)
6480ffcaf37SFelipe Balbi 		goto err1;
6490ffcaf37SFelipe Balbi 
6500ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
6510ffcaf37SFelipe Balbi 	if (ret)
6520ffcaf37SFelipe Balbi 		goto err2;
6530ffcaf37SFelipe Balbi 
65472246da4SFelipe Balbi 	return 0;
65572246da4SFelipe Balbi 
6560ffcaf37SFelipe Balbi err2:
6570ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
6580ffcaf37SFelipe Balbi 
6590ffcaf37SFelipe Balbi err1:
6600ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
6610ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
66257303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
66357303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
6640ffcaf37SFelipe Balbi 
66572246da4SFelipe Balbi err0:
66672246da4SFelipe Balbi 	return ret;
66772246da4SFelipe Balbi }
66872246da4SFelipe Balbi 
66972246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
67072246da4SFelipe Balbi {
6710ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
67201b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
67301b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
67457303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
67557303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
67672246da4SFelipe Balbi }
67772246da4SFelipe Balbi 
6783c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
67972246da4SFelipe Balbi {
6803c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
681941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
6823c9f94acSFelipe Balbi 	int ret;
68372246da4SFelipe Balbi 
6845088b6f5SKishon Vijay Abraham I 	if (node) {
6855088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
6865088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
687bb674907SFelipe Balbi 	} else {
688bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
689bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
6905088b6f5SKishon Vijay Abraham I 	}
6915088b6f5SKishon Vijay Abraham I 
692d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
693d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
694122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
695122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
696122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
697d105e7f8SFelipe Balbi 			return ret;
698122f06e6SKishon Vijay Abraham I 		} else {
69951e1e7bcSFelipe Balbi 			dev_err(dev, "no usb2 phy configured\n");
700122f06e6SKishon Vijay Abraham I 			return ret;
701122f06e6SKishon Vijay Abraham I 		}
70251e1e7bcSFelipe Balbi 	}
70351e1e7bcSFelipe Balbi 
704d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
705315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
706122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
707122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
708122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
709d105e7f8SFelipe Balbi 			return ret;
710122f06e6SKishon Vijay Abraham I 		} else {
71151e1e7bcSFelipe Balbi 			dev_err(dev, "no usb3 phy configured\n");
712122f06e6SKishon Vijay Abraham I 			return ret;
713122f06e6SKishon Vijay Abraham I 		}
71451e1e7bcSFelipe Balbi 	}
71551e1e7bcSFelipe Balbi 
71657303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
71757303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
71857303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
71957303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
72057303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
72157303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
72257303488SKishon Vijay Abraham I 			return ret;
72357303488SKishon Vijay Abraham I 		} else {
72457303488SKishon Vijay Abraham I 			dev_err(dev, "no usb2 phy configured\n");
72557303488SKishon Vijay Abraham I 			return ret;
72657303488SKishon Vijay Abraham I 		}
72757303488SKishon Vijay Abraham I 	}
72857303488SKishon Vijay Abraham I 
72957303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
73057303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
73157303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
73257303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
73357303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
73457303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
73557303488SKishon Vijay Abraham I 			return ret;
73657303488SKishon Vijay Abraham I 		} else {
73757303488SKishon Vijay Abraham I 			dev_err(dev, "no usb3 phy configured\n");
73857303488SKishon Vijay Abraham I 			return ret;
73957303488SKishon Vijay Abraham I 		}
74057303488SKishon Vijay Abraham I 	}
74157303488SKishon Vijay Abraham I 
7423c9f94acSFelipe Balbi 	return 0;
7433c9f94acSFelipe Balbi }
7443c9f94acSFelipe Balbi 
7455f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
7465f94adfeSFelipe Balbi {
7475f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
7485f94adfeSFelipe Balbi 	int ret;
7495f94adfeSFelipe Balbi 
7505f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
7515f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
7525f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
7535f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
7545f94adfeSFelipe Balbi 		if (ret) {
7555f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
7565f94adfeSFelipe Balbi 			return ret;
7575f94adfeSFelipe Balbi 		}
7585f94adfeSFelipe Balbi 		break;
7595f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
7605f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
7615f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
7625f94adfeSFelipe Balbi 		if (ret) {
7635f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
7645f94adfeSFelipe Balbi 			return ret;
7655f94adfeSFelipe Balbi 		}
7665f94adfeSFelipe Balbi 		break;
7675f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
7685f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
7695f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
7705f94adfeSFelipe Balbi 		if (ret) {
7715f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
7725f94adfeSFelipe Balbi 			return ret;
7735f94adfeSFelipe Balbi 		}
7745f94adfeSFelipe Balbi 
7755f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
7765f94adfeSFelipe Balbi 		if (ret) {
7775f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
7785f94adfeSFelipe Balbi 			return ret;
7795f94adfeSFelipe Balbi 		}
7805f94adfeSFelipe Balbi 		break;
7815f94adfeSFelipe Balbi 	default:
7825f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
7835f94adfeSFelipe Balbi 		return -EINVAL;
7845f94adfeSFelipe Balbi 	}
7855f94adfeSFelipe Balbi 
7865f94adfeSFelipe Balbi 	return 0;
7875f94adfeSFelipe Balbi }
7885f94adfeSFelipe Balbi 
7895f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
7905f94adfeSFelipe Balbi {
7915f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
7925f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
7935f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
7945f94adfeSFelipe Balbi 		break;
7955f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
7965f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
7975f94adfeSFelipe Balbi 		break;
7985f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
7995f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
8005f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
8015f94adfeSFelipe Balbi 		break;
8025f94adfeSFelipe Balbi 	default:
8035f94adfeSFelipe Balbi 		/* do nothing */
8045f94adfeSFelipe Balbi 		break;
8055f94adfeSFelipe Balbi 	}
8065f94adfeSFelipe Balbi }
8075f94adfeSFelipe Balbi 
8083c9f94acSFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
8093c9f94acSFelipe Balbi 
8103c9f94acSFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
8113c9f94acSFelipe Balbi {
8123c9f94acSFelipe Balbi 	struct device		*dev = &pdev->dev;
8133c9f94acSFelipe Balbi 	struct dwc3_platform_data *pdata = dev_get_platdata(dev);
8143c9f94acSFelipe Balbi 	struct resource		*res;
8153c9f94acSFelipe Balbi 	struct dwc3		*dwc;
81680caf7d2SHuang Rui 	u8			lpm_nyet_threshold;
8176b6a0c9aSHuang Rui 	u8			tx_de_emphasis;
818460d098cSHuang Rui 	u8			hird_threshold;
819db2be4e9SNikhil Badola 	u32			fladj = 0;
8203c9f94acSFelipe Balbi 
821b09e99eeSAndy Shevchenko 	int			ret;
8223c9f94acSFelipe Balbi 
8233c9f94acSFelipe Balbi 	void __iomem		*regs;
8243c9f94acSFelipe Balbi 	void			*mem;
8253c9f94acSFelipe Balbi 
8263c9f94acSFelipe Balbi 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
827734d5a53SJingoo Han 	if (!mem)
8283c9f94acSFelipe Balbi 		return -ENOMEM;
829734d5a53SJingoo Han 
8303c9f94acSFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
8313c9f94acSFelipe Balbi 	dwc->mem = mem;
8323c9f94acSFelipe Balbi 	dwc->dev = dev;
8333c9f94acSFelipe Balbi 
8343c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
8353c9f94acSFelipe Balbi 	if (!res) {
8363c9f94acSFelipe Balbi 		dev_err(dev, "missing IRQ\n");
8373c9f94acSFelipe Balbi 		return -ENODEV;
8383c9f94acSFelipe Balbi 	}
8393c9f94acSFelipe Balbi 	dwc->xhci_resources[1].start = res->start;
8403c9f94acSFelipe Balbi 	dwc->xhci_resources[1].end = res->end;
8413c9f94acSFelipe Balbi 	dwc->xhci_resources[1].flags = res->flags;
8423c9f94acSFelipe Balbi 	dwc->xhci_resources[1].name = res->name;
8433c9f94acSFelipe Balbi 
8443c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8453c9f94acSFelipe Balbi 	if (!res) {
8463c9f94acSFelipe Balbi 		dev_err(dev, "missing memory resource\n");
8473c9f94acSFelipe Balbi 		return -ENODEV;
8483c9f94acSFelipe Balbi 	}
8493c9f94acSFelipe Balbi 
850f32a5e23SVivek Gautam 	dwc->xhci_resources[0].start = res->start;
851f32a5e23SVivek Gautam 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
852f32a5e23SVivek Gautam 					DWC3_XHCI_REGS_END;
853f32a5e23SVivek Gautam 	dwc->xhci_resources[0].flags = res->flags;
854f32a5e23SVivek Gautam 	dwc->xhci_resources[0].name = res->name;
855f32a5e23SVivek Gautam 
856f32a5e23SVivek Gautam 	res->start += DWC3_GLOBALS_REGS_START;
857f32a5e23SVivek Gautam 
858f32a5e23SVivek Gautam 	/*
859f32a5e23SVivek Gautam 	 * Request memory region but exclude xHCI regs,
860f32a5e23SVivek Gautam 	 * since it will be requested by the xhci-plat driver.
861f32a5e23SVivek Gautam 	 */
862f32a5e23SVivek Gautam 	regs = devm_ioremap_resource(dev, res);
8633da1f6eeSFelipe Balbi 	if (IS_ERR(regs)) {
8643da1f6eeSFelipe Balbi 		ret = PTR_ERR(regs);
8653da1f6eeSFelipe Balbi 		goto err0;
8663da1f6eeSFelipe Balbi 	}
867f32a5e23SVivek Gautam 
868f32a5e23SVivek Gautam 	dwc->regs	= regs;
869f32a5e23SVivek Gautam 	dwc->regs_size	= resource_size(res);
870f32a5e23SVivek Gautam 
87180caf7d2SHuang Rui 	/* default to highest possible threshold */
87280caf7d2SHuang Rui 	lpm_nyet_threshold = 0xff;
87380caf7d2SHuang Rui 
8746b6a0c9aSHuang Rui 	/* default to -3.5dB de-emphasis */
8756b6a0c9aSHuang Rui 	tx_de_emphasis = 1;
8766b6a0c9aSHuang Rui 
877460d098cSHuang Rui 	/*
878460d098cSHuang Rui 	 * default to assert utmi_sleep_n and use maximum allowed HIRD
879460d098cSHuang Rui 	 * threshold value of 0b1100
880460d098cSHuang Rui 	 */
881460d098cSHuang Rui 	hird_threshold = 12;
882460d098cSHuang Rui 
88363863b98SHeikki Krogerus 	dwc->maximum_speed = usb_get_maximum_speed(dev);
88406e7114fSHeikki Krogerus 	dwc->dr_mode = usb_get_dr_mode(dev);
88563863b98SHeikki Krogerus 
8863d128919SHeikki Krogerus 	dwc->has_lpm_erratum = device_property_read_bool(dev,
88780caf7d2SHuang Rui 				"snps,has-lpm-erratum");
8883d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,lpm-nyet-threshold",
88980caf7d2SHuang Rui 				&lpm_nyet_threshold);
8903d128919SHeikki Krogerus 	dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
891460d098cSHuang Rui 				"snps,is-utmi-l1-suspend");
8923d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,hird-threshold",
893460d098cSHuang Rui 				&hird_threshold);
8943d128919SHeikki Krogerus 	dwc->usb3_lpm_capable = device_property_read_bool(dev,
895eac68e8fSRobert Baldyga 				"snps,usb3_lpm_capable");
8963c9f94acSFelipe Balbi 
8973d128919SHeikki Krogerus 	dwc->needs_fifo_resize = device_property_read_bool(dev,
89880caf7d2SHuang Rui 				"tx-fifo-resize");
8993b81221aSHuang Rui 
9003d128919SHeikki Krogerus 	dwc->disable_scramble_quirk = device_property_read_bool(dev,
9013b81221aSHuang Rui 				"snps,disable_scramble_quirk");
9023d128919SHeikki Krogerus 	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
9039a5b2f31SHuang Rui 				"snps,u2exit_lfps_quirk");
9043d128919SHeikki Krogerus 	dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
905b5a65c40SHuang Rui 				"snps,u2ss_inp3_quirk");
9063d128919SHeikki Krogerus 	dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
907df31f5b3SHuang Rui 				"snps,req_p1p2p3_quirk");
9083d128919SHeikki Krogerus 	dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
909a2a1d0f5SHuang Rui 				"snps,del_p1p2p3_quirk");
9103d128919SHeikki Krogerus 	dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
91141c06ffdSHuang Rui 				"snps,del_phy_power_chg_quirk");
9123d128919SHeikki Krogerus 	dwc->lfps_filter_quirk = device_property_read_bool(dev,
913fb67afcaSHuang Rui 				"snps,lfps_filter_quirk");
9143d128919SHeikki Krogerus 	dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
91514f4ac53SHuang Rui 				"snps,rx_detect_poll_quirk");
9163d128919SHeikki Krogerus 	dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
91759acfa20SHuang Rui 				"snps,dis_u3_susphy_quirk");
9183d128919SHeikki Krogerus 	dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
9190effe0a3SHuang Rui 				"snps,dis_u2_susphy_quirk");
920ec791d14SJohn Youn 	dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
921ec791d14SJohn Youn 				"snps,dis_enblslpm_quirk");
9226b6a0c9aSHuang Rui 
9233d128919SHeikki Krogerus 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
9246b6a0c9aSHuang Rui 				"snps,tx_de_emphasis_quirk");
9253d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,tx_de_emphasis",
9266b6a0c9aSHuang Rui 				&tx_de_emphasis);
9273d128919SHeikki Krogerus 	device_property_read_string(dev, "snps,hsphy_interface",
9283e10a2ceSHeikki Krogerus 				    &dwc->hsphy_interface);
9293d128919SHeikki Krogerus 	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
930db2be4e9SNikhil Badola 				 &fladj);
9313d128919SHeikki Krogerus 
9323d128919SHeikki Krogerus 	if (pdata) {
9333c9f94acSFelipe Balbi 		dwc->maximum_speed = pdata->maximum_speed;
93480caf7d2SHuang Rui 		dwc->has_lpm_erratum = pdata->has_lpm_erratum;
93580caf7d2SHuang Rui 		if (pdata->lpm_nyet_threshold)
93680caf7d2SHuang Rui 			lpm_nyet_threshold = pdata->lpm_nyet_threshold;
937460d098cSHuang Rui 		dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
938460d098cSHuang Rui 		if (pdata->hird_threshold)
939460d098cSHuang Rui 			hird_threshold = pdata->hird_threshold;
9403c9f94acSFelipe Balbi 
9413c9f94acSFelipe Balbi 		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
942eac68e8fSRobert Baldyga 		dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
9433c9f94acSFelipe Balbi 		dwc->dr_mode = pdata->dr_mode;
9443b81221aSHuang Rui 
9453b81221aSHuang Rui 		dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
9469a5b2f31SHuang Rui 		dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
947b5a65c40SHuang Rui 		dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
948df31f5b3SHuang Rui 		dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
949a2a1d0f5SHuang Rui 		dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
95041c06ffdSHuang Rui 		dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
951fb67afcaSHuang Rui 		dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
95214f4ac53SHuang Rui 		dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
95359acfa20SHuang Rui 		dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
9540effe0a3SHuang Rui 		dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
955ec791d14SJohn Youn 		dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
9566b6a0c9aSHuang Rui 
9576b6a0c9aSHuang Rui 		dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
9586b6a0c9aSHuang Rui 		if (pdata->tx_de_emphasis)
9596b6a0c9aSHuang Rui 			tx_de_emphasis = pdata->tx_de_emphasis;
9603e10a2ceSHeikki Krogerus 
9613e10a2ceSHeikki Krogerus 		dwc->hsphy_interface = pdata->hsphy_interface;
962db2be4e9SNikhil Badola 		fladj = pdata->fladj_value;
9633c9f94acSFelipe Balbi 	}
9643c9f94acSFelipe Balbi 
96580caf7d2SHuang Rui 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
9666b6a0c9aSHuang Rui 	dwc->tx_de_emphasis = tx_de_emphasis;
96780caf7d2SHuang Rui 
968460d098cSHuang Rui 	dwc->hird_threshold = hird_threshold
969460d098cSHuang Rui 		| (dwc->is_utmi_l1_suspend << 4);
970460d098cSHuang Rui 
9716c89cce0SHeikki Krogerus 	platform_set_drvdata(pdev, dwc);
9722917e718SHeikki Krogerus 	dwc3_cache_hwparams(dwc);
9736c89cce0SHeikki Krogerus 
97488bc9d19SHeikki Krogerus 	ret = dwc3_phy_setup(dwc);
97588bc9d19SHeikki Krogerus 	if (ret)
97688bc9d19SHeikki Krogerus 		goto err0;
97745bb7de2SHeikki Krogerus 
9783c9f94acSFelipe Balbi 	ret = dwc3_core_get_phy(dwc);
9793c9f94acSFelipe Balbi 	if (ret)
9803da1f6eeSFelipe Balbi 		goto err0;
9813c9f94acSFelipe Balbi 
98272246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
98372246da4SFelipe Balbi 
98419bacdc9SHeikki Krogerus 	if (!dev->dma_mask) {
985ddff14f1SKishon Vijay Abraham I 		dev->dma_mask = dev->parent->dma_mask;
986ddff14f1SKishon Vijay Abraham I 		dev->dma_parms = dev->parent->dma_parms;
987ddff14f1SKishon Vijay Abraham I 		dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
98819bacdc9SHeikki Krogerus 	}
989ddff14f1SKishon Vijay Abraham I 
990802ca850SChanho Park 	pm_runtime_enable(dev);
991802ca850SChanho Park 	pm_runtime_get_sync(dev);
992802ca850SChanho Park 	pm_runtime_forbid(dev);
99372246da4SFelipe Balbi 
9943921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
9953921426bSFelipe Balbi 	if (ret) {
9963921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
9973921426bSFelipe Balbi 		ret = -ENOMEM;
9983da1f6eeSFelipe Balbi 		goto err1;
9993921426bSFelipe Balbi 	}
10003921426bSFelipe Balbi 
100132a4a135SFelipe Balbi 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
100232a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_HOST;
100332a4a135SFelipe Balbi 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
100432a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
100532a4a135SFelipe Balbi 
100632a4a135SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
100732a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_OTG;
100832a4a135SFelipe Balbi 
100972246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
101072246da4SFelipe Balbi 	if (ret) {
1011802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
10123da1f6eeSFelipe Balbi 		goto err1;
101372246da4SFelipe Balbi 	}
101472246da4SFelipe Balbi 
10152c7f1bd9SJohn Youn 	/* default to superspeed if no maximum_speed passed */
10162c7f1bd9SJohn Youn 	if (dwc->maximum_speed == USB_SPEED_UNKNOWN) {
10172c7f1bd9SJohn Youn 		dwc->maximum_speed = USB_SPEED_SUPER;
10182c7f1bd9SJohn Youn 
10192c7f1bd9SJohn Youn 		/*
10202c7f1bd9SJohn Youn 		 * default to superspeed plus if we are capable.
10212c7f1bd9SJohn Youn 		 */
10222c7f1bd9SJohn Youn 		if (dwc3_is_usb31(dwc) &&
10232c7f1bd9SJohn Youn 		    (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
10242c7f1bd9SJohn Youn 		     DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
10252c7f1bd9SJohn Youn 			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
10262c7f1bd9SJohn Youn 	}
10272c7f1bd9SJohn Youn 
1028db2be4e9SNikhil Badola 	/* Adjust Frame Length */
1029db2be4e9SNikhil Badola 	dwc3_frame_length_adjustment(dwc, fladj);
1030db2be4e9SNikhil Badola 
10313088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
10323088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
103357303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb2_generic_phy);
103457303488SKishon Vijay Abraham I 	if (ret < 0)
10353da1f6eeSFelipe Balbi 		goto err2;
103657303488SKishon Vijay Abraham I 
103757303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb3_generic_phy);
103857303488SKishon Vijay Abraham I 	if (ret < 0)
10393da1f6eeSFelipe Balbi 		goto err3;
10403088f108SKishon Vijay Abraham I 
1041f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
1042f122d33eSFelipe Balbi 	if (ret) {
1043f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
10443da1f6eeSFelipe Balbi 		goto err4;
1045f122d33eSFelipe Balbi 	}
1046f122d33eSFelipe Balbi 
10475f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
10485f94adfeSFelipe Balbi 	if (ret)
10493da1f6eeSFelipe Balbi 		goto err5;
105072246da4SFelipe Balbi 
105172246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
105272246da4SFelipe Balbi 	if (ret) {
1053802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
10543da1f6eeSFelipe Balbi 		goto err6;
105572246da4SFelipe Balbi 	}
105672246da4SFelipe Balbi 
1057802ca850SChanho Park 	pm_runtime_allow(dev);
105872246da4SFelipe Balbi 
105972246da4SFelipe Balbi 	return 0;
106072246da4SFelipe Balbi 
10613da1f6eeSFelipe Balbi err6:
10625f94adfeSFelipe Balbi 	dwc3_core_exit_mode(dwc);
106372246da4SFelipe Balbi 
10643da1f6eeSFelipe Balbi err5:
1065f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
1066f122d33eSFelipe Balbi 
10673da1f6eeSFelipe Balbi err4:
106857303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
106957303488SKishon Vijay Abraham I 
10703da1f6eeSFelipe Balbi err3:
107157303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
107257303488SKishon Vijay Abraham I 
10733da1f6eeSFelipe Balbi err2:
1074501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
1075501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
107672246da4SFelipe Balbi 	dwc3_core_exit(dwc);
107772246da4SFelipe Balbi 
10783da1f6eeSFelipe Balbi err1:
10793921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
108088bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
10813921426bSFelipe Balbi 
10823da1f6eeSFelipe Balbi err0:
10833da1f6eeSFelipe Balbi 	/*
10843da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
10853da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
10863da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
10873da1f6eeSFelipe Balbi 	 */
10883da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
10893da1f6eeSFelipe Balbi 
109072246da4SFelipe Balbi 	return ret;
109172246da4SFelipe Balbi }
109272246da4SFelipe Balbi 
1093fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
109472246da4SFelipe Balbi {
109572246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
10963da1f6eeSFelipe Balbi 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
10973da1f6eeSFelipe Balbi 
10983da1f6eeSFelipe Balbi 	/*
10993da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
11003da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
11013da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
11023da1f6eeSFelipe Balbi 	 */
11033da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
110472246da4SFelipe Balbi 
1105dc99f16fSFelipe Balbi 	dwc3_debugfs_exit(dwc);
1106dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
1107dc99f16fSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
1108dc99f16fSFelipe Balbi 	dwc3_free_event_buffers(dwc);
1109dc99f16fSFelipe Balbi 
11108ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
11118ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
111257303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
111357303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
11148ba007a9SKishon Vijay Abraham I 
111572246da4SFelipe Balbi 	dwc3_core_exit(dwc);
111688bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
111772246da4SFelipe Balbi 
11187415f17cSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
11197415f17cSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
11207415f17cSFelipe Balbi 
112172246da4SFelipe Balbi 	return 0;
112272246da4SFelipe Balbi }
112372246da4SFelipe Balbi 
11247415f17cSFelipe Balbi #ifdef CONFIG_PM_SLEEP
11257415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
11267415f17cSFelipe Balbi {
11277415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
11287415f17cSFelipe Balbi 	unsigned long	flags;
11297415f17cSFelipe Balbi 
11307415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
11317415f17cSFelipe Balbi 
1132a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
1133a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
1134a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
11357415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
11367415f17cSFelipe Balbi 		/* FALLTHROUGH */
1137a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
11387415f17cSFelipe Balbi 	default:
11390b0231aaSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
11407415f17cSFelipe Balbi 		break;
11417415f17cSFelipe Balbi 	}
11427415f17cSFelipe Balbi 
11437415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
11447415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
11457415f17cSFelipe Balbi 
11467415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
11477415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
114857303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
114957303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
11507415f17cSFelipe Balbi 
11516344475fSSekhar Nori 	pinctrl_pm_select_sleep_state(dev);
11526344475fSSekhar Nori 
11537415f17cSFelipe Balbi 	return 0;
11547415f17cSFelipe Balbi }
11557415f17cSFelipe Balbi 
11567415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
11577415f17cSFelipe Balbi {
11587415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
11597415f17cSFelipe Balbi 	unsigned long	flags;
116057303488SKishon Vijay Abraham I 	int		ret;
11617415f17cSFelipe Balbi 
11626344475fSSekhar Nori 	pinctrl_pm_select_default_state(dev);
11636344475fSSekhar Nori 
11647415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
11657415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
116657303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
116757303488SKishon Vijay Abraham I 	if (ret < 0)
116857303488SKishon Vijay Abraham I 		return ret;
116957303488SKishon Vijay Abraham I 
117057303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
117157303488SKishon Vijay Abraham I 	if (ret < 0)
117257303488SKishon Vijay Abraham I 		goto err_usb2phy_init;
11737415f17cSFelipe Balbi 
11747415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
11757415f17cSFelipe Balbi 
11760b0231aaSFelipe Balbi 	dwc3_event_buffers_setup(dwc);
11777415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
11787415f17cSFelipe Balbi 
1179a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
1180a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
1181a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
11827415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
11837415f17cSFelipe Balbi 		/* FALLTHROUGH */
1184a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
11857415f17cSFelipe Balbi 	default:
11867415f17cSFelipe Balbi 		/* do nothing */
11877415f17cSFelipe Balbi 		break;
11887415f17cSFelipe Balbi 	}
11897415f17cSFelipe Balbi 
11907415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
11917415f17cSFelipe Balbi 
11927415f17cSFelipe Balbi 	pm_runtime_disable(dev);
11937415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
11947415f17cSFelipe Balbi 	pm_runtime_enable(dev);
11957415f17cSFelipe Balbi 
11967415f17cSFelipe Balbi 	return 0;
119757303488SKishon Vijay Abraham I 
119857303488SKishon Vijay Abraham I err_usb2phy_init:
119957303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
120057303488SKishon Vijay Abraham I 
120157303488SKishon Vijay Abraham I 	return ret;
12027415f17cSFelipe Balbi }
12037415f17cSFelipe Balbi 
12047415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
12057415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
12067415f17cSFelipe Balbi };
12077415f17cSFelipe Balbi 
12087415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
12097415f17cSFelipe Balbi #else
12107415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
12117415f17cSFelipe Balbi #endif
12127415f17cSFelipe Balbi 
12135088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
12145088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
12155088b6f5SKishon Vijay Abraham I 	{
121622a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
121722a5aa17SFelipe Balbi 	},
121822a5aa17SFelipe Balbi 	{
12195088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
12205088b6f5SKishon Vijay Abraham I 	},
12215088b6f5SKishon Vijay Abraham I 	{ },
12225088b6f5SKishon Vijay Abraham I };
12235088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
12245088b6f5SKishon Vijay Abraham I #endif
12255088b6f5SKishon Vijay Abraham I 
1226404905a6SHeikki Krogerus #ifdef CONFIG_ACPI
1227404905a6SHeikki Krogerus 
1228404905a6SHeikki Krogerus #define ACPI_ID_INTEL_BSW	"808622B7"
1229404905a6SHeikki Krogerus 
1230404905a6SHeikki Krogerus static const struct acpi_device_id dwc3_acpi_match[] = {
1231404905a6SHeikki Krogerus 	{ ACPI_ID_INTEL_BSW, 0 },
1232404905a6SHeikki Krogerus 	{ },
1233404905a6SHeikki Krogerus };
1234404905a6SHeikki Krogerus MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
1235404905a6SHeikki Krogerus #endif
1236404905a6SHeikki Krogerus 
123772246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
123872246da4SFelipe Balbi 	.probe		= dwc3_probe,
12397690417dSBill Pemberton 	.remove		= dwc3_remove,
124072246da4SFelipe Balbi 	.driver		= {
124172246da4SFelipe Balbi 		.name	= "dwc3",
12425088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
1243404905a6SHeikki Krogerus 		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
12447415f17cSFelipe Balbi 		.pm	= DWC3_PM_OPS,
124572246da4SFelipe Balbi 	},
124672246da4SFelipe Balbi };
124772246da4SFelipe Balbi 
1248b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
1249b1116dccSTobias Klauser 
12507ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
125172246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
12525945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
125372246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
1254