xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision d8c80bb3)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
272246da4SFelipe Balbi /**
372246da4SFelipe Balbi  * core.c - DesignWare USB3 DRD Controller Core file
472246da4SFelipe Balbi  *
572246da4SFelipe Balbi  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
672246da4SFelipe Balbi  *
772246da4SFelipe Balbi  * Authors: Felipe Balbi <balbi@ti.com>,
872246da4SFelipe Balbi  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
972246da4SFelipe Balbi  */
1072246da4SFelipe Balbi 
11fa0ea13eSFelipe Balbi #include <linux/version.h>
12a72e658bSFelipe Balbi #include <linux/module.h>
1372246da4SFelipe Balbi #include <linux/kernel.h>
1472246da4SFelipe Balbi #include <linux/slab.h>
1572246da4SFelipe Balbi #include <linux/spinlock.h>
1672246da4SFelipe Balbi #include <linux/platform_device.h>
1772246da4SFelipe Balbi #include <linux/pm_runtime.h>
1872246da4SFelipe Balbi #include <linux/interrupt.h>
1972246da4SFelipe Balbi #include <linux/ioport.h>
2072246da4SFelipe Balbi #include <linux/io.h>
2172246da4SFelipe Balbi #include <linux/list.h>
2272246da4SFelipe Balbi #include <linux/delay.h>
2372246da4SFelipe Balbi #include <linux/dma-mapping.h>
24457e84b6SFelipe Balbi #include <linux/of.h>
25404905a6SHeikki Krogerus #include <linux/acpi.h>
266344475fSSekhar Nori #include <linux/pinctrl/consumer.h>
2772246da4SFelipe Balbi 
2872246da4SFelipe Balbi #include <linux/usb/ch9.h>
2972246da4SFelipe Balbi #include <linux/usb/gadget.h>
30f7e846f0SFelipe Balbi #include <linux/usb/of.h>
31a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
3272246da4SFelipe Balbi 
3372246da4SFelipe Balbi #include "core.h"
3472246da4SFelipe Balbi #include "gadget.h"
3572246da4SFelipe Balbi #include "io.h"
3672246da4SFelipe Balbi 
3772246da4SFelipe Balbi #include "debug.h"
3872246da4SFelipe Balbi 
39fc8bb91bSFelipe Balbi #define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */
408300dd23SFelipe Balbi 
419d6173e1SThinh Nguyen /**
429d6173e1SThinh Nguyen  * dwc3_get_dr_mode - Validates and sets dr_mode
439d6173e1SThinh Nguyen  * @dwc: pointer to our context structure
449d6173e1SThinh Nguyen  */
459d6173e1SThinh Nguyen static int dwc3_get_dr_mode(struct dwc3 *dwc)
469d6173e1SThinh Nguyen {
479d6173e1SThinh Nguyen 	enum usb_dr_mode mode;
489d6173e1SThinh Nguyen 	struct device *dev = dwc->dev;
499d6173e1SThinh Nguyen 	unsigned int hw_mode;
509d6173e1SThinh Nguyen 
519d6173e1SThinh Nguyen 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
529d6173e1SThinh Nguyen 		dwc->dr_mode = USB_DR_MODE_OTG;
539d6173e1SThinh Nguyen 
549d6173e1SThinh Nguyen 	mode = dwc->dr_mode;
559d6173e1SThinh Nguyen 	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
569d6173e1SThinh Nguyen 
579d6173e1SThinh Nguyen 	switch (hw_mode) {
589d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_GADGET:
599d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
609d6173e1SThinh Nguyen 			dev_err(dev,
619d6173e1SThinh Nguyen 				"Controller does not support host mode.\n");
629d6173e1SThinh Nguyen 			return -EINVAL;
639d6173e1SThinh Nguyen 		}
649d6173e1SThinh Nguyen 		mode = USB_DR_MODE_PERIPHERAL;
659d6173e1SThinh Nguyen 		break;
669d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_HOST:
679d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
689d6173e1SThinh Nguyen 			dev_err(dev,
699d6173e1SThinh Nguyen 				"Controller does not support device mode.\n");
709d6173e1SThinh Nguyen 			return -EINVAL;
719d6173e1SThinh Nguyen 		}
729d6173e1SThinh Nguyen 		mode = USB_DR_MODE_HOST;
739d6173e1SThinh Nguyen 		break;
749d6173e1SThinh Nguyen 	default:
759d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
769d6173e1SThinh Nguyen 			mode = USB_DR_MODE_HOST;
779d6173e1SThinh Nguyen 		else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
789d6173e1SThinh Nguyen 			mode = USB_DR_MODE_PERIPHERAL;
799d6173e1SThinh Nguyen 	}
809d6173e1SThinh Nguyen 
819d6173e1SThinh Nguyen 	if (mode != dwc->dr_mode) {
829d6173e1SThinh Nguyen 		dev_warn(dev,
839d6173e1SThinh Nguyen 			 "Configuration mismatch. dr_mode forced to %s\n",
849d6173e1SThinh Nguyen 			 mode == USB_DR_MODE_HOST ? "host" : "gadget");
859d6173e1SThinh Nguyen 
869d6173e1SThinh Nguyen 		dwc->dr_mode = mode;
879d6173e1SThinh Nguyen 	}
889d6173e1SThinh Nguyen 
899d6173e1SThinh Nguyen 	return 0;
909d6173e1SThinh Nguyen }
919d6173e1SThinh Nguyen 
9241ce1456SRoger Quadros static void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
9341ce1456SRoger Quadros static int dwc3_event_buffers_setup(struct dwc3 *dwc);
9441ce1456SRoger Quadros 
9541ce1456SRoger Quadros static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
963140e8cbSSebastian Andrzej Siewior {
973140e8cbSSebastian Andrzej Siewior 	u32 reg;
983140e8cbSSebastian Andrzej Siewior 
993140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
1003140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
1013140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
1023140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
10341ce1456SRoger Quadros }
1046b3261a2SRoger Quadros 
10541ce1456SRoger Quadros static void __dwc3_set_mode(struct work_struct *work)
10641ce1456SRoger Quadros {
10741ce1456SRoger Quadros 	struct dwc3 *dwc = work_to_dwc(work);
10841ce1456SRoger Quadros 	unsigned long flags;
10941ce1456SRoger Quadros 	int ret;
11041ce1456SRoger Quadros 
11141ce1456SRoger Quadros 	if (!dwc->desired_dr_role)
11241ce1456SRoger Quadros 		return;
11341ce1456SRoger Quadros 
11441ce1456SRoger Quadros 	if (dwc->desired_dr_role == dwc->current_dr_role)
11541ce1456SRoger Quadros 		return;
11641ce1456SRoger Quadros 
11741ce1456SRoger Quadros 	if (dwc->dr_mode != USB_DR_MODE_OTG)
11841ce1456SRoger Quadros 		return;
11941ce1456SRoger Quadros 
12041ce1456SRoger Quadros 	switch (dwc->current_dr_role) {
12141ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_HOST:
12241ce1456SRoger Quadros 		dwc3_host_exit(dwc);
12341ce1456SRoger Quadros 		break;
12441ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_DEVICE:
12541ce1456SRoger Quadros 		dwc3_gadget_exit(dwc);
12641ce1456SRoger Quadros 		dwc3_event_buffers_cleanup(dwc);
12741ce1456SRoger Quadros 		break;
12841ce1456SRoger Quadros 	default:
12941ce1456SRoger Quadros 		break;
13041ce1456SRoger Quadros 	}
13141ce1456SRoger Quadros 
13241ce1456SRoger Quadros 	spin_lock_irqsave(&dwc->lock, flags);
13341ce1456SRoger Quadros 
13441ce1456SRoger Quadros 	dwc3_set_prtcap(dwc, dwc->desired_dr_role);
13541ce1456SRoger Quadros 
13641ce1456SRoger Quadros 	dwc->current_dr_role = dwc->desired_dr_role;
13741ce1456SRoger Quadros 
13841ce1456SRoger Quadros 	spin_unlock_irqrestore(&dwc->lock, flags);
13941ce1456SRoger Quadros 
14041ce1456SRoger Quadros 	switch (dwc->desired_dr_role) {
14141ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_HOST:
14241ce1456SRoger Quadros 		ret = dwc3_host_init(dwc);
143958d1a4cSFelipe Balbi 		if (ret) {
14441ce1456SRoger Quadros 			dev_err(dwc->dev, "failed to initialize host\n");
145958d1a4cSFelipe Balbi 		} else {
146958d1a4cSFelipe Balbi 			if (dwc->usb2_phy)
147958d1a4cSFelipe Balbi 				otg_set_vbus(dwc->usb2_phy->otg, true);
148958d1a4cSFelipe Balbi 			phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
149644cbbc3SManu Gautam 			phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
150d8c80bb3SVivek Gautam 			phy_calibrate(dwc->usb2_generic_phy);
151958d1a4cSFelipe Balbi 		}
15241ce1456SRoger Quadros 		break;
15341ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_DEVICE:
15441ce1456SRoger Quadros 		dwc3_event_buffers_setup(dwc);
155958d1a4cSFelipe Balbi 
156958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
157958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, false);
158958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
159644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
160958d1a4cSFelipe Balbi 
16141ce1456SRoger Quadros 		ret = dwc3_gadget_init(dwc);
16241ce1456SRoger Quadros 		if (ret)
16341ce1456SRoger Quadros 			dev_err(dwc->dev, "failed to initialize peripheral\n");
16441ce1456SRoger Quadros 		break;
16541ce1456SRoger Quadros 	default:
16641ce1456SRoger Quadros 		break;
16741ce1456SRoger Quadros 	}
16841ce1456SRoger Quadros }
16941ce1456SRoger Quadros 
17041ce1456SRoger Quadros void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
17141ce1456SRoger Quadros {
17241ce1456SRoger Quadros 	unsigned long flags;
17341ce1456SRoger Quadros 
17441ce1456SRoger Quadros 	spin_lock_irqsave(&dwc->lock, flags);
17541ce1456SRoger Quadros 	dwc->desired_dr_role = mode;
17641ce1456SRoger Quadros 	spin_unlock_irqrestore(&dwc->lock, flags);
17741ce1456SRoger Quadros 
17841ce1456SRoger Quadros 	queue_work(system_power_efficient_wq, &dwc->drd_work);
1793140e8cbSSebastian Andrzej Siewior }
1808300dd23SFelipe Balbi 
181cf6d867dSFelipe Balbi u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
182cf6d867dSFelipe Balbi {
183cf6d867dSFelipe Balbi 	struct dwc3		*dwc = dep->dwc;
184cf6d867dSFelipe Balbi 	u32			reg;
185cf6d867dSFelipe Balbi 
186cf6d867dSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
187cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_NUM(dep->number) |
188cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_TYPE(type));
189cf6d867dSFelipe Balbi 
190cf6d867dSFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
191cf6d867dSFelipe Balbi 
192cf6d867dSFelipe Balbi 	return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
193cf6d867dSFelipe Balbi }
194cf6d867dSFelipe Balbi 
19572246da4SFelipe Balbi /**
19672246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
19772246da4SFelipe Balbi  * @dwc: pointer to our context structure
19872246da4SFelipe Balbi  */
19957303488SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc)
20072246da4SFelipe Balbi {
20172246da4SFelipe Balbi 	u32		reg;
202f59dcab1SFelipe Balbi 	int		retries = 1000;
20357303488SKishon Vijay Abraham I 	int		ret;
20472246da4SFelipe Balbi 
20551e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
20651e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
20757303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
20857303488SKishon Vijay Abraham I 	if (ret < 0)
20957303488SKishon Vijay Abraham I 		return ret;
21057303488SKishon Vijay Abraham I 
21157303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
21257303488SKishon Vijay Abraham I 	if (ret < 0) {
21357303488SKishon Vijay Abraham I 		phy_exit(dwc->usb2_generic_phy);
21457303488SKishon Vijay Abraham I 		return ret;
21557303488SKishon Vijay Abraham I 	}
21672246da4SFelipe Balbi 
217f59dcab1SFelipe Balbi 	/*
218f59dcab1SFelipe Balbi 	 * We're resetting only the device side because, if we're in host mode,
219f59dcab1SFelipe Balbi 	 * XHCI driver will reset the host block. If dwc3 was configured for
220f59dcab1SFelipe Balbi 	 * host-only mode, then we can return early.
221f59dcab1SFelipe Balbi 	 */
222f59dcab1SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_HOST)
22357303488SKishon Vijay Abraham I 		return 0;
224f59dcab1SFelipe Balbi 
225f59dcab1SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
226f59dcab1SFelipe Balbi 	reg |= DWC3_DCTL_CSFTRST;
227f59dcab1SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
228f59dcab1SFelipe Balbi 
229f59dcab1SFelipe Balbi 	do {
230f59dcab1SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
231f59dcab1SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
232f59dcab1SFelipe Balbi 			return 0;
233f59dcab1SFelipe Balbi 
234f59dcab1SFelipe Balbi 		udelay(1);
235f59dcab1SFelipe Balbi 	} while (--retries);
236f59dcab1SFelipe Balbi 
237f59dcab1SFelipe Balbi 	return -ETIMEDOUT;
23872246da4SFelipe Balbi }
23972246da4SFelipe Balbi 
240db2be4e9SNikhil Badola /*
241db2be4e9SNikhil Badola  * dwc3_frame_length_adjustment - Adjusts frame length if required
242db2be4e9SNikhil Badola  * @dwc3: Pointer to our controller context structure
243db2be4e9SNikhil Badola  */
244bcdb3272SFelipe Balbi static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
245db2be4e9SNikhil Badola {
246db2be4e9SNikhil Badola 	u32 reg;
247db2be4e9SNikhil Badola 	u32 dft;
248db2be4e9SNikhil Badola 
249db2be4e9SNikhil Badola 	if (dwc->revision < DWC3_REVISION_250A)
250db2be4e9SNikhil Badola 		return;
251db2be4e9SNikhil Badola 
252bcdb3272SFelipe Balbi 	if (dwc->fladj == 0)
253db2be4e9SNikhil Badola 		return;
254db2be4e9SNikhil Badola 
255db2be4e9SNikhil Badola 	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
256db2be4e9SNikhil Badola 	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
257bcdb3272SFelipe Balbi 	if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
258db2be4e9SNikhil Badola 	    "request value same as default, ignoring\n")) {
259db2be4e9SNikhil Badola 		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
260bcdb3272SFelipe Balbi 		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
261db2be4e9SNikhil Badola 		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
262db2be4e9SNikhil Badola 	}
263db2be4e9SNikhil Badola }
264db2be4e9SNikhil Badola 
265c5cc74e8SHeikki Krogerus /**
26672246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
26772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
26872246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
26972246da4SFelipe Balbi  */
27072246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
27172246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
27272246da4SFelipe Balbi {
273d64ff406SArnd Bergmann 	dma_free_coherent(dwc->sysdev, evt->length, evt->buf, evt->dma);
27472246da4SFelipe Balbi }
27572246da4SFelipe Balbi 
27672246da4SFelipe Balbi /**
2771d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
27872246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
27972246da4SFelipe Balbi  * @length: size of the event buffer
28072246da4SFelipe Balbi  *
2811d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
28272246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
28372246da4SFelipe Balbi  */
28467d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
28567d0b500SFelipe Balbi 		unsigned length)
28672246da4SFelipe Balbi {
28772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
28872246da4SFelipe Balbi 
289380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
29072246da4SFelipe Balbi 	if (!evt)
29172246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
29272246da4SFelipe Balbi 
29372246da4SFelipe Balbi 	evt->dwc	= dwc;
29472246da4SFelipe Balbi 	evt->length	= length;
295d9fa4c63SJohn Youn 	evt->cache	= devm_kzalloc(dwc->dev, length, GFP_KERNEL);
296d9fa4c63SJohn Youn 	if (!evt->cache)
297d9fa4c63SJohn Youn 		return ERR_PTR(-ENOMEM);
298d9fa4c63SJohn Youn 
299d64ff406SArnd Bergmann 	evt->buf	= dma_alloc_coherent(dwc->sysdev, length,
30072246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
301e32672f0SFelipe Balbi 	if (!evt->buf)
30272246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
30372246da4SFelipe Balbi 
30472246da4SFelipe Balbi 	return evt;
30572246da4SFelipe Balbi }
30672246da4SFelipe Balbi 
30772246da4SFelipe Balbi /**
30872246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
30972246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
31072246da4SFelipe Balbi  */
31172246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
31272246da4SFelipe Balbi {
31372246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
31472246da4SFelipe Balbi 
315696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
31664b6c8a7SAnton Tikhomirov 	if (evt)
31772246da4SFelipe Balbi 		dwc3_free_one_event_buffer(dwc, evt);
31872246da4SFelipe Balbi }
31972246da4SFelipe Balbi 
32072246da4SFelipe Balbi /**
32172246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
3221d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
32372246da4SFelipe Balbi  * @length: size of event buffer
32472246da4SFelipe Balbi  *
3251d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
32672246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
32772246da4SFelipe Balbi  */
32841ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
32972246da4SFelipe Balbi {
33072246da4SFelipe Balbi 	struct dwc3_event_buffer *evt;
33172246da4SFelipe Balbi 
33272246da4SFelipe Balbi 	evt = dwc3_alloc_one_event_buffer(dwc, length);
33372246da4SFelipe Balbi 	if (IS_ERR(evt)) {
33472246da4SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffer\n");
33572246da4SFelipe Balbi 		return PTR_ERR(evt);
33672246da4SFelipe Balbi 	}
337696c8b12SFelipe Balbi 	dwc->ev_buf = evt;
33872246da4SFelipe Balbi 
33972246da4SFelipe Balbi 	return 0;
34072246da4SFelipe Balbi }
34172246da4SFelipe Balbi 
34272246da4SFelipe Balbi /**
34372246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
3441d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
34572246da4SFelipe Balbi  *
34672246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
34772246da4SFelipe Balbi  */
3487acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
34972246da4SFelipe Balbi {
35072246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
35172246da4SFelipe Balbi 
352696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
3537acd85e0SPaul Zimmerman 	evt->lpos = 0;
354660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
35572246da4SFelipe Balbi 			lower_32_bits(evt->dma));
356660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
35772246da4SFelipe Balbi 			upper_32_bits(evt->dma));
358660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
35968d6a01bSFelipe Balbi 			DWC3_GEVNTSIZ_SIZE(evt->length));
360660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
36172246da4SFelipe Balbi 
36272246da4SFelipe Balbi 	return 0;
36372246da4SFelipe Balbi }
36472246da4SFelipe Balbi 
36572246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
36672246da4SFelipe Balbi {
36772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
36872246da4SFelipe Balbi 
369696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
3707acd85e0SPaul Zimmerman 
3717acd85e0SPaul Zimmerman 	evt->lpos = 0;
3727acd85e0SPaul Zimmerman 
373660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
374660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
375660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
37668d6a01bSFelipe Balbi 			| DWC3_GEVNTSIZ_SIZE(0));
377660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
37872246da4SFelipe Balbi }
37972246da4SFelipe Balbi 
3800ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
3810ffcaf37SFelipe Balbi {
3820ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3830ffcaf37SFelipe Balbi 		return 0;
3840ffcaf37SFelipe Balbi 
3850ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3860ffcaf37SFelipe Balbi 		return 0;
3870ffcaf37SFelipe Balbi 
3880ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
3890ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
3900ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
3910ffcaf37SFelipe Balbi 		return -ENOMEM;
3920ffcaf37SFelipe Balbi 
3930ffcaf37SFelipe Balbi 	return 0;
3940ffcaf37SFelipe Balbi }
3950ffcaf37SFelipe Balbi 
3960ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
3970ffcaf37SFelipe Balbi {
3980ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
3990ffcaf37SFelipe Balbi 	u32 param;
4000ffcaf37SFelipe Balbi 	int ret;
4010ffcaf37SFelipe Balbi 
4020ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
4030ffcaf37SFelipe Balbi 		return 0;
4040ffcaf37SFelipe Balbi 
4050ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
4060ffcaf37SFelipe Balbi 		return 0;
4070ffcaf37SFelipe Balbi 
4080ffcaf37SFelipe Balbi 	 /* should never fall here */
4090ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
4100ffcaf37SFelipe Balbi 		return 0;
4110ffcaf37SFelipe Balbi 
412d64ff406SArnd Bergmann 	scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf,
4130ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
4140ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
415d64ff406SArnd Bergmann 	if (dma_mapping_error(dwc->sysdev, scratch_addr)) {
416d64ff406SArnd Bergmann 		dev_err(dwc->sysdev, "failed to map scratch buffer\n");
4170ffcaf37SFelipe Balbi 		ret = -EFAULT;
4180ffcaf37SFelipe Balbi 		goto err0;
4190ffcaf37SFelipe Balbi 	}
4200ffcaf37SFelipe Balbi 
4210ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
4220ffcaf37SFelipe Balbi 
4230ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
4240ffcaf37SFelipe Balbi 
4250ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
4260ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
4270ffcaf37SFelipe Balbi 	if (ret < 0)
4280ffcaf37SFelipe Balbi 		goto err1;
4290ffcaf37SFelipe Balbi 
4300ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
4310ffcaf37SFelipe Balbi 
4320ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
4330ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
4340ffcaf37SFelipe Balbi 	if (ret < 0)
4350ffcaf37SFelipe Balbi 		goto err1;
4360ffcaf37SFelipe Balbi 
4370ffcaf37SFelipe Balbi 	return 0;
4380ffcaf37SFelipe Balbi 
4390ffcaf37SFelipe Balbi err1:
440d64ff406SArnd Bergmann 	dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
4410ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
4420ffcaf37SFelipe Balbi 
4430ffcaf37SFelipe Balbi err0:
4440ffcaf37SFelipe Balbi 	return ret;
4450ffcaf37SFelipe Balbi }
4460ffcaf37SFelipe Balbi 
4470ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
4480ffcaf37SFelipe Balbi {
4490ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
4500ffcaf37SFelipe Balbi 		return;
4510ffcaf37SFelipe Balbi 
4520ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
4530ffcaf37SFelipe Balbi 		return;
4540ffcaf37SFelipe Balbi 
4550ffcaf37SFelipe Balbi 	 /* should never fall here */
4560ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
4570ffcaf37SFelipe Balbi 		return;
4580ffcaf37SFelipe Balbi 
459d64ff406SArnd Bergmann 	dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
4600ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
4610ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
4620ffcaf37SFelipe Balbi }
4630ffcaf37SFelipe Balbi 
464789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
465789451f6SFelipe Balbi {
466789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
467789451f6SFelipe Balbi 
46847d3946eSBryan O'Donoghue 	dwc->num_eps = DWC3_NUM_EPS(parms);
469789451f6SFelipe Balbi }
470789451f6SFelipe Balbi 
47141ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
47226ceca97SFelipe Balbi {
47326ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
47426ceca97SFelipe Balbi 
47526ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
47626ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
47726ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
47826ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
47926ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
48026ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
48126ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
48226ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
48326ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
48426ceca97SFelipe Balbi }
48526ceca97SFelipe Balbi 
48672246da4SFelipe Balbi /**
487b5a65c40SHuang Rui  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
488b5a65c40SHuang Rui  * @dwc: Pointer to our controller context structure
48988bc9d19SHeikki Krogerus  *
49088bc9d19SHeikki Krogerus  * Returns 0 on success. The USB PHY interfaces are configured but not
49188bc9d19SHeikki Krogerus  * initialized. The PHY interfaces and the PHYs get initialized together with
49288bc9d19SHeikki Krogerus  * the core in dwc3_core_init.
493b5a65c40SHuang Rui  */
49488bc9d19SHeikki Krogerus static int dwc3_phy_setup(struct dwc3 *dwc)
495b5a65c40SHuang Rui {
496b5a65c40SHuang Rui 	u32 reg;
49788bc9d19SHeikki Krogerus 	int ret;
498b5a65c40SHuang Rui 
499b5a65c40SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
500b5a65c40SHuang Rui 
5012164a476SHuang Rui 	/*
5021966b865SFelipe Balbi 	 * Make sure UX_EXIT_PX is cleared as that causes issues with some
5031966b865SFelipe Balbi 	 * PHYs. Also, this bit is not supposed to be used in normal operation.
5041966b865SFelipe Balbi 	 */
5051966b865SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
5061966b865SFelipe Balbi 
5071966b865SFelipe Balbi 	/*
5082164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
5092164a476SHuang Rui 	 * to '0' during coreConsultant configuration. So default value
5102164a476SHuang Rui 	 * will be '0' when the core is reset. Application needs to set it
5112164a476SHuang Rui 	 * to '1' after the core initialization is completed.
5122164a476SHuang Rui 	 */
5132164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
5142164a476SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
5152164a476SHuang Rui 
516b5a65c40SHuang Rui 	if (dwc->u2ss_inp3_quirk)
517b5a65c40SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
518b5a65c40SHuang Rui 
519e58dd357SRajesh Bhagat 	if (dwc->dis_rxdet_inp3_quirk)
520e58dd357SRajesh Bhagat 		reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
521e58dd357SRajesh Bhagat 
522df31f5b3SHuang Rui 	if (dwc->req_p1p2p3_quirk)
523df31f5b3SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
524df31f5b3SHuang Rui 
525a2a1d0f5SHuang Rui 	if (dwc->del_p1p2p3_quirk)
526a2a1d0f5SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
527a2a1d0f5SHuang Rui 
52841c06ffdSHuang Rui 	if (dwc->del_phy_power_chg_quirk)
52941c06ffdSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
53041c06ffdSHuang Rui 
531fb67afcaSHuang Rui 	if (dwc->lfps_filter_quirk)
532fb67afcaSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
533fb67afcaSHuang Rui 
53414f4ac53SHuang Rui 	if (dwc->rx_detect_poll_quirk)
53514f4ac53SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
53614f4ac53SHuang Rui 
5376b6a0c9aSHuang Rui 	if (dwc->tx_de_emphasis_quirk)
5386b6a0c9aSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
5396b6a0c9aSHuang Rui 
540cd72f890SFelipe Balbi 	if (dwc->dis_u3_susphy_quirk)
54159acfa20SHuang Rui 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
54259acfa20SHuang Rui 
54300fe081dSWilliam Wu 	if (dwc->dis_del_phy_power_chg_quirk)
54400fe081dSWilliam Wu 		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
54500fe081dSWilliam Wu 
546b5a65c40SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
547b5a65c40SHuang Rui 
5482164a476SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
5492164a476SHuang Rui 
5503e10a2ceSHeikki Krogerus 	/* Select the HS PHY interface */
5513e10a2ceSHeikki Krogerus 	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
5523e10a2ceSHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
55343cacb03SFelipe Balbi 		if (dwc->hsphy_interface &&
55443cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
5553e10a2ceSHeikki Krogerus 			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
55688bc9d19SHeikki Krogerus 			break;
55743cacb03SFelipe Balbi 		} else if (dwc->hsphy_interface &&
55843cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
5593e10a2ceSHeikki Krogerus 			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
56088bc9d19SHeikki Krogerus 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
5613e10a2ceSHeikki Krogerus 		} else {
56288bc9d19SHeikki Krogerus 			/* Relying on default value. */
56388bc9d19SHeikki Krogerus 			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
5643e10a2ceSHeikki Krogerus 				break;
5653e10a2ceSHeikki Krogerus 		}
5663e10a2ceSHeikki Krogerus 		/* FALLTHROUGH */
56788bc9d19SHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
56888bc9d19SHeikki Krogerus 		ret = dwc3_ulpi_init(dwc);
56988bc9d19SHeikki Krogerus 		if (ret)
57088bc9d19SHeikki Krogerus 			return ret;
57188bc9d19SHeikki Krogerus 		/* FALLTHROUGH */
5723e10a2ceSHeikki Krogerus 	default:
5733e10a2ceSHeikki Krogerus 		break;
5743e10a2ceSHeikki Krogerus 	}
5753e10a2ceSHeikki Krogerus 
57632f2ed86SWilliam Wu 	switch (dwc->hsphy_mode) {
57732f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMI:
57832f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
57932f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
58032f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
58132f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
58232f2ed86SWilliam Wu 		break;
58332f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMIW:
58432f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
58532f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
58632f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
58732f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
58832f2ed86SWilliam Wu 		break;
58932f2ed86SWilliam Wu 	default:
59032f2ed86SWilliam Wu 		break;
59132f2ed86SWilliam Wu 	}
59232f2ed86SWilliam Wu 
5932164a476SHuang Rui 	/*
5942164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
5952164a476SHuang Rui 	 * '0' during coreConsultant configuration. So default value will
5962164a476SHuang Rui 	 * be '0' when the core is reset. Application needs to set it to
5972164a476SHuang Rui 	 * '1' after the core initialization is completed.
5982164a476SHuang Rui 	 */
5992164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
6002164a476SHuang Rui 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
6012164a476SHuang Rui 
602cd72f890SFelipe Balbi 	if (dwc->dis_u2_susphy_quirk)
6030effe0a3SHuang Rui 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
6040effe0a3SHuang Rui 
605ec791d14SJohn Youn 	if (dwc->dis_enblslpm_quirk)
606ec791d14SJohn Youn 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
607ec791d14SJohn Youn 
60816199f33SWilliam Wu 	if (dwc->dis_u2_freeclk_exists_quirk)
60916199f33SWilliam Wu 		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
61016199f33SWilliam Wu 
6112164a476SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
61288bc9d19SHeikki Krogerus 
61388bc9d19SHeikki Krogerus 	return 0;
614b5a65c40SHuang Rui }
615b5a65c40SHuang Rui 
616c499ff71SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
617c499ff71SFelipe Balbi {
618c499ff71SFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
619c499ff71SFelipe Balbi 
620c499ff71SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
621c499ff71SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
622c499ff71SFelipe Balbi 	phy_exit(dwc->usb2_generic_phy);
623c499ff71SFelipe Balbi 	phy_exit(dwc->usb3_generic_phy);
624c499ff71SFelipe Balbi 
625c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 1);
626c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 1);
627c499ff71SFelipe Balbi 	phy_power_off(dwc->usb2_generic_phy);
628c499ff71SFelipe Balbi 	phy_power_off(dwc->usb3_generic_phy);
629c499ff71SFelipe Balbi }
630c499ff71SFelipe Balbi 
6310759956fSFelipe Balbi static bool dwc3_core_is_valid(struct dwc3 *dwc)
63272246da4SFelipe Balbi {
63372246da4SFelipe Balbi 	u32 reg;
63472246da4SFelipe Balbi 
6357650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
6360759956fSFelipe Balbi 
6377650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
638690fb371SJohn Youn 	if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
639690fb371SJohn Youn 		/* Detected DWC_usb3 IP */
640690fb371SJohn Youn 		dwc->revision = reg;
641690fb371SJohn Youn 	} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
642690fb371SJohn Youn 		/* Detected DWC_usb31 IP */
643690fb371SJohn Youn 		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
644690fb371SJohn Youn 		dwc->revision |= DWC3_REVISION_IS_DWC31;
645690fb371SJohn Youn 	} else {
6460759956fSFelipe Balbi 		return false;
6477650bd74SSebastian Andrzej Siewior 	}
6487650bd74SSebastian Andrzej Siewior 
6490759956fSFelipe Balbi 	return true;
6500e1e5c47SPaul Zimmerman }
6510e1e5c47SPaul Zimmerman 
652941f918eSFelipe Balbi static void dwc3_core_setup_global_control(struct dwc3 *dwc)
65372246da4SFelipe Balbi {
65472246da4SFelipe Balbi 	u32 hwparams4 = dwc->hwparams.hwparams4;
65572246da4SFelipe Balbi 	u32 reg;
656c499ff71SFelipe Balbi 
6574878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
6583e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
6594878a028SSebastian Andrzej Siewior 
660164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
6614878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
66232a4a135SFelipe Balbi 		/**
66332a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
66432a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
66532a4a135SFelipe Balbi 		 *
66632a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
66732a4a135SFelipe Balbi 		 * configurations.
66832a4a135SFelipe Balbi 		 *
66932a4a135SFelipe Balbi 		 * Refers to:
67032a4a135SFelipe Balbi 		 *
67132a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
67232a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
67332a4a135SFelipe Balbi 		 */
67432a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
67532a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
67632a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
67732a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
67832a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
67932a4a135SFelipe Balbi 		else
6804878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
6814878a028SSebastian Andrzej Siewior 		break;
6820ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
6830ffcaf37SFelipe Balbi 		/* enable hibernation here */
6840ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
6852eac3992SHuang Rui 
6862eac3992SHuang Rui 		/*
6872eac3992SHuang Rui 		 * REVISIT Enabling this bit so that host-mode hibernation
6882eac3992SHuang Rui 		 * will work. Device-mode hibernation is not yet implemented.
6892eac3992SHuang Rui 		 */
6902eac3992SHuang Rui 		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
6910ffcaf37SFelipe Balbi 		break;
6924878a028SSebastian Andrzej Siewior 	default:
6935eb30cedSFelipe Balbi 		/* nothing */
6945eb30cedSFelipe Balbi 		break;
6954878a028SSebastian Andrzej Siewior 	}
6964878a028SSebastian Andrzej Siewior 
697946bd579SHuang Rui 	/* check if current dwc3 is on simulation board */
698946bd579SHuang Rui 	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
6995eb30cedSFelipe Balbi 		dev_info(dwc->dev, "Running with FPGA optmizations\n");
700946bd579SHuang Rui 		dwc->is_fpga = true;
701946bd579SHuang Rui 	}
702946bd579SHuang Rui 
7033b81221aSHuang Rui 	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
7043b81221aSHuang Rui 			"disable_scramble cannot be used on non-FPGA builds\n");
7053b81221aSHuang Rui 
7063b81221aSHuang Rui 	if (dwc->disable_scramble_quirk && dwc->is_fpga)
7073b81221aSHuang Rui 		reg |= DWC3_GCTL_DISSCRAMBLE;
7083b81221aSHuang Rui 	else
7093b81221aSHuang Rui 		reg &= ~DWC3_GCTL_DISSCRAMBLE;
7103b81221aSHuang Rui 
7119a5b2f31SHuang Rui 	if (dwc->u2exit_lfps_quirk)
7129a5b2f31SHuang Rui 		reg |= DWC3_GCTL_U2EXIT_LFPS;
7139a5b2f31SHuang Rui 
7144878a028SSebastian Andrzej Siewior 	/*
7154878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
7161d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
7174878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
7181d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
7194878a028SSebastian Andrzej Siewior 	 */
7204878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
7214878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
7224878a028SSebastian Andrzej Siewior 
7234878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
724941f918eSFelipe Balbi }
7254878a028SSebastian Andrzej Siewior 
726f54edb53SFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc);
727f54edb53SFelipe Balbi 
728941f918eSFelipe Balbi /**
729941f918eSFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
730941f918eSFelipe Balbi  * @dwc: Pointer to our controller context structure
731941f918eSFelipe Balbi  *
732941f918eSFelipe Balbi  * Returns 0 on success otherwise negative errno.
733941f918eSFelipe Balbi  */
734941f918eSFelipe Balbi static int dwc3_core_init(struct dwc3 *dwc)
735941f918eSFelipe Balbi {
736941f918eSFelipe Balbi 	u32			reg;
737941f918eSFelipe Balbi 	int			ret;
738941f918eSFelipe Balbi 
739941f918eSFelipe Balbi 	if (!dwc3_core_is_valid(dwc)) {
740941f918eSFelipe Balbi 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
741941f918eSFelipe Balbi 		ret = -ENODEV;
742941f918eSFelipe Balbi 		goto err0;
743941f918eSFelipe Balbi 	}
744941f918eSFelipe Balbi 
745941f918eSFelipe Balbi 	/*
746941f918eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
747941f918eSFelipe Balbi 	 * out which kernel version a bug was found.
748941f918eSFelipe Balbi 	 */
749941f918eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
750941f918eSFelipe Balbi 
751941f918eSFelipe Balbi 	/* Handle USB2.0-only core configuration */
752941f918eSFelipe Balbi 	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
753941f918eSFelipe Balbi 			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
754941f918eSFelipe Balbi 		if (dwc->maximum_speed == USB_SPEED_SUPER)
755941f918eSFelipe Balbi 			dwc->maximum_speed = USB_SPEED_HIGH;
756941f918eSFelipe Balbi 	}
757941f918eSFelipe Balbi 
758541768b0SVignesh R 	ret = dwc3_core_get_phy(dwc);
759541768b0SVignesh R 	if (ret)
760541768b0SVignesh R 		goto err0;
761541768b0SVignesh R 
762941f918eSFelipe Balbi 	ret = dwc3_core_soft_reset(dwc);
763941f918eSFelipe Balbi 	if (ret)
764941f918eSFelipe Balbi 		goto err0;
765941f918eSFelipe Balbi 
766941f918eSFelipe Balbi 	ret = dwc3_phy_setup(dwc);
767941f918eSFelipe Balbi 	if (ret)
768941f918eSFelipe Balbi 		goto err0;
769941f918eSFelipe Balbi 
770941f918eSFelipe Balbi 	dwc3_core_setup_global_control(dwc);
771c499ff71SFelipe Balbi 	dwc3_core_num_eps(dwc);
7720ffcaf37SFelipe Balbi 
7730ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
7740ffcaf37SFelipe Balbi 	if (ret)
775c499ff71SFelipe Balbi 		goto err1;
776c499ff71SFelipe Balbi 
777c499ff71SFelipe Balbi 	/* Adjust Frame Length */
778c499ff71SFelipe Balbi 	dwc3_frame_length_adjustment(dwc);
779c499ff71SFelipe Balbi 
780c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 0);
781c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 0);
782c499ff71SFelipe Balbi 	ret = phy_power_on(dwc->usb2_generic_phy);
783c499ff71SFelipe Balbi 	if (ret < 0)
7840ffcaf37SFelipe Balbi 		goto err2;
7850ffcaf37SFelipe Balbi 
786c499ff71SFelipe Balbi 	ret = phy_power_on(dwc->usb3_generic_phy);
787c499ff71SFelipe Balbi 	if (ret < 0)
788c499ff71SFelipe Balbi 		goto err3;
789c499ff71SFelipe Balbi 
790c499ff71SFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
791c499ff71SFelipe Balbi 	if (ret) {
792c499ff71SFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
793c499ff71SFelipe Balbi 		goto err4;
794c499ff71SFelipe Balbi 	}
795c499ff71SFelipe Balbi 
79606281d46SJohn Youn 	/*
79706281d46SJohn Youn 	 * ENDXFER polling is available on version 3.10a and later of
79806281d46SJohn Youn 	 * the DWC_usb3 controller. It is NOT available in the
79906281d46SJohn Youn 	 * DWC_usb31 controller.
80006281d46SJohn Youn 	 */
80106281d46SJohn Youn 	if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
80206281d46SJohn Youn 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
80306281d46SJohn Youn 		reg |= DWC3_GUCTL2_RST_ACTBITLATER;
80406281d46SJohn Youn 		dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
80506281d46SJohn Youn 	}
80606281d46SJohn Youn 
80765db7a0cSWilliam Wu 	if (dwc->revision >= DWC3_REVISION_250A) {
8080bb39ca1SJohn Youn 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
80965db7a0cSWilliam Wu 
81065db7a0cSWilliam Wu 		/*
81165db7a0cSWilliam Wu 		 * Enable hardware control of sending remote wakeup
81265db7a0cSWilliam Wu 		 * in HS when the device is in the L1 state.
81365db7a0cSWilliam Wu 		 */
81465db7a0cSWilliam Wu 		if (dwc->revision >= DWC3_REVISION_290A)
8150bb39ca1SJohn Youn 			reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
81665db7a0cSWilliam Wu 
81765db7a0cSWilliam Wu 		if (dwc->dis_tx_ipgap_linecheck_quirk)
81865db7a0cSWilliam Wu 			reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
81965db7a0cSWilliam Wu 
8200bb39ca1SJohn Youn 		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
8210bb39ca1SJohn Youn 	}
8220bb39ca1SJohn Youn 
82372246da4SFelipe Balbi 	return 0;
82472246da4SFelipe Balbi 
825c499ff71SFelipe Balbi err4:
8269b9d7cddSVivek Gautam 	phy_power_off(dwc->usb3_generic_phy);
827c499ff71SFelipe Balbi 
828c499ff71SFelipe Balbi err3:
8299b9d7cddSVivek Gautam 	phy_power_off(dwc->usb2_generic_phy);
830c499ff71SFelipe Balbi 
8310ffcaf37SFelipe Balbi err2:
832c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 1);
833c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 1);
8340ffcaf37SFelipe Balbi 
8350ffcaf37SFelipe Balbi err1:
8360ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
8370ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
83857303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
83957303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
8400ffcaf37SFelipe Balbi 
84172246da4SFelipe Balbi err0:
84272246da4SFelipe Balbi 	return ret;
84372246da4SFelipe Balbi }
84472246da4SFelipe Balbi 
8453c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
84672246da4SFelipe Balbi {
8473c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
848941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
8493c9f94acSFelipe Balbi 	int ret;
85072246da4SFelipe Balbi 
8515088b6f5SKishon Vijay Abraham I 	if (node) {
8525088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
8535088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
854bb674907SFelipe Balbi 	} else {
855bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
856bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
8575088b6f5SKishon Vijay Abraham I 	}
8585088b6f5SKishon Vijay Abraham I 
859d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
860d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
861122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
862122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
863122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
864d105e7f8SFelipe Balbi 			return ret;
865122f06e6SKishon Vijay Abraham I 		} else {
86651e1e7bcSFelipe Balbi 			dev_err(dev, "no usb2 phy configured\n");
867122f06e6SKishon Vijay Abraham I 			return ret;
868122f06e6SKishon Vijay Abraham I 		}
86951e1e7bcSFelipe Balbi 	}
87051e1e7bcSFelipe Balbi 
871d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
872315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
873122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
874122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
875122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
876d105e7f8SFelipe Balbi 			return ret;
877122f06e6SKishon Vijay Abraham I 		} else {
87851e1e7bcSFelipe Balbi 			dev_err(dev, "no usb3 phy configured\n");
879122f06e6SKishon Vijay Abraham I 			return ret;
880122f06e6SKishon Vijay Abraham I 		}
88151e1e7bcSFelipe Balbi 	}
88251e1e7bcSFelipe Balbi 
88357303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
88457303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
88557303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
88657303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
88757303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
88857303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
88957303488SKishon Vijay Abraham I 			return ret;
89057303488SKishon Vijay Abraham I 		} else {
89157303488SKishon Vijay Abraham I 			dev_err(dev, "no usb2 phy configured\n");
89257303488SKishon Vijay Abraham I 			return ret;
89357303488SKishon Vijay Abraham I 		}
89457303488SKishon Vijay Abraham I 	}
89557303488SKishon Vijay Abraham I 
89657303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
89757303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
89857303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
89957303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
90057303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
90157303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
90257303488SKishon Vijay Abraham I 			return ret;
90357303488SKishon Vijay Abraham I 		} else {
90457303488SKishon Vijay Abraham I 			dev_err(dev, "no usb3 phy configured\n");
90557303488SKishon Vijay Abraham I 			return ret;
90657303488SKishon Vijay Abraham I 		}
90757303488SKishon Vijay Abraham I 	}
90857303488SKishon Vijay Abraham I 
9093c9f94acSFelipe Balbi 	return 0;
9103c9f94acSFelipe Balbi }
9113c9f94acSFelipe Balbi 
9125f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
9135f94adfeSFelipe Balbi {
9145f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
9155f94adfeSFelipe Balbi 	int ret;
9165f94adfeSFelipe Balbi 
9175f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
9185f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
919689bf72cSManu Gautam 		dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
92041ce1456SRoger Quadros 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
921958d1a4cSFelipe Balbi 
922958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
923958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, false);
924958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
925644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
926958d1a4cSFelipe Balbi 
9275f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
9285f94adfeSFelipe Balbi 		if (ret) {
9299522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
9305f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize gadget\n");
9315f94adfeSFelipe Balbi 			return ret;
9325f94adfeSFelipe Balbi 		}
9335f94adfeSFelipe Balbi 		break;
9345f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
935689bf72cSManu Gautam 		dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
93641ce1456SRoger Quadros 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
937958d1a4cSFelipe Balbi 
938958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
939958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, true);
940958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
941644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
942958d1a4cSFelipe Balbi 
9435f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
9445f94adfeSFelipe Balbi 		if (ret) {
9459522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
9465f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize host\n");
9475f94adfeSFelipe Balbi 			return ret;
9485f94adfeSFelipe Balbi 		}
949d8c80bb3SVivek Gautam 		phy_calibrate(dwc->usb2_generic_phy);
9505f94adfeSFelipe Balbi 		break;
9515f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
95241ce1456SRoger Quadros 		INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
9539840354fSRoger Quadros 		ret = dwc3_drd_init(dwc);
9549840354fSRoger Quadros 		if (ret) {
9559840354fSRoger Quadros 			if (ret != -EPROBE_DEFER)
9569840354fSRoger Quadros 				dev_err(dev, "failed to initialize dual-role\n");
9579840354fSRoger Quadros 			return ret;
9589840354fSRoger Quadros 		}
9595f94adfeSFelipe Balbi 		break;
9605f94adfeSFelipe Balbi 	default:
9615f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
9625f94adfeSFelipe Balbi 		return -EINVAL;
9635f94adfeSFelipe Balbi 	}
9645f94adfeSFelipe Balbi 
9655f94adfeSFelipe Balbi 	return 0;
9665f94adfeSFelipe Balbi }
9675f94adfeSFelipe Balbi 
9685f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
9695f94adfeSFelipe Balbi {
9705f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
9715f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
9725f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
9735f94adfeSFelipe Balbi 		break;
9745f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
9755f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
9765f94adfeSFelipe Balbi 		break;
9775f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
9789840354fSRoger Quadros 		dwc3_drd_exit(dwc);
9795f94adfeSFelipe Balbi 		break;
9805f94adfeSFelipe Balbi 	default:
9815f94adfeSFelipe Balbi 		/* do nothing */
9825f94adfeSFelipe Balbi 		break;
9835f94adfeSFelipe Balbi 	}
9845f94adfeSFelipe Balbi }
9855f94adfeSFelipe Balbi 
986c5ac6116SFelipe Balbi static void dwc3_get_properties(struct dwc3 *dwc)
9873c9f94acSFelipe Balbi {
988c5ac6116SFelipe Balbi 	struct device		*dev = dwc->dev;
98980caf7d2SHuang Rui 	u8			lpm_nyet_threshold;
9906b6a0c9aSHuang Rui 	u8			tx_de_emphasis;
991460d098cSHuang Rui 	u8			hird_threshold;
9923c9f94acSFelipe Balbi 
99380caf7d2SHuang Rui 	/* default to highest possible threshold */
99480caf7d2SHuang Rui 	lpm_nyet_threshold = 0xff;
99580caf7d2SHuang Rui 
9966b6a0c9aSHuang Rui 	/* default to -3.5dB de-emphasis */
9976b6a0c9aSHuang Rui 	tx_de_emphasis = 1;
9986b6a0c9aSHuang Rui 
999460d098cSHuang Rui 	/*
1000460d098cSHuang Rui 	 * default to assert utmi_sleep_n and use maximum allowed HIRD
1001460d098cSHuang Rui 	 * threshold value of 0b1100
1002460d098cSHuang Rui 	 */
1003460d098cSHuang Rui 	hird_threshold = 12;
1004460d098cSHuang Rui 
100563863b98SHeikki Krogerus 	dwc->maximum_speed = usb_get_maximum_speed(dev);
100606e7114fSHeikki Krogerus 	dwc->dr_mode = usb_get_dr_mode(dev);
100732f2ed86SWilliam Wu 	dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
100863863b98SHeikki Krogerus 
1009d64ff406SArnd Bergmann 	dwc->sysdev_is_parent = device_property_read_bool(dev,
1010d64ff406SArnd Bergmann 				"linux,sysdev_is_parent");
1011d64ff406SArnd Bergmann 	if (dwc->sysdev_is_parent)
1012d64ff406SArnd Bergmann 		dwc->sysdev = dwc->dev->parent;
1013d64ff406SArnd Bergmann 	else
1014d64ff406SArnd Bergmann 		dwc->sysdev = dwc->dev;
1015d64ff406SArnd Bergmann 
10163d128919SHeikki Krogerus 	dwc->has_lpm_erratum = device_property_read_bool(dev,
101780caf7d2SHuang Rui 				"snps,has-lpm-erratum");
10183d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,lpm-nyet-threshold",
101980caf7d2SHuang Rui 				&lpm_nyet_threshold);
10203d128919SHeikki Krogerus 	dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
1021460d098cSHuang Rui 				"snps,is-utmi-l1-suspend");
10223d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,hird-threshold",
1023460d098cSHuang Rui 				&hird_threshold);
10243d128919SHeikki Krogerus 	dwc->usb3_lpm_capable = device_property_read_bool(dev,
1025eac68e8fSRobert Baldyga 				"snps,usb3_lpm_capable");
10263c9f94acSFelipe Balbi 
10273d128919SHeikki Krogerus 	dwc->disable_scramble_quirk = device_property_read_bool(dev,
10283b81221aSHuang Rui 				"snps,disable_scramble_quirk");
10293d128919SHeikki Krogerus 	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
10309a5b2f31SHuang Rui 				"snps,u2exit_lfps_quirk");
10313d128919SHeikki Krogerus 	dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
1032b5a65c40SHuang Rui 				"snps,u2ss_inp3_quirk");
10333d128919SHeikki Krogerus 	dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
1034df31f5b3SHuang Rui 				"snps,req_p1p2p3_quirk");
10353d128919SHeikki Krogerus 	dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
1036a2a1d0f5SHuang Rui 				"snps,del_p1p2p3_quirk");
10373d128919SHeikki Krogerus 	dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
103841c06ffdSHuang Rui 				"snps,del_phy_power_chg_quirk");
10393d128919SHeikki Krogerus 	dwc->lfps_filter_quirk = device_property_read_bool(dev,
1040fb67afcaSHuang Rui 				"snps,lfps_filter_quirk");
10413d128919SHeikki Krogerus 	dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
104214f4ac53SHuang Rui 				"snps,rx_detect_poll_quirk");
10433d128919SHeikki Krogerus 	dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
104459acfa20SHuang Rui 				"snps,dis_u3_susphy_quirk");
10453d128919SHeikki Krogerus 	dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
10460effe0a3SHuang Rui 				"snps,dis_u2_susphy_quirk");
1047ec791d14SJohn Youn 	dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
1048ec791d14SJohn Youn 				"snps,dis_enblslpm_quirk");
1049e58dd357SRajesh Bhagat 	dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
1050e58dd357SRajesh Bhagat 				"snps,dis_rxdet_inp3_quirk");
105116199f33SWilliam Wu 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
105216199f33SWilliam Wu 				"snps,dis-u2-freeclk-exists-quirk");
105300fe081dSWilliam Wu 	dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
105400fe081dSWilliam Wu 				"snps,dis-del-phy-power-chg-quirk");
105565db7a0cSWilliam Wu 	dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
105665db7a0cSWilliam Wu 				"snps,dis-tx-ipgap-linecheck-quirk");
10576b6a0c9aSHuang Rui 
10583d128919SHeikki Krogerus 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
10596b6a0c9aSHuang Rui 				"snps,tx_de_emphasis_quirk");
10603d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,tx_de_emphasis",
10616b6a0c9aSHuang Rui 				&tx_de_emphasis);
10623d128919SHeikki Krogerus 	device_property_read_string(dev, "snps,hsphy_interface",
10633e10a2ceSHeikki Krogerus 				    &dwc->hsphy_interface);
10643d128919SHeikki Krogerus 	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
1065bcdb3272SFelipe Balbi 				 &dwc->fladj);
10663d128919SHeikki Krogerus 
106780caf7d2SHuang Rui 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
10686b6a0c9aSHuang Rui 	dwc->tx_de_emphasis = tx_de_emphasis;
106980caf7d2SHuang Rui 
1070460d098cSHuang Rui 	dwc->hird_threshold = hird_threshold
1071460d098cSHuang Rui 		| (dwc->is_utmi_l1_suspend << 4);
1072460d098cSHuang Rui 
1073cf40b86bSJohn Youn 	dwc->imod_interval = 0;
1074cf40b86bSJohn Youn }
1075cf40b86bSJohn Youn 
1076cf40b86bSJohn Youn /* check whether the core supports IMOD */
1077cf40b86bSJohn Youn bool dwc3_has_imod(struct dwc3 *dwc)
1078cf40b86bSJohn Youn {
1079cf40b86bSJohn Youn 	return ((dwc3_is_usb3(dwc) &&
1080cf40b86bSJohn Youn 		 dwc->revision >= DWC3_REVISION_300A) ||
1081cf40b86bSJohn Youn 		(dwc3_is_usb31(dwc) &&
1082cf40b86bSJohn Youn 		 dwc->revision >= DWC3_USB31_REVISION_120A));
1083c5ac6116SFelipe Balbi }
1084c5ac6116SFelipe Balbi 
10857ac51a12SJohn Youn static void dwc3_check_params(struct dwc3 *dwc)
10867ac51a12SJohn Youn {
10877ac51a12SJohn Youn 	struct device *dev = dwc->dev;
10887ac51a12SJohn Youn 
1089cf40b86bSJohn Youn 	/* Check for proper value of imod_interval */
1090cf40b86bSJohn Youn 	if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
1091cf40b86bSJohn Youn 		dev_warn(dwc->dev, "Interrupt moderation not supported\n");
1092cf40b86bSJohn Youn 		dwc->imod_interval = 0;
1093cf40b86bSJohn Youn 	}
1094cf40b86bSJohn Youn 
109528632b44SJohn Youn 	/*
109628632b44SJohn Youn 	 * Workaround for STAR 9000961433 which affects only version
109728632b44SJohn Youn 	 * 3.00a of the DWC_usb3 core. This prevents the controller
109828632b44SJohn Youn 	 * interrupt from being masked while handling events. IMOD
109928632b44SJohn Youn 	 * allows us to work around this issue. Enable it for the
110028632b44SJohn Youn 	 * affected version.
110128632b44SJohn Youn 	 */
110228632b44SJohn Youn 	if (!dwc->imod_interval &&
110328632b44SJohn Youn 	    (dwc->revision == DWC3_REVISION_300A))
110428632b44SJohn Youn 		dwc->imod_interval = 1;
110528632b44SJohn Youn 
11067ac51a12SJohn Youn 	/* Check the maximum_speed parameter */
11077ac51a12SJohn Youn 	switch (dwc->maximum_speed) {
11087ac51a12SJohn Youn 	case USB_SPEED_LOW:
11097ac51a12SJohn Youn 	case USB_SPEED_FULL:
11107ac51a12SJohn Youn 	case USB_SPEED_HIGH:
11117ac51a12SJohn Youn 	case USB_SPEED_SUPER:
11127ac51a12SJohn Youn 	case USB_SPEED_SUPER_PLUS:
11137ac51a12SJohn Youn 		break;
11147ac51a12SJohn Youn 	default:
11157ac51a12SJohn Youn 		dev_err(dev, "invalid maximum_speed parameter %d\n",
11167ac51a12SJohn Youn 			dwc->maximum_speed);
11177ac51a12SJohn Youn 		/* fall through */
11187ac51a12SJohn Youn 	case USB_SPEED_UNKNOWN:
11197ac51a12SJohn Youn 		/* default to superspeed */
11207ac51a12SJohn Youn 		dwc->maximum_speed = USB_SPEED_SUPER;
11217ac51a12SJohn Youn 
11227ac51a12SJohn Youn 		/*
11237ac51a12SJohn Youn 		 * default to superspeed plus if we are capable.
11247ac51a12SJohn Youn 		 */
11257ac51a12SJohn Youn 		if (dwc3_is_usb31(dwc) &&
11267ac51a12SJohn Youn 		    (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
11277ac51a12SJohn Youn 		     DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
11287ac51a12SJohn Youn 			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
11297ac51a12SJohn Youn 
11307ac51a12SJohn Youn 		break;
11317ac51a12SJohn Youn 	}
11327ac51a12SJohn Youn }
11337ac51a12SJohn Youn 
1134c5ac6116SFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
1135c5ac6116SFelipe Balbi {
1136c5ac6116SFelipe Balbi 	struct device		*dev = &pdev->dev;
1137c5ac6116SFelipe Balbi 	struct resource		*res;
1138c5ac6116SFelipe Balbi 	struct dwc3		*dwc;
1139c5ac6116SFelipe Balbi 
1140c5ac6116SFelipe Balbi 	int			ret;
1141c5ac6116SFelipe Balbi 
1142c5ac6116SFelipe Balbi 	void __iomem		*regs;
1143c5ac6116SFelipe Balbi 
1144c5ac6116SFelipe Balbi 	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
1145c5ac6116SFelipe Balbi 	if (!dwc)
1146c5ac6116SFelipe Balbi 		return -ENOMEM;
1147c5ac6116SFelipe Balbi 
1148c5ac6116SFelipe Balbi 	dwc->dev = dev;
1149c5ac6116SFelipe Balbi 
1150c5ac6116SFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1151c5ac6116SFelipe Balbi 	if (!res) {
1152c5ac6116SFelipe Balbi 		dev_err(dev, "missing memory resource\n");
1153c5ac6116SFelipe Balbi 		return -ENODEV;
1154c5ac6116SFelipe Balbi 	}
1155c5ac6116SFelipe Balbi 
1156c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].start = res->start;
1157c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
1158c5ac6116SFelipe Balbi 					DWC3_XHCI_REGS_END;
1159c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].flags = res->flags;
1160c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].name = res->name;
1161c5ac6116SFelipe Balbi 
1162c5ac6116SFelipe Balbi 	res->start += DWC3_GLOBALS_REGS_START;
1163c5ac6116SFelipe Balbi 
1164c5ac6116SFelipe Balbi 	/*
1165c5ac6116SFelipe Balbi 	 * Request memory region but exclude xHCI regs,
1166c5ac6116SFelipe Balbi 	 * since it will be requested by the xhci-plat driver.
1167c5ac6116SFelipe Balbi 	 */
1168c5ac6116SFelipe Balbi 	regs = devm_ioremap_resource(dev, res);
1169c5ac6116SFelipe Balbi 	if (IS_ERR(regs)) {
1170c5ac6116SFelipe Balbi 		ret = PTR_ERR(regs);
1171c5ac6116SFelipe Balbi 		goto err0;
1172c5ac6116SFelipe Balbi 	}
1173c5ac6116SFelipe Balbi 
1174c5ac6116SFelipe Balbi 	dwc->regs	= regs;
1175c5ac6116SFelipe Balbi 	dwc->regs_size	= resource_size(res);
1176c5ac6116SFelipe Balbi 
1177c5ac6116SFelipe Balbi 	dwc3_get_properties(dwc);
1178c5ac6116SFelipe Balbi 
11796c89cce0SHeikki Krogerus 	platform_set_drvdata(pdev, dwc);
11802917e718SHeikki Krogerus 	dwc3_cache_hwparams(dwc);
11816c89cce0SHeikki Krogerus 
118272246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
118372246da4SFelipe Balbi 
1184fc8bb91bSFelipe Balbi 	pm_runtime_set_active(dev);
1185fc8bb91bSFelipe Balbi 	pm_runtime_use_autosuspend(dev);
1186fc8bb91bSFelipe Balbi 	pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
1187802ca850SChanho Park 	pm_runtime_enable(dev);
118832808237SRoger Quadros 	ret = pm_runtime_get_sync(dev);
118932808237SRoger Quadros 	if (ret < 0)
119032808237SRoger Quadros 		goto err1;
119132808237SRoger Quadros 
1192802ca850SChanho Park 	pm_runtime_forbid(dev);
119372246da4SFelipe Balbi 
11943921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
11953921426bSFelipe Balbi 	if (ret) {
11963921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
11973921426bSFelipe Balbi 		ret = -ENOMEM;
119832808237SRoger Quadros 		goto err2;
11993921426bSFelipe Balbi 	}
12003921426bSFelipe Balbi 
12019d6173e1SThinh Nguyen 	ret = dwc3_get_dr_mode(dwc);
12029d6173e1SThinh Nguyen 	if (ret)
12039d6173e1SThinh Nguyen 		goto err3;
120432a4a135SFelipe Balbi 
1205c499ff71SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
1206c499ff71SFelipe Balbi 	if (ret)
120732808237SRoger Quadros 		goto err3;
1208c499ff71SFelipe Balbi 
120972246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
121072246da4SFelipe Balbi 	if (ret) {
1211802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
121232808237SRoger Quadros 		goto err4;
121372246da4SFelipe Balbi 	}
121472246da4SFelipe Balbi 
12157ac51a12SJohn Youn 	dwc3_check_params(dwc);
12162c7f1bd9SJohn Youn 
12175f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
12185f94adfeSFelipe Balbi 	if (ret)
121932808237SRoger Quadros 		goto err5;
122072246da4SFelipe Balbi 
12214e9f3118SDu, Changbin 	dwc3_debugfs_init(dwc);
1222fc8bb91bSFelipe Balbi 	pm_runtime_put(dev);
122372246da4SFelipe Balbi 
122472246da4SFelipe Balbi 	return 0;
122572246da4SFelipe Balbi 
122632808237SRoger Quadros err5:
1227f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
1228f122d33eSFelipe Balbi 
122932808237SRoger Quadros err4:
1230c499ff71SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
123172246da4SFelipe Balbi 
123232808237SRoger Quadros err3:
12333921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
123488bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
12353921426bSFelipe Balbi 
123632808237SRoger Quadros err2:
123732808237SRoger Quadros 	pm_runtime_allow(&pdev->dev);
123832808237SRoger Quadros 
123932808237SRoger Quadros err1:
124032808237SRoger Quadros 	pm_runtime_put_sync(&pdev->dev);
124132808237SRoger Quadros 	pm_runtime_disable(&pdev->dev);
124232808237SRoger Quadros 
12433da1f6eeSFelipe Balbi err0:
12443da1f6eeSFelipe Balbi 	/*
12453da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
12463da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
12473da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
12483da1f6eeSFelipe Balbi 	 */
12493da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
12503da1f6eeSFelipe Balbi 
125172246da4SFelipe Balbi 	return ret;
125272246da4SFelipe Balbi }
125372246da4SFelipe Balbi 
1254fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
125572246da4SFelipe Balbi {
125672246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
12573da1f6eeSFelipe Balbi 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
12583da1f6eeSFelipe Balbi 
1259fc8bb91bSFelipe Balbi 	pm_runtime_get_sync(&pdev->dev);
12603da1f6eeSFelipe Balbi 	/*
12613da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
12623da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
12633da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
12643da1f6eeSFelipe Balbi 	 */
12653da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
126672246da4SFelipe Balbi 
1267dc99f16fSFelipe Balbi 	dwc3_debugfs_exit(dwc);
1268dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
12698ba007a9SKishon Vijay Abraham I 
127072246da4SFelipe Balbi 	dwc3_core_exit(dwc);
127188bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
127272246da4SFelipe Balbi 
1273fc8bb91bSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
1274fc8bb91bSFelipe Balbi 	pm_runtime_allow(&pdev->dev);
1275fc8bb91bSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
1276fc8bb91bSFelipe Balbi 
1277c499ff71SFelipe Balbi 	dwc3_free_event_buffers(dwc);
1278c499ff71SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
1279c499ff71SFelipe Balbi 
128072246da4SFelipe Balbi 	return 0;
128172246da4SFelipe Balbi }
128272246da4SFelipe Balbi 
1283fc8bb91bSFelipe Balbi #ifdef CONFIG_PM
1284fc8bb91bSFelipe Balbi static int dwc3_suspend_common(struct dwc3 *dwc)
12857415f17cSFelipe Balbi {
1286fc8bb91bSFelipe Balbi 	unsigned long	flags;
12877415f17cSFelipe Balbi 
1288689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1289689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1290fc8bb91bSFelipe Balbi 		spin_lock_irqsave(&dwc->lock, flags);
12917415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
1292fc8bb91bSFelipe Balbi 		spin_unlock_irqrestore(&dwc->lock, flags);
1293689bf72cSManu Gautam 		dwc3_core_exit(dwc);
129451f5d49aSFelipe Balbi 		break;
1295689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
12967415f17cSFelipe Balbi 	default:
129751f5d49aSFelipe Balbi 		/* do nothing */
12987415f17cSFelipe Balbi 		break;
12997415f17cSFelipe Balbi 	}
13007415f17cSFelipe Balbi 
1301fc8bb91bSFelipe Balbi 	return 0;
1302fc8bb91bSFelipe Balbi }
1303fc8bb91bSFelipe Balbi 
1304fc8bb91bSFelipe Balbi static int dwc3_resume_common(struct dwc3 *dwc)
1305fc8bb91bSFelipe Balbi {
1306fc8bb91bSFelipe Balbi 	unsigned long	flags;
1307fc8bb91bSFelipe Balbi 	int		ret;
1308fc8bb91bSFelipe Balbi 
1309689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1310689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1311fc8bb91bSFelipe Balbi 		ret = dwc3_core_init(dwc);
1312fc8bb91bSFelipe Balbi 		if (ret)
1313fc8bb91bSFelipe Balbi 			return ret;
1314fc8bb91bSFelipe Balbi 
1315fc8bb91bSFelipe Balbi 		spin_lock_irqsave(&dwc->lock, flags);
1316fc8bb91bSFelipe Balbi 		dwc3_gadget_resume(dwc);
1317fc8bb91bSFelipe Balbi 		spin_unlock_irqrestore(&dwc->lock, flags);
1318689bf72cSManu Gautam 		break;
1319689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1320fc8bb91bSFelipe Balbi 	default:
1321fc8bb91bSFelipe Balbi 		/* do nothing */
1322fc8bb91bSFelipe Balbi 		break;
1323fc8bb91bSFelipe Balbi 	}
1324fc8bb91bSFelipe Balbi 
1325fc8bb91bSFelipe Balbi 	return 0;
1326fc8bb91bSFelipe Balbi }
1327fc8bb91bSFelipe Balbi 
1328fc8bb91bSFelipe Balbi static int dwc3_runtime_checks(struct dwc3 *dwc)
1329fc8bb91bSFelipe Balbi {
1330689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1331fc8bb91bSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
1332fc8bb91bSFelipe Balbi 	case USB_DR_MODE_OTG:
1333fc8bb91bSFelipe Balbi 		if (dwc->connected)
1334fc8bb91bSFelipe Balbi 			return -EBUSY;
1335fc8bb91bSFelipe Balbi 		break;
1336fc8bb91bSFelipe Balbi 	case USB_DR_MODE_HOST:
1337fc8bb91bSFelipe Balbi 	default:
1338fc8bb91bSFelipe Balbi 		/* do nothing */
1339fc8bb91bSFelipe Balbi 		break;
1340fc8bb91bSFelipe Balbi 	}
1341fc8bb91bSFelipe Balbi 
1342fc8bb91bSFelipe Balbi 	return 0;
1343fc8bb91bSFelipe Balbi }
1344fc8bb91bSFelipe Balbi 
1345fc8bb91bSFelipe Balbi static int dwc3_runtime_suspend(struct device *dev)
1346fc8bb91bSFelipe Balbi {
1347fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1348fc8bb91bSFelipe Balbi 	int		ret;
1349fc8bb91bSFelipe Balbi 
1350fc8bb91bSFelipe Balbi 	if (dwc3_runtime_checks(dwc))
1351fc8bb91bSFelipe Balbi 		return -EBUSY;
1352fc8bb91bSFelipe Balbi 
1353fc8bb91bSFelipe Balbi 	ret = dwc3_suspend_common(dwc);
1354fc8bb91bSFelipe Balbi 	if (ret)
1355fc8bb91bSFelipe Balbi 		return ret;
1356fc8bb91bSFelipe Balbi 
1357fc8bb91bSFelipe Balbi 	device_init_wakeup(dev, true);
1358fc8bb91bSFelipe Balbi 
1359fc8bb91bSFelipe Balbi 	return 0;
1360fc8bb91bSFelipe Balbi }
1361fc8bb91bSFelipe Balbi 
1362fc8bb91bSFelipe Balbi static int dwc3_runtime_resume(struct device *dev)
1363fc8bb91bSFelipe Balbi {
1364fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1365fc8bb91bSFelipe Balbi 	int		ret;
1366fc8bb91bSFelipe Balbi 
1367fc8bb91bSFelipe Balbi 	device_init_wakeup(dev, false);
1368fc8bb91bSFelipe Balbi 
1369fc8bb91bSFelipe Balbi 	ret = dwc3_resume_common(dwc);
1370fc8bb91bSFelipe Balbi 	if (ret)
1371fc8bb91bSFelipe Balbi 		return ret;
1372fc8bb91bSFelipe Balbi 
1373689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1374689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1375fc8bb91bSFelipe Balbi 		dwc3_gadget_process_pending_events(dwc);
1376fc8bb91bSFelipe Balbi 		break;
1377689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1378fc8bb91bSFelipe Balbi 	default:
1379fc8bb91bSFelipe Balbi 		/* do nothing */
1380fc8bb91bSFelipe Balbi 		break;
1381fc8bb91bSFelipe Balbi 	}
1382fc8bb91bSFelipe Balbi 
1383fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
1384fc8bb91bSFelipe Balbi 
1385fc8bb91bSFelipe Balbi 	return 0;
1386fc8bb91bSFelipe Balbi }
1387fc8bb91bSFelipe Balbi 
1388fc8bb91bSFelipe Balbi static int dwc3_runtime_idle(struct device *dev)
1389fc8bb91bSFelipe Balbi {
1390fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1391fc8bb91bSFelipe Balbi 
1392689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1393689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1394fc8bb91bSFelipe Balbi 		if (dwc3_runtime_checks(dwc))
1395fc8bb91bSFelipe Balbi 			return -EBUSY;
1396fc8bb91bSFelipe Balbi 		break;
1397689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1398fc8bb91bSFelipe Balbi 	default:
1399fc8bb91bSFelipe Balbi 		/* do nothing */
1400fc8bb91bSFelipe Balbi 		break;
1401fc8bb91bSFelipe Balbi 	}
1402fc8bb91bSFelipe Balbi 
1403fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
1404fc8bb91bSFelipe Balbi 	pm_runtime_autosuspend(dev);
1405fc8bb91bSFelipe Balbi 
1406fc8bb91bSFelipe Balbi 	return 0;
1407fc8bb91bSFelipe Balbi }
1408fc8bb91bSFelipe Balbi #endif /* CONFIG_PM */
1409fc8bb91bSFelipe Balbi 
1410fc8bb91bSFelipe Balbi #ifdef CONFIG_PM_SLEEP
1411fc8bb91bSFelipe Balbi static int dwc3_suspend(struct device *dev)
1412fc8bb91bSFelipe Balbi {
1413fc8bb91bSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
1414fc8bb91bSFelipe Balbi 	int		ret;
1415fc8bb91bSFelipe Balbi 
1416fc8bb91bSFelipe Balbi 	ret = dwc3_suspend_common(dwc);
1417fc8bb91bSFelipe Balbi 	if (ret)
1418fc8bb91bSFelipe Balbi 		return ret;
1419fc8bb91bSFelipe Balbi 
14206344475fSSekhar Nori 	pinctrl_pm_select_sleep_state(dev);
14216344475fSSekhar Nori 
14227415f17cSFelipe Balbi 	return 0;
14237415f17cSFelipe Balbi }
14247415f17cSFelipe Balbi 
14257415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
14267415f17cSFelipe Balbi {
14277415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
142857303488SKishon Vijay Abraham I 	int		ret;
14297415f17cSFelipe Balbi 
14306344475fSSekhar Nori 	pinctrl_pm_select_default_state(dev);
14316344475fSSekhar Nori 
1432fc8bb91bSFelipe Balbi 	ret = dwc3_resume_common(dwc);
143351f5d49aSFelipe Balbi 	if (ret)
14345c4ad318SFelipe Balbi 		return ret;
14355c4ad318SFelipe Balbi 
14367415f17cSFelipe Balbi 	pm_runtime_disable(dev);
14377415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
14387415f17cSFelipe Balbi 	pm_runtime_enable(dev);
14397415f17cSFelipe Balbi 
14407415f17cSFelipe Balbi 	return 0;
14417415f17cSFelipe Balbi }
14427f370ed0SFelipe Balbi #endif /* CONFIG_PM_SLEEP */
14437415f17cSFelipe Balbi 
14447415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
14457415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
1446fc8bb91bSFelipe Balbi 	SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
1447fc8bb91bSFelipe Balbi 			dwc3_runtime_idle)
14487415f17cSFelipe Balbi };
14497415f17cSFelipe Balbi 
14505088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
14515088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
14525088b6f5SKishon Vijay Abraham I 	{
145322a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
145422a5aa17SFelipe Balbi 	},
145522a5aa17SFelipe Balbi 	{
14565088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
14575088b6f5SKishon Vijay Abraham I 	},
14585088b6f5SKishon Vijay Abraham I 	{ },
14595088b6f5SKishon Vijay Abraham I };
14605088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
14615088b6f5SKishon Vijay Abraham I #endif
14625088b6f5SKishon Vijay Abraham I 
1463404905a6SHeikki Krogerus #ifdef CONFIG_ACPI
1464404905a6SHeikki Krogerus 
1465404905a6SHeikki Krogerus #define ACPI_ID_INTEL_BSW	"808622B7"
1466404905a6SHeikki Krogerus 
1467404905a6SHeikki Krogerus static const struct acpi_device_id dwc3_acpi_match[] = {
1468404905a6SHeikki Krogerus 	{ ACPI_ID_INTEL_BSW, 0 },
1469404905a6SHeikki Krogerus 	{ },
1470404905a6SHeikki Krogerus };
1471404905a6SHeikki Krogerus MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
1472404905a6SHeikki Krogerus #endif
1473404905a6SHeikki Krogerus 
147472246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
147572246da4SFelipe Balbi 	.probe		= dwc3_probe,
14767690417dSBill Pemberton 	.remove		= dwc3_remove,
147772246da4SFelipe Balbi 	.driver		= {
147872246da4SFelipe Balbi 		.name	= "dwc3",
14795088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
1480404905a6SHeikki Krogerus 		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
14817f370ed0SFelipe Balbi 		.pm	= &dwc3_dev_pm_ops,
148272246da4SFelipe Balbi 	},
148372246da4SFelipe Balbi };
148472246da4SFelipe Balbi 
1485b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
1486b1116dccSTobias Klauser 
14877ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
148872246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
14895945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
149072246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
1491