xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision f09cc79b)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
272246da4SFelipe Balbi /**
372246da4SFelipe Balbi  * core.c - DesignWare USB3 DRD Controller Core file
472246da4SFelipe Balbi  *
572246da4SFelipe Balbi  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
672246da4SFelipe Balbi  *
772246da4SFelipe Balbi  * Authors: Felipe Balbi <balbi@ti.com>,
872246da4SFelipe Balbi  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
972246da4SFelipe Balbi  */
1072246da4SFelipe Balbi 
11fa0ea13eSFelipe Balbi #include <linux/version.h>
12a72e658bSFelipe Balbi #include <linux/module.h>
1372246da4SFelipe Balbi #include <linux/kernel.h>
1472246da4SFelipe Balbi #include <linux/slab.h>
1572246da4SFelipe Balbi #include <linux/spinlock.h>
1672246da4SFelipe Balbi #include <linux/platform_device.h>
1772246da4SFelipe Balbi #include <linux/pm_runtime.h>
1872246da4SFelipe Balbi #include <linux/interrupt.h>
1972246da4SFelipe Balbi #include <linux/ioport.h>
2072246da4SFelipe Balbi #include <linux/io.h>
2172246da4SFelipe Balbi #include <linux/list.h>
2272246da4SFelipe Balbi #include <linux/delay.h>
2372246da4SFelipe Balbi #include <linux/dma-mapping.h>
24457e84b6SFelipe Balbi #include <linux/of.h>
25404905a6SHeikki Krogerus #include <linux/acpi.h>
266344475fSSekhar Nori #include <linux/pinctrl/consumer.h>
2772246da4SFelipe Balbi 
2872246da4SFelipe Balbi #include <linux/usb/ch9.h>
2972246da4SFelipe Balbi #include <linux/usb/gadget.h>
30f7e846f0SFelipe Balbi #include <linux/usb/of.h>
31a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
3272246da4SFelipe Balbi 
3372246da4SFelipe Balbi #include "core.h"
3472246da4SFelipe Balbi #include "gadget.h"
3572246da4SFelipe Balbi #include "io.h"
3672246da4SFelipe Balbi 
3772246da4SFelipe Balbi #include "debug.h"
3872246da4SFelipe Balbi 
39fc8bb91bSFelipe Balbi #define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */
408300dd23SFelipe Balbi 
419d6173e1SThinh Nguyen /**
429d6173e1SThinh Nguyen  * dwc3_get_dr_mode - Validates and sets dr_mode
439d6173e1SThinh Nguyen  * @dwc: pointer to our context structure
449d6173e1SThinh Nguyen  */
459d6173e1SThinh Nguyen static int dwc3_get_dr_mode(struct dwc3 *dwc)
469d6173e1SThinh Nguyen {
479d6173e1SThinh Nguyen 	enum usb_dr_mode mode;
489d6173e1SThinh Nguyen 	struct device *dev = dwc->dev;
499d6173e1SThinh Nguyen 	unsigned int hw_mode;
509d6173e1SThinh Nguyen 
519d6173e1SThinh Nguyen 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
529d6173e1SThinh Nguyen 		dwc->dr_mode = USB_DR_MODE_OTG;
539d6173e1SThinh Nguyen 
549d6173e1SThinh Nguyen 	mode = dwc->dr_mode;
559d6173e1SThinh Nguyen 	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
569d6173e1SThinh Nguyen 
579d6173e1SThinh Nguyen 	switch (hw_mode) {
589d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_GADGET:
599d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
609d6173e1SThinh Nguyen 			dev_err(dev,
619d6173e1SThinh Nguyen 				"Controller does not support host mode.\n");
629d6173e1SThinh Nguyen 			return -EINVAL;
639d6173e1SThinh Nguyen 		}
649d6173e1SThinh Nguyen 		mode = USB_DR_MODE_PERIPHERAL;
659d6173e1SThinh Nguyen 		break;
669d6173e1SThinh Nguyen 	case DWC3_GHWPARAMS0_MODE_HOST:
679d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
689d6173e1SThinh Nguyen 			dev_err(dev,
699d6173e1SThinh Nguyen 				"Controller does not support device mode.\n");
709d6173e1SThinh Nguyen 			return -EINVAL;
719d6173e1SThinh Nguyen 		}
729d6173e1SThinh Nguyen 		mode = USB_DR_MODE_HOST;
739d6173e1SThinh Nguyen 		break;
749d6173e1SThinh Nguyen 	default:
759d6173e1SThinh Nguyen 		if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
769d6173e1SThinh Nguyen 			mode = USB_DR_MODE_HOST;
779d6173e1SThinh Nguyen 		else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
789d6173e1SThinh Nguyen 			mode = USB_DR_MODE_PERIPHERAL;
799d6173e1SThinh Nguyen 	}
809d6173e1SThinh Nguyen 
819d6173e1SThinh Nguyen 	if (mode != dwc->dr_mode) {
829d6173e1SThinh Nguyen 		dev_warn(dev,
839d6173e1SThinh Nguyen 			 "Configuration mismatch. dr_mode forced to %s\n",
849d6173e1SThinh Nguyen 			 mode == USB_DR_MODE_HOST ? "host" : "gadget");
859d6173e1SThinh Nguyen 
869d6173e1SThinh Nguyen 		dwc->dr_mode = mode;
879d6173e1SThinh Nguyen 	}
889d6173e1SThinh Nguyen 
899d6173e1SThinh Nguyen 	return 0;
909d6173e1SThinh Nguyen }
919d6173e1SThinh Nguyen 
92f09cc79bSRoger Quadros void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
933140e8cbSSebastian Andrzej Siewior {
943140e8cbSSebastian Andrzej Siewior 	u32 reg;
953140e8cbSSebastian Andrzej Siewior 
963140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
973140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
983140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
993140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
100c4a5153eSManu Gautam 
101c4a5153eSManu Gautam 	dwc->current_dr_role = mode;
10241ce1456SRoger Quadros }
1036b3261a2SRoger Quadros 
10441ce1456SRoger Quadros static void __dwc3_set_mode(struct work_struct *work)
10541ce1456SRoger Quadros {
10641ce1456SRoger Quadros 	struct dwc3 *dwc = work_to_dwc(work);
10741ce1456SRoger Quadros 	unsigned long flags;
10841ce1456SRoger Quadros 	int ret;
10941ce1456SRoger Quadros 
110f09cc79bSRoger Quadros 	if (dwc->dr_mode != USB_DR_MODE_OTG)
111f09cc79bSRoger Quadros 		return;
112f09cc79bSRoger Quadros 
113f09cc79bSRoger Quadros 	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
114f09cc79bSRoger Quadros 		dwc3_otg_update(dwc, 0);
115f09cc79bSRoger Quadros 
11641ce1456SRoger Quadros 	if (!dwc->desired_dr_role)
11741ce1456SRoger Quadros 		return;
11841ce1456SRoger Quadros 
11941ce1456SRoger Quadros 	if (dwc->desired_dr_role == dwc->current_dr_role)
12041ce1456SRoger Quadros 		return;
12141ce1456SRoger Quadros 
122f09cc79bSRoger Quadros 	if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
123daaecc65SRoger Quadros 		return;
124daaecc65SRoger Quadros 
12541ce1456SRoger Quadros 	switch (dwc->current_dr_role) {
12641ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_HOST:
12741ce1456SRoger Quadros 		dwc3_host_exit(dwc);
12841ce1456SRoger Quadros 		break;
12941ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_DEVICE:
13041ce1456SRoger Quadros 		dwc3_gadget_exit(dwc);
13141ce1456SRoger Quadros 		dwc3_event_buffers_cleanup(dwc);
13241ce1456SRoger Quadros 		break;
133f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
134f09cc79bSRoger Quadros 		dwc3_otg_exit(dwc);
135f09cc79bSRoger Quadros 		spin_lock_irqsave(&dwc->lock, flags);
136f09cc79bSRoger Quadros 		dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
137f09cc79bSRoger Quadros 		spin_unlock_irqrestore(&dwc->lock, flags);
138f09cc79bSRoger Quadros 		dwc3_otg_update(dwc, 1);
139f09cc79bSRoger Quadros 		break;
14041ce1456SRoger Quadros 	default:
14141ce1456SRoger Quadros 		break;
14241ce1456SRoger Quadros 	}
14341ce1456SRoger Quadros 
14441ce1456SRoger Quadros 	spin_lock_irqsave(&dwc->lock, flags);
14541ce1456SRoger Quadros 
14641ce1456SRoger Quadros 	dwc3_set_prtcap(dwc, dwc->desired_dr_role);
14741ce1456SRoger Quadros 
14841ce1456SRoger Quadros 	spin_unlock_irqrestore(&dwc->lock, flags);
14941ce1456SRoger Quadros 
15041ce1456SRoger Quadros 	switch (dwc->desired_dr_role) {
15141ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_HOST:
15241ce1456SRoger Quadros 		ret = dwc3_host_init(dwc);
153958d1a4cSFelipe Balbi 		if (ret) {
15441ce1456SRoger Quadros 			dev_err(dwc->dev, "failed to initialize host\n");
155958d1a4cSFelipe Balbi 		} else {
156958d1a4cSFelipe Balbi 			if (dwc->usb2_phy)
157958d1a4cSFelipe Balbi 				otg_set_vbus(dwc->usb2_phy->otg, true);
158958d1a4cSFelipe Balbi 			phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
159644cbbc3SManu Gautam 			phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
160d8c80bb3SVivek Gautam 			phy_calibrate(dwc->usb2_generic_phy);
161958d1a4cSFelipe Balbi 		}
16241ce1456SRoger Quadros 		break;
16341ce1456SRoger Quadros 	case DWC3_GCTL_PRTCAP_DEVICE:
16441ce1456SRoger Quadros 		dwc3_event_buffers_setup(dwc);
165958d1a4cSFelipe Balbi 
166958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
167958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, false);
168958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
169644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
170958d1a4cSFelipe Balbi 
17141ce1456SRoger Quadros 		ret = dwc3_gadget_init(dwc);
17241ce1456SRoger Quadros 		if (ret)
17341ce1456SRoger Quadros 			dev_err(dwc->dev, "failed to initialize peripheral\n");
17441ce1456SRoger Quadros 		break;
175f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
176f09cc79bSRoger Quadros 		dwc3_otg_init(dwc);
177f09cc79bSRoger Quadros 		dwc3_otg_update(dwc, 0);
178f09cc79bSRoger Quadros 		break;
17941ce1456SRoger Quadros 	default:
18041ce1456SRoger Quadros 		break;
18141ce1456SRoger Quadros 	}
182f09cc79bSRoger Quadros 
18341ce1456SRoger Quadros }
18441ce1456SRoger Quadros 
18541ce1456SRoger Quadros void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
18641ce1456SRoger Quadros {
18741ce1456SRoger Quadros 	unsigned long flags;
18841ce1456SRoger Quadros 
18941ce1456SRoger Quadros 	spin_lock_irqsave(&dwc->lock, flags);
19041ce1456SRoger Quadros 	dwc->desired_dr_role = mode;
19141ce1456SRoger Quadros 	spin_unlock_irqrestore(&dwc->lock, flags);
19241ce1456SRoger Quadros 
19341ce1456SRoger Quadros 	queue_work(system_power_efficient_wq, &dwc->drd_work);
1943140e8cbSSebastian Andrzej Siewior }
1958300dd23SFelipe Balbi 
196cf6d867dSFelipe Balbi u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
197cf6d867dSFelipe Balbi {
198cf6d867dSFelipe Balbi 	struct dwc3		*dwc = dep->dwc;
199cf6d867dSFelipe Balbi 	u32			reg;
200cf6d867dSFelipe Balbi 
201cf6d867dSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
202cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_NUM(dep->number) |
203cf6d867dSFelipe Balbi 			DWC3_GDBGFIFOSPACE_TYPE(type));
204cf6d867dSFelipe Balbi 
205cf6d867dSFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
206cf6d867dSFelipe Balbi 
207cf6d867dSFelipe Balbi 	return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
208cf6d867dSFelipe Balbi }
209cf6d867dSFelipe Balbi 
21072246da4SFelipe Balbi /**
21172246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
21272246da4SFelipe Balbi  * @dwc: pointer to our context structure
21372246da4SFelipe Balbi  */
21457303488SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc)
21572246da4SFelipe Balbi {
21672246da4SFelipe Balbi 	u32		reg;
217f59dcab1SFelipe Balbi 	int		retries = 1000;
21857303488SKishon Vijay Abraham I 	int		ret;
21972246da4SFelipe Balbi 
22051e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
22151e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
22257303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
22357303488SKishon Vijay Abraham I 	if (ret < 0)
22457303488SKishon Vijay Abraham I 		return ret;
22557303488SKishon Vijay Abraham I 
22657303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
22757303488SKishon Vijay Abraham I 	if (ret < 0) {
22857303488SKishon Vijay Abraham I 		phy_exit(dwc->usb2_generic_phy);
22957303488SKishon Vijay Abraham I 		return ret;
23057303488SKishon Vijay Abraham I 	}
23172246da4SFelipe Balbi 
232f59dcab1SFelipe Balbi 	/*
233f59dcab1SFelipe Balbi 	 * We're resetting only the device side because, if we're in host mode,
234f59dcab1SFelipe Balbi 	 * XHCI driver will reset the host block. If dwc3 was configured for
235f59dcab1SFelipe Balbi 	 * host-only mode, then we can return early.
236f59dcab1SFelipe Balbi 	 */
237c4a5153eSManu Gautam 	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
23857303488SKishon Vijay Abraham I 		return 0;
239f59dcab1SFelipe Balbi 
240f59dcab1SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
241f59dcab1SFelipe Balbi 	reg |= DWC3_DCTL_CSFTRST;
242f59dcab1SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
243f59dcab1SFelipe Balbi 
244f59dcab1SFelipe Balbi 	do {
245f59dcab1SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
246f59dcab1SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
247f59dcab1SFelipe Balbi 			return 0;
248f59dcab1SFelipe Balbi 
249f59dcab1SFelipe Balbi 		udelay(1);
250f59dcab1SFelipe Balbi 	} while (--retries);
251f59dcab1SFelipe Balbi 
25200b42170SBrian Norris 	phy_exit(dwc->usb3_generic_phy);
25300b42170SBrian Norris 	phy_exit(dwc->usb2_generic_phy);
25400b42170SBrian Norris 
255f59dcab1SFelipe Balbi 	return -ETIMEDOUT;
25672246da4SFelipe Balbi }
25772246da4SFelipe Balbi 
258db2be4e9SNikhil Badola /*
259db2be4e9SNikhil Badola  * dwc3_frame_length_adjustment - Adjusts frame length if required
260db2be4e9SNikhil Badola  * @dwc3: Pointer to our controller context structure
261db2be4e9SNikhil Badola  */
262bcdb3272SFelipe Balbi static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
263db2be4e9SNikhil Badola {
264db2be4e9SNikhil Badola 	u32 reg;
265db2be4e9SNikhil Badola 	u32 dft;
266db2be4e9SNikhil Badola 
267db2be4e9SNikhil Badola 	if (dwc->revision < DWC3_REVISION_250A)
268db2be4e9SNikhil Badola 		return;
269db2be4e9SNikhil Badola 
270bcdb3272SFelipe Balbi 	if (dwc->fladj == 0)
271db2be4e9SNikhil Badola 		return;
272db2be4e9SNikhil Badola 
273db2be4e9SNikhil Badola 	reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
274db2be4e9SNikhil Badola 	dft = reg & DWC3_GFLADJ_30MHZ_MASK;
275bcdb3272SFelipe Balbi 	if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
276db2be4e9SNikhil Badola 	    "request value same as default, ignoring\n")) {
277db2be4e9SNikhil Badola 		reg &= ~DWC3_GFLADJ_30MHZ_MASK;
278bcdb3272SFelipe Balbi 		reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
279db2be4e9SNikhil Badola 		dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
280db2be4e9SNikhil Badola 	}
281db2be4e9SNikhil Badola }
282db2be4e9SNikhil Badola 
283c5cc74e8SHeikki Krogerus /**
28472246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
28572246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
28672246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
28772246da4SFelipe Balbi  */
28872246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
28972246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
29072246da4SFelipe Balbi {
291d64ff406SArnd Bergmann 	dma_free_coherent(dwc->sysdev, evt->length, evt->buf, evt->dma);
29272246da4SFelipe Balbi }
29372246da4SFelipe Balbi 
29472246da4SFelipe Balbi /**
2951d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
29672246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
29772246da4SFelipe Balbi  * @length: size of the event buffer
29872246da4SFelipe Balbi  *
2991d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
30072246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
30172246da4SFelipe Balbi  */
30267d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
30367d0b500SFelipe Balbi 		unsigned length)
30472246da4SFelipe Balbi {
30572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
30672246da4SFelipe Balbi 
307380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
30872246da4SFelipe Balbi 	if (!evt)
30972246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
31072246da4SFelipe Balbi 
31172246da4SFelipe Balbi 	evt->dwc	= dwc;
31272246da4SFelipe Balbi 	evt->length	= length;
313d9fa4c63SJohn Youn 	evt->cache	= devm_kzalloc(dwc->dev, length, GFP_KERNEL);
314d9fa4c63SJohn Youn 	if (!evt->cache)
315d9fa4c63SJohn Youn 		return ERR_PTR(-ENOMEM);
316d9fa4c63SJohn Youn 
317d64ff406SArnd Bergmann 	evt->buf	= dma_alloc_coherent(dwc->sysdev, length,
31872246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
319e32672f0SFelipe Balbi 	if (!evt->buf)
32072246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
32172246da4SFelipe Balbi 
32272246da4SFelipe Balbi 	return evt;
32372246da4SFelipe Balbi }
32472246da4SFelipe Balbi 
32572246da4SFelipe Balbi /**
32672246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
32772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
32872246da4SFelipe Balbi  */
32972246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
33072246da4SFelipe Balbi {
33172246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
33272246da4SFelipe Balbi 
333696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
33464b6c8a7SAnton Tikhomirov 	if (evt)
33572246da4SFelipe Balbi 		dwc3_free_one_event_buffer(dwc, evt);
33672246da4SFelipe Balbi }
33772246da4SFelipe Balbi 
33872246da4SFelipe Balbi /**
33972246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
3401d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
34172246da4SFelipe Balbi  * @length: size of event buffer
34272246da4SFelipe Balbi  *
3431d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
34472246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
34572246da4SFelipe Balbi  */
34641ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
34772246da4SFelipe Balbi {
34872246da4SFelipe Balbi 	struct dwc3_event_buffer *evt;
34972246da4SFelipe Balbi 
35072246da4SFelipe Balbi 	evt = dwc3_alloc_one_event_buffer(dwc, length);
35172246da4SFelipe Balbi 	if (IS_ERR(evt)) {
35272246da4SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffer\n");
35372246da4SFelipe Balbi 		return PTR_ERR(evt);
35472246da4SFelipe Balbi 	}
355696c8b12SFelipe Balbi 	dwc->ev_buf = evt;
35672246da4SFelipe Balbi 
35772246da4SFelipe Balbi 	return 0;
35872246da4SFelipe Balbi }
35972246da4SFelipe Balbi 
36072246da4SFelipe Balbi /**
36172246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
3621d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
36372246da4SFelipe Balbi  *
36472246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
36572246da4SFelipe Balbi  */
366f09cc79bSRoger Quadros int dwc3_event_buffers_setup(struct dwc3 *dwc)
36772246da4SFelipe Balbi {
36872246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
36972246da4SFelipe Balbi 
370696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
3717acd85e0SPaul Zimmerman 	evt->lpos = 0;
372660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
37372246da4SFelipe Balbi 			lower_32_bits(evt->dma));
374660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
37572246da4SFelipe Balbi 			upper_32_bits(evt->dma));
376660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
37768d6a01bSFelipe Balbi 			DWC3_GEVNTSIZ_SIZE(evt->length));
378660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
37972246da4SFelipe Balbi 
38072246da4SFelipe Balbi 	return 0;
38172246da4SFelipe Balbi }
38272246da4SFelipe Balbi 
383f09cc79bSRoger Quadros void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
38472246da4SFelipe Balbi {
38572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
38672246da4SFelipe Balbi 
387696c8b12SFelipe Balbi 	evt = dwc->ev_buf;
3887acd85e0SPaul Zimmerman 
3897acd85e0SPaul Zimmerman 	evt->lpos = 0;
3907acd85e0SPaul Zimmerman 
391660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
392660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
393660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
39468d6a01bSFelipe Balbi 			| DWC3_GEVNTSIZ_SIZE(0));
395660e9bdeSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
39672246da4SFelipe Balbi }
39772246da4SFelipe Balbi 
3980ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
3990ffcaf37SFelipe Balbi {
4000ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
4010ffcaf37SFelipe Balbi 		return 0;
4020ffcaf37SFelipe Balbi 
4030ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
4040ffcaf37SFelipe Balbi 		return 0;
4050ffcaf37SFelipe Balbi 
4060ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
4070ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
4080ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
4090ffcaf37SFelipe Balbi 		return -ENOMEM;
4100ffcaf37SFelipe Balbi 
4110ffcaf37SFelipe Balbi 	return 0;
4120ffcaf37SFelipe Balbi }
4130ffcaf37SFelipe Balbi 
4140ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
4150ffcaf37SFelipe Balbi {
4160ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
4170ffcaf37SFelipe Balbi 	u32 param;
4180ffcaf37SFelipe Balbi 	int ret;
4190ffcaf37SFelipe Balbi 
4200ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
4210ffcaf37SFelipe Balbi 		return 0;
4220ffcaf37SFelipe Balbi 
4230ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
4240ffcaf37SFelipe Balbi 		return 0;
4250ffcaf37SFelipe Balbi 
4260ffcaf37SFelipe Balbi 	 /* should never fall here */
4270ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
4280ffcaf37SFelipe Balbi 		return 0;
4290ffcaf37SFelipe Balbi 
430d64ff406SArnd Bergmann 	scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf,
4310ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
4320ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
433d64ff406SArnd Bergmann 	if (dma_mapping_error(dwc->sysdev, scratch_addr)) {
434d64ff406SArnd Bergmann 		dev_err(dwc->sysdev, "failed to map scratch buffer\n");
4350ffcaf37SFelipe Balbi 		ret = -EFAULT;
4360ffcaf37SFelipe Balbi 		goto err0;
4370ffcaf37SFelipe Balbi 	}
4380ffcaf37SFelipe Balbi 
4390ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
4400ffcaf37SFelipe Balbi 
4410ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
4420ffcaf37SFelipe Balbi 
4430ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
4440ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
4450ffcaf37SFelipe Balbi 	if (ret < 0)
4460ffcaf37SFelipe Balbi 		goto err1;
4470ffcaf37SFelipe Balbi 
4480ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
4490ffcaf37SFelipe Balbi 
4500ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
4510ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
4520ffcaf37SFelipe Balbi 	if (ret < 0)
4530ffcaf37SFelipe Balbi 		goto err1;
4540ffcaf37SFelipe Balbi 
4550ffcaf37SFelipe Balbi 	return 0;
4560ffcaf37SFelipe Balbi 
4570ffcaf37SFelipe Balbi err1:
458d64ff406SArnd Bergmann 	dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
4590ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
4600ffcaf37SFelipe Balbi 
4610ffcaf37SFelipe Balbi err0:
4620ffcaf37SFelipe Balbi 	return ret;
4630ffcaf37SFelipe Balbi }
4640ffcaf37SFelipe Balbi 
4650ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
4660ffcaf37SFelipe Balbi {
4670ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
4680ffcaf37SFelipe Balbi 		return;
4690ffcaf37SFelipe Balbi 
4700ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
4710ffcaf37SFelipe Balbi 		return;
4720ffcaf37SFelipe Balbi 
4730ffcaf37SFelipe Balbi 	 /* should never fall here */
4740ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
4750ffcaf37SFelipe Balbi 		return;
4760ffcaf37SFelipe Balbi 
477d64ff406SArnd Bergmann 	dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
4780ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
4790ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
4800ffcaf37SFelipe Balbi }
4810ffcaf37SFelipe Balbi 
482789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
483789451f6SFelipe Balbi {
484789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
485789451f6SFelipe Balbi 
48647d3946eSBryan O'Donoghue 	dwc->num_eps = DWC3_NUM_EPS(parms);
487789451f6SFelipe Balbi }
488789451f6SFelipe Balbi 
48941ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
49026ceca97SFelipe Balbi {
49126ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
49226ceca97SFelipe Balbi 
49326ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
49426ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
49526ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
49626ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
49726ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
49826ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
49926ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
50026ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
50126ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
50226ceca97SFelipe Balbi }
50326ceca97SFelipe Balbi 
50498112041SRoger Quadros static int dwc3_core_ulpi_init(struct dwc3 *dwc)
50598112041SRoger Quadros {
50698112041SRoger Quadros 	int intf;
50798112041SRoger Quadros 	int ret = 0;
50898112041SRoger Quadros 
50998112041SRoger Quadros 	intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3);
51098112041SRoger Quadros 
51198112041SRoger Quadros 	if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI ||
51298112041SRoger Quadros 	    (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI &&
51398112041SRoger Quadros 	     dwc->hsphy_interface &&
51498112041SRoger Quadros 	     !strncmp(dwc->hsphy_interface, "ulpi", 4)))
51598112041SRoger Quadros 		ret = dwc3_ulpi_init(dwc);
51698112041SRoger Quadros 
51798112041SRoger Quadros 	return ret;
51898112041SRoger Quadros }
51998112041SRoger Quadros 
52072246da4SFelipe Balbi /**
521b5a65c40SHuang Rui  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
522b5a65c40SHuang Rui  * @dwc: Pointer to our controller context structure
52388bc9d19SHeikki Krogerus  *
52488bc9d19SHeikki Krogerus  * Returns 0 on success. The USB PHY interfaces are configured but not
52588bc9d19SHeikki Krogerus  * initialized. The PHY interfaces and the PHYs get initialized together with
52688bc9d19SHeikki Krogerus  * the core in dwc3_core_init.
527b5a65c40SHuang Rui  */
52888bc9d19SHeikki Krogerus static int dwc3_phy_setup(struct dwc3 *dwc)
529b5a65c40SHuang Rui {
530b5a65c40SHuang Rui 	u32 reg;
531b5a65c40SHuang Rui 
532b5a65c40SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
533b5a65c40SHuang Rui 
5342164a476SHuang Rui 	/*
5351966b865SFelipe Balbi 	 * Make sure UX_EXIT_PX is cleared as that causes issues with some
5361966b865SFelipe Balbi 	 * PHYs. Also, this bit is not supposed to be used in normal operation.
5371966b865SFelipe Balbi 	 */
5381966b865SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
5391966b865SFelipe Balbi 
5401966b865SFelipe Balbi 	/*
5412164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
5422164a476SHuang Rui 	 * to '0' during coreConsultant configuration. So default value
5432164a476SHuang Rui 	 * will be '0' when the core is reset. Application needs to set it
5442164a476SHuang Rui 	 * to '1' after the core initialization is completed.
5452164a476SHuang Rui 	 */
5462164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
5472164a476SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
5482164a476SHuang Rui 
549b5a65c40SHuang Rui 	if (dwc->u2ss_inp3_quirk)
550b5a65c40SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
551b5a65c40SHuang Rui 
552e58dd357SRajesh Bhagat 	if (dwc->dis_rxdet_inp3_quirk)
553e58dd357SRajesh Bhagat 		reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
554e58dd357SRajesh Bhagat 
555df31f5b3SHuang Rui 	if (dwc->req_p1p2p3_quirk)
556df31f5b3SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
557df31f5b3SHuang Rui 
558a2a1d0f5SHuang Rui 	if (dwc->del_p1p2p3_quirk)
559a2a1d0f5SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
560a2a1d0f5SHuang Rui 
56141c06ffdSHuang Rui 	if (dwc->del_phy_power_chg_quirk)
56241c06ffdSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
56341c06ffdSHuang Rui 
564fb67afcaSHuang Rui 	if (dwc->lfps_filter_quirk)
565fb67afcaSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
566fb67afcaSHuang Rui 
56714f4ac53SHuang Rui 	if (dwc->rx_detect_poll_quirk)
56814f4ac53SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
56914f4ac53SHuang Rui 
5706b6a0c9aSHuang Rui 	if (dwc->tx_de_emphasis_quirk)
5716b6a0c9aSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
5726b6a0c9aSHuang Rui 
573cd72f890SFelipe Balbi 	if (dwc->dis_u3_susphy_quirk)
57459acfa20SHuang Rui 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
57559acfa20SHuang Rui 
57600fe081dSWilliam Wu 	if (dwc->dis_del_phy_power_chg_quirk)
57700fe081dSWilliam Wu 		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
57800fe081dSWilliam Wu 
579b5a65c40SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
580b5a65c40SHuang Rui 
5812164a476SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
5822164a476SHuang Rui 
5833e10a2ceSHeikki Krogerus 	/* Select the HS PHY interface */
5843e10a2ceSHeikki Krogerus 	switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
5853e10a2ceSHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
58643cacb03SFelipe Balbi 		if (dwc->hsphy_interface &&
58743cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "utmi", 4)) {
5883e10a2ceSHeikki Krogerus 			reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
58988bc9d19SHeikki Krogerus 			break;
59043cacb03SFelipe Balbi 		} else if (dwc->hsphy_interface &&
59143cacb03SFelipe Balbi 				!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
5923e10a2ceSHeikki Krogerus 			reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
59388bc9d19SHeikki Krogerus 			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
5943e10a2ceSHeikki Krogerus 		} else {
59588bc9d19SHeikki Krogerus 			/* Relying on default value. */
59688bc9d19SHeikki Krogerus 			if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
5973e10a2ceSHeikki Krogerus 				break;
5983e10a2ceSHeikki Krogerus 		}
5993e10a2ceSHeikki Krogerus 		/* FALLTHROUGH */
60088bc9d19SHeikki Krogerus 	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
60188bc9d19SHeikki Krogerus 		/* FALLTHROUGH */
6023e10a2ceSHeikki Krogerus 	default:
6033e10a2ceSHeikki Krogerus 		break;
6043e10a2ceSHeikki Krogerus 	}
6053e10a2ceSHeikki Krogerus 
60632f2ed86SWilliam Wu 	switch (dwc->hsphy_mode) {
60732f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMI:
60832f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
60932f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
61032f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
61132f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
61232f2ed86SWilliam Wu 		break;
61332f2ed86SWilliam Wu 	case USBPHY_INTERFACE_MODE_UTMIW:
61432f2ed86SWilliam Wu 		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
61532f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
61632f2ed86SWilliam Wu 		reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
61732f2ed86SWilliam Wu 		       DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
61832f2ed86SWilliam Wu 		break;
61932f2ed86SWilliam Wu 	default:
62032f2ed86SWilliam Wu 		break;
62132f2ed86SWilliam Wu 	}
62232f2ed86SWilliam Wu 
6232164a476SHuang Rui 	/*
6242164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
6252164a476SHuang Rui 	 * '0' during coreConsultant configuration. So default value will
6262164a476SHuang Rui 	 * be '0' when the core is reset. Application needs to set it to
6272164a476SHuang Rui 	 * '1' after the core initialization is completed.
6282164a476SHuang Rui 	 */
6292164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
6302164a476SHuang Rui 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
6312164a476SHuang Rui 
632cd72f890SFelipe Balbi 	if (dwc->dis_u2_susphy_quirk)
6330effe0a3SHuang Rui 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
6340effe0a3SHuang Rui 
635ec791d14SJohn Youn 	if (dwc->dis_enblslpm_quirk)
636ec791d14SJohn Youn 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
637ec791d14SJohn Youn 
63816199f33SWilliam Wu 	if (dwc->dis_u2_freeclk_exists_quirk)
63916199f33SWilliam Wu 		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
64016199f33SWilliam Wu 
6412164a476SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
64288bc9d19SHeikki Krogerus 
64388bc9d19SHeikki Krogerus 	return 0;
644b5a65c40SHuang Rui }
645b5a65c40SHuang Rui 
646c499ff71SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
647c499ff71SFelipe Balbi {
648c499ff71SFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
649c499ff71SFelipe Balbi 
650c499ff71SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
651c499ff71SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
652c499ff71SFelipe Balbi 	phy_exit(dwc->usb2_generic_phy);
653c499ff71SFelipe Balbi 	phy_exit(dwc->usb3_generic_phy);
654c499ff71SFelipe Balbi 
655c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 1);
656c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 1);
657c499ff71SFelipe Balbi 	phy_power_off(dwc->usb2_generic_phy);
658c499ff71SFelipe Balbi 	phy_power_off(dwc->usb3_generic_phy);
659c499ff71SFelipe Balbi }
660c499ff71SFelipe Balbi 
6610759956fSFelipe Balbi static bool dwc3_core_is_valid(struct dwc3 *dwc)
66272246da4SFelipe Balbi {
66372246da4SFelipe Balbi 	u32 reg;
66472246da4SFelipe Balbi 
6657650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
6660759956fSFelipe Balbi 
6677650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
668690fb371SJohn Youn 	if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
669690fb371SJohn Youn 		/* Detected DWC_usb3 IP */
670690fb371SJohn Youn 		dwc->revision = reg;
671690fb371SJohn Youn 	} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
672690fb371SJohn Youn 		/* Detected DWC_usb31 IP */
673690fb371SJohn Youn 		dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
674690fb371SJohn Youn 		dwc->revision |= DWC3_REVISION_IS_DWC31;
675690fb371SJohn Youn 	} else {
6760759956fSFelipe Balbi 		return false;
6777650bd74SSebastian Andrzej Siewior 	}
6787650bd74SSebastian Andrzej Siewior 
6790759956fSFelipe Balbi 	return true;
6800e1e5c47SPaul Zimmerman }
6810e1e5c47SPaul Zimmerman 
682941f918eSFelipe Balbi static void dwc3_core_setup_global_control(struct dwc3 *dwc)
68372246da4SFelipe Balbi {
68472246da4SFelipe Balbi 	u32 hwparams4 = dwc->hwparams.hwparams4;
68572246da4SFelipe Balbi 	u32 reg;
686c499ff71SFelipe Balbi 
6874878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
6883e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
6894878a028SSebastian Andrzej Siewior 
690164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
6914878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
69232a4a135SFelipe Balbi 		/**
69332a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
69432a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
69532a4a135SFelipe Balbi 		 *
69632a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
69732a4a135SFelipe Balbi 		 * configurations.
69832a4a135SFelipe Balbi 		 *
69932a4a135SFelipe Balbi 		 * Refers to:
70032a4a135SFelipe Balbi 		 *
70132a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
70232a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
70332a4a135SFelipe Balbi 		 */
70432a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
70532a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
70632a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
70732a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
70832a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
70932a4a135SFelipe Balbi 		else
7104878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
7114878a028SSebastian Andrzej Siewior 		break;
7120ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
7130ffcaf37SFelipe Balbi 		/* enable hibernation here */
7140ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
7152eac3992SHuang Rui 
7162eac3992SHuang Rui 		/*
7172eac3992SHuang Rui 		 * REVISIT Enabling this bit so that host-mode hibernation
7182eac3992SHuang Rui 		 * will work. Device-mode hibernation is not yet implemented.
7192eac3992SHuang Rui 		 */
7202eac3992SHuang Rui 		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
7210ffcaf37SFelipe Balbi 		break;
7224878a028SSebastian Andrzej Siewior 	default:
7235eb30cedSFelipe Balbi 		/* nothing */
7245eb30cedSFelipe Balbi 		break;
7254878a028SSebastian Andrzej Siewior 	}
7264878a028SSebastian Andrzej Siewior 
727946bd579SHuang Rui 	/* check if current dwc3 is on simulation board */
728946bd579SHuang Rui 	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
7295eb30cedSFelipe Balbi 		dev_info(dwc->dev, "Running with FPGA optmizations\n");
730946bd579SHuang Rui 		dwc->is_fpga = true;
731946bd579SHuang Rui 	}
732946bd579SHuang Rui 
7333b81221aSHuang Rui 	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
7343b81221aSHuang Rui 			"disable_scramble cannot be used on non-FPGA builds\n");
7353b81221aSHuang Rui 
7363b81221aSHuang Rui 	if (dwc->disable_scramble_quirk && dwc->is_fpga)
7373b81221aSHuang Rui 		reg |= DWC3_GCTL_DISSCRAMBLE;
7383b81221aSHuang Rui 	else
7393b81221aSHuang Rui 		reg &= ~DWC3_GCTL_DISSCRAMBLE;
7403b81221aSHuang Rui 
7419a5b2f31SHuang Rui 	if (dwc->u2exit_lfps_quirk)
7429a5b2f31SHuang Rui 		reg |= DWC3_GCTL_U2EXIT_LFPS;
7439a5b2f31SHuang Rui 
7444878a028SSebastian Andrzej Siewior 	/*
7454878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
7461d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
7474878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
7481d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
7494878a028SSebastian Andrzej Siewior 	 */
7504878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
7514878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
7524878a028SSebastian Andrzej Siewior 
7534878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
754941f918eSFelipe Balbi }
7554878a028SSebastian Andrzej Siewior 
756f54edb53SFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc);
75798112041SRoger Quadros static int dwc3_core_ulpi_init(struct dwc3 *dwc);
758f54edb53SFelipe Balbi 
759941f918eSFelipe Balbi /**
760941f918eSFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
761941f918eSFelipe Balbi  * @dwc: Pointer to our controller context structure
762941f918eSFelipe Balbi  *
763941f918eSFelipe Balbi  * Returns 0 on success otherwise negative errno.
764941f918eSFelipe Balbi  */
765941f918eSFelipe Balbi static int dwc3_core_init(struct dwc3 *dwc)
766941f918eSFelipe Balbi {
767941f918eSFelipe Balbi 	u32			reg;
768941f918eSFelipe Balbi 	int			ret;
769941f918eSFelipe Balbi 
770941f918eSFelipe Balbi 	if (!dwc3_core_is_valid(dwc)) {
771941f918eSFelipe Balbi 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
772941f918eSFelipe Balbi 		ret = -ENODEV;
773941f918eSFelipe Balbi 		goto err0;
774941f918eSFelipe Balbi 	}
775941f918eSFelipe Balbi 
776941f918eSFelipe Balbi 	/*
777941f918eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
778941f918eSFelipe Balbi 	 * out which kernel version a bug was found.
779941f918eSFelipe Balbi 	 */
780941f918eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
781941f918eSFelipe Balbi 
782941f918eSFelipe Balbi 	/* Handle USB2.0-only core configuration */
783941f918eSFelipe Balbi 	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
784941f918eSFelipe Balbi 			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
785941f918eSFelipe Balbi 		if (dwc->maximum_speed == USB_SPEED_SUPER)
786941f918eSFelipe Balbi 			dwc->maximum_speed = USB_SPEED_HIGH;
787941f918eSFelipe Balbi 	}
788941f918eSFelipe Balbi 
789941f918eSFelipe Balbi 	ret = dwc3_phy_setup(dwc);
790941f918eSFelipe Balbi 	if (ret)
791941f918eSFelipe Balbi 		goto err0;
792941f918eSFelipe Balbi 
79398112041SRoger Quadros 	if (!dwc->ulpi_ready) {
79498112041SRoger Quadros 		ret = dwc3_core_ulpi_init(dwc);
79598112041SRoger Quadros 		if (ret)
79698112041SRoger Quadros 			goto err0;
79798112041SRoger Quadros 		dwc->ulpi_ready = true;
79898112041SRoger Quadros 	}
79998112041SRoger Quadros 
80098112041SRoger Quadros 	if (!dwc->phys_ready) {
80198112041SRoger Quadros 		ret = dwc3_core_get_phy(dwc);
80298112041SRoger Quadros 		if (ret)
80398112041SRoger Quadros 			goto err0a;
80498112041SRoger Quadros 		dwc->phys_ready = true;
80598112041SRoger Quadros 	}
80698112041SRoger Quadros 
80798112041SRoger Quadros 	ret = dwc3_core_soft_reset(dwc);
80898112041SRoger Quadros 	if (ret)
80998112041SRoger Quadros 		goto err0a;
81098112041SRoger Quadros 
811941f918eSFelipe Balbi 	dwc3_core_setup_global_control(dwc);
812c499ff71SFelipe Balbi 	dwc3_core_num_eps(dwc);
8130ffcaf37SFelipe Balbi 
8140ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
8150ffcaf37SFelipe Balbi 	if (ret)
816c499ff71SFelipe Balbi 		goto err1;
817c499ff71SFelipe Balbi 
818c499ff71SFelipe Balbi 	/* Adjust Frame Length */
819c499ff71SFelipe Balbi 	dwc3_frame_length_adjustment(dwc);
820c499ff71SFelipe Balbi 
821c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 0);
822c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 0);
823c499ff71SFelipe Balbi 	ret = phy_power_on(dwc->usb2_generic_phy);
824c499ff71SFelipe Balbi 	if (ret < 0)
8250ffcaf37SFelipe Balbi 		goto err2;
8260ffcaf37SFelipe Balbi 
827c499ff71SFelipe Balbi 	ret = phy_power_on(dwc->usb3_generic_phy);
828c499ff71SFelipe Balbi 	if (ret < 0)
829c499ff71SFelipe Balbi 		goto err3;
830c499ff71SFelipe Balbi 
831c499ff71SFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
832c499ff71SFelipe Balbi 	if (ret) {
833c499ff71SFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
834c499ff71SFelipe Balbi 		goto err4;
835c499ff71SFelipe Balbi 	}
836c499ff71SFelipe Balbi 
83706281d46SJohn Youn 	/*
83806281d46SJohn Youn 	 * ENDXFER polling is available on version 3.10a and later of
83906281d46SJohn Youn 	 * the DWC_usb3 controller. It is NOT available in the
84006281d46SJohn Youn 	 * DWC_usb31 controller.
84106281d46SJohn Youn 	 */
84206281d46SJohn Youn 	if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
84306281d46SJohn Youn 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
84406281d46SJohn Youn 		reg |= DWC3_GUCTL2_RST_ACTBITLATER;
84506281d46SJohn Youn 		dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
84606281d46SJohn Youn 	}
84706281d46SJohn Youn 
84865db7a0cSWilliam Wu 	if (dwc->revision >= DWC3_REVISION_250A) {
8490bb39ca1SJohn Youn 		reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
85065db7a0cSWilliam Wu 
85165db7a0cSWilliam Wu 		/*
85265db7a0cSWilliam Wu 		 * Enable hardware control of sending remote wakeup
85365db7a0cSWilliam Wu 		 * in HS when the device is in the L1 state.
85465db7a0cSWilliam Wu 		 */
85565db7a0cSWilliam Wu 		if (dwc->revision >= DWC3_REVISION_290A)
8560bb39ca1SJohn Youn 			reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
85765db7a0cSWilliam Wu 
85865db7a0cSWilliam Wu 		if (dwc->dis_tx_ipgap_linecheck_quirk)
85965db7a0cSWilliam Wu 			reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
86065db7a0cSWilliam Wu 
8610bb39ca1SJohn Youn 		dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
8620bb39ca1SJohn Youn 	}
8630bb39ca1SJohn Youn 
86472246da4SFelipe Balbi 	return 0;
86572246da4SFelipe Balbi 
866c499ff71SFelipe Balbi err4:
8679b9d7cddSVivek Gautam 	phy_power_off(dwc->usb3_generic_phy);
868c499ff71SFelipe Balbi 
869c499ff71SFelipe Balbi err3:
8709b9d7cddSVivek Gautam 	phy_power_off(dwc->usb2_generic_phy);
871c499ff71SFelipe Balbi 
8720ffcaf37SFelipe Balbi err2:
873c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb2_phy, 1);
874c499ff71SFelipe Balbi 	usb_phy_set_suspend(dwc->usb3_phy, 1);
8750ffcaf37SFelipe Balbi 
8760ffcaf37SFelipe Balbi err1:
8770ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
8780ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
87957303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
88057303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
8810ffcaf37SFelipe Balbi 
88298112041SRoger Quadros err0a:
88398112041SRoger Quadros 	dwc3_ulpi_exit(dwc);
88498112041SRoger Quadros 
88572246da4SFelipe Balbi err0:
88672246da4SFelipe Balbi 	return ret;
88772246da4SFelipe Balbi }
88872246da4SFelipe Balbi 
8893c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
89072246da4SFelipe Balbi {
8913c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
892941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
8933c9f94acSFelipe Balbi 	int ret;
89472246da4SFelipe Balbi 
8955088b6f5SKishon Vijay Abraham I 	if (node) {
8965088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
8975088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
898bb674907SFelipe Balbi 	} else {
899bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
900bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
9015088b6f5SKishon Vijay Abraham I 	}
9025088b6f5SKishon Vijay Abraham I 
903d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
904d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
905122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
906122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
907122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
908d105e7f8SFelipe Balbi 			return ret;
909122f06e6SKishon Vijay Abraham I 		} else {
91051e1e7bcSFelipe Balbi 			dev_err(dev, "no usb2 phy configured\n");
911122f06e6SKishon Vijay Abraham I 			return ret;
912122f06e6SKishon Vijay Abraham I 		}
91351e1e7bcSFelipe Balbi 	}
91451e1e7bcSFelipe Balbi 
915d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
916315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
917122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
918122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
919122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
920d105e7f8SFelipe Balbi 			return ret;
921122f06e6SKishon Vijay Abraham I 		} else {
92251e1e7bcSFelipe Balbi 			dev_err(dev, "no usb3 phy configured\n");
923122f06e6SKishon Vijay Abraham I 			return ret;
924122f06e6SKishon Vijay Abraham I 		}
92551e1e7bcSFelipe Balbi 	}
92651e1e7bcSFelipe Balbi 
92757303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
92857303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
92957303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
93057303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
93157303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
93257303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
93357303488SKishon Vijay Abraham I 			return ret;
93457303488SKishon Vijay Abraham I 		} else {
93557303488SKishon Vijay Abraham I 			dev_err(dev, "no usb2 phy configured\n");
93657303488SKishon Vijay Abraham I 			return ret;
93757303488SKishon Vijay Abraham I 		}
93857303488SKishon Vijay Abraham I 	}
93957303488SKishon Vijay Abraham I 
94057303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
94157303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
94257303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
94357303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
94457303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
94557303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
94657303488SKishon Vijay Abraham I 			return ret;
94757303488SKishon Vijay Abraham I 		} else {
94857303488SKishon Vijay Abraham I 			dev_err(dev, "no usb3 phy configured\n");
94957303488SKishon Vijay Abraham I 			return ret;
95057303488SKishon Vijay Abraham I 		}
95157303488SKishon Vijay Abraham I 	}
95257303488SKishon Vijay Abraham I 
9533c9f94acSFelipe Balbi 	return 0;
9543c9f94acSFelipe Balbi }
9553c9f94acSFelipe Balbi 
9565f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
9575f94adfeSFelipe Balbi {
9585f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
9595f94adfeSFelipe Balbi 	int ret;
9605f94adfeSFelipe Balbi 
9615f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
9625f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
96341ce1456SRoger Quadros 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
964958d1a4cSFelipe Balbi 
965958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
966958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, false);
967958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
968644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
969958d1a4cSFelipe Balbi 
9705f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
9715f94adfeSFelipe Balbi 		if (ret) {
9729522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
9735f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize gadget\n");
9745f94adfeSFelipe Balbi 			return ret;
9755f94adfeSFelipe Balbi 		}
9765f94adfeSFelipe Balbi 		break;
9775f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
97841ce1456SRoger Quadros 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
979958d1a4cSFelipe Balbi 
980958d1a4cSFelipe Balbi 		if (dwc->usb2_phy)
981958d1a4cSFelipe Balbi 			otg_set_vbus(dwc->usb2_phy->otg, true);
982958d1a4cSFelipe Balbi 		phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
983644cbbc3SManu Gautam 		phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
984958d1a4cSFelipe Balbi 
9855f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
9865f94adfeSFelipe Balbi 		if (ret) {
9879522def4SRoger Quadros 			if (ret != -EPROBE_DEFER)
9885f94adfeSFelipe Balbi 				dev_err(dev, "failed to initialize host\n");
9895f94adfeSFelipe Balbi 			return ret;
9905f94adfeSFelipe Balbi 		}
991d8c80bb3SVivek Gautam 		phy_calibrate(dwc->usb2_generic_phy);
9925f94adfeSFelipe Balbi 		break;
9935f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
99441ce1456SRoger Quadros 		INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
9959840354fSRoger Quadros 		ret = dwc3_drd_init(dwc);
9969840354fSRoger Quadros 		if (ret) {
9979840354fSRoger Quadros 			if (ret != -EPROBE_DEFER)
9989840354fSRoger Quadros 				dev_err(dev, "failed to initialize dual-role\n");
9999840354fSRoger Quadros 			return ret;
10009840354fSRoger Quadros 		}
10015f94adfeSFelipe Balbi 		break;
10025f94adfeSFelipe Balbi 	default:
10035f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
10045f94adfeSFelipe Balbi 		return -EINVAL;
10055f94adfeSFelipe Balbi 	}
10065f94adfeSFelipe Balbi 
10075f94adfeSFelipe Balbi 	return 0;
10085f94adfeSFelipe Balbi }
10095f94adfeSFelipe Balbi 
10105f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
10115f94adfeSFelipe Balbi {
10125f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
10135f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
10145f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
10155f94adfeSFelipe Balbi 		break;
10165f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
10175f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
10185f94adfeSFelipe Balbi 		break;
10195f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
10209840354fSRoger Quadros 		dwc3_drd_exit(dwc);
10215f94adfeSFelipe Balbi 		break;
10225f94adfeSFelipe Balbi 	default:
10235f94adfeSFelipe Balbi 		/* do nothing */
10245f94adfeSFelipe Balbi 		break;
10255f94adfeSFelipe Balbi 	}
10265f94adfeSFelipe Balbi }
10275f94adfeSFelipe Balbi 
1028c5ac6116SFelipe Balbi static void dwc3_get_properties(struct dwc3 *dwc)
10293c9f94acSFelipe Balbi {
1030c5ac6116SFelipe Balbi 	struct device		*dev = dwc->dev;
103180caf7d2SHuang Rui 	u8			lpm_nyet_threshold;
10326b6a0c9aSHuang Rui 	u8			tx_de_emphasis;
1033460d098cSHuang Rui 	u8			hird_threshold;
10343c9f94acSFelipe Balbi 
103580caf7d2SHuang Rui 	/* default to highest possible threshold */
103680caf7d2SHuang Rui 	lpm_nyet_threshold = 0xff;
103780caf7d2SHuang Rui 
10386b6a0c9aSHuang Rui 	/* default to -3.5dB de-emphasis */
10396b6a0c9aSHuang Rui 	tx_de_emphasis = 1;
10406b6a0c9aSHuang Rui 
1041460d098cSHuang Rui 	/*
1042460d098cSHuang Rui 	 * default to assert utmi_sleep_n and use maximum allowed HIRD
1043460d098cSHuang Rui 	 * threshold value of 0b1100
1044460d098cSHuang Rui 	 */
1045460d098cSHuang Rui 	hird_threshold = 12;
1046460d098cSHuang Rui 
104763863b98SHeikki Krogerus 	dwc->maximum_speed = usb_get_maximum_speed(dev);
104806e7114fSHeikki Krogerus 	dwc->dr_mode = usb_get_dr_mode(dev);
104932f2ed86SWilliam Wu 	dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
105063863b98SHeikki Krogerus 
1051d64ff406SArnd Bergmann 	dwc->sysdev_is_parent = device_property_read_bool(dev,
1052d64ff406SArnd Bergmann 				"linux,sysdev_is_parent");
1053d64ff406SArnd Bergmann 	if (dwc->sysdev_is_parent)
1054d64ff406SArnd Bergmann 		dwc->sysdev = dwc->dev->parent;
1055d64ff406SArnd Bergmann 	else
1056d64ff406SArnd Bergmann 		dwc->sysdev = dwc->dev;
1057d64ff406SArnd Bergmann 
10583d128919SHeikki Krogerus 	dwc->has_lpm_erratum = device_property_read_bool(dev,
105980caf7d2SHuang Rui 				"snps,has-lpm-erratum");
10603d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,lpm-nyet-threshold",
106180caf7d2SHuang Rui 				&lpm_nyet_threshold);
10623d128919SHeikki Krogerus 	dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
1063460d098cSHuang Rui 				"snps,is-utmi-l1-suspend");
10643d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,hird-threshold",
1065460d098cSHuang Rui 				&hird_threshold);
10663d128919SHeikki Krogerus 	dwc->usb3_lpm_capable = device_property_read_bool(dev,
1067eac68e8fSRobert Baldyga 				"snps,usb3_lpm_capable");
10683c9f94acSFelipe Balbi 
10693d128919SHeikki Krogerus 	dwc->disable_scramble_quirk = device_property_read_bool(dev,
10703b81221aSHuang Rui 				"snps,disable_scramble_quirk");
10713d128919SHeikki Krogerus 	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
10729a5b2f31SHuang Rui 				"snps,u2exit_lfps_quirk");
10733d128919SHeikki Krogerus 	dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
1074b5a65c40SHuang Rui 				"snps,u2ss_inp3_quirk");
10753d128919SHeikki Krogerus 	dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
1076df31f5b3SHuang Rui 				"snps,req_p1p2p3_quirk");
10773d128919SHeikki Krogerus 	dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
1078a2a1d0f5SHuang Rui 				"snps,del_p1p2p3_quirk");
10793d128919SHeikki Krogerus 	dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
108041c06ffdSHuang Rui 				"snps,del_phy_power_chg_quirk");
10813d128919SHeikki Krogerus 	dwc->lfps_filter_quirk = device_property_read_bool(dev,
1082fb67afcaSHuang Rui 				"snps,lfps_filter_quirk");
10833d128919SHeikki Krogerus 	dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
108414f4ac53SHuang Rui 				"snps,rx_detect_poll_quirk");
10853d128919SHeikki Krogerus 	dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
108659acfa20SHuang Rui 				"snps,dis_u3_susphy_quirk");
10873d128919SHeikki Krogerus 	dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
10880effe0a3SHuang Rui 				"snps,dis_u2_susphy_quirk");
1089ec791d14SJohn Youn 	dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
1090ec791d14SJohn Youn 				"snps,dis_enblslpm_quirk");
1091e58dd357SRajesh Bhagat 	dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
1092e58dd357SRajesh Bhagat 				"snps,dis_rxdet_inp3_quirk");
109316199f33SWilliam Wu 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
109416199f33SWilliam Wu 				"snps,dis-u2-freeclk-exists-quirk");
109500fe081dSWilliam Wu 	dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
109600fe081dSWilliam Wu 				"snps,dis-del-phy-power-chg-quirk");
109765db7a0cSWilliam Wu 	dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
109865db7a0cSWilliam Wu 				"snps,dis-tx-ipgap-linecheck-quirk");
10996b6a0c9aSHuang Rui 
11003d128919SHeikki Krogerus 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
11016b6a0c9aSHuang Rui 				"snps,tx_de_emphasis_quirk");
11023d128919SHeikki Krogerus 	device_property_read_u8(dev, "snps,tx_de_emphasis",
11036b6a0c9aSHuang Rui 				&tx_de_emphasis);
11043d128919SHeikki Krogerus 	device_property_read_string(dev, "snps,hsphy_interface",
11053e10a2ceSHeikki Krogerus 				    &dwc->hsphy_interface);
11063d128919SHeikki Krogerus 	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
1107bcdb3272SFelipe Balbi 				 &dwc->fladj);
11083d128919SHeikki Krogerus 
110942bf02ecSRoger Quadros 	dwc->dis_metastability_quirk = device_property_read_bool(dev,
111042bf02ecSRoger Quadros 				"snps,dis_metastability_quirk");
111142bf02ecSRoger Quadros 
111280caf7d2SHuang Rui 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
11136b6a0c9aSHuang Rui 	dwc->tx_de_emphasis = tx_de_emphasis;
111480caf7d2SHuang Rui 
1115460d098cSHuang Rui 	dwc->hird_threshold = hird_threshold
1116460d098cSHuang Rui 		| (dwc->is_utmi_l1_suspend << 4);
1117460d098cSHuang Rui 
1118cf40b86bSJohn Youn 	dwc->imod_interval = 0;
1119cf40b86bSJohn Youn }
1120cf40b86bSJohn Youn 
1121cf40b86bSJohn Youn /* check whether the core supports IMOD */
1122cf40b86bSJohn Youn bool dwc3_has_imod(struct dwc3 *dwc)
1123cf40b86bSJohn Youn {
1124cf40b86bSJohn Youn 	return ((dwc3_is_usb3(dwc) &&
1125cf40b86bSJohn Youn 		 dwc->revision >= DWC3_REVISION_300A) ||
1126cf40b86bSJohn Youn 		(dwc3_is_usb31(dwc) &&
1127cf40b86bSJohn Youn 		 dwc->revision >= DWC3_USB31_REVISION_120A));
1128c5ac6116SFelipe Balbi }
1129c5ac6116SFelipe Balbi 
11307ac51a12SJohn Youn static void dwc3_check_params(struct dwc3 *dwc)
11317ac51a12SJohn Youn {
11327ac51a12SJohn Youn 	struct device *dev = dwc->dev;
11337ac51a12SJohn Youn 
1134cf40b86bSJohn Youn 	/* Check for proper value of imod_interval */
1135cf40b86bSJohn Youn 	if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
1136cf40b86bSJohn Youn 		dev_warn(dwc->dev, "Interrupt moderation not supported\n");
1137cf40b86bSJohn Youn 		dwc->imod_interval = 0;
1138cf40b86bSJohn Youn 	}
1139cf40b86bSJohn Youn 
114028632b44SJohn Youn 	/*
114128632b44SJohn Youn 	 * Workaround for STAR 9000961433 which affects only version
114228632b44SJohn Youn 	 * 3.00a of the DWC_usb3 core. This prevents the controller
114328632b44SJohn Youn 	 * interrupt from being masked while handling events. IMOD
114428632b44SJohn Youn 	 * allows us to work around this issue. Enable it for the
114528632b44SJohn Youn 	 * affected version.
114628632b44SJohn Youn 	 */
114728632b44SJohn Youn 	if (!dwc->imod_interval &&
114828632b44SJohn Youn 	    (dwc->revision == DWC3_REVISION_300A))
114928632b44SJohn Youn 		dwc->imod_interval = 1;
115028632b44SJohn Youn 
11517ac51a12SJohn Youn 	/* Check the maximum_speed parameter */
11527ac51a12SJohn Youn 	switch (dwc->maximum_speed) {
11537ac51a12SJohn Youn 	case USB_SPEED_LOW:
11547ac51a12SJohn Youn 	case USB_SPEED_FULL:
11557ac51a12SJohn Youn 	case USB_SPEED_HIGH:
11567ac51a12SJohn Youn 	case USB_SPEED_SUPER:
11577ac51a12SJohn Youn 	case USB_SPEED_SUPER_PLUS:
11587ac51a12SJohn Youn 		break;
11597ac51a12SJohn Youn 	default:
11607ac51a12SJohn Youn 		dev_err(dev, "invalid maximum_speed parameter %d\n",
11617ac51a12SJohn Youn 			dwc->maximum_speed);
11627ac51a12SJohn Youn 		/* fall through */
11637ac51a12SJohn Youn 	case USB_SPEED_UNKNOWN:
11647ac51a12SJohn Youn 		/* default to superspeed */
11657ac51a12SJohn Youn 		dwc->maximum_speed = USB_SPEED_SUPER;
11667ac51a12SJohn Youn 
11677ac51a12SJohn Youn 		/*
11687ac51a12SJohn Youn 		 * default to superspeed plus if we are capable.
11697ac51a12SJohn Youn 		 */
11707ac51a12SJohn Youn 		if (dwc3_is_usb31(dwc) &&
11717ac51a12SJohn Youn 		    (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
11727ac51a12SJohn Youn 		     DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
11737ac51a12SJohn Youn 			dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
11747ac51a12SJohn Youn 
11757ac51a12SJohn Youn 		break;
11767ac51a12SJohn Youn 	}
11777ac51a12SJohn Youn }
11787ac51a12SJohn Youn 
1179c5ac6116SFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
1180c5ac6116SFelipe Balbi {
1181c5ac6116SFelipe Balbi 	struct device		*dev = &pdev->dev;
1182c5ac6116SFelipe Balbi 	struct resource		*res;
1183c5ac6116SFelipe Balbi 	struct dwc3		*dwc;
1184c5ac6116SFelipe Balbi 
1185c5ac6116SFelipe Balbi 	int			ret;
1186c5ac6116SFelipe Balbi 
1187c5ac6116SFelipe Balbi 	void __iomem		*regs;
1188c5ac6116SFelipe Balbi 
1189c5ac6116SFelipe Balbi 	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
1190c5ac6116SFelipe Balbi 	if (!dwc)
1191c5ac6116SFelipe Balbi 		return -ENOMEM;
1192c5ac6116SFelipe Balbi 
1193c5ac6116SFelipe Balbi 	dwc->dev = dev;
1194c5ac6116SFelipe Balbi 
1195c5ac6116SFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1196c5ac6116SFelipe Balbi 	if (!res) {
1197c5ac6116SFelipe Balbi 		dev_err(dev, "missing memory resource\n");
1198c5ac6116SFelipe Balbi 		return -ENODEV;
1199c5ac6116SFelipe Balbi 	}
1200c5ac6116SFelipe Balbi 
1201c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].start = res->start;
1202c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
1203c5ac6116SFelipe Balbi 					DWC3_XHCI_REGS_END;
1204c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].flags = res->flags;
1205c5ac6116SFelipe Balbi 	dwc->xhci_resources[0].name = res->name;
1206c5ac6116SFelipe Balbi 
1207c5ac6116SFelipe Balbi 	res->start += DWC3_GLOBALS_REGS_START;
1208c5ac6116SFelipe Balbi 
1209c5ac6116SFelipe Balbi 	/*
1210c5ac6116SFelipe Balbi 	 * Request memory region but exclude xHCI regs,
1211c5ac6116SFelipe Balbi 	 * since it will be requested by the xhci-plat driver.
1212c5ac6116SFelipe Balbi 	 */
1213c5ac6116SFelipe Balbi 	regs = devm_ioremap_resource(dev, res);
1214c5ac6116SFelipe Balbi 	if (IS_ERR(regs)) {
1215c5ac6116SFelipe Balbi 		ret = PTR_ERR(regs);
1216c5ac6116SFelipe Balbi 		goto err0;
1217c5ac6116SFelipe Balbi 	}
1218c5ac6116SFelipe Balbi 
1219c5ac6116SFelipe Balbi 	dwc->regs	= regs;
1220c5ac6116SFelipe Balbi 	dwc->regs_size	= resource_size(res);
1221c5ac6116SFelipe Balbi 
1222c5ac6116SFelipe Balbi 	dwc3_get_properties(dwc);
1223c5ac6116SFelipe Balbi 
12246c89cce0SHeikki Krogerus 	platform_set_drvdata(pdev, dwc);
12252917e718SHeikki Krogerus 	dwc3_cache_hwparams(dwc);
12266c89cce0SHeikki Krogerus 
122772246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
122872246da4SFelipe Balbi 
1229fc8bb91bSFelipe Balbi 	pm_runtime_set_active(dev);
1230fc8bb91bSFelipe Balbi 	pm_runtime_use_autosuspend(dev);
1231fc8bb91bSFelipe Balbi 	pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
1232802ca850SChanho Park 	pm_runtime_enable(dev);
123332808237SRoger Quadros 	ret = pm_runtime_get_sync(dev);
123432808237SRoger Quadros 	if (ret < 0)
123532808237SRoger Quadros 		goto err1;
123632808237SRoger Quadros 
1237802ca850SChanho Park 	pm_runtime_forbid(dev);
123872246da4SFelipe Balbi 
12393921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
12403921426bSFelipe Balbi 	if (ret) {
12413921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
12423921426bSFelipe Balbi 		ret = -ENOMEM;
124332808237SRoger Quadros 		goto err2;
12443921426bSFelipe Balbi 	}
12453921426bSFelipe Balbi 
12469d6173e1SThinh Nguyen 	ret = dwc3_get_dr_mode(dwc);
12479d6173e1SThinh Nguyen 	if (ret)
12489d6173e1SThinh Nguyen 		goto err3;
124932a4a135SFelipe Balbi 
1250c499ff71SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
1251c499ff71SFelipe Balbi 	if (ret)
125232808237SRoger Quadros 		goto err3;
1253c499ff71SFelipe Balbi 
125472246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
125572246da4SFelipe Balbi 	if (ret) {
1256802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
125732808237SRoger Quadros 		goto err4;
125872246da4SFelipe Balbi 	}
125972246da4SFelipe Balbi 
12607ac51a12SJohn Youn 	dwc3_check_params(dwc);
12612c7f1bd9SJohn Youn 
12625f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
12635f94adfeSFelipe Balbi 	if (ret)
126432808237SRoger Quadros 		goto err5;
126572246da4SFelipe Balbi 
12664e9f3118SDu, Changbin 	dwc3_debugfs_init(dwc);
1267fc8bb91bSFelipe Balbi 	pm_runtime_put(dev);
126872246da4SFelipe Balbi 
126972246da4SFelipe Balbi 	return 0;
127072246da4SFelipe Balbi 
127132808237SRoger Quadros err5:
1272f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
1273f122d33eSFelipe Balbi 
127432808237SRoger Quadros err4:
1275c499ff71SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
127672246da4SFelipe Balbi 
127732808237SRoger Quadros err3:
12783921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
12793921426bSFelipe Balbi 
128032808237SRoger Quadros err2:
128132808237SRoger Quadros 	pm_runtime_allow(&pdev->dev);
128232808237SRoger Quadros 
128332808237SRoger Quadros err1:
128432808237SRoger Quadros 	pm_runtime_put_sync(&pdev->dev);
128532808237SRoger Quadros 	pm_runtime_disable(&pdev->dev);
128632808237SRoger Quadros 
12873da1f6eeSFelipe Balbi err0:
12883da1f6eeSFelipe Balbi 	/*
12893da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
12903da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
12913da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
12923da1f6eeSFelipe Balbi 	 */
12933da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
12943da1f6eeSFelipe Balbi 
129572246da4SFelipe Balbi 	return ret;
129672246da4SFelipe Balbi }
129772246da4SFelipe Balbi 
1298fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
129972246da4SFelipe Balbi {
130072246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
13013da1f6eeSFelipe Balbi 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
13023da1f6eeSFelipe Balbi 
1303fc8bb91bSFelipe Balbi 	pm_runtime_get_sync(&pdev->dev);
13043da1f6eeSFelipe Balbi 	/*
13053da1f6eeSFelipe Balbi 	 * restore res->start back to its original value so that, in case the
13063da1f6eeSFelipe Balbi 	 * probe is deferred, we don't end up getting error in request the
13073da1f6eeSFelipe Balbi 	 * memory region the next time probe is called.
13083da1f6eeSFelipe Balbi 	 */
13093da1f6eeSFelipe Balbi 	res->start -= DWC3_GLOBALS_REGS_START;
131072246da4SFelipe Balbi 
1311dc99f16fSFelipe Balbi 	dwc3_debugfs_exit(dwc);
1312dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
13138ba007a9SKishon Vijay Abraham I 
131472246da4SFelipe Balbi 	dwc3_core_exit(dwc);
131588bc9d19SHeikki Krogerus 	dwc3_ulpi_exit(dwc);
131672246da4SFelipe Balbi 
1317fc8bb91bSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
1318fc8bb91bSFelipe Balbi 	pm_runtime_allow(&pdev->dev);
1319fc8bb91bSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
1320fc8bb91bSFelipe Balbi 
1321c499ff71SFelipe Balbi 	dwc3_free_event_buffers(dwc);
1322c499ff71SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
1323c499ff71SFelipe Balbi 
132472246da4SFelipe Balbi 	return 0;
132572246da4SFelipe Balbi }
132672246da4SFelipe Balbi 
1327fc8bb91bSFelipe Balbi #ifdef CONFIG_PM
1328c4a5153eSManu Gautam static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
13297415f17cSFelipe Balbi {
1330fc8bb91bSFelipe Balbi 	unsigned long	flags;
13317415f17cSFelipe Balbi 
1332689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1333689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1334fc8bb91bSFelipe Balbi 		spin_lock_irqsave(&dwc->lock, flags);
13357415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
1336fc8bb91bSFelipe Balbi 		spin_unlock_irqrestore(&dwc->lock, flags);
1337689bf72cSManu Gautam 		dwc3_core_exit(dwc);
133851f5d49aSFelipe Balbi 		break;
1339689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1340c4a5153eSManu Gautam 		/* do nothing during host runtime_suspend */
1341c4a5153eSManu Gautam 		if (!PMSG_IS_AUTO(msg))
1342c4a5153eSManu Gautam 			dwc3_core_exit(dwc);
1343c4a5153eSManu Gautam 		break;
1344f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
1345f09cc79bSRoger Quadros 		/* do nothing during runtime_suspend */
1346f09cc79bSRoger Quadros 		if (PMSG_IS_AUTO(msg))
1347f09cc79bSRoger Quadros 			break;
1348f09cc79bSRoger Quadros 
1349f09cc79bSRoger Quadros 		if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
1350f09cc79bSRoger Quadros 			spin_lock_irqsave(&dwc->lock, flags);
1351f09cc79bSRoger Quadros 			dwc3_gadget_suspend(dwc);
1352f09cc79bSRoger Quadros 			spin_unlock_irqrestore(&dwc->lock, flags);
1353f09cc79bSRoger Quadros 		}
1354f09cc79bSRoger Quadros 
1355f09cc79bSRoger Quadros 		dwc3_otg_exit(dwc);
1356f09cc79bSRoger Quadros 		dwc3_core_exit(dwc);
1357f09cc79bSRoger Quadros 		break;
13587415f17cSFelipe Balbi 	default:
135951f5d49aSFelipe Balbi 		/* do nothing */
13607415f17cSFelipe Balbi 		break;
13617415f17cSFelipe Balbi 	}
13627415f17cSFelipe Balbi 
1363fc8bb91bSFelipe Balbi 	return 0;
1364fc8bb91bSFelipe Balbi }
1365fc8bb91bSFelipe Balbi 
1366c4a5153eSManu Gautam static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
1367fc8bb91bSFelipe Balbi {
1368fc8bb91bSFelipe Balbi 	unsigned long	flags;
1369fc8bb91bSFelipe Balbi 	int		ret;
1370fc8bb91bSFelipe Balbi 
1371689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1372689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1373fc8bb91bSFelipe Balbi 		ret = dwc3_core_init(dwc);
1374fc8bb91bSFelipe Balbi 		if (ret)
1375fc8bb91bSFelipe Balbi 			return ret;
1376fc8bb91bSFelipe Balbi 
1377fc8bb91bSFelipe Balbi 		spin_lock_irqsave(&dwc->lock, flags);
1378fc8bb91bSFelipe Balbi 		dwc3_gadget_resume(dwc);
1379fc8bb91bSFelipe Balbi 		spin_unlock_irqrestore(&dwc->lock, flags);
1380689bf72cSManu Gautam 		break;
1381689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1382c4a5153eSManu Gautam 		/* nothing to do on host runtime_resume */
1383c4a5153eSManu Gautam 		if (!PMSG_IS_AUTO(msg)) {
1384c4a5153eSManu Gautam 			ret = dwc3_core_init(dwc);
1385c4a5153eSManu Gautam 			if (ret)
1386c4a5153eSManu Gautam 				return ret;
1387c4a5153eSManu Gautam 		}
1388c4a5153eSManu Gautam 		break;
1389f09cc79bSRoger Quadros 	case DWC3_GCTL_PRTCAP_OTG:
1390f09cc79bSRoger Quadros 		/* nothing to do on runtime_resume */
1391f09cc79bSRoger Quadros 		if (PMSG_IS_AUTO(msg))
1392f09cc79bSRoger Quadros 			break;
1393f09cc79bSRoger Quadros 
1394f09cc79bSRoger Quadros 		ret = dwc3_core_init(dwc);
1395f09cc79bSRoger Quadros 		if (ret)
1396f09cc79bSRoger Quadros 			return ret;
1397f09cc79bSRoger Quadros 
1398f09cc79bSRoger Quadros 		dwc3_set_prtcap(dwc, dwc->current_dr_role);
1399f09cc79bSRoger Quadros 
1400f09cc79bSRoger Quadros 		dwc3_otg_init(dwc);
1401f09cc79bSRoger Quadros 		if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
1402f09cc79bSRoger Quadros 			dwc3_otg_host_init(dwc);
1403f09cc79bSRoger Quadros 		} else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
1404f09cc79bSRoger Quadros 			spin_lock_irqsave(&dwc->lock, flags);
1405f09cc79bSRoger Quadros 			dwc3_gadget_resume(dwc);
1406f09cc79bSRoger Quadros 			spin_unlock_irqrestore(&dwc->lock, flags);
1407f09cc79bSRoger Quadros 		}
1408f09cc79bSRoger Quadros 
1409f09cc79bSRoger Quadros 		break;
1410fc8bb91bSFelipe Balbi 	default:
1411fc8bb91bSFelipe Balbi 		/* do nothing */
1412fc8bb91bSFelipe Balbi 		break;
1413fc8bb91bSFelipe Balbi 	}
1414fc8bb91bSFelipe Balbi 
1415fc8bb91bSFelipe Balbi 	return 0;
1416fc8bb91bSFelipe Balbi }
1417fc8bb91bSFelipe Balbi 
1418fc8bb91bSFelipe Balbi static int dwc3_runtime_checks(struct dwc3 *dwc)
1419fc8bb91bSFelipe Balbi {
1420689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1421c4a5153eSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1422fc8bb91bSFelipe Balbi 		if (dwc->connected)
1423fc8bb91bSFelipe Balbi 			return -EBUSY;
1424fc8bb91bSFelipe Balbi 		break;
1425c4a5153eSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1426fc8bb91bSFelipe Balbi 	default:
1427fc8bb91bSFelipe Balbi 		/* do nothing */
1428fc8bb91bSFelipe Balbi 		break;
1429fc8bb91bSFelipe Balbi 	}
1430fc8bb91bSFelipe Balbi 
1431fc8bb91bSFelipe Balbi 	return 0;
1432fc8bb91bSFelipe Balbi }
1433fc8bb91bSFelipe Balbi 
1434fc8bb91bSFelipe Balbi static int dwc3_runtime_suspend(struct device *dev)
1435fc8bb91bSFelipe Balbi {
1436fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1437fc8bb91bSFelipe Balbi 	int		ret;
1438fc8bb91bSFelipe Balbi 
1439fc8bb91bSFelipe Balbi 	if (dwc3_runtime_checks(dwc))
1440fc8bb91bSFelipe Balbi 		return -EBUSY;
1441fc8bb91bSFelipe Balbi 
1442c4a5153eSManu Gautam 	ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);
1443fc8bb91bSFelipe Balbi 	if (ret)
1444fc8bb91bSFelipe Balbi 		return ret;
1445fc8bb91bSFelipe Balbi 
1446fc8bb91bSFelipe Balbi 	device_init_wakeup(dev, true);
1447fc8bb91bSFelipe Balbi 
1448fc8bb91bSFelipe Balbi 	return 0;
1449fc8bb91bSFelipe Balbi }
1450fc8bb91bSFelipe Balbi 
1451fc8bb91bSFelipe Balbi static int dwc3_runtime_resume(struct device *dev)
1452fc8bb91bSFelipe Balbi {
1453fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1454fc8bb91bSFelipe Balbi 	int		ret;
1455fc8bb91bSFelipe Balbi 
1456fc8bb91bSFelipe Balbi 	device_init_wakeup(dev, false);
1457fc8bb91bSFelipe Balbi 
1458c4a5153eSManu Gautam 	ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
1459fc8bb91bSFelipe Balbi 	if (ret)
1460fc8bb91bSFelipe Balbi 		return ret;
1461fc8bb91bSFelipe Balbi 
1462689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1463689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1464fc8bb91bSFelipe Balbi 		dwc3_gadget_process_pending_events(dwc);
1465fc8bb91bSFelipe Balbi 		break;
1466689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1467fc8bb91bSFelipe Balbi 	default:
1468fc8bb91bSFelipe Balbi 		/* do nothing */
1469fc8bb91bSFelipe Balbi 		break;
1470fc8bb91bSFelipe Balbi 	}
1471fc8bb91bSFelipe Balbi 
1472fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
1473fc8bb91bSFelipe Balbi 
1474fc8bb91bSFelipe Balbi 	return 0;
1475fc8bb91bSFelipe Balbi }
1476fc8bb91bSFelipe Balbi 
1477fc8bb91bSFelipe Balbi static int dwc3_runtime_idle(struct device *dev)
1478fc8bb91bSFelipe Balbi {
1479fc8bb91bSFelipe Balbi 	struct dwc3     *dwc = dev_get_drvdata(dev);
1480fc8bb91bSFelipe Balbi 
1481689bf72cSManu Gautam 	switch (dwc->current_dr_role) {
1482689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_DEVICE:
1483fc8bb91bSFelipe Balbi 		if (dwc3_runtime_checks(dwc))
1484fc8bb91bSFelipe Balbi 			return -EBUSY;
1485fc8bb91bSFelipe Balbi 		break;
1486689bf72cSManu Gautam 	case DWC3_GCTL_PRTCAP_HOST:
1487fc8bb91bSFelipe Balbi 	default:
1488fc8bb91bSFelipe Balbi 		/* do nothing */
1489fc8bb91bSFelipe Balbi 		break;
1490fc8bb91bSFelipe Balbi 	}
1491fc8bb91bSFelipe Balbi 
1492fc8bb91bSFelipe Balbi 	pm_runtime_mark_last_busy(dev);
1493fc8bb91bSFelipe Balbi 	pm_runtime_autosuspend(dev);
1494fc8bb91bSFelipe Balbi 
1495fc8bb91bSFelipe Balbi 	return 0;
1496fc8bb91bSFelipe Balbi }
1497fc8bb91bSFelipe Balbi #endif /* CONFIG_PM */
1498fc8bb91bSFelipe Balbi 
1499fc8bb91bSFelipe Balbi #ifdef CONFIG_PM_SLEEP
1500fc8bb91bSFelipe Balbi static int dwc3_suspend(struct device *dev)
1501fc8bb91bSFelipe Balbi {
1502fc8bb91bSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
1503fc8bb91bSFelipe Balbi 	int		ret;
1504fc8bb91bSFelipe Balbi 
1505c4a5153eSManu Gautam 	ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
1506fc8bb91bSFelipe Balbi 	if (ret)
1507fc8bb91bSFelipe Balbi 		return ret;
1508fc8bb91bSFelipe Balbi 
15096344475fSSekhar Nori 	pinctrl_pm_select_sleep_state(dev);
15106344475fSSekhar Nori 
15117415f17cSFelipe Balbi 	return 0;
15127415f17cSFelipe Balbi }
15137415f17cSFelipe Balbi 
15147415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
15157415f17cSFelipe Balbi {
15167415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
151757303488SKishon Vijay Abraham I 	int		ret;
15187415f17cSFelipe Balbi 
15196344475fSSekhar Nori 	pinctrl_pm_select_default_state(dev);
15206344475fSSekhar Nori 
1521c4a5153eSManu Gautam 	ret = dwc3_resume_common(dwc, PMSG_RESUME);
152251f5d49aSFelipe Balbi 	if (ret)
15235c4ad318SFelipe Balbi 		return ret;
15245c4ad318SFelipe Balbi 
15257415f17cSFelipe Balbi 	pm_runtime_disable(dev);
15267415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
15277415f17cSFelipe Balbi 	pm_runtime_enable(dev);
15287415f17cSFelipe Balbi 
15297415f17cSFelipe Balbi 	return 0;
15307415f17cSFelipe Balbi }
15317f370ed0SFelipe Balbi #endif /* CONFIG_PM_SLEEP */
15327415f17cSFelipe Balbi 
15337415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
15347415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
1535fc8bb91bSFelipe Balbi 	SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
1536fc8bb91bSFelipe Balbi 			dwc3_runtime_idle)
15377415f17cSFelipe Balbi };
15387415f17cSFelipe Balbi 
15395088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
15405088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
15415088b6f5SKishon Vijay Abraham I 	{
154222a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
154322a5aa17SFelipe Balbi 	},
154422a5aa17SFelipe Balbi 	{
15455088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
15465088b6f5SKishon Vijay Abraham I 	},
15475088b6f5SKishon Vijay Abraham I 	{ },
15485088b6f5SKishon Vijay Abraham I };
15495088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
15505088b6f5SKishon Vijay Abraham I #endif
15515088b6f5SKishon Vijay Abraham I 
1552404905a6SHeikki Krogerus #ifdef CONFIG_ACPI
1553404905a6SHeikki Krogerus 
1554404905a6SHeikki Krogerus #define ACPI_ID_INTEL_BSW	"808622B7"
1555404905a6SHeikki Krogerus 
1556404905a6SHeikki Krogerus static const struct acpi_device_id dwc3_acpi_match[] = {
1557404905a6SHeikki Krogerus 	{ ACPI_ID_INTEL_BSW, 0 },
1558404905a6SHeikki Krogerus 	{ },
1559404905a6SHeikki Krogerus };
1560404905a6SHeikki Krogerus MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
1561404905a6SHeikki Krogerus #endif
1562404905a6SHeikki Krogerus 
156372246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
156472246da4SFelipe Balbi 	.probe		= dwc3_probe,
15657690417dSBill Pemberton 	.remove		= dwc3_remove,
156672246da4SFelipe Balbi 	.driver		= {
156772246da4SFelipe Balbi 		.name	= "dwc3",
15685088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
1569404905a6SHeikki Krogerus 		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
15707f370ed0SFelipe Balbi 		.pm	= &dwc3_dev_pm_ops,
157172246da4SFelipe Balbi 	},
157272246da4SFelipe Balbi };
157372246da4SFelipe Balbi 
1574b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
1575b1116dccSTobias Klauser 
15767ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
157772246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
15785945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
157972246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
1580