xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision e3dbb657)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2cbdc0f54SMauro Carvalho Chehab /*
372246da4SFelipe Balbi  * core.c - DesignWare USB3 DRD Controller Core file
472246da4SFelipe Balbi  *
510623b87SAlexander A. Klimov  * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://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 
11fe8abf33SMasahiro Yamada #include <linux/clk.h>
12fa0ea13eSFelipe Balbi #include <linux/version.h>
13a72e658bSFelipe Balbi #include <linux/module.h>
1472246da4SFelipe Balbi #include <linux/kernel.h>
1572246da4SFelipe Balbi #include <linux/slab.h>
1672246da4SFelipe Balbi #include <linux/spinlock.h>
1772246da4SFelipe Balbi #include <linux/platform_device.h>
1872246da4SFelipe Balbi #include <linux/pm_runtime.h>
1972246da4SFelipe Balbi #include <linux/interrupt.h>
2072246da4SFelipe Balbi #include <linux/ioport.h>
2172246da4SFelipe Balbi #include <linux/io.h>
2272246da4SFelipe Balbi #include <linux/list.h>
2372246da4SFelipe Balbi #include <linux/delay.h>
2472246da4SFelipe Balbi #include <linux/dma-mapping.h>
25457e84b6SFelipe Balbi #include <linux/of.h>
26d182c2e1SAndrey Smirnov #include <linux/of_graph.h>
27404905a6SHeikki Krogerus #include <linux/acpi.h>
286344475fSSekhar Nori #include <linux/pinctrl/consumer.h>
29fe8abf33SMasahiro Yamada #include <linux/reset.h>
307bee3188SBalaji Prakash J #include <linux/bitfield.h>
3172246da4SFelipe Balbi 
3272246da4SFelipe Balbi #include <linux/usb/ch9.h>
3372246da4SFelipe Balbi #include <linux/usb/gadget.h>
34f7e846f0SFelipe Balbi #include <linux/usb/of.h>
35a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
3672246da4SFelipe Balbi 
3772246da4SFelipe Balbi #include "core.h"
3872246da4SFelipe Balbi #include "gadget.h"
3972246da4SFelipe Balbi #include "io.h"
4072246da4SFelipe Balbi 
4172246da4SFelipe Balbi #include "debug.h"
4272246da4SFelipe Balbi 
43fc8bb91bSFelipe Balbi #define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */
448300dd23SFelipe Balbi 
459d6173e1SThinh Nguyen /**
469d6173e1SThinh Nguyen  * dwc3_get_dr_mode - Validates and sets dr_mode
479d6173e1SThinh Nguyen  * @dwc: pointer to our context structure
489d6173e1SThinh Nguyen  */
499d6173e1SThinh Nguyen static int dwc3_get_dr_mode(struct dwc3 *dwc)
509d6173e1SThinh Nguyen {
519d6173e1SThinh Nguyen 	enum usb_dr_mode mode;
529d6173e1SThinh Nguyen 	struct device *dev = dwc->dev;
539d6173e1SThinh Nguyen 	unsigned int hw_mode;
549d6173e1SThinh Nguyen 
559d6173e1SThinh Nguyen 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
569d6173e1SThinh Nguyen 		dwc->dr_mode = USB_DR_MODE_OTG;
579d6173e1SThinh Nguyen 
589d6173e1SThinh Nguyen 	mode = dwc->dr_mode;
599d6173e1SThinh Nguyen 	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
609d6173e1SThinh Nguyen 
619d6173e1SThinh Nguyen 	switch (hw_mode) {
629d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_GADGET:
639d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
649d6173e1SThinh Nguyen 			dev_err(dev,
659d6173e1SThinh Nguyen 				"Controller does not support host mode.\n");
669d6173e1SThinh Nguyen 			return -EINVAL;
679d6173e1SThinh Nguyen 		}
689d6173e1SThinh Nguyen 		mode = USB_DR_MODE_PERIPHERAL;
699d6173e1SThinh Nguyen 		break;
709d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_HOST:
719d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
729d6173e1SThinh Nguyen 			dev_err(dev,
739d6173e1SThinh Nguyen 				"Controller does not support device mode.\n");
749d6173e1SThinh Nguyen 			return -EINVAL;
759d6173e1SThinh Nguyen 		}
769d6173e1SThinh Nguyen 		mode = USB_DR_MODE_HOST;
779d6173e1SThinh Nguyen 		break;
789d6173e1SThinh Nguyen 	default:
799d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
809d6173e1SThinh Nguyen 			mode = USB_DR_MODE_HOST;
819d6173e1SThinh Nguyen 		else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
829d6173e1SThinh Nguyen 			mode = USB_DR_MODE_PERIPHERAL;
83a7700468SThinh Nguyen 
84a7700468SThinh Nguyen 		/*
8589a9cc47SThinh Nguyen 		 * DWC_usb31 and DWC_usb3 v3.30a and higher do not support OTG
8689a9cc47SThinh Nguyen 		 * mode. If the controller supports DRD but the dr_mode is not
8789a9cc47SThinh Nguyen 		 * specified or set to OTG, then set the mode to peripheral.
88a7700468SThinh Nguyen 		 */
89d182c2e1SAndrey Smirnov 		if (mode == USB_DR_MODE_OTG && !dwc->edev &&
908bb14308SThinh Nguyen 		    (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
918bb14308SThinh Nguyen 		     !device_property_read_bool(dwc->dev, "usb-role-switch")) &&
929af21dd6SThinh Nguyen 		    !DWC3_VER_IS_PRIOR(DWC3, 330A))
93a7700468SThinh Nguyen 			mode = USB_DR_MODE_PERIPHERAL;
949d6173e1SThinh Nguyen 	}
959d6173e1SThinh Nguyen 
969d6173e1SThinh Nguyen 	if (mode != dwc->dr_mode) {
979d6173e1SThinh Nguyen 		dev_warn(dev,
989d6173e1SThinh Nguyen 			 "Configuration mismatch. dr_mode forced to %s\n",
999d6173e1SThinh Nguyen 			 mode == USB_DR_MODE_HOST ? "host" : "gadget");
1009d6173e1SThinh Nguyen 
1019d6173e1SThinh Nguyen 		dwc->dr_mode = mode;
1029d6173e1SThinh Nguyen 	}
1039d6173e1SThinh Nguyen 
1049d6173e1SThinh Nguyen 	return 0;
1059d6173e1SThinh Nguyen }
1069d6173e1SThinh Nguyen 
107f09cc79bSRoger Quadros void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
1083140e8cbSSebastian Andrzej Siewior {
1093140e8cbSSebastian Andrzej Siewior 	u32 reg;
1103140e8cbSSebastian Andrzej Siewior 
1113140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
1123140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
1133140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
1143140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
115c4a5153eSManu Gautam 
116c4a5153eSManu Gautam 	dwc->current_dr_role = mode;
11741ce1456SRoger Quadros }
1186b3261a2SRoger Quadros 
11941ce1456SRoger Quadros static void __dwc3_set_mode(struct work_struct *work)
12041ce1456SRoger Quadros {
12141ce1456SRoger Quadros 	struct dwc3 *dwc = work_to_dwc(work);
12241ce1456SRoger Quadros 	unsigned long flags;
12341ce1456SRoger Quadros 	int ret;
124f580170fSYu Chen 	u32 reg;
12562c73bfeSSven Peter 	u32 desired_dr_role;
12641ce1456SRoger Quadros 
127f88359e1SYu Chen 	mutex_lock(&dwc->mutex);
12862c73bfeSSven Peter 	spin_lock_irqsave(&dwc->lock, flags);
12962c73bfeSSven Peter 	desired_dr_role = dwc->desired_dr_role;
13062c73bfeSSven Peter 	spin_unlock_irqrestore(&dwc->lock, flags);
131f88359e1SYu Chen 
132c2cd3452SMartin Kepplinger 	pm_runtime_get_sync(dwc->dev);
133c2cd3452SMartin Kepplinger 
134f09cc79bSRoger Quadros 	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
135f09cc79bSRoger Quadros 		dwc3_otg_update(dwc, 0);
136f09cc79bSRoger Quadros 
13762c73bfeSSven Peter 	if (!desired_dr_role)
138c2cd3452SMartin Kepplinger 		goto out;
13941ce1456SRoger Quadros 
14062c73bfeSSven Peter 	if (desired_dr_role == dwc->current_dr_role)
141c2cd3452SMartin Kepplinger 		goto out;
14241ce1456SRoger Quadros 
14362c73bfeSSven Peter 	if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
144c2cd3452SMartin Kepplinger 		goto out;
14541ce1456SRoger Quadros 
14641ce1456SRoger Quadros 	switch (dwc->current_dr_role) {
14741ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_HOST:
14841ce1456SRoger Quadros 		dwc3_host_exit(dwc);
14941ce1456SRoger Quadros 		break;
15041ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_DEVICE:
15141ce1456SRoger Quadros 		dwc3_gadget_exit(dwc);
15241ce1456SRoger Quadros 		dwc3_event_buffers_cleanup(dwc);
15341ce1456SRoger Quadros 		break;
154f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
155f09cc79bSRoger Quadros 		dwc3_otg_exit(dwc);
156f09cc79bSRoger Quadros 		spin_lock_irqsave(&dwc->lock, flags);
157f09cc79bSRoger Quadros 		dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
158f09cc79bSRoger Quadros 		spin_unlock_irqrestore(&dwc->lock, flags);
159f09cc79bSRoger Quadros 		dwc3_otg_update(dwc, 1);
160f09cc79bSRoger Quadros 		break;
16141ce1456SRoger Quadros 	default:
16241ce1456SRoger Quadros 		break;
16341ce1456SRoger Quadros 	}
16441ce1456SRoger Quadros 
16507903626SRohith Kollalsi 	/*
16607903626SRohith Kollalsi 	 * When current_dr_role is not set, there's no role switching.
16707903626SRohith Kollalsi 	 * Only perform GCTL.CoreSoftReset when there's DRD role switching.
16807903626SRohith Kollalsi 	 */
16907903626SRohith Kollalsi 	if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
17007903626SRohith Kollalsi 			DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
17162c73bfeSSven Peter 			desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
172f88359e1SYu Chen 		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
173f88359e1SYu Chen 		reg |= DWC3_GCTL_CORESOFTRESET;
174f88359e1SYu Chen 		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
175f88359e1SYu Chen 
176f88359e1SYu Chen 		/*
177f88359e1SYu Chen 		 * Wait for internal clocks to synchronized. DWC_usb31 and
178f88359e1SYu Chen 		 * DWC_usb32 may need at least 50ms (less for DWC_usb3). To
179f88359e1SYu Chen 		 * keep it consistent across different IPs, let's wait up to
180f88359e1SYu Chen 		 * 100ms before clearing GCTL.CORESOFTRESET.
181f88359e1SYu Chen 		 */
182f88359e1SYu Chen 		msleep(100);
183f88359e1SYu Chen 
184f88359e1SYu Chen 		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
185f88359e1SYu Chen 		reg &= ~DWC3_GCTL_CORESOFTRESET;
186f88359e1SYu Chen 		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
187f88359e1SYu Chen 	}
188f88359e1SYu Chen 
18941ce1456SRoger Quadros 	spin_lock_irqsave(&dwc->lock, flags);
19041ce1456SRoger Quadros 
19162c73bfeSSven Peter 	dwc3_set_prtcap(dwc, desired_dr_role);
19241ce1456SRoger Quadros 
19341ce1456SRoger Quadros 	spin_unlock_irqrestore(&dwc->lock, flags);
19441ce1456SRoger Quadros 
19562c73bfeSSven Peter 	switch (desired_dr_role) {
19641ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_HOST:
19741ce1456SRoger Quadros 		ret = dwc3_host_init(dwc);
198958d1a4cSFelipe Balbi 		if (ret) {
19941ce1456SRoger Quadros 			dev_err(dwc->dev, "failed to initialize host\n");
200958d1a4cSFelipe Balbi 		} else {
201958d1a4cSFelipe Balbi 			if (dwc->usb2_phy)
202958d1a4cSFelipe Balbi 				otg_set_vbus(dwc->usb2_phy->otg, true);
203958d1a4cSFelipe Balbi 			phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
204644cbbc3SManu Gautam 			phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
205f580170fSYu Chen 			if (dwc->dis_split_quirk) {
206f580170fSYu Chen 				reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
207f580170fSYu Chen 				reg |= DWC3_GUCTL3_SPLITDISABLE;
208f580170fSYu Chen 				dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
209f580170fSYu Chen 			}
210958d1a4cSFelipe Balbi 		}
21141ce1456SRoger Quadros 		break;
21241ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_DEVICE:
213f88359e1SYu Chen 		dwc3_core_soft_reset(dwc);
214f88359e1SYu Chen 
21541ce1456SRoger Quadros 		dwc3_event_buffers_setup(dwc);
216958d1a4cSFelipe Balbi 
217958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
218958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, false);
219958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
220644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
221958d1a4cSFelipe Balbi 
22241ce1456SRoger Quadros 		ret = dwc3_gadget_init(dwc);
22341ce1456SRoger Quadros 		if (ret)
22441ce1456SRoger Quadros 			dev_err(dwc->dev, "failed to initialize peripheral\n");
22541ce1456SRoger Quadros 		break;
226f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
227f09cc79bSRoger Quadros 		dwc3_otg_init(dwc);
228f09cc79bSRoger Quadros 		dwc3_otg_update(dwc, 0);
229f09cc79bSRoger Quadros 		break;
23041ce1456SRoger Quadros 	default:
23141ce1456SRoger Quadros 		break;
23241ce1456SRoger Quadros 	}
233f09cc79bSRoger Quadros 
234c2cd3452SMartin Kepplinger out:
235c2cd3452SMartin Kepplinger 	pm_runtime_mark_last_busy(dwc->dev);
236c2cd3452SMartin Kepplinger 	pm_runtime_put_autosuspend(dwc->dev);
237f88359e1SYu Chen 	mutex_unlock(&dwc->mutex);
23841ce1456SRoger Quadros }
23941ce1456SRoger Quadros 
24041ce1456SRoger Quadros void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
24141ce1456SRoger Quadros {
24241ce1456SRoger Quadros 	unsigned long flags;
24341ce1456SRoger Quadros 
244dc336b19SLi Jun 	if (dwc->dr_mode != USB_DR_MODE_OTG)
245dc336b19SLi Jun 		return;
246dc336b19SLi Jun 
24741ce1456SRoger Quadros 	spin_lock_irqsave(&dwc->lock, flags);
24841ce1456SRoger Quadros 	dwc->desired_dr_role = mode;
24941ce1456SRoger Quadros 	spin_unlock_irqrestore(&dwc->lock, flags);
25041ce1456SRoger Quadros 
251084a804eSRoger Quadros 	queue_work(system_freezable_wq, &dwc->drd_work);
2523140e8cbSSebastian Andrzej Siewior }
2538300dd23SFelipe Balbi 
254cf6d867dSFelipe Balbi u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
255cf6d867dSFelipe Balbi {
256cf6d867dSFelipe Balbi 	struct dwc3		*dwc = dep->dwc;
257cf6d867dSFelipe Balbi 	u32			reg;
258cf6d867dSFelipe Balbi 
259cf6d867dSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
260cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_NUM(dep->number) |
261cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_TYPE(type));
262cf6d867dSFelipe Balbi 
263cf6d867dSFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
264cf6d867dSFelipe Balbi 
265cf6d867dSFelipe Balbi 	return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
266cf6d867dSFelipe Balbi }
267cf6d867dSFelipe Balbi 
26872246da4SFelipe Balbi /**
26972246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
27072246da4SFelipe Balbi  * @dwc: pointer to our context structure
27172246da4SFelipe Balbi  */
2720066472dSWesley Cheng int dwc3_core_soft_reset(struct dwc3 *dwc)
27372246da4SFelipe Balbi {
27472246da4SFelipe Balbi 	u32		reg;
275f59dcab1SFelipe Balbi 	int		retries = 1000;
27672246da4SFelipe Balbi 
277f59dcab1SFelipe Balbi 	/*
278f59dcab1SFelipe Balbi 	 * We're resetting only the device side because, if we're in host mode,
279f59dcab1SFelipe Balbi 	 * XHCI driver will reset the host block. If dwc3 was configured for
280f59dcab1SFelipe Balbi 	 * host-only mode, then we can return early.
281f59dcab1SFelipe Balbi 	 */
282c4a5153eSManu Gautam 	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
28357303488SKishon Vijay Abraham I 		return 0;
284f59dcab1SFelipe Balbi 
285f59dcab1SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
286f59dcab1SFelipe Balbi 	reg |= DWC3_DCTL_CSFTRST;
287f4fd84aeSThinh Nguyen 	reg &= ~DWC3_DCTL_RUN_STOP;
288f4fd84aeSThinh Nguyen 	dwc3_gadget_dctl_write_safe(dwc, reg);
289f59dcab1SFelipe Balbi 
2904749e0e6SThinh Nguyen 	/*
2914749e0e6SThinh Nguyen 	 * For DWC_usb31 controller 1.90a and later, the DCTL.CSFRST bit
2924749e0e6SThinh Nguyen 	 * is cleared only after all the clocks are synchronized. This can
2934749e0e6SThinh Nguyen 	 * take a little more than 50ms. Set the polling rate at 20ms
2944749e0e6SThinh Nguyen 	 * for 10 times instead.
2954749e0e6SThinh Nguyen 	 */
2969af21dd6SThinh Nguyen 	if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
2974749e0e6SThinh Nguyen 		retries = 10;
2984749e0e6SThinh Nguyen 
299f59dcab1SFelipe Balbi 	do {
300f59dcab1SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
301f59dcab1SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
302fab38333SThinh Nguyen 			goto done;
303f59dcab1SFelipe Balbi 
3049af21dd6SThinh Nguyen 		if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32))
3054749e0e6SThinh Nguyen 			msleep(20);
3064749e0e6SThinh Nguyen 		else
307f59dcab1SFelipe Balbi 			udelay(1);
308f59dcab1SFelipe Balbi 	} while (--retries);
309f59dcab1SFelipe Balbi 
310859bdc35SMayank Rana 	dev_warn(dwc->dev, "DWC3 controller soft reset failed.\n");
311f59dcab1SFelipe Balbi 	return -ETIMEDOUT;
312fab38333SThinh Nguyen 
313fab38333SThinh Nguyen done:
314fab38333SThinh Nguyen 	/*
3154749e0e6SThinh Nguyen 	 * For DWC_usb31 controller 1.80a and prior, once DCTL.CSFRST bit
3164749e0e6SThinh Nguyen 	 * is cleared, we must wait at least 50ms before accessing the PHY
3174749e0e6SThinh Nguyen 	 * domain (synchronization delay).
318fab38333SThinh Nguyen 	 */
3199af21dd6SThinh Nguyen 	if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A))
320fab38333SThinh Nguyen 		msleep(50);
321fab38333SThinh Nguyen 
322fab38333SThinh Nguyen 	return 0;
32372246da4SFelipe Balbi }
32472246da4SFelipe Balbi 
325db2be4e9SNikhil Badola /*
326db2be4e9SNikhil Badola  * dwc3_frame_length_adjustment - Adjusts frame length if required
327db2be4e9SNikhil Badola  * @dwc3: Pointer to our controller context structure
328db2be4e9SNikhil Badola  */
329bcdb3272SFelipe Balbi static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
330db2be4e9SNikhil Badola {
331db2be4e9SNikhil Badola 	u32 reg;
332db2be4e9SNikhil Badola 	u32 dft;
333db2be4e9SNikhil Badola 
3349af21dd6SThinh Nguyen 	if (DWC3_VER_IS_PRIOR(DWC3, 250A))
335db2be4e9SNikhil Badola 		return;
336db2be4e9SNikhil Badola 
337bcdb3272SFelipe Balbi 	if (dwc->fladj == 0)
338db2be4e9SNikhil Badola 		return;
339db2be4e9SNikhil Badola 
340db2be4e9SNikhil Badola 	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
341db2be4e9SNikhil Badola 	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
342a7d9874cSYinbo Zhu 	if (dft != dwc->fladj) {
343db2be4e9SNikhil Badola 		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
344bcdb3272SFelipe Balbi 		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
345db2be4e9SNikhil Badola 		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
346db2be4e9SNikhil Badola 	}
347db2be4e9SNikhil Badola }
348db2be4e9SNikhil Badola 
349c5cc74e8SHeikki Krogerus /**
3507bee3188SBalaji Prakash J  * dwc3_ref_clk_period - Reference clock period configuration
3517bee3188SBalaji Prakash J  *		Default reference clock period depends on hardware
3527bee3188SBalaji Prakash J  *		configuration. For systems with reference clock that differs
3537bee3188SBalaji Prakash J  *		from the default, this will set clock period in DWC3_GUCTL
3547bee3188SBalaji Prakash J  *		register.
3557bee3188SBalaji Prakash J  * @dwc: Pointer to our controller context structure
3567bee3188SBalaji Prakash J  */
3577bee3188SBalaji Prakash J static void dwc3_ref_clk_period(struct dwc3 *dwc)
3587bee3188SBalaji Prakash J {
3595114c3eeSSean Anderson 	unsigned long period;
360596c8785SSean Anderson 	unsigned long fladj;
361596c8785SSean Anderson 	unsigned long decr;
3625114c3eeSSean Anderson 	unsigned long rate;
3637bee3188SBalaji Prakash J 	u32 reg;
3647bee3188SBalaji Prakash J 
3655114c3eeSSean Anderson 	if (dwc->ref_clk) {
3665114c3eeSSean Anderson 		rate = clk_get_rate(dwc->ref_clk);
3675114c3eeSSean Anderson 		if (!rate)
3687bee3188SBalaji Prakash J 			return;
3695114c3eeSSean Anderson 		period = NSEC_PER_SEC / rate;
3705114c3eeSSean Anderson 	} else if (dwc->ref_clk_per) {
3715114c3eeSSean Anderson 		period = dwc->ref_clk_per;
372596c8785SSean Anderson 		rate = NSEC_PER_SEC / period;
3735114c3eeSSean Anderson 	} else {
3745114c3eeSSean Anderson 		return;
3755114c3eeSSean Anderson 	}
3767bee3188SBalaji Prakash J 
3777bee3188SBalaji Prakash J 	reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
3787bee3188SBalaji Prakash J 	reg &= ~DWC3_GUCTL_REFCLKPER_MASK;
3795114c3eeSSean Anderson 	reg |=  FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, period);
3807bee3188SBalaji Prakash J 	dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
3817bee3188SBalaji Prakash J 
382596c8785SSean Anderson 	if (DWC3_VER_IS_PRIOR(DWC3, 250A))
383596c8785SSean Anderson 		return;
384596c8785SSean Anderson 
385596c8785SSean Anderson 	/*
386596c8785SSean Anderson 	 * The calculation below is
387596c8785SSean Anderson 	 *
388596c8785SSean Anderson 	 * 125000 * (NSEC_PER_SEC / (rate * period) - 1)
389596c8785SSean Anderson 	 *
390596c8785SSean Anderson 	 * but rearranged for fixed-point arithmetic. The division must be
391596c8785SSean Anderson 	 * 64-bit because 125000 * NSEC_PER_SEC doesn't fit in 32 bits (and
392596c8785SSean Anderson 	 * neither does rate * period).
393596c8785SSean Anderson 	 *
394596c8785SSean Anderson 	 * Note that rate * period ~= NSEC_PER_SECOND, minus the number of
395596c8785SSean Anderson 	 * nanoseconds of error caused by the truncation which happened during
396596c8785SSean Anderson 	 * the division when calculating rate or period (whichever one was
397596c8785SSean Anderson 	 * derived from the other). We first calculate the relative error, then
398596c8785SSean Anderson 	 * scale it to units of 8 ppm.
399596c8785SSean Anderson 	 */
400596c8785SSean Anderson 	fladj = div64_u64(125000ULL * NSEC_PER_SEC, (u64)rate * period);
401596c8785SSean Anderson 	fladj -= 125000;
402596c8785SSean Anderson 
403596c8785SSean Anderson 	/*
404596c8785SSean Anderson 	 * The documented 240MHz constant is scaled by 2 to get PLS1 as well.
405596c8785SSean Anderson 	 */
406596c8785SSean Anderson 	decr = 480000000 / rate;
407596c8785SSean Anderson 
408596c8785SSean Anderson 	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
409596c8785SSean Anderson 	reg &= ~DWC3_GFLADJ_REFCLK_FLADJ_MASK
410596c8785SSean Anderson 	    &  ~DWC3_GFLADJ_240MHZDECR
411596c8785SSean Anderson 	    &  ~DWC3_GFLADJ_240MHZDECR_PLS1;
412596c8785SSean Anderson 	reg |= FIELD_PREP(DWC3_GFLADJ_REFCLK_FLADJ_MASK, fladj)
413596c8785SSean Anderson 	    |  FIELD_PREP(DWC3_GFLADJ_240MHZDECR, decr >> 1)
414596c8785SSean Anderson 	    |  FIELD_PREP(DWC3_GFLADJ_240MHZDECR_PLS1, decr & 1);
415a6fc2f1bSAlexander Stein 
416a6fc2f1bSAlexander Stein 	if (dwc->gfladj_refclk_lpm_sel)
417a6fc2f1bSAlexander Stein 		reg |=  DWC3_GFLADJ_REFCLK_LPM_SEL;
418a6fc2f1bSAlexander Stein 
419596c8785SSean Anderson 	dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
420596c8785SSean Anderson }
4217bee3188SBalaji Prakash J 
4227bee3188SBalaji Prakash J /**
42372246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
42472246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
42572246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
42672246da4SFelipe Balbi  */
42772246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
42872246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
42972246da4SFelipe Balbi {
430d64ff406SArnd Bergmann 	dma_free_coherent(dwc->sysdev, evt->length, evt->buf, evt->dma);
43172246da4SFelipe Balbi }
43272246da4SFelipe Balbi 
43372246da4SFelipe Balbi /**
4341d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
43572246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
43672246da4SFelipe Balbi  * @length: size of the event buffer
43772246da4SFelipe Balbi  *
4381d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
43972246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
44072246da4SFelipe Balbi  */
44167d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
442ca80ca61SKushagra Verma 		unsigned int length)
44372246da4SFelipe Balbi {
44472246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
44572246da4SFelipe Balbi 
446380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
44772246da4SFelipe Balbi 	if (!evt)
44872246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
44972246da4SFelipe Balbi 
45072246da4SFelipe Balbi 	evt->dwc	= dwc;
45172246da4SFelipe Balbi 	evt->length	= length;
452d9fa4c63SJohn Youn 	evt->cache	= devm_kzalloc(dwc->dev, length, GFP_KERNEL);
453d9fa4c63SJohn Youn 	if (!evt->cache)
454d9fa4c63SJohn Youn 		return ERR_PTR(-ENOMEM);
455d9fa4c63SJohn Youn 
456d64ff406SArnd Bergmann 	evt->buf	= dma_alloc_coherent(dwc->sysdev, length,
45772246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
458e32672f0SFelipe Balbi 	if (!evt->buf)
45972246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
46072246da4SFelipe Balbi 
46172246da4SFelipe Balbi 	return evt;
46272246da4SFelipe Balbi }
46372246da4SFelipe Balbi 
46472246da4SFelipe Balbi /**
46572246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
46672246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
46772246da4SFelipe Balbi  */
46872246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
46972246da4SFelipe Balbi {
47072246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
47172246da4SFelipe Balbi 
472696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
47364b6c8a7SAnton Tikhomirov 	if (evt)
47472246da4SFelipe Balbi 		dwc3_free_one_event_buffer(dwc, evt);
47572246da4SFelipe Balbi }
47672246da4SFelipe Balbi 
47772246da4SFelipe Balbi /**
47872246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
4791d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
48072246da4SFelipe Balbi  * @length: size of event buffer
48172246da4SFelipe Balbi  *
4821d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
48372246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
48472246da4SFelipe Balbi  */
485ca80ca61SKushagra Verma static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length)
48672246da4SFelipe Balbi {
48772246da4SFelipe Balbi 	struct dwc3_event_buffer *evt;
48872246da4SFelipe Balbi 
48972246da4SFelipe Balbi 	evt = dwc3_alloc_one_event_buffer(dwc, length);
49072246da4SFelipe Balbi 	if (IS_ERR(evt)) {
49172246da4SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffer\n");
49272246da4SFelipe Balbi 		return PTR_ERR(evt);
49372246da4SFelipe Balbi 	}
494696c8b12SFelipe Balbi 	dwc->ev_buf = evt;
49572246da4SFelipe Balbi 
49672246da4SFelipe Balbi 	return 0;
49772246da4SFelipe Balbi }
49872246da4SFelipe Balbi 
49972246da4SFelipe Balbi /**
50072246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
5011d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
50272246da4SFelipe Balbi  *
50372246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
50472246da4SFelipe Balbi  */
505f09cc79bSRoger Quadros int dwc3_event_buffers_setup(struct dwc3 *dwc)
50672246da4SFelipe Balbi {
50772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
50872246da4SFelipe Balbi 
509696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
5107acd85e0SPaul Zimmerman 	evt->lpos = 0;
511660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
51272246da4SFelipe Balbi 			lower_32_bits(evt->dma));
513660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
51472246da4SFelipe Balbi 			upper_32_bits(evt->dma));
515660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
51668d6a01bSFelipe Balbi 			DWC3_GEVNTSIZ_SIZE(evt->length));
517660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
51872246da4SFelipe Balbi 
51972246da4SFelipe Balbi 	return 0;
52072246da4SFelipe Balbi }
52172246da4SFelipe Balbi 
522f09cc79bSRoger Quadros void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
52372246da4SFelipe Balbi {
52472246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
52572246da4SFelipe Balbi 
526696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
5277acd85e0SPaul Zimmerman 
5287acd85e0SPaul Zimmerman 	evt->lpos = 0;
5297acd85e0SPaul Zimmerman 
530660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
531660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
532660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
53368d6a01bSFelipe Balbi 			| DWC3_GEVNTSIZ_SIZE(0));
534660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
53572246da4SFelipe Balbi }
53672246da4SFelipe Balbi 
537789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
538789451f6SFelipe Balbi {
539789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
540789451f6SFelipe Balbi 
54147d3946eSBryan O'Donoghue 	dwc->num_eps = DWC3_NUM_EPS(parms);
542789451f6SFelipe Balbi }
543789451f6SFelipe Balbi 
54441ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
54526ceca97SFelipe Balbi {
54626ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
54726ceca97SFelipe Balbi 
54826ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
54926ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
55026ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
55126ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
55226ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
55326ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
55426ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
55526ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
55626ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
55716710380SThinh Nguyen 
55816710380SThinh Nguyen 	if (DWC3_IP_IS(DWC32))
55916710380SThinh Nguyen 		parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9);
56026ceca97SFelipe Balbi }
56126ceca97SFelipe Balbi 
56298112041SRoger Quadros static int dwc3_core_ulpi_init(struct dwc3 *dwc)
56398112041SRoger Quadros {
56498112041SRoger Quadros 	int intf;
56598112041SRoger Quadros 	int ret = 0;
56698112041SRoger Quadros 
56798112041SRoger Quadros 	intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3);
56898112041SRoger Quadros 
56998112041SRoger Quadros 	if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI ||
57098112041SRoger Quadros 	    (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI &&
57198112041SRoger Quadros 	     dwc->hsphy_interface &&
57298112041SRoger Quadros 	     !strncmp(dwc->hsphy_interface, "ulpi", 4)))
57398112041SRoger Quadros 		ret = dwc3_ulpi_init(dwc);
57498112041SRoger Quadros 
57598112041SRoger Quadros 	return ret;
57698112041SRoger Quadros }
57798112041SRoger Quadros 
57872246da4SFelipe Balbi /**
579b5a65c40SHuang Rui  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
580b5a65c40SHuang Rui  * @dwc: Pointer to our controller context structure
58188bc9d19SHeikki Krogerus  *
58288bc9d19SHeikki Krogerus  * Returns 0 on success. The USB PHY interfaces are configured but not
58388bc9d19SHeikki Krogerus  * initialized. The PHY interfaces and the PHYs get initialized together with
58488bc9d19SHeikki Krogerus  * the core in dwc3_core_init.
585b5a65c40SHuang Rui  */
58688bc9d19SHeikki Krogerus static int dwc3_phy_setup(struct dwc3 *dwc)
587b5a65c40SHuang Rui {
5889ba3aca8SThinh Nguyen 	unsigned int hw_mode;
589b5a65c40SHuang Rui 	u32 reg;
590b5a65c40SHuang Rui 
5919ba3aca8SThinh Nguyen 	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
5929ba3aca8SThinh Nguyen 
593b5a65c40SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
594b5a65c40SHuang Rui 
5952164a476SHuang Rui 	/*
5961966b865SFelipe Balbi 	 * Make sure UX_EXIT_PX is cleared as that causes issues with some
5971966b865SFelipe Balbi 	 * PHYs. Also, this bit is not supposed to be used in normal operation.
5981966b865SFelipe Balbi 	 */
5991966b865SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
6001966b865SFelipe Balbi 
6011966b865SFelipe Balbi 	/*
6022164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
6032164a476SHuang Rui 	 * to '0' during coreConsultant configuration. So default value
6042164a476SHuang Rui 	 * will be '0' when the core is reset. Application needs to set it
6052164a476SHuang Rui 	 * to '1' after the core initialization is completed.
6062164a476SHuang Rui 	 */
6079af21dd6SThinh Nguyen 	if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
6082164a476SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
6092164a476SHuang Rui 
6109ba3aca8SThinh Nguyen 	/*
6119ba3aca8SThinh Nguyen 	 * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
6129ba3aca8SThinh Nguyen 	 * power-on reset, and it can be set after core initialization, which is
6139ba3aca8SThinh Nguyen 	 * after device soft-reset during initialization.
6149ba3aca8SThinh Nguyen 	 */
6159ba3aca8SThinh Nguyen 	if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
6169ba3aca8SThinh Nguyen 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
6179ba3aca8SThinh Nguyen 
618b5a65c40SHuang Rui 	if (dwc->u2ss_inp3_quirk)
619b5a65c40SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
620b5a65c40SHuang Rui 
621e58dd357SRajesh Bhagat 	if (dwc->dis_rxdet_inp3_quirk)
622e58dd357SRajesh Bhagat 		reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
623e58dd357SRajesh Bhagat 
624df31f5b3SHuang Rui 	if (dwc->req_p1p2p3_quirk)
625df31f5b3SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
626df31f5b3SHuang Rui 
627a2a1d0f5SHuang Rui 	if (dwc->del_p1p2p3_quirk)
628a2a1d0f5SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
629a2a1d0f5SHuang Rui 
63041c06ffdSHuang Rui 	if (dwc->del_phy_power_chg_quirk)
63141c06ffdSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
63241c06ffdSHuang Rui 
633fb67afcaSHuang Rui 	if (dwc->lfps_filter_quirk)
634fb67afcaSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
635fb67afcaSHuang Rui 
63614f4ac53SHuang Rui 	if (dwc->rx_detect_poll_quirk)
63714f4ac53SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
63814f4ac53SHuang Rui 
6396b6a0c9aSHuang Rui 	if (dwc->tx_de_emphasis_quirk)
6406b6a0c9aSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
6416b6a0c9aSHuang Rui 
642cd72f890SFelipe Balbi 	if (dwc->dis_u3_susphy_quirk)
64359acfa20SHuang Rui 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
64459acfa20SHuang Rui 
64500fe081dSWilliam Wu 	if (dwc->dis_del_phy_power_chg_quirk)
64600fe081dSWilliam Wu 		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
64700fe081dSWilliam Wu 
648b5a65c40SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
649b5a65c40SHuang Rui 
6502164a476SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
6512164a476SHuang Rui 
6523e10a2ceSHeikki Krogerus 	/* Select the HS PHY interface */
6533e10a2ceSHeikki Krogerus 	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
6543e10a2ceSHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
65543cacb03SFelipe Balbi 		if (dwc->hsphy_interface &&
65643cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
6573e10a2ceSHeikki Krogerus 			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
65888bc9d19SHeikki Krogerus 			break;
65943cacb03SFelipe Balbi 		} else if (dwc->hsphy_interface &&
66043cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
6613e10a2ceSHeikki Krogerus 			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
66288bc9d19SHeikki Krogerus 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
6633e10a2ceSHeikki Krogerus 		} else {
66488bc9d19SHeikki Krogerus 			/* Relying on default value. */
66588bc9d19SHeikki Krogerus 			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
6663e10a2ceSHeikki Krogerus 				break;
6673e10a2ceSHeikki Krogerus 		}
668df561f66SGustavo A. R. Silva 		fallthrough;
66988bc9d19SHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
6703e10a2ceSHeikki Krogerus 	default:
6713e10a2ceSHeikki Krogerus 		break;
6723e10a2ceSHeikki Krogerus 	}
6733e10a2ceSHeikki Krogerus 
67432f2ed86SWilliam Wu 	switch (dwc->hsphy_mode) {
67532f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMI:
67632f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
67732f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
67832f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
67932f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
68032f2ed86SWilliam Wu 		break;
68132f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMIW:
68232f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
68332f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
68432f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
68532f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
68632f2ed86SWilliam Wu 		break;
68732f2ed86SWilliam Wu 	default:
68832f2ed86SWilliam Wu 		break;
68932f2ed86SWilliam Wu 	}
69032f2ed86SWilliam Wu 
6912164a476SHuang Rui 	/*
6922164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
6932164a476SHuang Rui 	 * '0' during coreConsultant configuration. So default value will
6942164a476SHuang Rui 	 * be '0' when the core is reset. Application needs to set it to
6952164a476SHuang Rui 	 * '1' after the core initialization is completed.
6962164a476SHuang Rui 	 */
6979af21dd6SThinh Nguyen 	if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
6982164a476SHuang Rui 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
6992164a476SHuang Rui 
7009ba3aca8SThinh Nguyen 	/*
7019ba3aca8SThinh Nguyen 	 * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
7029ba3aca8SThinh Nguyen 	 * power-on reset, and it can be set after core initialization, which is
7039ba3aca8SThinh Nguyen 	 * after device soft-reset during initialization.
7049ba3aca8SThinh Nguyen 	 */
7059ba3aca8SThinh Nguyen 	if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
7069ba3aca8SThinh Nguyen 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
7079ba3aca8SThinh Nguyen 
708cd72f890SFelipe Balbi 	if (dwc->dis_u2_susphy_quirk)
7090effe0a3SHuang Rui 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
7100effe0a3SHuang Rui 
711ec791d14SJohn Youn 	if (dwc->dis_enblslpm_quirk)
712ec791d14SJohn Youn 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
713eafeacf1SThinh Nguyen 	else
714eafeacf1SThinh Nguyen 		reg |= DWC3_GUSB2PHYCFG_ENBLSLPM;
715ec791d14SJohn Youn 
716a6fc2f1bSAlexander Stein 	if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel)
71716199f33SWilliam Wu 		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
71816199f33SWilliam Wu 
719b84ba26cSPiyush Mehta 	/*
720b84ba26cSPiyush Mehta 	 * Some ULPI USB PHY does not support internal VBUS supply, to drive
721b84ba26cSPiyush Mehta 	 * the CPEN pin requires the configuration of the ULPI DRVVBUSEXTERNAL
722b84ba26cSPiyush Mehta 	 * bit of OTG_CTRL register. Controller configures the USB2 PHY
723b84ba26cSPiyush Mehta 	 * ULPIEXTVBUSDRV bit[17] of the GUSB2PHYCFG register to drive vBus
724b84ba26cSPiyush Mehta 	 * with an external supply.
725b84ba26cSPiyush Mehta 	 */
726b84ba26cSPiyush Mehta 	if (dwc->ulpi_ext_vbus_drv)
727b84ba26cSPiyush Mehta 		reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV;
728b84ba26cSPiyush Mehta 
7292164a476SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
73088bc9d19SHeikki Krogerus 
73188bc9d19SHeikki Krogerus 	return 0;
732b5a65c40SHuang Rui }
733b5a65c40SHuang Rui 
7341d72fab4SJohan Hovold static int dwc3_phy_init(struct dwc3 *dwc)
7351d72fab4SJohan Hovold {
7361d72fab4SJohan Hovold 	int ret;
7371d72fab4SJohan Hovold 
7381d72fab4SJohan Hovold 	usb_phy_init(dwc->usb2_phy);
7391d72fab4SJohan Hovold 	usb_phy_init(dwc->usb3_phy);
7401d72fab4SJohan Hovold 
7411d72fab4SJohan Hovold 	ret = phy_init(dwc->usb2_generic_phy);
7421d72fab4SJohan Hovold 	if (ret < 0)
7431d72fab4SJohan Hovold 		goto err_shutdown_usb3_phy;
7441d72fab4SJohan Hovold 
7451d72fab4SJohan Hovold 	ret = phy_init(dwc->usb3_generic_phy);
7461d72fab4SJohan Hovold 	if (ret < 0)
7471d72fab4SJohan Hovold 		goto err_exit_usb2_phy;
7481d72fab4SJohan Hovold 
7491d72fab4SJohan Hovold 	return 0;
7501d72fab4SJohan Hovold 
7511d72fab4SJohan Hovold err_exit_usb2_phy:
7521d72fab4SJohan Hovold 	phy_exit(dwc->usb2_generic_phy);
7531d72fab4SJohan Hovold err_shutdown_usb3_phy:
7541d72fab4SJohan Hovold 	usb_phy_shutdown(dwc->usb3_phy);
7551d72fab4SJohan Hovold 	usb_phy_shutdown(dwc->usb2_phy);
7561d72fab4SJohan Hovold 
7571d72fab4SJohan Hovold 	return ret;
7581d72fab4SJohan Hovold }
7591d72fab4SJohan Hovold 
7601d72fab4SJohan Hovold static void dwc3_phy_exit(struct dwc3 *dwc)
7611d72fab4SJohan Hovold {
7621d72fab4SJohan Hovold 	phy_exit(dwc->usb3_generic_phy);
7631d72fab4SJohan Hovold 	phy_exit(dwc->usb2_generic_phy);
7641d72fab4SJohan Hovold 
7651d72fab4SJohan Hovold 	usb_phy_shutdown(dwc->usb3_phy);
7661d72fab4SJohan Hovold 	usb_phy_shutdown(dwc->usb2_phy);
7671d72fab4SJohan Hovold }
7681d72fab4SJohan Hovold 
7691d72fab4SJohan Hovold static int dwc3_phy_power_on(struct dwc3 *dwc)
7701d72fab4SJohan Hovold {
7711d72fab4SJohan Hovold 	int ret;
7721d72fab4SJohan Hovold 
7731d72fab4SJohan Hovold 	usb_phy_set_suspend(dwc->usb2_phy, 0);
7741d72fab4SJohan Hovold 	usb_phy_set_suspend(dwc->usb3_phy, 0);
7751d72fab4SJohan Hovold 
7761d72fab4SJohan Hovold 	ret = phy_power_on(dwc->usb2_generic_phy);
7771d72fab4SJohan Hovold 	if (ret < 0)
7781d72fab4SJohan Hovold 		goto err_suspend_usb3_phy;
7791d72fab4SJohan Hovold 
7801d72fab4SJohan Hovold 	ret = phy_power_on(dwc->usb3_generic_phy);
7811d72fab4SJohan Hovold 	if (ret < 0)
7821d72fab4SJohan Hovold 		goto err_power_off_usb2_phy;
7831d72fab4SJohan Hovold 
7841d72fab4SJohan Hovold 	return 0;
7851d72fab4SJohan Hovold 
7861d72fab4SJohan Hovold err_power_off_usb2_phy:
7871d72fab4SJohan Hovold 	phy_power_off(dwc->usb2_generic_phy);
7881d72fab4SJohan Hovold err_suspend_usb3_phy:
7891d72fab4SJohan Hovold 	usb_phy_set_suspend(dwc->usb3_phy, 1);
7901d72fab4SJohan Hovold 	usb_phy_set_suspend(dwc->usb2_phy, 1);
7911d72fab4SJohan Hovold 
7921d72fab4SJohan Hovold 	return ret;
7931d72fab4SJohan Hovold }
7941d72fab4SJohan Hovold 
7951d72fab4SJohan Hovold static void dwc3_phy_power_off(struct dwc3 *dwc)
7961d72fab4SJohan Hovold {
7971d72fab4SJohan Hovold 	phy_power_off(dwc->usb3_generic_phy);
7981d72fab4SJohan Hovold 	phy_power_off(dwc->usb2_generic_phy);
7991d72fab4SJohan Hovold 
8001d72fab4SJohan Hovold 	usb_phy_set_suspend(dwc->usb3_phy, 1);
8011d72fab4SJohan Hovold 	usb_phy_set_suspend(dwc->usb2_phy, 1);
8021d72fab4SJohan Hovold }
8031d72fab4SJohan Hovold 
80433fb697eSSean Anderson static int dwc3_clk_enable(struct dwc3 *dwc)
80533fb697eSSean Anderson {
80633fb697eSSean Anderson 	int ret;
80733fb697eSSean Anderson 
80833fb697eSSean Anderson 	ret = clk_prepare_enable(dwc->bus_clk);
80933fb697eSSean Anderson 	if (ret)
81033fb697eSSean Anderson 		return ret;
81133fb697eSSean Anderson 
81233fb697eSSean Anderson 	ret = clk_prepare_enable(dwc->ref_clk);
81333fb697eSSean Anderson 	if (ret)
81433fb697eSSean Anderson 		goto disable_bus_clk;
81533fb697eSSean Anderson 
81633fb697eSSean Anderson 	ret = clk_prepare_enable(dwc->susp_clk);
81733fb697eSSean Anderson 	if (ret)
81833fb697eSSean Anderson 		goto disable_ref_clk;
81933fb697eSSean Anderson 
82033fb697eSSean Anderson 	return 0;
82133fb697eSSean Anderson 
82233fb697eSSean Anderson disable_ref_clk:
82333fb697eSSean Anderson 	clk_disable_unprepare(dwc->ref_clk);
82433fb697eSSean Anderson disable_bus_clk:
82533fb697eSSean Anderson 	clk_disable_unprepare(dwc->bus_clk);
82633fb697eSSean Anderson 	return ret;
82733fb697eSSean Anderson }
82833fb697eSSean Anderson 
82933fb697eSSean Anderson static void dwc3_clk_disable(struct dwc3 *dwc)
83033fb697eSSean Anderson {
83133fb697eSSean Anderson 	clk_disable_unprepare(dwc->susp_clk);
83233fb697eSSean Anderson 	clk_disable_unprepare(dwc->ref_clk);
83333fb697eSSean Anderson 	clk_disable_unprepare(dwc->bus_clk);
83433fb697eSSean Anderson }
83533fb697eSSean Anderson 
836c499ff71SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
837c499ff71SFelipe Balbi {
838c499ff71SFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
8391d72fab4SJohan Hovold 	dwc3_phy_power_off(dwc);
8401d72fab4SJohan Hovold 	dwc3_phy_exit(dwc);
84133fb697eSSean Anderson 	dwc3_clk_disable(dwc);
842fe8abf33SMasahiro Yamada 	reset_control_assert(dwc->reset);
843c499ff71SFelipe Balbi }
844c499ff71SFelipe Balbi 
8450759956fSFelipe Balbi static bool dwc3_core_is_valid(struct dwc3 *dwc)
84672246da4SFelipe Balbi {
84772246da4SFelipe Balbi 	u32 reg;
84872246da4SFelipe Balbi 
8497650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
8509af21dd6SThinh Nguyen 	dwc->ip = DWC3_GSNPS_ID(reg);
8510759956fSFelipe Balbi 
8527650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
8539af21dd6SThinh Nguyen 	if (DWC3_IP_IS(DWC3)) {
854690fb371SJohn Youn 		dwc->revision = reg;
8559af21dd6SThinh Nguyen 	} else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) {
856690fb371SJohn Youn 		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
857475d8e01SThinh Nguyen 		dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE);
858690fb371SJohn Youn 	} else {
8590759956fSFelipe Balbi 		return false;
8607650bd74SSebastian Andrzej Siewior 	}
8617650bd74SSebastian Andrzej Siewior 
8620759956fSFelipe Balbi 	return true;
8630e1e5c47SPaul Zimmerman }
8640e1e5c47SPaul Zimmerman 
865941f918eSFelipe Balbi static void dwc3_core_setup_global_control(struct dwc3 *dwc)
86672246da4SFelipe Balbi {
86772246da4SFelipe Balbi 	u32 reg;
868c499ff71SFelipe Balbi 
8694878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
8703e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
8714878a028SSebastian Andrzej Siewior 
872164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
8734878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
87432a4a135SFelipe Balbi 		/**
87532a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
87632a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
87732a4a135SFelipe Balbi 		 *
87832a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
87932a4a135SFelipe Balbi 		 * configurations.
88032a4a135SFelipe Balbi 		 *
88132a4a135SFelipe Balbi 		 * Refers to:
88232a4a135SFelipe Balbi 		 *
88332a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
88432a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
88532a4a135SFelipe Balbi 		 */
88632a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
88732a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
8889af21dd6SThinh Nguyen 				DWC3_VER_IS_WITHIN(DWC3, 210A, 250A))
88932a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
89032a4a135SFelipe Balbi 		else
8914878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
8924878a028SSebastian Andrzej Siewior 		break;
8930ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
8942eac3992SHuang Rui 		/*
8952eac3992SHuang Rui 		 * REVISIT Enabling this bit so that host-mode hibernation
8962eac3992SHuang Rui 		 * will work. Device-mode hibernation is not yet implemented.
8972eac3992SHuang Rui 		 */
8982eac3992SHuang Rui 		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
8990ffcaf37SFelipe Balbi 		break;
9004878a028SSebastian Andrzej Siewior 	default:
9015eb30cedSFelipe Balbi 		/* nothing */
9025eb30cedSFelipe Balbi 		break;
9034878a028SSebastian Andrzej Siewior 	}
9044878a028SSebastian Andrzej Siewior 
905946bd579SHuang Rui 	/* check if current dwc3 is on simulation board */
906946bd579SHuang Rui 	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
9076af19fd1SFaisal Mehmood 		dev_info(dwc->dev, "Running with FPGA optimizations\n");
908946bd579SHuang Rui 		dwc->is_fpga = true;
909946bd579SHuang Rui 	}
910946bd579SHuang Rui 
9113b81221aSHuang Rui 	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
9123b81221aSHuang Rui 			"disable_scramble cannot be used on non-FPGA builds\n");
9133b81221aSHuang Rui 
9143b81221aSHuang Rui 	if (dwc->disable_scramble_quirk && dwc->is_fpga)
9153b81221aSHuang Rui 		reg |= DWC3_GCTL_DISSCRAMBLE;
9163b81221aSHuang Rui 	else
9173b81221aSHuang Rui 		reg &= ~DWC3_GCTL_DISSCRAMBLE;
9183b81221aSHuang Rui 
9199a5b2f31SHuang Rui 	if (dwc->u2exit_lfps_quirk)
9209a5b2f31SHuang Rui 		reg |= DWC3_GCTL_U2EXIT_LFPS;
9219a5b2f31SHuang Rui 
9224878a028SSebastian Andrzej Siewior 	/*
9234878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
9241d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
9254878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
9261d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
9274878a028SSebastian Andrzej Siewior 	 */
9289af21dd6SThinh Nguyen 	if (DWC3_VER_IS_PRIOR(DWC3, 190A))
9294878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
9304878a028SSebastian Andrzej Siewior 
9314878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
932941f918eSFelipe Balbi }
9334878a028SSebastian Andrzej Siewior 
934f54edb53SFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc);
93598112041SRoger Quadros static int dwc3_core_ulpi_init(struct dwc3 *dwc);
936f54edb53SFelipe Balbi 
937d9612c2fSPengbo Mu /* set global incr burst type configuration registers */
938d9612c2fSPengbo Mu static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
939d9612c2fSPengbo Mu {
940d9612c2fSPengbo Mu 	struct device *dev = dwc->dev;
941d9612c2fSPengbo Mu 	/* incrx_mode : for INCR burst type. */
942d9612c2fSPengbo Mu 	bool incrx_mode;
943d9612c2fSPengbo Mu 	/* incrx_size : for size of INCRX burst. */
944d9612c2fSPengbo Mu 	u32 incrx_size;
945d9612c2fSPengbo Mu 	u32 *vals;
946d9612c2fSPengbo Mu 	u32 cfg;
947d9612c2fSPengbo Mu 	int ntype;
948d9612c2fSPengbo Mu 	int ret;
949d9612c2fSPengbo Mu 	int i;
950d9612c2fSPengbo Mu 
951d9612c2fSPengbo Mu 	cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
952d9612c2fSPengbo Mu 
953d9612c2fSPengbo Mu 	/*
954d9612c2fSPengbo Mu 	 * Handle property "snps,incr-burst-type-adjustment".
955d9612c2fSPengbo Mu 	 * Get the number of value from this property:
956d9612c2fSPengbo Mu 	 * result <= 0, means this property is not supported.
957d9612c2fSPengbo Mu 	 * result = 1, means INCRx burst mode supported.
958d9612c2fSPengbo Mu 	 * result > 1, means undefined length burst mode supported.
959d9612c2fSPengbo Mu 	 */
960a6e5e679SAndy Shevchenko 	ntype = device_property_count_u32(dev, "snps,incr-burst-type-adjustment");
961d9612c2fSPengbo Mu 	if (ntype <= 0)
962d9612c2fSPengbo Mu 		return;
963d9612c2fSPengbo Mu 
964d9612c2fSPengbo Mu 	vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL);
9654ea15088SKushagra Verma 	if (!vals)
966d9612c2fSPengbo Mu 		return;
967d9612c2fSPengbo Mu 
968d9612c2fSPengbo Mu 	/* Get INCR burst type, and parse it */
969d9612c2fSPengbo Mu 	ret = device_property_read_u32_array(dev,
970d9612c2fSPengbo Mu 			"snps,incr-burst-type-adjustment", vals, ntype);
971d9612c2fSPengbo Mu 	if (ret) {
97275ecb9ddSAndy Shevchenko 		kfree(vals);
973d9612c2fSPengbo Mu 		dev_err(dev, "Error to get property\n");
974d9612c2fSPengbo Mu 		return;
975d9612c2fSPengbo Mu 	}
976d9612c2fSPengbo Mu 
977d9612c2fSPengbo Mu 	incrx_size = *vals;
978d9612c2fSPengbo Mu 
979d9612c2fSPengbo Mu 	if (ntype > 1) {
980d9612c2fSPengbo Mu 		/* INCRX (undefined length) burst mode */
981d9612c2fSPengbo Mu 		incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE;
982d9612c2fSPengbo Mu 		for (i = 1; i < ntype; i++) {
983d9612c2fSPengbo Mu 			if (vals[i] > incrx_size)
984d9612c2fSPengbo Mu 				incrx_size = vals[i];
985d9612c2fSPengbo Mu 		}
986d9612c2fSPengbo Mu 	} else {
987d9612c2fSPengbo Mu 		/* INCRX burst mode */
988d9612c2fSPengbo Mu 		incrx_mode = INCRX_BURST_MODE;
989d9612c2fSPengbo Mu 	}
990d9612c2fSPengbo Mu 
99175ecb9ddSAndy Shevchenko 	kfree(vals);
99275ecb9ddSAndy Shevchenko 
993d9612c2fSPengbo Mu 	/* Enable Undefined Length INCR Burst and Enable INCRx Burst */
994d9612c2fSPengbo Mu 	cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
995d9612c2fSPengbo Mu 	if (incrx_mode)
996d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCRBRSTENA;
997d9612c2fSPengbo Mu 	switch (incrx_size) {
998d9612c2fSPengbo Mu 	case 256:
999d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA;
1000d9612c2fSPengbo Mu 		break;
1001d9612c2fSPengbo Mu 	case 128:
1002d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA;
1003d9612c2fSPengbo Mu 		break;
1004d9612c2fSPengbo Mu 	case 64:
1005d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA;
1006d9612c2fSPengbo Mu 		break;
1007d9612c2fSPengbo Mu 	case 32:
1008d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA;
1009d9612c2fSPengbo Mu 		break;
1010d9612c2fSPengbo Mu 	case 16:
1011d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA;
1012d9612c2fSPengbo Mu 		break;
1013d9612c2fSPengbo Mu 	case 8:
1014d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA;
1015d9612c2fSPengbo Mu 		break;
1016d9612c2fSPengbo Mu 	case 4:
1017d9612c2fSPengbo Mu 		cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA;
1018d9612c2fSPengbo Mu 		break;
1019d9612c2fSPengbo Mu 	case 1:
1020d9612c2fSPengbo Mu 		break;
1021d9612c2fSPengbo Mu 	default:
1022d9612c2fSPengbo Mu 		dev_err(dev, "Invalid property\n");
1023d9612c2fSPengbo Mu 		break;
1024d9612c2fSPengbo Mu 	}
1025d9612c2fSPengbo Mu 
1026d9612c2fSPengbo Mu 	dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
1027d9612c2fSPengbo Mu }
1028d9612c2fSPengbo Mu 
10293497b9a5SLi Jun static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc)
10303497b9a5SLi Jun {
10313497b9a5SLi Jun 	u32 scale;
10323497b9a5SLi Jun 	u32 reg;
10333497b9a5SLi Jun 
10343497b9a5SLi Jun 	if (!dwc->susp_clk)
10353497b9a5SLi Jun 		return;
10363497b9a5SLi Jun 
10373497b9a5SLi Jun 	/*
10383497b9a5SLi Jun 	 * The power down scale field specifies how many suspend_clk
10393497b9a5SLi Jun 	 * periods fit into a 16KHz clock period. When performing
10403497b9a5SLi Jun 	 * the division, round up the remainder.
10413497b9a5SLi Jun 	 *
10423497b9a5SLi Jun 	 * The power down scale value is calculated using the fastest
10433497b9a5SLi Jun 	 * frequency of the suspend_clk. If it isn't fixed (but within
10443497b9a5SLi Jun 	 * the accuracy requirement), the driver may not know the max
10453497b9a5SLi Jun 	 * rate of the suspend_clk, so only update the power down scale
10463497b9a5SLi Jun 	 * if the default is less than the calculated value from
10473497b9a5SLi Jun 	 * clk_get_rate() or if the default is questionably high
10483497b9a5SLi Jun 	 * (3x or more) to be within the requirement.
10493497b9a5SLi Jun 	 */
10503497b9a5SLi Jun 	scale = DIV_ROUND_UP(clk_get_rate(dwc->susp_clk), 16000);
10513497b9a5SLi Jun 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
10523497b9a5SLi Jun 	if ((reg & DWC3_GCTL_PWRDNSCALE_MASK) < DWC3_GCTL_PWRDNSCALE(scale) ||
10533497b9a5SLi Jun 	    (reg & DWC3_GCTL_PWRDNSCALE_MASK) > DWC3_GCTL_PWRDNSCALE(scale*3)) {
10543497b9a5SLi Jun 		reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK);
10553497b9a5SLi Jun 		reg |= DWC3_GCTL_PWRDNSCALE(scale);
10563497b9a5SLi Jun 		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
10573497b9a5SLi Jun 	}
10583497b9a5SLi Jun }
10593497b9a5SLi Jun 
1060941f918eSFelipe Balbi /**
1061941f918eSFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
1062941f918eSFelipe Balbi  * @dwc: Pointer to our controller context structure
1063941f918eSFelipe Balbi  *
1064941f918eSFelipe Balbi  * Returns 0 on success otherwise negative errno.
1065941f918eSFelipe Balbi  */
1066941f918eSFelipe Balbi static int dwc3_core_init(struct dwc3 *dwc)
1067941f918eSFelipe Balbi {
10689ba3aca8SThinh Nguyen 	unsigned int		hw_mode;
1069941f918eSFelipe Balbi 	u32			reg;
1070941f918eSFelipe Balbi 	int			ret;
1071941f918eSFelipe Balbi 
10729ba3aca8SThinh Nguyen 	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
10739ba3aca8SThinh Nguyen 
1074941f918eSFelipe Balbi 	/*
1075941f918eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
1076941f918eSFelipe Balbi 	 * out which kernel version a bug was found.
1077941f918eSFelipe Balbi 	 */
1078941f918eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
1079941f918eSFelipe Balbi 
1080941f918eSFelipe Balbi 	ret = dwc3_phy_setup(dwc);
1081941f918eSFelipe Balbi 	if (ret)
1082d2f19782SJohan Hovold 		return ret;
1083941f918eSFelipe Balbi 
108498112041SRoger Quadros 	if (!dwc->ulpi_ready) {
108598112041SRoger Quadros 		ret = dwc3_core_ulpi_init(dwc);
108663130462SFerry Toth 		if (ret) {
108763130462SFerry Toth 			if (ret == -ETIMEDOUT) {
108863130462SFerry Toth 				dwc3_core_soft_reset(dwc);
108963130462SFerry Toth 				ret = -EPROBE_DEFER;
109063130462SFerry Toth 			}
1091d2f19782SJohan Hovold 			return ret;
109263130462SFerry Toth 		}
109398112041SRoger Quadros 		dwc->ulpi_ready = true;
109498112041SRoger Quadros 	}
109598112041SRoger Quadros 
109698112041SRoger Quadros 	if (!dwc->phys_ready) {
109798112041SRoger Quadros 		ret = dwc3_core_get_phy(dwc);
109898112041SRoger Quadros 		if (ret)
1099d2f19782SJohan Hovold 			goto err_exit_ulpi;
110098112041SRoger Quadros 		dwc->phys_ready = true;
110198112041SRoger Quadros 	}
110298112041SRoger Quadros 
11031d72fab4SJohan Hovold 	ret = dwc3_phy_init(dwc);
11041d72fab4SJohan Hovold 	if (ret)
11051d72fab4SJohan Hovold 		goto err_exit_ulpi;
11068cfac9a6SLi Jun 
110798112041SRoger Quadros 	ret = dwc3_core_soft_reset(dwc);
110898112041SRoger Quadros 	if (ret)
11091d72fab4SJohan Hovold 		goto err_exit_phy;
111098112041SRoger Quadros 
11119ba3aca8SThinh Nguyen 	if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
11129af21dd6SThinh Nguyen 	    !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
11139ba3aca8SThinh Nguyen 		if (!dwc->dis_u3_susphy_quirk) {
11149ba3aca8SThinh Nguyen 			reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
11159ba3aca8SThinh Nguyen 			reg |= DWC3_GUSB3PIPECTL_SUSPHY;
11169ba3aca8SThinh Nguyen 			dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
11179ba3aca8SThinh Nguyen 		}
11189ba3aca8SThinh Nguyen 
11199ba3aca8SThinh Nguyen 		if (!dwc->dis_u2_susphy_quirk) {
11209ba3aca8SThinh Nguyen 			reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
11219ba3aca8SThinh Nguyen 			reg |= DWC3_GUSB2PHYCFG_SUSPHY;
11229ba3aca8SThinh Nguyen 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
11239ba3aca8SThinh Nguyen 		}
11249ba3aca8SThinh Nguyen 	}
11259ba3aca8SThinh Nguyen 
1126941f918eSFelipe Balbi 	dwc3_core_setup_global_control(dwc);
1127c499ff71SFelipe Balbi 	dwc3_core_num_eps(dwc);
11280ffcaf37SFelipe Balbi 
11293497b9a5SLi Jun 	/* Set power down scale of suspend_clk */
11303497b9a5SLi Jun 	dwc3_set_power_down_clk_scale(dwc);
11313497b9a5SLi Jun 
1132c499ff71SFelipe Balbi 	/* Adjust Frame Length */
1133c499ff71SFelipe Balbi 	dwc3_frame_length_adjustment(dwc);
1134c499ff71SFelipe Balbi 
11357bee3188SBalaji Prakash J 	/* Adjust Reference Clock Period */
11367bee3188SBalaji Prakash J 	dwc3_ref_clk_period(dwc);
11377bee3188SBalaji Prakash J 
1138d9612c2fSPengbo Mu 	dwc3_set_incr_burst_type(dwc);
1139d9612c2fSPengbo Mu 
11408018018dSDan Carpenter 	ret = dwc3_phy_power_on(dwc);
11411d72fab4SJohan Hovold 	if (ret)
11421d72fab4SJohan Hovold 		goto err_exit_phy;
1143c499ff71SFelipe Balbi 
1144c499ff71SFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
1145c499ff71SFelipe Balbi 	if (ret) {
1146c499ff71SFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
11471d72fab4SJohan Hovold 		goto err_power_off_phy;
1148c499ff71SFelipe Balbi 	}
1149c499ff71SFelipe Balbi 
115006281d46SJohn Youn 	/*
115106281d46SJohn Youn 	 * ENDXFER polling is available on version 3.10a and later of
115206281d46SJohn Youn 	 * the DWC_usb3 controller. It is NOT available in the
115306281d46SJohn Youn 	 * DWC_usb31 controller.
115406281d46SJohn Youn 	 */
11559af21dd6SThinh Nguyen 	if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) {
115606281d46SJohn Youn 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
115706281d46SJohn Youn 		reg |= DWC3_GUCTL2_RST_ACTBITLATER;
115806281d46SJohn Youn 		dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
115906281d46SJohn Youn 	}
116006281d46SJohn Youn 
116163d7f981SPiyush Mehta 	/*
116263d7f981SPiyush Mehta 	 * When configured in HOST mode, after issuing U3/L2 exit controller
116363d7f981SPiyush Mehta 	 * fails to send proper CRC checksum in CRC5 feild. Because of this
116463d7f981SPiyush Mehta 	 * behaviour Transaction Error is generated, resulting in reset and
116563d7f981SPiyush Mehta 	 * re-enumeration of usb device attached. All the termsel, xcvrsel,
116663d7f981SPiyush Mehta 	 * opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1
116763d7f981SPiyush Mehta 	 * will correct this problem. This option is to support certain
116863d7f981SPiyush Mehta 	 * legacy ULPI PHYs.
116963d7f981SPiyush Mehta 	 */
117063d7f981SPiyush Mehta 	if (dwc->resume_hs_terminations) {
117163d7f981SPiyush Mehta 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
117263d7f981SPiyush Mehta 		reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST;
117363d7f981SPiyush Mehta 		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
117463d7f981SPiyush Mehta 	}
117563d7f981SPiyush Mehta 
11769af21dd6SThinh Nguyen 	if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) {
11770bb39ca1SJohn Youn 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
117865db7a0cSWilliam Wu 
117965db7a0cSWilliam Wu 		/*
118065db7a0cSWilliam Wu 		 * Enable hardware control of sending remote wakeup
118165db7a0cSWilliam Wu 		 * in HS when the device is in the L1 state.
118265db7a0cSWilliam Wu 		 */
11839af21dd6SThinh Nguyen 		if (!DWC3_VER_IS_PRIOR(DWC3, 290A))
11840bb39ca1SJohn Youn 			reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
118565db7a0cSWilliam Wu 
1186843714bbSJack Pham 		/*
1187843714bbSJack Pham 		 * Decouple USB 2.0 L1 & L2 events which will allow for
1188843714bbSJack Pham 		 * gadget driver to only receive U3/L2 suspend & wakeup
1189843714bbSJack Pham 		 * events and prevent the more frequent L1 LPM transitions
1190843714bbSJack Pham 		 * from interrupting the driver.
1191843714bbSJack Pham 		 */
1192843714bbSJack Pham 		if (!DWC3_VER_IS_PRIOR(DWC3, 300A))
1193843714bbSJack Pham 			reg |= DWC3_GUCTL1_DEV_DECOUPLE_L1L2_EVT;
1194843714bbSJack Pham 
119565db7a0cSWilliam Wu 		if (dwc->dis_tx_ipgap_linecheck_quirk)
119665db7a0cSWilliam Wu 			reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
119765db7a0cSWilliam Wu 
11987ba6b09fSNeil Armstrong 		if (dwc->parkmode_disable_ss_quirk)
11997ba6b09fSNeil Armstrong 			reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
12007ba6b09fSNeil Armstrong 
1201d21a797aSStanley Chang 		if (dwc->parkmode_disable_hs_quirk)
1202d21a797aSStanley Chang 			reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS;
1203d21a797aSStanley Chang 
120462b20e6eSBin Yang 		if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) &&
120562b20e6eSBin Yang 		    (dwc->maximum_speed == USB_SPEED_HIGH ||
120662b20e6eSBin Yang 		     dwc->maximum_speed == USB_SPEED_FULL))
120762b20e6eSBin Yang 			reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK;
120862b20e6eSBin Yang 
12090bb39ca1SJohn Youn 		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
12100bb39ca1SJohn Youn 	}
12110bb39ca1SJohn Youn 
1212b138e23dSAnurag Kumar Vulisha 	if (dwc->dr_mode == USB_DR_MODE_HOST ||
1213b138e23dSAnurag Kumar Vulisha 	    dwc->dr_mode == USB_DR_MODE_OTG) {
1214b138e23dSAnurag Kumar Vulisha 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
1215b138e23dSAnurag Kumar Vulisha 
1216b138e23dSAnurag Kumar Vulisha 		/*
1217b138e23dSAnurag Kumar Vulisha 		 * Enable Auto retry Feature to make the controller operating in
1218b138e23dSAnurag Kumar Vulisha 		 * Host mode on seeing transaction errors(CRC errors or internal
1219b138e23dSAnurag Kumar Vulisha 		 * overrun scenerios) on IN transfers to reply to the device
1220b138e23dSAnurag Kumar Vulisha 		 * with a non-terminating retry ACK (i.e, an ACK transcation
1221b138e23dSAnurag Kumar Vulisha 		 * packet with Retry=1 & Nump != 0)
1222b138e23dSAnurag Kumar Vulisha 		 */
1223b138e23dSAnurag Kumar Vulisha 		reg |= DWC3_GUCTL_HSTINAUTORETRY;
1224b138e23dSAnurag Kumar Vulisha 
1225b138e23dSAnurag Kumar Vulisha 		dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
1226b138e23dSAnurag Kumar Vulisha 	}
1227b138e23dSAnurag Kumar Vulisha 
1228938a5ad1SThinh Nguyen 	/*
1229938a5ad1SThinh Nguyen 	 * Must config both number of packets and max burst settings to enable
1230938a5ad1SThinh Nguyen 	 * RX and/or TX threshold.
1231938a5ad1SThinh Nguyen 	 */
12329af21dd6SThinh Nguyen 	if (!DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) {
1233938a5ad1SThinh Nguyen 		u8 rx_thr_num = dwc->rx_thr_num_pkt_prd;
1234938a5ad1SThinh Nguyen 		u8 rx_maxburst = dwc->rx_max_burst_prd;
1235938a5ad1SThinh Nguyen 		u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
1236938a5ad1SThinh Nguyen 		u8 tx_maxburst = dwc->tx_max_burst_prd;
1237938a5ad1SThinh Nguyen 
1238938a5ad1SThinh Nguyen 		if (rx_thr_num && rx_maxburst) {
1239938a5ad1SThinh Nguyen 			reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
1240938a5ad1SThinh Nguyen 			reg |= DWC31_RXTHRNUMPKTSEL_PRD;
1241938a5ad1SThinh Nguyen 
1242938a5ad1SThinh Nguyen 			reg &= ~DWC31_RXTHRNUMPKT_PRD(~0);
1243938a5ad1SThinh Nguyen 			reg |= DWC31_RXTHRNUMPKT_PRD(rx_thr_num);
1244938a5ad1SThinh Nguyen 
1245938a5ad1SThinh Nguyen 			reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0);
1246938a5ad1SThinh Nguyen 			reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst);
1247938a5ad1SThinh Nguyen 
1248938a5ad1SThinh Nguyen 			dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
1249938a5ad1SThinh Nguyen 		}
1250938a5ad1SThinh Nguyen 
1251938a5ad1SThinh Nguyen 		if (tx_thr_num && tx_maxburst) {
1252938a5ad1SThinh Nguyen 			reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
1253938a5ad1SThinh Nguyen 			reg |= DWC31_TXTHRNUMPKTSEL_PRD;
1254938a5ad1SThinh Nguyen 
1255938a5ad1SThinh Nguyen 			reg &= ~DWC31_TXTHRNUMPKT_PRD(~0);
1256938a5ad1SThinh Nguyen 			reg |= DWC31_TXTHRNUMPKT_PRD(tx_thr_num);
1257938a5ad1SThinh Nguyen 
1258938a5ad1SThinh Nguyen 			reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0);
1259938a5ad1SThinh Nguyen 			reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst);
1260938a5ad1SThinh Nguyen 
1261938a5ad1SThinh Nguyen 			dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
1262938a5ad1SThinh Nguyen 		}
1263938a5ad1SThinh Nguyen 	}
1264938a5ad1SThinh Nguyen 
126572246da4SFelipe Balbi 	return 0;
126672246da4SFelipe Balbi 
12671d72fab4SJohan Hovold err_power_off_phy:
12681d72fab4SJohan Hovold 	dwc3_phy_power_off(dwc);
12691d72fab4SJohan Hovold err_exit_phy:
12701d72fab4SJohan Hovold 	dwc3_phy_exit(dwc);
1271d2f19782SJohan Hovold err_exit_ulpi:
127298112041SRoger Quadros 	dwc3_ulpi_exit(dwc);
127398112041SRoger Quadros 
127472246da4SFelipe Balbi 	return ret;
127572246da4SFelipe Balbi }
127672246da4SFelipe Balbi 
12773c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
127872246da4SFelipe Balbi {
12793c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
1280941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
12813c9f94acSFelipe Balbi 	int ret;
128272246da4SFelipe Balbi 
12835088b6f5SKishon Vijay Abraham I 	if (node) {
12845088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
12855088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
1286bb674907SFelipe Balbi 	} else {
1287bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
1288bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
12895088b6f5SKishon Vijay Abraham I 	}
12905088b6f5SKishon Vijay Abraham I 
1291d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
1292d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
1293d090c7a2SKushagra Verma 		if (ret == -ENXIO || ret == -ENODEV)
1294122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
1295d090c7a2SKushagra Verma 		else
12960c0a20f6SAndy Shevchenko 			return dev_err_probe(dev, ret, "no usb2 phy configured\n");
1297122f06e6SKishon Vijay Abraham I 	}
129851e1e7bcSFelipe Balbi 
1299d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
1300315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
1301d090c7a2SKushagra Verma 		if (ret == -ENXIO || ret == -ENODEV)
1302122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
1303d090c7a2SKushagra Verma 		else
13040c0a20f6SAndy Shevchenko 			return dev_err_probe(dev, ret, "no usb3 phy configured\n");
1305122f06e6SKishon Vijay Abraham I 	}
130651e1e7bcSFelipe Balbi 
130757303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
130857303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
130957303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
1310fb119dcbSThinh Nguyen 		if (ret == -ENOSYS || ret == -ENODEV)
131157303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
1312d090c7a2SKushagra Verma 		else
13130c0a20f6SAndy Shevchenko 			return dev_err_probe(dev, ret, "no usb2 phy configured\n");
131457303488SKishon Vijay Abraham I 	}
131557303488SKishon Vijay Abraham I 
131657303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
131757303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
131857303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
1319fb119dcbSThinh Nguyen 		if (ret == -ENOSYS || ret == -ENODEV)
132057303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
1321d090c7a2SKushagra Verma 		else
13220c0a20f6SAndy Shevchenko 			return dev_err_probe(dev, ret, "no usb3 phy configured\n");
132357303488SKishon Vijay Abraham I 	}
132457303488SKishon Vijay Abraham I 
13253c9f94acSFelipe Balbi 	return 0;
13263c9f94acSFelipe Balbi }
13273c9f94acSFelipe Balbi 
13285f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
13295f94adfeSFelipe Balbi {
13305f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
13315f94adfeSFelipe Balbi 	int ret;
13325f94adfeSFelipe Balbi 
13335f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
13345f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
133541ce1456SRoger Quadros 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
1336958d1a4cSFelipe Balbi 
1337958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
1338958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, false);
1339958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
1340644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
1341958d1a4cSFelipe Balbi 
13425f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
13430c0a20f6SAndy Shevchenko 		if (ret)
13440c0a20f6SAndy Shevchenko 			return dev_err_probe(dev, ret, "failed to initialize gadget\n");
13455f94adfeSFelipe Balbi 		break;
13465f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
134741ce1456SRoger Quadros 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
1348958d1a4cSFelipe Balbi 
1349958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
1350958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, true);
1351958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
1352644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
1353958d1a4cSFelipe Balbi 
13545f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
13550c0a20f6SAndy Shevchenko 		if (ret)
13560c0a20f6SAndy Shevchenko 			return dev_err_probe(dev, ret, "failed to initialize host\n");
13575f94adfeSFelipe Balbi 		break;
13585f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
135941ce1456SRoger Quadros 		INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
13609840354fSRoger Quadros 		ret = dwc3_drd_init(dwc);
13610c0a20f6SAndy Shevchenko 		if (ret)
13620c0a20f6SAndy Shevchenko 			return dev_err_probe(dev, ret, "failed to initialize dual-role\n");
13635f94adfeSFelipe Balbi 		break;
13645f94adfeSFelipe Balbi 	default:
13655f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
13665f94adfeSFelipe Balbi 		return -EINVAL;
13675f94adfeSFelipe Balbi 	}
13685f94adfeSFelipe Balbi 
13695f94adfeSFelipe Balbi 	return 0;
13705f94adfeSFelipe Balbi }
13715f94adfeSFelipe Balbi 
13725f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
13735f94adfeSFelipe Balbi {
13745f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
13755f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
13765f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
13775f94adfeSFelipe Balbi 		break;
13785f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
13795f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
13805f94adfeSFelipe Balbi 		break;
13815f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
13829840354fSRoger Quadros 		dwc3_drd_exit(dwc);
13835f94adfeSFelipe Balbi 		break;
13845f94adfeSFelipe Balbi 	default:
13855f94adfeSFelipe Balbi 		/* do nothing */
13865f94adfeSFelipe Balbi 		break;
13875f94adfeSFelipe Balbi 	}
138809ed259fSBin Liu 
138909ed259fSBin Liu 	/* de-assert DRVVBUS for HOST and OTG mode */
139009ed259fSBin Liu 	dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
13915f94adfeSFelipe Balbi }
13925f94adfeSFelipe Balbi 
1393c5ac6116SFelipe Balbi static void dwc3_get_properties(struct dwc3 *dwc)
13943c9f94acSFelipe Balbi {
1395c5ac6116SFelipe Balbi 	struct device		*dev = dwc->dev;
139680caf7d2SHuang Rui 	u8			lpm_nyet_threshold;
13976b6a0c9aSHuang Rui 	u8			tx_de_emphasis;
1398460d098cSHuang Rui 	u8			hird_threshold;
1399f28ad906SThinh Nguyen 	u8			rx_thr_num_pkt_prd = 0;
1400f28ad906SThinh Nguyen 	u8			rx_max_burst_prd = 0;
1401f28ad906SThinh Nguyen 	u8			tx_thr_num_pkt_prd = 0;
1402f28ad906SThinh Nguyen 	u8			tx_max_burst_prd = 0;
14039f607a30SWesley Cheng 	u8			tx_fifo_resize_max_num;
14046f0764b5SRay Chi 	const char		*usb_psy_name;
14056f0764b5SRay Chi 	int			ret;
14063c9f94acSFelipe Balbi 
140780caf7d2SHuang Rui 	/* default to highest possible threshold */
14088d791929SThinh Nguyen 	lpm_nyet_threshold = 0xf;
140980caf7d2SHuang Rui 
14106b6a0c9aSHuang Rui 	/* default to -3.5dB de-emphasis */
14116b6a0c9aSHuang Rui 	tx_de_emphasis = 1;
14126b6a0c9aSHuang Rui 
1413460d098cSHuang Rui 	/*
1414460d098cSHuang Rui 	 * default to assert utmi_sleep_n and use maximum allowed HIRD
1415460d098cSHuang Rui 	 * threshold value of 0b1100
1416460d098cSHuang Rui 	 */
1417460d098cSHuang Rui 	hird_threshold = 12;
1418460d098cSHuang Rui 
14199f607a30SWesley Cheng 	/*
14209f607a30SWesley Cheng 	 * default to a TXFIFO size large enough to fit 6 max packets.  This
14219f607a30SWesley Cheng 	 * allows for systems with larger bus latencies to have some headroom
14229f607a30SWesley Cheng 	 * for endpoints that have a large bMaxBurst value.
14239f607a30SWesley Cheng 	 */
14249f607a30SWesley Cheng 	tx_fifo_resize_max_num = 6;
14259f607a30SWesley Cheng 
142663863b98SHeikki Krogerus 	dwc->maximum_speed = usb_get_maximum_speed(dev);
142767848146SThinh Nguyen 	dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev);
142806e7114fSHeikki Krogerus 	dwc->dr_mode = usb_get_dr_mode(dev);
142932f2ed86SWilliam Wu 	dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
143063863b98SHeikki Krogerus 
1431d64ff406SArnd Bergmann 	dwc->sysdev_is_parent = device_property_read_bool(dev,
1432d64ff406SArnd Bergmann 				"linux,sysdev_is_parent");
1433d64ff406SArnd Bergmann 	if (dwc->sysdev_is_parent)
1434d64ff406SArnd Bergmann 		dwc->sysdev = dwc->dev->parent;
1435d64ff406SArnd Bergmann 	else
1436d64ff406SArnd Bergmann 		dwc->sysdev = dwc->dev;
1437d64ff406SArnd Bergmann 
14386f0764b5SRay Chi 	ret = device_property_read_string(dev, "usb-psy-name", &usb_psy_name);
14396f0764b5SRay Chi 	if (ret >= 0) {
14406f0764b5SRay Chi 		dwc->usb_psy = power_supply_get_by_name(usb_psy_name);
14416f0764b5SRay Chi 		if (!dwc->usb_psy)
14426f0764b5SRay Chi 			dev_err(dev, "couldn't get usb power supply\n");
14436f0764b5SRay Chi 	}
14446f0764b5SRay Chi 
14453d128919SHeikki Krogerus 	dwc->has_lpm_erratum = device_property_read_bool(dev,
144680caf7d2SHuang Rui 				"snps,has-lpm-erratum");
14473d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,lpm-nyet-threshold",
144880caf7d2SHuang Rui 				&lpm_nyet_threshold);
14493d128919SHeikki Krogerus 	dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
1450460d098cSHuang Rui 				"snps,is-utmi-l1-suspend");
14513d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,hird-threshold",
1452460d098cSHuang Rui 				&hird_threshold);
1453d92021f6SThinh Nguyen 	dwc->dis_start_transfer_quirk = device_property_read_bool(dev,
1454d92021f6SThinh Nguyen 				"snps,dis-start-transfer-quirk");
14553d128919SHeikki Krogerus 	dwc->usb3_lpm_capable = device_property_read_bool(dev,
1456eac68e8fSRobert Baldyga 				"snps,usb3_lpm_capable");
1457022a0208SThinh Nguyen 	dwc->usb2_lpm_disable = device_property_read_bool(dev,
1458022a0208SThinh Nguyen 				"snps,usb2-lpm-disable");
1459475e8be5SThinh Nguyen 	dwc->usb2_gadget_lpm_disable = device_property_read_bool(dev,
1460475e8be5SThinh Nguyen 				"snps,usb2-gadget-lpm-disable");
1461938a5ad1SThinh Nguyen 	device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd",
1462938a5ad1SThinh Nguyen 				&rx_thr_num_pkt_prd);
1463938a5ad1SThinh Nguyen 	device_property_read_u8(dev, "snps,rx-max-burst-prd",
1464938a5ad1SThinh Nguyen 				&rx_max_burst_prd);
1465938a5ad1SThinh Nguyen 	device_property_read_u8(dev, "snps,tx-thr-num-pkt-prd",
1466938a5ad1SThinh Nguyen 				&tx_thr_num_pkt_prd);
1467938a5ad1SThinh Nguyen 	device_property_read_u8(dev, "snps,tx-max-burst-prd",
1468938a5ad1SThinh Nguyen 				&tx_max_burst_prd);
14699f607a30SWesley Cheng 	dwc->do_fifo_resize = device_property_read_bool(dev,
14709f607a30SWesley Cheng 							"tx-fifo-resize");
14719f607a30SWesley Cheng 	if (dwc->do_fifo_resize)
14729f607a30SWesley Cheng 		device_property_read_u8(dev, "tx-fifo-max-num",
14739f607a30SWesley Cheng 					&tx_fifo_resize_max_num);
14743c9f94acSFelipe Balbi 
14753d128919SHeikki Krogerus 	dwc->disable_scramble_quirk = device_property_read_bool(dev,
14763b81221aSHuang Rui 				"snps,disable_scramble_quirk");
14773d128919SHeikki Krogerus 	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
14789a5b2f31SHuang Rui 				"snps,u2exit_lfps_quirk");
14793d128919SHeikki Krogerus 	dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
1480b5a65c40SHuang Rui 				"snps,u2ss_inp3_quirk");
14813d128919SHeikki Krogerus 	dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
1482df31f5b3SHuang Rui 				"snps,req_p1p2p3_quirk");
14833d128919SHeikki Krogerus 	dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
1484a2a1d0f5SHuang Rui 				"snps,del_p1p2p3_quirk");
14853d128919SHeikki Krogerus 	dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
148641c06ffdSHuang Rui 				"snps,del_phy_power_chg_quirk");
14873d128919SHeikki Krogerus 	dwc->lfps_filter_quirk = device_property_read_bool(dev,
1488fb67afcaSHuang Rui 				"snps,lfps_filter_quirk");
14893d128919SHeikki Krogerus 	dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
149014f4ac53SHuang Rui 				"snps,rx_detect_poll_quirk");
14913d128919SHeikki Krogerus 	dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
149259acfa20SHuang Rui 				"snps,dis_u3_susphy_quirk");
14933d128919SHeikki Krogerus 	dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
14940effe0a3SHuang Rui 				"snps,dis_u2_susphy_quirk");
1495ec791d14SJohn Youn 	dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
1496ec791d14SJohn Youn 				"snps,dis_enblslpm_quirk");
1497729dcffdSAnurag Kumar Vulisha 	dwc->dis_u1_entry_quirk = device_property_read_bool(dev,
1498729dcffdSAnurag Kumar Vulisha 				"snps,dis-u1-entry-quirk");
1499729dcffdSAnurag Kumar Vulisha 	dwc->dis_u2_entry_quirk = device_property_read_bool(dev,
1500729dcffdSAnurag Kumar Vulisha 				"snps,dis-u2-entry-quirk");
1501e58dd357SRajesh Bhagat 	dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
1502e58dd357SRajesh Bhagat 				"snps,dis_rxdet_inp3_quirk");
150316199f33SWilliam Wu 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
150416199f33SWilliam Wu 				"snps,dis-u2-freeclk-exists-quirk");
150500fe081dSWilliam Wu 	dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
150600fe081dSWilliam Wu 				"snps,dis-del-phy-power-chg-quirk");
150765db7a0cSWilliam Wu 	dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
150865db7a0cSWilliam Wu 				"snps,dis-tx-ipgap-linecheck-quirk");
150963d7f981SPiyush Mehta 	dwc->resume_hs_terminations = device_property_read_bool(dev,
151063d7f981SPiyush Mehta 				"snps,resume-hs-terminations");
1511b84ba26cSPiyush Mehta 	dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev,
1512b84ba26cSPiyush Mehta 				"snps,ulpi-ext-vbus-drv");
15137ba6b09fSNeil Armstrong 	dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
15147ba6b09fSNeil Armstrong 				"snps,parkmode-disable-ss-quirk");
1515d21a797aSStanley Chang 	dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev,
1516d21a797aSStanley Chang 				"snps,parkmode-disable-hs-quirk");
1517a6fc2f1bSAlexander Stein 	dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev,
1518a6fc2f1bSAlexander Stein 				"snps,gfladj-refclk-lpm-sel-quirk");
15196b6a0c9aSHuang Rui 
15203d128919SHeikki Krogerus 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
15216b6a0c9aSHuang Rui 				"snps,tx_de_emphasis_quirk");
15223d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,tx_de_emphasis",
15236b6a0c9aSHuang Rui 				&tx_de_emphasis);
15243d128919SHeikki Krogerus 	device_property_read_string(dev, "snps,hsphy_interface",
15253e10a2ceSHeikki Krogerus 				    &dwc->hsphy_interface);
15263d128919SHeikki Krogerus 	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
1527bcdb3272SFelipe Balbi 				 &dwc->fladj);
15287bee3188SBalaji Prakash J 	device_property_read_u32(dev, "snps,ref-clock-period-ns",
15297bee3188SBalaji Prakash J 				 &dwc->ref_clk_per);
15303d128919SHeikki Krogerus 
153142bf02ecSRoger Quadros 	dwc->dis_metastability_quirk = device_property_read_bool(dev,
153242bf02ecSRoger Quadros 				"snps,dis_metastability_quirk");
153342bf02ecSRoger Quadros 
1534f580170fSYu Chen 	dwc->dis_split_quirk = device_property_read_bool(dev,
1535f580170fSYu Chen 				"snps,dis-split-quirk");
1536f580170fSYu Chen 
153780caf7d2SHuang Rui 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
15386b6a0c9aSHuang Rui 	dwc->tx_de_emphasis = tx_de_emphasis;
153980caf7d2SHuang Rui 
154016fe4f30SThinh Nguyen 	dwc->hird_threshold = hird_threshold;
1541460d098cSHuang Rui 
1542938a5ad1SThinh Nguyen 	dwc->rx_thr_num_pkt_prd = rx_thr_num_pkt_prd;
1543938a5ad1SThinh Nguyen 	dwc->rx_max_burst_prd = rx_max_burst_prd;
1544938a5ad1SThinh Nguyen 
1545938a5ad1SThinh Nguyen 	dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
1546938a5ad1SThinh Nguyen 	dwc->tx_max_burst_prd = tx_max_burst_prd;
1547938a5ad1SThinh Nguyen 
1548cf40b86bSJohn Youn 	dwc->imod_interval = 0;
15499f607a30SWesley Cheng 
15509f607a30SWesley Cheng 	dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
1551cf40b86bSJohn Youn }
1552cf40b86bSJohn Youn 
1553cf40b86bSJohn Youn /* check whether the core supports IMOD */
1554cf40b86bSJohn Youn bool dwc3_has_imod(struct dwc3 *dwc)
1555cf40b86bSJohn Youn {
15569af21dd6SThinh Nguyen 	return DWC3_VER_IS_WITHIN(DWC3, 300A, ANY) ||
15579af21dd6SThinh Nguyen 		DWC3_VER_IS_WITHIN(DWC31, 120A, ANY) ||
15589af21dd6SThinh Nguyen 		DWC3_IP_IS(DWC32);
1559c5ac6116SFelipe Balbi }
1560c5ac6116SFelipe Balbi 
15617ac51a12SJohn Youn static void dwc3_check_params(struct dwc3 *dwc)
15627ac51a12SJohn Youn {
15637ac51a12SJohn Youn 	struct device *dev = dwc->dev;
1564b574ce3eSThinh Nguyen 	unsigned int hwparam_gen =
1565b574ce3eSThinh Nguyen 		DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3);
15667ac51a12SJohn Youn 
1567cf40b86bSJohn Youn 	/* Check for proper value of imod_interval */
1568cf40b86bSJohn Youn 	if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
1569cf40b86bSJohn Youn 		dev_warn(dwc->dev, "Interrupt moderation not supported\n");
1570cf40b86bSJohn Youn 		dwc->imod_interval = 0;
1571cf40b86bSJohn Youn 	}
1572cf40b86bSJohn Youn 
157328632b44SJohn Youn 	/*
157428632b44SJohn Youn 	 * Workaround for STAR 9000961433 which affects only version
157528632b44SJohn Youn 	 * 3.00a of the DWC_usb3 core. This prevents the controller
157628632b44SJohn Youn 	 * interrupt from being masked while handling events. IMOD
157728632b44SJohn Youn 	 * allows us to work around this issue. Enable it for the
157828632b44SJohn Youn 	 * affected version.
157928632b44SJohn Youn 	 */
158028632b44SJohn Youn 	if (!dwc->imod_interval &&
15819af21dd6SThinh Nguyen 	    DWC3_VER_IS(DWC3, 300A))
158228632b44SJohn Youn 		dwc->imod_interval = 1;
158328632b44SJohn Youn 
15847ac51a12SJohn Youn 	/* Check the maximum_speed parameter */
15857ac51a12SJohn Youn 	switch (dwc->maximum_speed) {
15867ac51a12SJohn Youn 	case USB_SPEED_FULL:
15877ac51a12SJohn Youn 	case USB_SPEED_HIGH:
1588e518bdd9SThinh Nguyen 		break;
15897ac51a12SJohn Youn 	case USB_SPEED_SUPER:
1590e518bdd9SThinh Nguyen 		if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS)
1591e518bdd9SThinh Nguyen 			dev_warn(dev, "UDC doesn't support Gen 1\n");
1592e518bdd9SThinh Nguyen 		break;
15937ac51a12SJohn Youn 	case USB_SPEED_SUPER_PLUS:
1594e518bdd9SThinh Nguyen 		if ((DWC3_IP_IS(DWC32) &&
1595e518bdd9SThinh Nguyen 		     hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) ||
1596e518bdd9SThinh Nguyen 		    (!DWC3_IP_IS(DWC32) &&
1597e518bdd9SThinh Nguyen 		     hwparam_gen != DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
1598e518bdd9SThinh Nguyen 			dev_warn(dev, "UDC doesn't support SSP\n");
15997ac51a12SJohn Youn 		break;
16007ac51a12SJohn Youn 	default:
16017ac51a12SJohn Youn 		dev_err(dev, "invalid maximum_speed parameter %d\n",
16027ac51a12SJohn Youn 			dwc->maximum_speed);
1603df561f66SGustavo A. R. Silva 		fallthrough;
16047ac51a12SJohn Youn 	case USB_SPEED_UNKNOWN:
1605b574ce3eSThinh Nguyen 		switch (hwparam_gen) {
1606b574ce3eSThinh Nguyen 		case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2:
16077ac51a12SJohn Youn 			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
1608b574ce3eSThinh Nguyen 			break;
1609b574ce3eSThinh Nguyen 		case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1:
1610b574ce3eSThinh Nguyen 			if (DWC3_IP_IS(DWC32))
1611b574ce3eSThinh Nguyen 				dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
1612b574ce3eSThinh Nguyen 			else
1613b574ce3eSThinh Nguyen 				dwc->maximum_speed = USB_SPEED_SUPER;
1614b574ce3eSThinh Nguyen 			break;
1615b574ce3eSThinh Nguyen 		case DWC3_GHWPARAMS3_SSPHY_IFC_DIS:
1616b574ce3eSThinh Nguyen 			dwc->maximum_speed = USB_SPEED_HIGH;
1617b574ce3eSThinh Nguyen 			break;
1618b574ce3eSThinh Nguyen 		default:
1619b574ce3eSThinh Nguyen 			dwc->maximum_speed = USB_SPEED_SUPER;
1620b574ce3eSThinh Nguyen 			break;
1621b574ce3eSThinh Nguyen 		}
16227ac51a12SJohn Youn 		break;
16237ac51a12SJohn Youn 	}
162467848146SThinh Nguyen 
162567848146SThinh Nguyen 	/*
162667848146SThinh Nguyen 	 * Currently the controller does not have visibility into the HW
162767848146SThinh Nguyen 	 * parameter to determine the maximum number of lanes the HW supports.
162867848146SThinh Nguyen 	 * If the number of lanes is not specified in the device property, then
162967848146SThinh Nguyen 	 * set the default to support dual-lane for DWC_usb32 and single-lane
163067848146SThinh Nguyen 	 * for DWC_usb31 for super-speed-plus.
163167848146SThinh Nguyen 	 */
163267848146SThinh Nguyen 	if (dwc->maximum_speed == USB_SPEED_SUPER_PLUS) {
163367848146SThinh Nguyen 		switch (dwc->max_ssp_rate) {
163467848146SThinh Nguyen 		case USB_SSP_GEN_2x1:
163567848146SThinh Nguyen 			if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_GEN1)
163667848146SThinh Nguyen 				dev_warn(dev, "UDC only supports Gen 1\n");
163767848146SThinh Nguyen 			break;
163867848146SThinh Nguyen 		case USB_SSP_GEN_1x2:
163967848146SThinh Nguyen 		case USB_SSP_GEN_2x2:
164067848146SThinh Nguyen 			if (DWC3_IP_IS(DWC31))
164167848146SThinh Nguyen 				dev_warn(dev, "UDC only supports single lane\n");
164267848146SThinh Nguyen 			break;
164367848146SThinh Nguyen 		case USB_SSP_GEN_UNKNOWN:
164467848146SThinh Nguyen 		default:
164567848146SThinh Nguyen 			switch (hwparam_gen) {
164667848146SThinh Nguyen 			case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2:
164767848146SThinh Nguyen 				if (DWC3_IP_IS(DWC32))
164867848146SThinh Nguyen 					dwc->max_ssp_rate = USB_SSP_GEN_2x2;
164967848146SThinh Nguyen 				else
165067848146SThinh Nguyen 					dwc->max_ssp_rate = USB_SSP_GEN_2x1;
165167848146SThinh Nguyen 				break;
165267848146SThinh Nguyen 			case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1:
165367848146SThinh Nguyen 				if (DWC3_IP_IS(DWC32))
165467848146SThinh Nguyen 					dwc->max_ssp_rate = USB_SSP_GEN_1x2;
165567848146SThinh Nguyen 				break;
165667848146SThinh Nguyen 			}
165767848146SThinh Nguyen 			break;
165867848146SThinh Nguyen 		}
165967848146SThinh Nguyen 	}
16607ac51a12SJohn Youn }
16617ac51a12SJohn Youn 
1662d182c2e1SAndrey Smirnov static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
1663d182c2e1SAndrey Smirnov {
1664d182c2e1SAndrey Smirnov 	struct device *dev = dwc->dev;
1665d182c2e1SAndrey Smirnov 	struct device_node *np_phy;
1666d182c2e1SAndrey Smirnov 	struct extcon_dev *edev = NULL;
1667d182c2e1SAndrey Smirnov 	const char *name;
1668d182c2e1SAndrey Smirnov 
1669d182c2e1SAndrey Smirnov 	if (device_property_read_bool(dev, "extcon"))
1670d182c2e1SAndrey Smirnov 		return extcon_get_edev_by_phandle(dev, 0);
1671d182c2e1SAndrey Smirnov 
1672d182c2e1SAndrey Smirnov 	/*
1673d182c2e1SAndrey Smirnov 	 * Device tree platforms should get extcon via phandle.
1674d182c2e1SAndrey Smirnov 	 * On ACPI platforms, we get the name from a device property.
1675d182c2e1SAndrey Smirnov 	 * This device property is for kernel internal use only and
1676d182c2e1SAndrey Smirnov 	 * is expected to be set by the glue code.
1677d182c2e1SAndrey Smirnov 	 */
1678d182c2e1SAndrey Smirnov 	if (device_property_read_string(dev, "linux,extcon-name", &name) == 0)
1679d182c2e1SAndrey Smirnov 		return extcon_get_extcon_dev(name);
1680d182c2e1SAndrey Smirnov 
1681d182c2e1SAndrey Smirnov 	/*
1682d68cc25bSJanne Grunau 	 * Check explicitly if "usb-role-switch" is used since
1683d68cc25bSJanne Grunau 	 * extcon_find_edev_by_node() can not be used to check the absence of
1684d68cc25bSJanne Grunau 	 * an extcon device. In the absence of an device it will always return
1685d68cc25bSJanne Grunau 	 * EPROBE_DEFER.
1686d68cc25bSJanne Grunau 	 */
1687d68cc25bSJanne Grunau 	if (IS_ENABLED(CONFIG_USB_ROLE_SWITCH) &&
1688d68cc25bSJanne Grunau 	    device_property_read_bool(dev, "usb-role-switch"))
1689d68cc25bSJanne Grunau 		return NULL;
1690d68cc25bSJanne Grunau 
1691d68cc25bSJanne Grunau 	/*
1692d182c2e1SAndrey Smirnov 	 * Try to get an extcon device from the USB PHY controller's "port"
1693d182c2e1SAndrey Smirnov 	 * node. Check if it has the "port" node first, to avoid printing the
1694d182c2e1SAndrey Smirnov 	 * error message from underlying code, as it's a valid case: extcon
1695d182c2e1SAndrey Smirnov 	 * device (and "port" node) may be missing in case of "usb-role-switch"
1696d182c2e1SAndrey Smirnov 	 * or OTG mode.
1697d182c2e1SAndrey Smirnov 	 */
1698d182c2e1SAndrey Smirnov 	np_phy = of_parse_phandle(dev->of_node, "phys", 0);
1699d182c2e1SAndrey Smirnov 	if (of_graph_is_present(np_phy)) {
1700d182c2e1SAndrey Smirnov 		struct device_node *np_conn;
1701d182c2e1SAndrey Smirnov 
1702d182c2e1SAndrey Smirnov 		np_conn = of_graph_get_remote_node(np_phy, -1, -1);
1703d182c2e1SAndrey Smirnov 		if (np_conn)
1704d182c2e1SAndrey Smirnov 			edev = extcon_find_edev_by_node(np_conn);
1705d182c2e1SAndrey Smirnov 		of_node_put(np_conn);
1706d182c2e1SAndrey Smirnov 	}
1707d182c2e1SAndrey Smirnov 	of_node_put(np_phy);
1708d182c2e1SAndrey Smirnov 
1709d182c2e1SAndrey Smirnov 	return edev;
1710d182c2e1SAndrey Smirnov }
1711d182c2e1SAndrey Smirnov 
1712bd828574SJohan Hovold static int dwc3_get_clocks(struct dwc3 *dwc)
1713bd828574SJohan Hovold {
1714bd828574SJohan Hovold 	struct device *dev = dwc->dev;
1715bd828574SJohan Hovold 
1716bd828574SJohan Hovold 	if (!dev->of_node)
1717bd828574SJohan Hovold 		return 0;
1718bd828574SJohan Hovold 
1719bd828574SJohan Hovold 	/*
1720bd828574SJohan Hovold 	 * Clocks are optional, but new DT platforms should support all clocks
1721bd828574SJohan Hovold 	 * as required by the DT-binding.
1722bd828574SJohan Hovold 	 * Some devices have different clock names in legacy device trees,
1723bd828574SJohan Hovold 	 * check for them to retain backwards compatibility.
1724bd828574SJohan Hovold 	 */
1725bd828574SJohan Hovold 	dwc->bus_clk = devm_clk_get_optional(dev, "bus_early");
1726bd828574SJohan Hovold 	if (IS_ERR(dwc->bus_clk)) {
1727bd828574SJohan Hovold 		return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
1728bd828574SJohan Hovold 				"could not get bus clock\n");
1729bd828574SJohan Hovold 	}
1730bd828574SJohan Hovold 
1731bd828574SJohan Hovold 	if (dwc->bus_clk == NULL) {
1732bd828574SJohan Hovold 		dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk");
1733bd828574SJohan Hovold 		if (IS_ERR(dwc->bus_clk)) {
1734bd828574SJohan Hovold 			return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
1735bd828574SJohan Hovold 					"could not get bus clock\n");
1736bd828574SJohan Hovold 		}
1737bd828574SJohan Hovold 	}
1738bd828574SJohan Hovold 
1739bd828574SJohan Hovold 	dwc->ref_clk = devm_clk_get_optional(dev, "ref");
1740bd828574SJohan Hovold 	if (IS_ERR(dwc->ref_clk)) {
1741bd828574SJohan Hovold 		return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
1742bd828574SJohan Hovold 				"could not get ref clock\n");
1743bd828574SJohan Hovold 	}
1744bd828574SJohan Hovold 
1745bd828574SJohan Hovold 	if (dwc->ref_clk == NULL) {
1746bd828574SJohan Hovold 		dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk");
1747bd828574SJohan Hovold 		if (IS_ERR(dwc->ref_clk)) {
1748bd828574SJohan Hovold 			return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
1749bd828574SJohan Hovold 					"could not get ref clock\n");
1750bd828574SJohan Hovold 		}
1751bd828574SJohan Hovold 	}
1752bd828574SJohan Hovold 
1753bd828574SJohan Hovold 	dwc->susp_clk = devm_clk_get_optional(dev, "suspend");
1754bd828574SJohan Hovold 	if (IS_ERR(dwc->susp_clk)) {
1755bd828574SJohan Hovold 		return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
1756bd828574SJohan Hovold 				"could not get suspend clock\n");
1757bd828574SJohan Hovold 	}
1758bd828574SJohan Hovold 
1759bd828574SJohan Hovold 	if (dwc->susp_clk == NULL) {
1760bd828574SJohan Hovold 		dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk");
1761bd828574SJohan Hovold 		if (IS_ERR(dwc->susp_clk)) {
1762bd828574SJohan Hovold 			return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
1763bd828574SJohan Hovold 					"could not get suspend clock\n");
1764bd828574SJohan Hovold 		}
1765bd828574SJohan Hovold 	}
1766bd828574SJohan Hovold 
1767bd828574SJohan Hovold 	return 0;
1768bd828574SJohan Hovold }
1769bd828574SJohan Hovold 
1770c5ac6116SFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
1771c5ac6116SFelipe Balbi {
1772c5ac6116SFelipe Balbi 	struct device		*dev = &pdev->dev;
177344feb8e6SMasahiro Yamada 	struct resource		*res, dwc_res;
1774c5ac6116SFelipe Balbi 	void __iomem		*regs;
17759a4d7dd1SJohan Hovold 	struct dwc3		*dwc;
17769a4d7dd1SJohan Hovold 	int			ret;
1777c5ac6116SFelipe Balbi 
1778c5ac6116SFelipe Balbi 	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
1779c5ac6116SFelipe Balbi 	if (!dwc)
1780c5ac6116SFelipe Balbi 		return -ENOMEM;
1781c5ac6116SFelipe Balbi 
1782c5ac6116SFelipe Balbi 	dwc->dev = dev;
1783c5ac6116SFelipe Balbi 
1784c5ac6116SFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1785c5ac6116SFelipe Balbi 	if (!res) {
1786c5ac6116SFelipe Balbi 		dev_err(dev, "missing memory resource\n");
1787c5ac6116SFelipe Balbi 		return -ENODEV;
1788c5ac6116SFelipe Balbi 	}
1789c5ac6116SFelipe Balbi 
1790c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].start = res->start;
1791c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
1792c5ac6116SFelipe Balbi 					DWC3_XHCI_REGS_END;
1793c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].flags = res->flags;
1794c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].name = res->name;
1795c5ac6116SFelipe Balbi 
1796c5ac6116SFelipe Balbi 	/*
1797c5ac6116SFelipe Balbi 	 * Request memory region but exclude xHCI regs,
1798c5ac6116SFelipe Balbi 	 * since it will be requested by the xhci-plat driver.
1799c5ac6116SFelipe Balbi 	 */
180044feb8e6SMasahiro Yamada 	dwc_res = *res;
180144feb8e6SMasahiro Yamada 	dwc_res.start += DWC3_GLOBALS_REGS_START;
180244feb8e6SMasahiro Yamada 
180344feb8e6SMasahiro Yamada 	regs = devm_ioremap_resource(dev, &dwc_res);
180444feb8e6SMasahiro Yamada 	if (IS_ERR(regs))
180544feb8e6SMasahiro Yamada 		return PTR_ERR(regs);
1806c5ac6116SFelipe Balbi 
1807c5ac6116SFelipe Balbi 	dwc->regs	= regs;
180844feb8e6SMasahiro Yamada 	dwc->regs_size	= resource_size(&dwc_res);
1809c5ac6116SFelipe Balbi 
1810c5ac6116SFelipe Balbi 	dwc3_get_properties(dwc);
1811c5ac6116SFelipe Balbi 
1812babbdfc9SYejune Deng 	dwc->reset = devm_reset_control_array_get_optional_shared(dev);
18132a735e4bSDan Carpenter 	if (IS_ERR(dwc->reset)) {
18142a735e4bSDan Carpenter 		ret = PTR_ERR(dwc->reset);
1815fe296046SJohan Hovold 		goto err_put_psy;
18162a735e4bSDan Carpenter 	}
1817fe8abf33SMasahiro Yamada 
1818bd828574SJohan Hovold 	ret = dwc3_get_clocks(dwc);
1819bd828574SJohan Hovold 	if (ret)
1820fe296046SJohan Hovold 		goto err_put_psy;
1821fe8abf33SMasahiro Yamada 
1822fe8abf33SMasahiro Yamada 	ret = reset_control_deassert(dwc->reset);
1823fe8abf33SMasahiro Yamada 	if (ret)
1824fe296046SJohan Hovold 		goto err_put_psy;
1825fe8abf33SMasahiro Yamada 
182633fb697eSSean Anderson 	ret = dwc3_clk_enable(dwc);
1827fe8abf33SMasahiro Yamada 	if (ret)
1828fe296046SJohan Hovold 		goto err_assert_reset;
1829fe8abf33SMasahiro Yamada 
1830dc1b5d9aSEnric Balletbo i Serra 	if (!dwc3_core_is_valid(dwc)) {
1831dc1b5d9aSEnric Balletbo i Serra 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
1832dc1b5d9aSEnric Balletbo i Serra 		ret = -ENODEV;
1833fe296046SJohan Hovold 		goto err_disable_clks;
1834dc1b5d9aSEnric Balletbo i Serra 	}
1835dc1b5d9aSEnric Balletbo i Serra 
18366c89cce0SHeikki Krogerus 	platform_set_drvdata(pdev, dwc);
18372917e718SHeikki Krogerus 	dwc3_cache_hwparams(dwc);
18386c89cce0SHeikki Krogerus 
183991062e66SWilliam Wu 	if (!dwc->sysdev_is_parent &&
184091062e66SWilliam Wu 	    DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) {
184191062e66SWilliam Wu 		ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
184291062e66SWilliam Wu 		if (ret)
1843fe296046SJohan Hovold 			goto err_disable_clks;
184491062e66SWilliam Wu 	}
184591062e66SWilliam Wu 
184672246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
1847f88359e1SYu Chen 	mutex_init(&dwc->mutex);
184872246da4SFelipe Balbi 
18499a8ad10cSJohan Hovold 	pm_runtime_get_noresume(dev);
1850fc8bb91bSFelipe Balbi 	pm_runtime_set_active(dev);
1851fc8bb91bSFelipe Balbi 	pm_runtime_use_autosuspend(dev);
1852fc8bb91bSFelipe Balbi 	pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
1853802ca850SChanho Park 	pm_runtime_enable(dev);
185432808237SRoger Quadros 
1855802ca850SChanho Park 	pm_runtime_forbid(dev);
185672246da4SFelipe Balbi 
18573921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
18583921426bSFelipe Balbi 	if (ret) {
18593921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
18603921426bSFelipe Balbi 		ret = -ENOMEM;
1861fe296046SJohan Hovold 		goto err_allow_rpm;
18623921426bSFelipe Balbi 	}
18633921426bSFelipe Balbi 
1864d182c2e1SAndrey Smirnov 	dwc->edev = dwc3_get_extcon(dwc);
1865d182c2e1SAndrey Smirnov 	if (IS_ERR(dwc->edev)) {
1866d182c2e1SAndrey Smirnov 		ret = dev_err_probe(dwc->dev, PTR_ERR(dwc->edev), "failed to get extcon\n");
1867fe296046SJohan Hovold 		goto err_free_event_buffers;
1868d182c2e1SAndrey Smirnov 	}
1869d182c2e1SAndrey Smirnov 
18709d6173e1SThinh Nguyen 	ret = dwc3_get_dr_mode(dwc);
18719d6173e1SThinh Nguyen 	if (ret)
1872fe296046SJohan Hovold 		goto err_free_event_buffers;
187332a4a135SFelipe Balbi 
187472246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
187572246da4SFelipe Balbi 	if (ret) {
18760c0a20f6SAndy Shevchenko 		dev_err_probe(dev, ret, "failed to initialize core\n");
1877fe296046SJohan Hovold 		goto err_free_event_buffers;
187872246da4SFelipe Balbi 	}
187972246da4SFelipe Balbi 
18807ac51a12SJohn Youn 	dwc3_check_params(dwc);
188184524d12SMinas Harutyunyan 	dwc3_debugfs_init(dwc);
18822c7f1bd9SJohn Youn 
18835f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
18845f94adfeSFelipe Balbi 	if (ret)
1885fe296046SJohan Hovold 		goto err_exit_debugfs;
188672246da4SFelipe Balbi 
1887fc8bb91bSFelipe Balbi 	pm_runtime_put(dev);
188872246da4SFelipe Balbi 
188972246da4SFelipe Balbi 	return 0;
189072246da4SFelipe Balbi 
1891fe296046SJohan Hovold err_exit_debugfs:
189284524d12SMinas Harutyunyan 	dwc3_debugfs_exit(dwc);
1893f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
18941d72fab4SJohan Hovold 	dwc3_phy_power_off(dwc);
18951d72fab4SJohan Hovold 	dwc3_phy_exit(dwc);
189608fd9a82SAndy Shevchenko 	dwc3_ulpi_exit(dwc);
1897fe296046SJohan Hovold err_free_event_buffers:
18983921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
1899fe296046SJohan Hovold err_allow_rpm:
19009a8ad10cSJohan Hovold 	pm_runtime_allow(dev);
19019a8ad10cSJohan Hovold 	pm_runtime_disable(dev);
19026b3b2402SJohan Hovold 	pm_runtime_dont_use_autosuspend(dev);
19039a8ad10cSJohan Hovold 	pm_runtime_set_suspended(dev);
19049a8ad10cSJohan Hovold 	pm_runtime_put_noidle(dev);
1905fe296046SJohan Hovold err_disable_clks:
190633fb697eSSean Anderson 	dwc3_clk_disable(dwc);
1907fe296046SJohan Hovold err_assert_reset:
1908fe8abf33SMasahiro Yamada 	reset_control_assert(dwc->reset);
1909fe296046SJohan Hovold err_put_psy:
1910b0bf77cdSColin Ian King 	if (dwc->usb_psy)
19116f0764b5SRay Chi 		power_supply_put(dwc->usb_psy);
19126f0764b5SRay Chi 
191372246da4SFelipe Balbi 	return ret;
191472246da4SFelipe Balbi }
191572246da4SFelipe Balbi 
1916fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
191772246da4SFelipe Balbi {
191872246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
19193da1f6eeSFelipe Balbi 
1920fc8bb91bSFelipe Balbi 	pm_runtime_get_sync(&pdev->dev);
192172246da4SFelipe Balbi 
1922dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
19232a042767SPeter Chen 	dwc3_debugfs_exit(dwc);
19248ba007a9SKishon Vijay Abraham I 
192572246da4SFelipe Balbi 	dwc3_core_exit(dwc);
192688bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
192772246da4SFelipe Balbi 
192844d257e9SJohan Hovold 	pm_runtime_allow(&pdev->dev);
1929fc8bb91bSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
19306b3b2402SJohan Hovold 	pm_runtime_dont_use_autosuspend(&pdev->dev);
1931266d0493SLi Jun 	pm_runtime_put_noidle(&pdev->dev);
1932*e3dbb657SJohan Hovold 	/*
1933*e3dbb657SJohan Hovold 	 * HACK: Clear the driver data, which is currently accessed by parent
1934*e3dbb657SJohan Hovold 	 * glue drivers, before allowing the parent to suspend.
1935*e3dbb657SJohan Hovold 	 */
1936*e3dbb657SJohan Hovold 	platform_set_drvdata(pdev, NULL);
1937266d0493SLi Jun 	pm_runtime_set_suspended(&pdev->dev);
1938fc8bb91bSFelipe Balbi 
1939c499ff71SFelipe Balbi 	dwc3_free_event_buffers(dwc);
1940c499ff71SFelipe Balbi 
1941b0bf77cdSColin Ian King 	if (dwc->usb_psy)
19426f0764b5SRay Chi 		power_supply_put(dwc->usb_psy);
19436f0764b5SRay Chi 
194472246da4SFelipe Balbi 	return 0;
194572246da4SFelipe Balbi }
194672246da4SFelipe Balbi 
1947fc8bb91bSFelipe Balbi #ifdef CONFIG_PM
1948fe8abf33SMasahiro Yamada static int dwc3_core_init_for_resume(struct dwc3 *dwc)
1949fe8abf33SMasahiro Yamada {
1950fe8abf33SMasahiro Yamada 	int ret;
1951fe8abf33SMasahiro Yamada 
1952fe8abf33SMasahiro Yamada 	ret = reset_control_deassert(dwc->reset);
1953fe8abf33SMasahiro Yamada 	if (ret)
1954fe8abf33SMasahiro Yamada 		return ret;
1955fe8abf33SMasahiro Yamada 
195633fb697eSSean Anderson 	ret = dwc3_clk_enable(dwc);
1957fe8abf33SMasahiro Yamada 	if (ret)
1958fe8abf33SMasahiro Yamada 		goto assert_reset;
1959fe8abf33SMasahiro Yamada 
1960fe8abf33SMasahiro Yamada 	ret = dwc3_core_init(dwc);
1961fe8abf33SMasahiro Yamada 	if (ret)
1962fe8abf33SMasahiro Yamada 		goto disable_clks;
1963fe8abf33SMasahiro Yamada 
1964fe8abf33SMasahiro Yamada 	return 0;
1965fe8abf33SMasahiro Yamada 
1966fe8abf33SMasahiro Yamada disable_clks:
196733fb697eSSean Anderson 	dwc3_clk_disable(dwc);
1968fe8abf33SMasahiro Yamada assert_reset:
1969fe8abf33SMasahiro Yamada 	reset_control_assert(dwc->reset);
1970fe8abf33SMasahiro Yamada 
1971fe8abf33SMasahiro Yamada 	return ret;
1972fe8abf33SMasahiro Yamada }
1973fe8abf33SMasahiro Yamada 
1974c4a5153eSManu Gautam static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
19757415f17cSFelipe Balbi {
1976fc8bb91bSFelipe Balbi 	unsigned long	flags;
1977bcb12877SManu Gautam 	u32 reg;
19787415f17cSFelipe Balbi 
1979689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1980689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
19810227cc84SLi Jun 		if (pm_runtime_suspended(dwc->dev))
19820227cc84SLi Jun 			break;
19837415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
198441a91c60SMarek Szyprowski 		synchronize_irq(dwc->irq_gadget);
1985689bf72cSManu Gautam 		dwc3_core_exit(dwc);
198651f5d49aSFelipe Balbi 		break;
1987689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1988e3fafbd8SJohan Hovold 		if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
1989c4a5153eSManu Gautam 			dwc3_core_exit(dwc);
1990c4a5153eSManu Gautam 			break;
1991bcb12877SManu Gautam 		}
1992bcb12877SManu Gautam 
1993bcb12877SManu Gautam 		/* Let controller to suspend HSPHY before PHY driver suspends */
1994bcb12877SManu Gautam 		if (dwc->dis_u2_susphy_quirk ||
1995bcb12877SManu Gautam 		    dwc->dis_enblslpm_quirk) {
1996bcb12877SManu Gautam 			reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
1997bcb12877SManu Gautam 			reg |=  DWC3_GUSB2PHYCFG_ENBLSLPM |
1998bcb12877SManu Gautam 				DWC3_GUSB2PHYCFG_SUSPHY;
1999bcb12877SManu Gautam 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
2000bcb12877SManu Gautam 
2001bcb12877SManu Gautam 			/* Give some time for USB2 PHY to suspend */
2002bcb12877SManu Gautam 			usleep_range(5000, 6000);
2003bcb12877SManu Gautam 		}
2004bcb12877SManu Gautam 
2005bcb12877SManu Gautam 		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
2006bcb12877SManu Gautam 		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
2007bcb12877SManu Gautam 		break;
2008f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
2009f09cc79bSRoger Quadros 		/* do nothing during runtime_suspend */
2010f09cc79bSRoger Quadros 		if (PMSG_IS_AUTO(msg))
2011f09cc79bSRoger Quadros 			break;
2012f09cc79bSRoger Quadros 
2013f09cc79bSRoger Quadros 		if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
2014f09cc79bSRoger Quadros 			spin_lock_irqsave(&dwc->lock, flags);
2015f09cc79bSRoger Quadros 			dwc3_gadget_suspend(dwc);
2016f09cc79bSRoger Quadros 			spin_unlock_irqrestore(&dwc->lock, flags);
201741a91c60SMarek Szyprowski 			synchronize_irq(dwc->irq_gadget);
2018f09cc79bSRoger Quadros 		}
2019f09cc79bSRoger Quadros 
2020f09cc79bSRoger Quadros 		dwc3_otg_exit(dwc);
2021f09cc79bSRoger Quadros 		dwc3_core_exit(dwc);
2022f09cc79bSRoger Quadros 		break;
20237415f17cSFelipe Balbi 	default:
202451f5d49aSFelipe Balbi 		/* do nothing */
20257415f17cSFelipe Balbi 		break;
20267415f17cSFelipe Balbi 	}
20277415f17cSFelipe Balbi 
2028fc8bb91bSFelipe Balbi 	return 0;
2029fc8bb91bSFelipe Balbi }
2030fc8bb91bSFelipe Balbi 
2031c4a5153eSManu Gautam static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
2032fc8bb91bSFelipe Balbi {
2033fc8bb91bSFelipe Balbi 	unsigned long	flags;
2034fc8bb91bSFelipe Balbi 	int		ret;
2035bcb12877SManu Gautam 	u32		reg;
2036fc8bb91bSFelipe Balbi 
2037689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
2038689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
2039fe8abf33SMasahiro Yamada 		ret = dwc3_core_init_for_resume(dwc);
2040fc8bb91bSFelipe Balbi 		if (ret)
2041fc8bb91bSFelipe Balbi 			return ret;
2042fc8bb91bSFelipe Balbi 
20437d11c3acSRoger Quadros 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
2044fc8bb91bSFelipe Balbi 		dwc3_gadget_resume(dwc);
2045689bf72cSManu Gautam 		break;
2046689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
2047e3fafbd8SJohan Hovold 		if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
2048fe8abf33SMasahiro Yamada 			ret = dwc3_core_init_for_resume(dwc);
2049c4a5153eSManu Gautam 			if (ret)
2050c4a5153eSManu Gautam 				return ret;
20517d11c3acSRoger Quadros 			dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
2052bcb12877SManu Gautam 			break;
2053c4a5153eSManu Gautam 		}
2054bcb12877SManu Gautam 		/* Restore GUSB2PHYCFG bits that were modified in suspend */
2055bcb12877SManu Gautam 		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
2056bcb12877SManu Gautam 		if (dwc->dis_u2_susphy_quirk)
2057bcb12877SManu Gautam 			reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
2058bcb12877SManu Gautam 
2059bcb12877SManu Gautam 		if (dwc->dis_enblslpm_quirk)
2060bcb12877SManu Gautam 			reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
2061bcb12877SManu Gautam 
2062bcb12877SManu Gautam 		dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
2063bcb12877SManu Gautam 
2064bcb12877SManu Gautam 		phy_pm_runtime_get_sync(dwc->usb2_generic_phy);
2065bcb12877SManu Gautam 		phy_pm_runtime_get_sync(dwc->usb3_generic_phy);
2066c4a5153eSManu Gautam 		break;
2067f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
2068f09cc79bSRoger Quadros 		/* nothing to do on runtime_resume */
2069f09cc79bSRoger Quadros 		if (PMSG_IS_AUTO(msg))
2070f09cc79bSRoger Quadros 			break;
2071f09cc79bSRoger Quadros 
20720e5a3c82SGary Bisson 		ret = dwc3_core_init_for_resume(dwc);
2073f09cc79bSRoger Quadros 		if (ret)
2074f09cc79bSRoger Quadros 			return ret;
2075f09cc79bSRoger Quadros 
2076f09cc79bSRoger Quadros 		dwc3_set_prtcap(dwc, dwc->current_dr_role);
2077f09cc79bSRoger Quadros 
2078f09cc79bSRoger Quadros 		dwc3_otg_init(dwc);
2079f09cc79bSRoger Quadros 		if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
2080f09cc79bSRoger Quadros 			dwc3_otg_host_init(dwc);
2081f09cc79bSRoger Quadros 		} else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
2082f09cc79bSRoger Quadros 			spin_lock_irqsave(&dwc->lock, flags);
2083f09cc79bSRoger Quadros 			dwc3_gadget_resume(dwc);
2084f09cc79bSRoger Quadros 			spin_unlock_irqrestore(&dwc->lock, flags);
2085f09cc79bSRoger Quadros 		}
2086f09cc79bSRoger Quadros 
2087f09cc79bSRoger Quadros 		break;
2088fc8bb91bSFelipe Balbi 	default:
2089fc8bb91bSFelipe Balbi 		/* do nothing */
2090fc8bb91bSFelipe Balbi 		break;
2091fc8bb91bSFelipe Balbi 	}
2092fc8bb91bSFelipe Balbi 
2093fc8bb91bSFelipe Balbi 	return 0;
2094fc8bb91bSFelipe Balbi }
2095fc8bb91bSFelipe Balbi 
2096fc8bb91bSFelipe Balbi static int dwc3_runtime_checks(struct dwc3 *dwc)
2097fc8bb91bSFelipe Balbi {
2098689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
2099c4a5153eSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
2100fc8bb91bSFelipe Balbi 		if (dwc->connected)
2101fc8bb91bSFelipe Balbi 			return -EBUSY;
2102fc8bb91bSFelipe Balbi 		break;
2103c4a5153eSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
2104fc8bb91bSFelipe Balbi 	default:
2105fc8bb91bSFelipe Balbi 		/* do nothing */
2106fc8bb91bSFelipe Balbi 		break;
2107fc8bb91bSFelipe Balbi 	}
2108fc8bb91bSFelipe Balbi 
2109fc8bb91bSFelipe Balbi 	return 0;
2110fc8bb91bSFelipe Balbi }
2111fc8bb91bSFelipe Balbi 
2112fc8bb91bSFelipe Balbi static int dwc3_runtime_suspend(struct device *dev)
2113fc8bb91bSFelipe Balbi {
2114fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
2115fc8bb91bSFelipe Balbi 	int		ret;
2116fc8bb91bSFelipe Balbi 
2117fc8bb91bSFelipe Balbi 	if (dwc3_runtime_checks(dwc))
2118fc8bb91bSFelipe Balbi 		return -EBUSY;
2119fc8bb91bSFelipe Balbi 
2120c4a5153eSManu Gautam 	ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);
2121fc8bb91bSFelipe Balbi 	if (ret)
2122fc8bb91bSFelipe Balbi 		return ret;
2123fc8bb91bSFelipe Balbi 
2124fc8bb91bSFelipe Balbi 	return 0;
2125fc8bb91bSFelipe Balbi }
2126fc8bb91bSFelipe Balbi 
2127fc8bb91bSFelipe Balbi static int dwc3_runtime_resume(struct device *dev)
2128fc8bb91bSFelipe Balbi {
2129fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
2130fc8bb91bSFelipe Balbi 	int		ret;
2131fc8bb91bSFelipe Balbi 
2132c4a5153eSManu Gautam 	ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
2133fc8bb91bSFelipe Balbi 	if (ret)
2134fc8bb91bSFelipe Balbi 		return ret;
2135fc8bb91bSFelipe Balbi 
2136689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
2137689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
2138fc8bb91bSFelipe Balbi 		dwc3_gadget_process_pending_events(dwc);
2139fc8bb91bSFelipe Balbi 		break;
2140689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
2141fc8bb91bSFelipe Balbi 	default:
2142fc8bb91bSFelipe Balbi 		/* do nothing */
2143fc8bb91bSFelipe Balbi 		break;
2144fc8bb91bSFelipe Balbi 	}
2145fc8bb91bSFelipe Balbi 
2146fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
2147fc8bb91bSFelipe Balbi 
2148fc8bb91bSFelipe Balbi 	return 0;
2149fc8bb91bSFelipe Balbi }
2150fc8bb91bSFelipe Balbi 
2151fc8bb91bSFelipe Balbi static int dwc3_runtime_idle(struct device *dev)
2152fc8bb91bSFelipe Balbi {
2153fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
2154fc8bb91bSFelipe Balbi 
2155689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
2156689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
2157fc8bb91bSFelipe Balbi 		if (dwc3_runtime_checks(dwc))
2158fc8bb91bSFelipe Balbi 			return -EBUSY;
2159fc8bb91bSFelipe Balbi 		break;
2160689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
2161fc8bb91bSFelipe Balbi 	default:
2162fc8bb91bSFelipe Balbi 		/* do nothing */
2163fc8bb91bSFelipe Balbi 		break;
2164fc8bb91bSFelipe Balbi 	}
2165fc8bb91bSFelipe Balbi 
2166fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
2167fc8bb91bSFelipe Balbi 	pm_runtime_autosuspend(dev);
2168fc8bb91bSFelipe Balbi 
2169fc8bb91bSFelipe Balbi 	return 0;
2170fc8bb91bSFelipe Balbi }
2171fc8bb91bSFelipe Balbi #endif /* CONFIG_PM */
2172fc8bb91bSFelipe Balbi 
2173fc8bb91bSFelipe Balbi #ifdef CONFIG_PM_SLEEP
2174fc8bb91bSFelipe Balbi static int dwc3_suspend(struct device *dev)
2175fc8bb91bSFelipe Balbi {
2176fc8bb91bSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
2177fc8bb91bSFelipe Balbi 	int		ret;
2178fc8bb91bSFelipe Balbi 
2179c4a5153eSManu Gautam 	ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
2180fc8bb91bSFelipe Balbi 	if (ret)
2181fc8bb91bSFelipe Balbi 		return ret;
2182fc8bb91bSFelipe Balbi 
21836344475fSSekhar Nori 	pinctrl_pm_select_sleep_state(dev);
21846344475fSSekhar Nori 
21857415f17cSFelipe Balbi 	return 0;
21867415f17cSFelipe Balbi }
21877415f17cSFelipe Balbi 
21887415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
21897415f17cSFelipe Balbi {
21907415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
219157303488SKishon Vijay Abraham I 	int		ret;
21927415f17cSFelipe Balbi 
21936344475fSSekhar Nori 	pinctrl_pm_select_default_state(dev);
21946344475fSSekhar Nori 
2195c4a5153eSManu Gautam 	ret = dwc3_resume_common(dwc, PMSG_RESUME);
219651f5d49aSFelipe Balbi 	if (ret)
21975c4ad318SFelipe Balbi 		return ret;
21985c4ad318SFelipe Balbi 
21997415f17cSFelipe Balbi 	pm_runtime_disable(dev);
22007415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
22017415f17cSFelipe Balbi 	pm_runtime_enable(dev);
22027415f17cSFelipe Balbi 
22037415f17cSFelipe Balbi 	return 0;
22047415f17cSFelipe Balbi }
2205f580170fSYu Chen 
2206f580170fSYu Chen static void dwc3_complete(struct device *dev)
2207f580170fSYu Chen {
2208f580170fSYu Chen 	struct dwc3	*dwc = dev_get_drvdata(dev);
2209f580170fSYu Chen 	u32		reg;
2210f580170fSYu Chen 
2211f580170fSYu Chen 	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
2212f580170fSYu Chen 			dwc->dis_split_quirk) {
2213f580170fSYu Chen 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
2214f580170fSYu Chen 		reg |= DWC3_GUCTL3_SPLITDISABLE;
2215f580170fSYu Chen 		dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
2216f580170fSYu Chen 	}
2217f580170fSYu Chen }
2218f580170fSYu Chen #else
2219f580170fSYu Chen #define dwc3_complete NULL
22207f370ed0SFelipe Balbi #endif /* CONFIG_PM_SLEEP */
22217415f17cSFelipe Balbi 
22227415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
22237415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
2224f580170fSYu Chen 	.complete = dwc3_complete,
2225fc8bb91bSFelipe Balbi 	SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
2226fc8bb91bSFelipe Balbi 			dwc3_runtime_idle)
22277415f17cSFelipe Balbi };
22287415f17cSFelipe Balbi 
22295088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
22305088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
22315088b6f5SKishon Vijay Abraham I 	{
223222a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
223322a5aa17SFelipe Balbi 	},
223422a5aa17SFelipe Balbi 	{
22355088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
22365088b6f5SKishon Vijay Abraham I 	},
22375088b6f5SKishon Vijay Abraham I 	{ },
22385088b6f5SKishon Vijay Abraham I };
22395088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
22405088b6f5SKishon Vijay Abraham I #endif
22415088b6f5SKishon Vijay Abraham I 
2242404905a6SHeikki Krogerus #ifdef CONFIG_ACPI
2243404905a6SHeikki Krogerus 
2244404905a6SHeikki Krogerus #define ACPI_ID_INTEL_BSW	"808622B7"
2245404905a6SHeikki Krogerus 
2246404905a6SHeikki Krogerus static const struct acpi_device_id dwc3_acpi_match[] = {
2247404905a6SHeikki Krogerus 	{ ACPI_ID_INTEL_BSW, 0 },
2248404905a6SHeikki Krogerus 	{ },
2249404905a6SHeikki Krogerus };
2250404905a6SHeikki Krogerus MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
2251404905a6SHeikki Krogerus #endif
2252404905a6SHeikki Krogerus 
225372246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
225472246da4SFelipe Balbi 	.probe		= dwc3_probe,
22557690417dSBill Pemberton 	.remove		= dwc3_remove,
225672246da4SFelipe Balbi 	.driver		= {
225772246da4SFelipe Balbi 		.name	= "dwc3",
22585088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
2259404905a6SHeikki Krogerus 		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
22607f370ed0SFelipe Balbi 		.pm	= &dwc3_dev_pm_ops,
226172246da4SFelipe Balbi 	},
226272246da4SFelipe Balbi };
226372246da4SFelipe Balbi 
2264b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
2265b1116dccSTobias Klauser 
22667ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
226772246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
22685945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
226972246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
2270