xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 460d098c)
172246da4SFelipe Balbi /**
272246da4SFelipe Balbi  * core.c - DesignWare USB3 DRD Controller Core file
372246da4SFelipe Balbi  *
472246da4SFelipe Balbi  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
572246da4SFelipe Balbi  *
672246da4SFelipe Balbi  * Authors: Felipe Balbi <balbi@ti.com>,
772246da4SFelipe Balbi  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
872246da4SFelipe Balbi  *
95945f789SFelipe Balbi  * This program is free software: you can redistribute it and/or modify
105945f789SFelipe Balbi  * it under the terms of the GNU General Public License version 2  of
115945f789SFelipe Balbi  * the License as published by the Free Software Foundation.
1272246da4SFelipe Balbi  *
135945f789SFelipe Balbi  * This program is distributed in the hope that it will be useful,
145945f789SFelipe Balbi  * but WITHOUT ANY WARRANTY; without even the implied warranty of
155945f789SFelipe Balbi  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165945f789SFelipe Balbi  * GNU General Public License for more details.
1772246da4SFelipe Balbi  *
185945f789SFelipe Balbi  * You should have received a copy of the GNU General Public License
195945f789SFelipe Balbi  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2072246da4SFelipe Balbi  */
2172246da4SFelipe Balbi 
22fa0ea13eSFelipe Balbi #include <linux/version.h>
23a72e658bSFelipe Balbi #include <linux/module.h>
2472246da4SFelipe Balbi #include <linux/kernel.h>
2572246da4SFelipe Balbi #include <linux/slab.h>
2672246da4SFelipe Balbi #include <linux/spinlock.h>
2772246da4SFelipe Balbi #include <linux/platform_device.h>
2872246da4SFelipe Balbi #include <linux/pm_runtime.h>
2972246da4SFelipe Balbi #include <linux/interrupt.h>
3072246da4SFelipe Balbi #include <linux/ioport.h>
3172246da4SFelipe Balbi #include <linux/io.h>
3272246da4SFelipe Balbi #include <linux/list.h>
3372246da4SFelipe Balbi #include <linux/delay.h>
3472246da4SFelipe Balbi #include <linux/dma-mapping.h>
35457e84b6SFelipe Balbi #include <linux/of.h>
36404905a6SHeikki Krogerus #include <linux/acpi.h>
3772246da4SFelipe Balbi 
3872246da4SFelipe Balbi #include <linux/usb/ch9.h>
3972246da4SFelipe Balbi #include <linux/usb/gadget.h>
40f7e846f0SFelipe Balbi #include <linux/usb/of.h>
41a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
4272246da4SFelipe Balbi 
436462cbd5SFelipe Balbi #include "platform_data.h"
4472246da4SFelipe Balbi #include "core.h"
4572246da4SFelipe Balbi #include "gadget.h"
4672246da4SFelipe Balbi #include "io.h"
4772246da4SFelipe Balbi 
4872246da4SFelipe Balbi #include "debug.h"
4972246da4SFelipe Balbi 
508300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
518300dd23SFelipe Balbi 
523140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
533140e8cbSSebastian Andrzej Siewior {
543140e8cbSSebastian Andrzej Siewior 	u32 reg;
553140e8cbSSebastian Andrzej Siewior 
563140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
573140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
583140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
593140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
603140e8cbSSebastian Andrzej Siewior }
618300dd23SFelipe Balbi 
6272246da4SFelipe Balbi /**
6372246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
6472246da4SFelipe Balbi  * @dwc: pointer to our context structure
6572246da4SFelipe Balbi  */
6657303488SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc)
6772246da4SFelipe Balbi {
6872246da4SFelipe Balbi 	u32		reg;
6957303488SKishon Vijay Abraham I 	int		ret;
7072246da4SFelipe Balbi 
7172246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
7272246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
7372246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
7472246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
7572246da4SFelipe Balbi 
7672246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
7772246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
7872246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
7972246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
8072246da4SFelipe Balbi 
8172246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
8272246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
8372246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
8472246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
8572246da4SFelipe Balbi 
8651e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
8751e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
8857303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
8957303488SKishon Vijay Abraham I 	if (ret < 0)
9057303488SKishon Vijay Abraham I 		return ret;
9157303488SKishon Vijay Abraham I 
9257303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
9357303488SKishon Vijay Abraham I 	if (ret < 0) {
9457303488SKishon Vijay Abraham I 		phy_exit(dwc->usb2_generic_phy);
9557303488SKishon Vijay Abraham I 		return ret;
9657303488SKishon Vijay Abraham I 	}
9772246da4SFelipe Balbi 	mdelay(100);
9872246da4SFelipe Balbi 
9972246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
10072246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
10172246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
10272246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
10372246da4SFelipe Balbi 
10472246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
10572246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
10672246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
10772246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
10872246da4SFelipe Balbi 
10945627ac6SPratyush Anand 	mdelay(100);
11045627ac6SPratyush Anand 
11172246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
11272246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
11372246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
11472246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
11557303488SKishon Vijay Abraham I 
11657303488SKishon Vijay Abraham I 	return 0;
11772246da4SFelipe Balbi }
11872246da4SFelipe Balbi 
11972246da4SFelipe Balbi /**
12072246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
12172246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
12272246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
12372246da4SFelipe Balbi  */
12472246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
12572246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
12672246da4SFelipe Balbi {
12772246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
12872246da4SFelipe Balbi }
12972246da4SFelipe Balbi 
13072246da4SFelipe Balbi /**
1311d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
13272246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
13372246da4SFelipe Balbi  * @length: size of the event buffer
13472246da4SFelipe Balbi  *
1351d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
13672246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
13772246da4SFelipe Balbi  */
13867d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
13967d0b500SFelipe Balbi 		unsigned length)
14072246da4SFelipe Balbi {
14172246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
14272246da4SFelipe Balbi 
143380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
14472246da4SFelipe Balbi 	if (!evt)
14572246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
14672246da4SFelipe Balbi 
14772246da4SFelipe Balbi 	evt->dwc	= dwc;
14872246da4SFelipe Balbi 	evt->length	= length;
14972246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
15072246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
151e32672f0SFelipe Balbi 	if (!evt->buf)
15272246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
15372246da4SFelipe Balbi 
15472246da4SFelipe Balbi 	return evt;
15572246da4SFelipe Balbi }
15672246da4SFelipe Balbi 
15772246da4SFelipe Balbi /**
15872246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
15972246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
16072246da4SFelipe Balbi  */
16172246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
16272246da4SFelipe Balbi {
16372246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
16472246da4SFelipe Balbi 	int i;
16572246da4SFelipe Balbi 
1669f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
16772246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
16864b6c8a7SAnton Tikhomirov 		if (evt)
16972246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
17072246da4SFelipe Balbi 	}
17172246da4SFelipe Balbi }
17272246da4SFelipe Balbi 
17372246da4SFelipe Balbi /**
17472246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
1751d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
17672246da4SFelipe Balbi  * @length: size of event buffer
17772246da4SFelipe Balbi  *
1781d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
17972246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
18072246da4SFelipe Balbi  */
18141ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
18272246da4SFelipe Balbi {
1839f622b2aSFelipe Balbi 	int			num;
18472246da4SFelipe Balbi 	int			i;
18572246da4SFelipe Balbi 
1869f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
1879f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
1889f622b2aSFelipe Balbi 
189380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
190380f0d28SFelipe Balbi 			GFP_KERNEL);
191734d5a53SJingoo Han 	if (!dwc->ev_buffs)
192457d3f21SFelipe Balbi 		return -ENOMEM;
193457d3f21SFelipe Balbi 
19472246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
19572246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
19672246da4SFelipe Balbi 
19772246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
19872246da4SFelipe Balbi 		if (IS_ERR(evt)) {
19972246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
20072246da4SFelipe Balbi 			return PTR_ERR(evt);
20172246da4SFelipe Balbi 		}
20272246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
20372246da4SFelipe Balbi 	}
20472246da4SFelipe Balbi 
20572246da4SFelipe Balbi 	return 0;
20672246da4SFelipe Balbi }
20772246da4SFelipe Balbi 
20872246da4SFelipe Balbi /**
20972246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
2101d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
21172246da4SFelipe Balbi  *
21272246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
21372246da4SFelipe Balbi  */
2147acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
21572246da4SFelipe Balbi {
21672246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
21772246da4SFelipe Balbi 	int				n;
21872246da4SFelipe Balbi 
2199f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
22072246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
22172246da4SFelipe Balbi 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
22272246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
22372246da4SFelipe Balbi 				evt->length);
22472246da4SFelipe Balbi 
2257acd85e0SPaul Zimmerman 		evt->lpos = 0;
2267acd85e0SPaul Zimmerman 
22772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
22872246da4SFelipe Balbi 				lower_32_bits(evt->dma));
22972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
23072246da4SFelipe Balbi 				upper_32_bits(evt->dma));
23172246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
23268d6a01bSFelipe Balbi 				DWC3_GEVNTSIZ_SIZE(evt->length));
23372246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
23472246da4SFelipe Balbi 	}
23572246da4SFelipe Balbi 
23672246da4SFelipe Balbi 	return 0;
23772246da4SFelipe Balbi }
23872246da4SFelipe Balbi 
23972246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
24072246da4SFelipe Balbi {
24172246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
24272246da4SFelipe Balbi 	int				n;
24372246da4SFelipe Balbi 
2449f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
24572246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2467acd85e0SPaul Zimmerman 
2477acd85e0SPaul Zimmerman 		evt->lpos = 0;
2487acd85e0SPaul Zimmerman 
24972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
25072246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
25168d6a01bSFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
25268d6a01bSFelipe Balbi 				| DWC3_GEVNTSIZ_SIZE(0));
25372246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
25472246da4SFelipe Balbi 	}
25572246da4SFelipe Balbi }
25672246da4SFelipe Balbi 
2570ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
2580ffcaf37SFelipe Balbi {
2590ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
2600ffcaf37SFelipe Balbi 		return 0;
2610ffcaf37SFelipe Balbi 
2620ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
2630ffcaf37SFelipe Balbi 		return 0;
2640ffcaf37SFelipe Balbi 
2650ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
2660ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
2670ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
2680ffcaf37SFelipe Balbi 		return -ENOMEM;
2690ffcaf37SFelipe Balbi 
2700ffcaf37SFelipe Balbi 	return 0;
2710ffcaf37SFelipe Balbi }
2720ffcaf37SFelipe Balbi 
2730ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
2740ffcaf37SFelipe Balbi {
2750ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
2760ffcaf37SFelipe Balbi 	u32 param;
2770ffcaf37SFelipe Balbi 	int ret;
2780ffcaf37SFelipe Balbi 
2790ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
2800ffcaf37SFelipe Balbi 		return 0;
2810ffcaf37SFelipe Balbi 
2820ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
2830ffcaf37SFelipe Balbi 		return 0;
2840ffcaf37SFelipe Balbi 
2850ffcaf37SFelipe Balbi 	 /* should never fall here */
2860ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
2870ffcaf37SFelipe Balbi 		return 0;
2880ffcaf37SFelipe Balbi 
2890ffcaf37SFelipe Balbi 	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
2900ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
2910ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
2920ffcaf37SFelipe Balbi 	if (dma_mapping_error(dwc->dev, scratch_addr)) {
2930ffcaf37SFelipe Balbi 		dev_err(dwc->dev, "failed to map scratch buffer\n");
2940ffcaf37SFelipe Balbi 		ret = -EFAULT;
2950ffcaf37SFelipe Balbi 		goto err0;
2960ffcaf37SFelipe Balbi 	}
2970ffcaf37SFelipe Balbi 
2980ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
2990ffcaf37SFelipe Balbi 
3000ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
3010ffcaf37SFelipe Balbi 
3020ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3030ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
3040ffcaf37SFelipe Balbi 	if (ret < 0)
3050ffcaf37SFelipe Balbi 		goto err1;
3060ffcaf37SFelipe Balbi 
3070ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
3080ffcaf37SFelipe Balbi 
3090ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3100ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
3110ffcaf37SFelipe Balbi 	if (ret < 0)
3120ffcaf37SFelipe Balbi 		goto err1;
3130ffcaf37SFelipe Balbi 
3140ffcaf37SFelipe Balbi 	return 0;
3150ffcaf37SFelipe Balbi 
3160ffcaf37SFelipe Balbi err1:
3170ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3180ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3190ffcaf37SFelipe Balbi 
3200ffcaf37SFelipe Balbi err0:
3210ffcaf37SFelipe Balbi 	return ret;
3220ffcaf37SFelipe Balbi }
3230ffcaf37SFelipe Balbi 
3240ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
3250ffcaf37SFelipe Balbi {
3260ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3270ffcaf37SFelipe Balbi 		return;
3280ffcaf37SFelipe Balbi 
3290ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3300ffcaf37SFelipe Balbi 		return;
3310ffcaf37SFelipe Balbi 
3320ffcaf37SFelipe Balbi 	 /* should never fall here */
3330ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3340ffcaf37SFelipe Balbi 		return;
3350ffcaf37SFelipe Balbi 
3360ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3370ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3380ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
3390ffcaf37SFelipe Balbi }
3400ffcaf37SFelipe Balbi 
341789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
342789451f6SFelipe Balbi {
343789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
344789451f6SFelipe Balbi 
345789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
346789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
347789451f6SFelipe Balbi 
348789451f6SFelipe Balbi 	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
349789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
350789451f6SFelipe Balbi }
351789451f6SFelipe Balbi 
35241ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
35326ceca97SFelipe Balbi {
35426ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
35526ceca97SFelipe Balbi 
35626ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
35726ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
35826ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
35926ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
36026ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
36126ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
36226ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
36326ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
36426ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
36526ceca97SFelipe Balbi }
36626ceca97SFelipe Balbi 
36772246da4SFelipe Balbi /**
368b5a65c40SHuang Rui  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
369b5a65c40SHuang Rui  * @dwc: Pointer to our controller context structure
370b5a65c40SHuang Rui  */
371b5a65c40SHuang Rui static void dwc3_phy_setup(struct dwc3 *dwc)
372b5a65c40SHuang Rui {
373b5a65c40SHuang Rui 	u32 reg;
374b5a65c40SHuang Rui 
375b5a65c40SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
376b5a65c40SHuang Rui 
3772164a476SHuang Rui 	/*
3782164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
3792164a476SHuang Rui 	 * to '0' during coreConsultant configuration. So default value
3802164a476SHuang Rui 	 * will be '0' when the core is reset. Application needs to set it
3812164a476SHuang Rui 	 * to '1' after the core initialization is completed.
3822164a476SHuang Rui 	 */
3832164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
3842164a476SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
3852164a476SHuang Rui 
386b5a65c40SHuang Rui 	if (dwc->u2ss_inp3_quirk)
387b5a65c40SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
388b5a65c40SHuang Rui 
389df31f5b3SHuang Rui 	if (dwc->req_p1p2p3_quirk)
390df31f5b3SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
391df31f5b3SHuang Rui 
392a2a1d0f5SHuang Rui 	if (dwc->del_p1p2p3_quirk)
393a2a1d0f5SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
394a2a1d0f5SHuang Rui 
39541c06ffdSHuang Rui 	if (dwc->del_phy_power_chg_quirk)
39641c06ffdSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
39741c06ffdSHuang Rui 
398fb67afcaSHuang Rui 	if (dwc->lfps_filter_quirk)
399fb67afcaSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
400fb67afcaSHuang Rui 
40114f4ac53SHuang Rui 	if (dwc->rx_detect_poll_quirk)
40214f4ac53SHuang Rui 		reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
40314f4ac53SHuang Rui 
4046b6a0c9aSHuang Rui 	if (dwc->tx_de_emphasis_quirk)
4056b6a0c9aSHuang Rui 		reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
4066b6a0c9aSHuang Rui 
40759acfa20SHuang Rui 	if (dwc->dis_u3_susphy_quirk && dwc->is_fpga)
40859acfa20SHuang Rui 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
40959acfa20SHuang Rui 
410b5a65c40SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
411b5a65c40SHuang Rui 
412b5a65c40SHuang Rui 	mdelay(100);
4132164a476SHuang Rui 
4142164a476SHuang Rui 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
4152164a476SHuang Rui 
4162164a476SHuang Rui 	/*
4172164a476SHuang Rui 	 * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
4182164a476SHuang Rui 	 * '0' during coreConsultant configuration. So default value will
4192164a476SHuang Rui 	 * be '0' when the core is reset. Application needs to set it to
4202164a476SHuang Rui 	 * '1' after the core initialization is completed.
4212164a476SHuang Rui 	 */
4222164a476SHuang Rui 	if (dwc->revision > DWC3_REVISION_194A)
4232164a476SHuang Rui 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
4242164a476SHuang Rui 
4250effe0a3SHuang Rui 	if (dwc->dis_u2_susphy_quirk && dwc->is_fpga)
4260effe0a3SHuang Rui 		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
4270effe0a3SHuang Rui 
4282164a476SHuang Rui 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
4292164a476SHuang Rui 
4302164a476SHuang Rui 	mdelay(100);
431b5a65c40SHuang Rui }
432b5a65c40SHuang Rui 
433b5a65c40SHuang Rui /**
43472246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
43572246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
43672246da4SFelipe Balbi  *
43772246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
43872246da4SFelipe Balbi  */
43941ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
44072246da4SFelipe Balbi {
44172246da4SFelipe Balbi 	unsigned long		timeout;
4420ffcaf37SFelipe Balbi 	u32			hwparams4 = dwc->hwparams.hwparams4;
44372246da4SFelipe Balbi 	u32			reg;
44472246da4SFelipe Balbi 	int			ret;
44572246da4SFelipe Balbi 
4467650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
4477650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
4487650bd74SSebastian Andrzej Siewior 	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
4497650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
4507650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
4517650bd74SSebastian Andrzej Siewior 		goto err0;
4527650bd74SSebastian Andrzej Siewior 	}
453248b122bSFelipe Balbi 	dwc->revision = reg;
4547650bd74SSebastian Andrzej Siewior 
455fa0ea13eSFelipe Balbi 	/*
456fa0ea13eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
457fa0ea13eSFelipe Balbi 	 * out which kernel version a bug was found.
458fa0ea13eSFelipe Balbi 	 */
459fa0ea13eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
460fa0ea13eSFelipe Balbi 
4610e1e5c47SPaul Zimmerman 	/* Handle USB2.0-only core configuration */
4620e1e5c47SPaul Zimmerman 	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
4630e1e5c47SPaul Zimmerman 			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
4640e1e5c47SPaul Zimmerman 		if (dwc->maximum_speed == USB_SPEED_SUPER)
4650e1e5c47SPaul Zimmerman 			dwc->maximum_speed = USB_SPEED_HIGH;
4660e1e5c47SPaul Zimmerman 	}
4670e1e5c47SPaul Zimmerman 
46872246da4SFelipe Balbi 	/* issue device SoftReset too */
46972246da4SFelipe Balbi 	timeout = jiffies + msecs_to_jiffies(500);
47072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
47172246da4SFelipe Balbi 	do {
47272246da4SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
47372246da4SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
47472246da4SFelipe Balbi 			break;
47572246da4SFelipe Balbi 
47672246da4SFelipe Balbi 		if (time_after(jiffies, timeout)) {
47772246da4SFelipe Balbi 			dev_err(dwc->dev, "Reset Timed Out\n");
47872246da4SFelipe Balbi 			ret = -ETIMEDOUT;
47972246da4SFelipe Balbi 			goto err0;
48072246da4SFelipe Balbi 		}
48172246da4SFelipe Balbi 
48272246da4SFelipe Balbi 		cpu_relax();
48372246da4SFelipe Balbi 	} while (true);
48472246da4SFelipe Balbi 
48557303488SKishon Vijay Abraham I 	ret = dwc3_core_soft_reset(dwc);
48657303488SKishon Vijay Abraham I 	if (ret)
48757303488SKishon Vijay Abraham I 		goto err0;
48858a0f23fSPratyush Anand 
4894878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
4903e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
4914878a028SSebastian Andrzej Siewior 
492164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
4934878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
49432a4a135SFelipe Balbi 		/**
49532a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
49632a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
49732a4a135SFelipe Balbi 		 *
49832a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
49932a4a135SFelipe Balbi 		 * configurations.
50032a4a135SFelipe Balbi 		 *
50132a4a135SFelipe Balbi 		 * Refers to:
50232a4a135SFelipe Balbi 		 *
50332a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
50432a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
50532a4a135SFelipe Balbi 		 */
50632a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
50732a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
50832a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
50932a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
51032a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
51132a4a135SFelipe Balbi 		else
5124878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
5134878a028SSebastian Andrzej Siewior 		break;
5140ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
5150ffcaf37SFelipe Balbi 		/* enable hibernation here */
5160ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
5172eac3992SHuang Rui 
5182eac3992SHuang Rui 		/*
5192eac3992SHuang Rui 		 * REVISIT Enabling this bit so that host-mode hibernation
5202eac3992SHuang Rui 		 * will work. Device-mode hibernation is not yet implemented.
5212eac3992SHuang Rui 		 */
5222eac3992SHuang Rui 		reg |= DWC3_GCTL_GBLHIBERNATIONEN;
5230ffcaf37SFelipe Balbi 		break;
5244878a028SSebastian Andrzej Siewior 	default:
5254878a028SSebastian Andrzej Siewior 		dev_dbg(dwc->dev, "No power optimization available\n");
5264878a028SSebastian Andrzej Siewior 	}
5274878a028SSebastian Andrzej Siewior 
528946bd579SHuang Rui 	/* check if current dwc3 is on simulation board */
529946bd579SHuang Rui 	if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
530946bd579SHuang Rui 		dev_dbg(dwc->dev, "it is on FPGA board\n");
531946bd579SHuang Rui 		dwc->is_fpga = true;
532946bd579SHuang Rui 	}
533946bd579SHuang Rui 
5343b81221aSHuang Rui 	WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
5353b81221aSHuang Rui 			"disable_scramble cannot be used on non-FPGA builds\n");
5363b81221aSHuang Rui 
5373b81221aSHuang Rui 	if (dwc->disable_scramble_quirk && dwc->is_fpga)
5383b81221aSHuang Rui 		reg |= DWC3_GCTL_DISSCRAMBLE;
5393b81221aSHuang Rui 	else
5403b81221aSHuang Rui 		reg &= ~DWC3_GCTL_DISSCRAMBLE;
5413b81221aSHuang Rui 
5429a5b2f31SHuang Rui 	if (dwc->u2exit_lfps_quirk)
5439a5b2f31SHuang Rui 		reg |= DWC3_GCTL_U2EXIT_LFPS;
5449a5b2f31SHuang Rui 
5454878a028SSebastian Andrzej Siewior 	/*
5464878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
5471d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
5484878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
5491d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
5504878a028SSebastian Andrzej Siewior 	 */
5514878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
5524878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
5534878a028SSebastian Andrzej Siewior 
554789451f6SFelipe Balbi 	dwc3_core_num_eps(dwc);
555789451f6SFelipe Balbi 
5564878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
5574878a028SSebastian Andrzej Siewior 
558b5a65c40SHuang Rui 	dwc3_phy_setup(dwc);
559b5a65c40SHuang Rui 
5600ffcaf37SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
5610ffcaf37SFelipe Balbi 	if (ret)
5620ffcaf37SFelipe Balbi 		goto err1;
5630ffcaf37SFelipe Balbi 
5640ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
5650ffcaf37SFelipe Balbi 	if (ret)
5660ffcaf37SFelipe Balbi 		goto err2;
5670ffcaf37SFelipe Balbi 
56872246da4SFelipe Balbi 	return 0;
56972246da4SFelipe Balbi 
5700ffcaf37SFelipe Balbi err2:
5710ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
5720ffcaf37SFelipe Balbi 
5730ffcaf37SFelipe Balbi err1:
5740ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
5750ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
57657303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
57757303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
5780ffcaf37SFelipe Balbi 
57972246da4SFelipe Balbi err0:
58072246da4SFelipe Balbi 	return ret;
58172246da4SFelipe Balbi }
58272246da4SFelipe Balbi 
58372246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
58472246da4SFelipe Balbi {
5850ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
58601b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
58701b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
58857303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
58957303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
59072246da4SFelipe Balbi }
59172246da4SFelipe Balbi 
5923c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
59372246da4SFelipe Balbi {
5943c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
595941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
5963c9f94acSFelipe Balbi 	int ret;
59772246da4SFelipe Balbi 
5985088b6f5SKishon Vijay Abraham I 	if (node) {
5995088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
6005088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
601bb674907SFelipe Balbi 	} else {
602bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
603bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
6045088b6f5SKishon Vijay Abraham I 	}
6055088b6f5SKishon Vijay Abraham I 
606d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
607d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
608122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
609122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
610122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
611d105e7f8SFelipe Balbi 			return ret;
612122f06e6SKishon Vijay Abraham I 		} else {
61351e1e7bcSFelipe Balbi 			dev_err(dev, "no usb2 phy configured\n");
614122f06e6SKishon Vijay Abraham I 			return ret;
615122f06e6SKishon Vijay Abraham I 		}
61651e1e7bcSFelipe Balbi 	}
61751e1e7bcSFelipe Balbi 
618d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
619315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
620122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
621122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
622122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
623d105e7f8SFelipe Balbi 			return ret;
624122f06e6SKishon Vijay Abraham I 		} else {
62551e1e7bcSFelipe Balbi 			dev_err(dev, "no usb3 phy configured\n");
626122f06e6SKishon Vijay Abraham I 			return ret;
627122f06e6SKishon Vijay Abraham I 		}
62851e1e7bcSFelipe Balbi 	}
62951e1e7bcSFelipe Balbi 
63057303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
63157303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
63257303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
63357303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
63457303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
63557303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
63657303488SKishon Vijay Abraham I 			return ret;
63757303488SKishon Vijay Abraham I 		} else {
63857303488SKishon Vijay Abraham I 			dev_err(dev, "no usb2 phy configured\n");
63957303488SKishon Vijay Abraham I 			return ret;
64057303488SKishon Vijay Abraham I 		}
64157303488SKishon Vijay Abraham I 	}
64257303488SKishon Vijay Abraham I 
64357303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
64457303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
64557303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
64657303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
64757303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
64857303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
64957303488SKishon Vijay Abraham I 			return ret;
65057303488SKishon Vijay Abraham I 		} else {
65157303488SKishon Vijay Abraham I 			dev_err(dev, "no usb3 phy configured\n");
65257303488SKishon Vijay Abraham I 			return ret;
65357303488SKishon Vijay Abraham I 		}
65457303488SKishon Vijay Abraham I 	}
65557303488SKishon Vijay Abraham I 
6563c9f94acSFelipe Balbi 	return 0;
6573c9f94acSFelipe Balbi }
6583c9f94acSFelipe Balbi 
6595f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
6605f94adfeSFelipe Balbi {
6615f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
6625f94adfeSFelipe Balbi 	int ret;
6635f94adfeSFelipe Balbi 
6645f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
6655f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
6665f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
6675f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
6685f94adfeSFelipe Balbi 		if (ret) {
6695f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
6705f94adfeSFelipe Balbi 			return ret;
6715f94adfeSFelipe Balbi 		}
6725f94adfeSFelipe Balbi 		break;
6735f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
6745f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
6755f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
6765f94adfeSFelipe Balbi 		if (ret) {
6775f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
6785f94adfeSFelipe Balbi 			return ret;
6795f94adfeSFelipe Balbi 		}
6805f94adfeSFelipe Balbi 		break;
6815f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
6825f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
6835f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
6845f94adfeSFelipe Balbi 		if (ret) {
6855f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
6865f94adfeSFelipe Balbi 			return ret;
6875f94adfeSFelipe Balbi 		}
6885f94adfeSFelipe Balbi 
6895f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
6905f94adfeSFelipe Balbi 		if (ret) {
6915f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
6925f94adfeSFelipe Balbi 			return ret;
6935f94adfeSFelipe Balbi 		}
6945f94adfeSFelipe Balbi 		break;
6955f94adfeSFelipe Balbi 	default:
6965f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
6975f94adfeSFelipe Balbi 		return -EINVAL;
6985f94adfeSFelipe Balbi 	}
6995f94adfeSFelipe Balbi 
7005f94adfeSFelipe Balbi 	return 0;
7015f94adfeSFelipe Balbi }
7025f94adfeSFelipe Balbi 
7035f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
7045f94adfeSFelipe Balbi {
7055f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
7065f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
7075f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
7085f94adfeSFelipe Balbi 		break;
7095f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
7105f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
7115f94adfeSFelipe Balbi 		break;
7125f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
7135f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
7145f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
7155f94adfeSFelipe Balbi 		break;
7165f94adfeSFelipe Balbi 	default:
7175f94adfeSFelipe Balbi 		/* do nothing */
7185f94adfeSFelipe Balbi 		break;
7195f94adfeSFelipe Balbi 	}
7205f94adfeSFelipe Balbi }
7215f94adfeSFelipe Balbi 
7223c9f94acSFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
7233c9f94acSFelipe Balbi 
7243c9f94acSFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
7253c9f94acSFelipe Balbi {
7263c9f94acSFelipe Balbi 	struct device		*dev = &pdev->dev;
7273c9f94acSFelipe Balbi 	struct dwc3_platform_data *pdata = dev_get_platdata(dev);
7283c9f94acSFelipe Balbi 	struct device_node	*node = dev->of_node;
7293c9f94acSFelipe Balbi 	struct resource		*res;
7303c9f94acSFelipe Balbi 	struct dwc3		*dwc;
73180caf7d2SHuang Rui 	u8			lpm_nyet_threshold;
7326b6a0c9aSHuang Rui 	u8			tx_de_emphasis;
733460d098cSHuang Rui 	u8			hird_threshold;
7343c9f94acSFelipe Balbi 
735b09e99eeSAndy Shevchenko 	int			ret;
7363c9f94acSFelipe Balbi 
7373c9f94acSFelipe Balbi 	void __iomem		*regs;
7383c9f94acSFelipe Balbi 	void			*mem;
7393c9f94acSFelipe Balbi 
7403c9f94acSFelipe Balbi 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
741734d5a53SJingoo Han 	if (!mem)
7423c9f94acSFelipe Balbi 		return -ENOMEM;
743734d5a53SJingoo Han 
7443c9f94acSFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
7453c9f94acSFelipe Balbi 	dwc->mem = mem;
7463c9f94acSFelipe Balbi 	dwc->dev = dev;
7473c9f94acSFelipe Balbi 
7483c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
7493c9f94acSFelipe Balbi 	if (!res) {
7503c9f94acSFelipe Balbi 		dev_err(dev, "missing IRQ\n");
7513c9f94acSFelipe Balbi 		return -ENODEV;
7523c9f94acSFelipe Balbi 	}
7533c9f94acSFelipe Balbi 	dwc->xhci_resources[1].start = res->start;
7543c9f94acSFelipe Balbi 	dwc->xhci_resources[1].end = res->end;
7553c9f94acSFelipe Balbi 	dwc->xhci_resources[1].flags = res->flags;
7563c9f94acSFelipe Balbi 	dwc->xhci_resources[1].name = res->name;
7573c9f94acSFelipe Balbi 
7583c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
7593c9f94acSFelipe Balbi 	if (!res) {
7603c9f94acSFelipe Balbi 		dev_err(dev, "missing memory resource\n");
7613c9f94acSFelipe Balbi 		return -ENODEV;
7623c9f94acSFelipe Balbi 	}
7633c9f94acSFelipe Balbi 
764f32a5e23SVivek Gautam 	dwc->xhci_resources[0].start = res->start;
765f32a5e23SVivek Gautam 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
766f32a5e23SVivek Gautam 					DWC3_XHCI_REGS_END;
767f32a5e23SVivek Gautam 	dwc->xhci_resources[0].flags = res->flags;
768f32a5e23SVivek Gautam 	dwc->xhci_resources[0].name = res->name;
769f32a5e23SVivek Gautam 
770f32a5e23SVivek Gautam 	res->start += DWC3_GLOBALS_REGS_START;
771f32a5e23SVivek Gautam 
772f32a5e23SVivek Gautam 	/*
773f32a5e23SVivek Gautam 	 * Request memory region but exclude xHCI regs,
774f32a5e23SVivek Gautam 	 * since it will be requested by the xhci-plat driver.
775f32a5e23SVivek Gautam 	 */
776f32a5e23SVivek Gautam 	regs = devm_ioremap_resource(dev, res);
777f32a5e23SVivek Gautam 	if (IS_ERR(regs))
778f32a5e23SVivek Gautam 		return PTR_ERR(regs);
779f32a5e23SVivek Gautam 
780f32a5e23SVivek Gautam 	dwc->regs	= regs;
781f32a5e23SVivek Gautam 	dwc->regs_size	= resource_size(res);
782f32a5e23SVivek Gautam 	/*
783f32a5e23SVivek Gautam 	 * restore res->start back to its original value so that,
784f32a5e23SVivek Gautam 	 * in case the probe is deferred, we don't end up getting error in
785f32a5e23SVivek Gautam 	 * request the memory region the next time probe is called.
786f32a5e23SVivek Gautam 	 */
787f32a5e23SVivek Gautam 	res->start -= DWC3_GLOBALS_REGS_START;
788f32a5e23SVivek Gautam 
78980caf7d2SHuang Rui 	/* default to highest possible threshold */
79080caf7d2SHuang Rui 	lpm_nyet_threshold = 0xff;
79180caf7d2SHuang Rui 
7926b6a0c9aSHuang Rui 	/* default to -3.5dB de-emphasis */
7936b6a0c9aSHuang Rui 	tx_de_emphasis = 1;
7946b6a0c9aSHuang Rui 
795460d098cSHuang Rui 	/*
796460d098cSHuang Rui 	 * default to assert utmi_sleep_n and use maximum allowed HIRD
797460d098cSHuang Rui 	 * threshold value of 0b1100
798460d098cSHuang Rui 	 */
799460d098cSHuang Rui 	hird_threshold = 12;
800460d098cSHuang Rui 
8013c9f94acSFelipe Balbi 	if (node) {
8023c9f94acSFelipe Balbi 		dwc->maximum_speed = of_usb_get_maximum_speed(node);
80380caf7d2SHuang Rui 		dwc->has_lpm_erratum = of_property_read_bool(node,
80480caf7d2SHuang Rui 				"snps,has-lpm-erratum");
80580caf7d2SHuang Rui 		of_property_read_u8(node, "snps,lpm-nyet-threshold",
80680caf7d2SHuang Rui 				&lpm_nyet_threshold);
807460d098cSHuang Rui 		dwc->is_utmi_l1_suspend = of_property_read_bool(node,
808460d098cSHuang Rui 				"snps,is-utmi-l1-suspend");
809460d098cSHuang Rui 		of_property_read_u8(node, "snps,hird-threshold",
810460d098cSHuang Rui 				&hird_threshold);
8113c9f94acSFelipe Balbi 
81280caf7d2SHuang Rui 		dwc->needs_fifo_resize = of_property_read_bool(node,
81380caf7d2SHuang Rui 				"tx-fifo-resize");
8143c9f94acSFelipe Balbi 		dwc->dr_mode = of_usb_get_dr_mode(node);
8153b81221aSHuang Rui 
8163b81221aSHuang Rui 		dwc->disable_scramble_quirk = of_property_read_bool(node,
8173b81221aSHuang Rui 				"snps,disable_scramble_quirk");
8189a5b2f31SHuang Rui 		dwc->u2exit_lfps_quirk = of_property_read_bool(node,
8199a5b2f31SHuang Rui 				"snps,u2exit_lfps_quirk");
820b5a65c40SHuang Rui 		dwc->u2ss_inp3_quirk = of_property_read_bool(node,
821b5a65c40SHuang Rui 				"snps,u2ss_inp3_quirk");
822df31f5b3SHuang Rui 		dwc->req_p1p2p3_quirk = of_property_read_bool(node,
823df31f5b3SHuang Rui 				"snps,req_p1p2p3_quirk");
824a2a1d0f5SHuang Rui 		dwc->del_p1p2p3_quirk = of_property_read_bool(node,
825a2a1d0f5SHuang Rui 				"snps,del_p1p2p3_quirk");
82641c06ffdSHuang Rui 		dwc->del_phy_power_chg_quirk = of_property_read_bool(node,
82741c06ffdSHuang Rui 				"snps,del_phy_power_chg_quirk");
828fb67afcaSHuang Rui 		dwc->lfps_filter_quirk = of_property_read_bool(node,
829fb67afcaSHuang Rui 				"snps,lfps_filter_quirk");
83014f4ac53SHuang Rui 		dwc->rx_detect_poll_quirk = of_property_read_bool(node,
83114f4ac53SHuang Rui 				"snps,rx_detect_poll_quirk");
83259acfa20SHuang Rui 		dwc->dis_u3_susphy_quirk = of_property_read_bool(node,
83359acfa20SHuang Rui 				"snps,dis_u3_susphy_quirk");
8340effe0a3SHuang Rui 		dwc->dis_u2_susphy_quirk = of_property_read_bool(node,
8350effe0a3SHuang Rui 				"snps,dis_u2_susphy_quirk");
8366b6a0c9aSHuang Rui 
8376b6a0c9aSHuang Rui 		dwc->tx_de_emphasis_quirk = of_property_read_bool(node,
8386b6a0c9aSHuang Rui 				"snps,tx_de_emphasis_quirk");
8396b6a0c9aSHuang Rui 		of_property_read_u8(node, "snps,tx_de_emphasis",
8406b6a0c9aSHuang Rui 				&tx_de_emphasis);
8413c9f94acSFelipe Balbi 	} else if (pdata) {
8423c9f94acSFelipe Balbi 		dwc->maximum_speed = pdata->maximum_speed;
84380caf7d2SHuang Rui 		dwc->has_lpm_erratum = pdata->has_lpm_erratum;
84480caf7d2SHuang Rui 		if (pdata->lpm_nyet_threshold)
84580caf7d2SHuang Rui 			lpm_nyet_threshold = pdata->lpm_nyet_threshold;
846460d098cSHuang Rui 		dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
847460d098cSHuang Rui 		if (pdata->hird_threshold)
848460d098cSHuang Rui 			hird_threshold = pdata->hird_threshold;
8493c9f94acSFelipe Balbi 
8503c9f94acSFelipe Balbi 		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
8513c9f94acSFelipe Balbi 		dwc->dr_mode = pdata->dr_mode;
8523b81221aSHuang Rui 
8533b81221aSHuang Rui 		dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
8549a5b2f31SHuang Rui 		dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
855b5a65c40SHuang Rui 		dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
856df31f5b3SHuang Rui 		dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
857a2a1d0f5SHuang Rui 		dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
85841c06ffdSHuang Rui 		dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
859fb67afcaSHuang Rui 		dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
86014f4ac53SHuang Rui 		dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
86159acfa20SHuang Rui 		dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
8620effe0a3SHuang Rui 		dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
8636b6a0c9aSHuang Rui 
8646b6a0c9aSHuang Rui 		dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
8656b6a0c9aSHuang Rui 		if (pdata->tx_de_emphasis)
8666b6a0c9aSHuang Rui 			tx_de_emphasis = pdata->tx_de_emphasis;
8673c9f94acSFelipe Balbi 	}
8683c9f94acSFelipe Balbi 
8693c9f94acSFelipe Balbi 	/* default to superspeed if no maximum_speed passed */
8703c9f94acSFelipe Balbi 	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
8713c9f94acSFelipe Balbi 		dwc->maximum_speed = USB_SPEED_SUPER;
8723c9f94acSFelipe Balbi 
87380caf7d2SHuang Rui 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
8746b6a0c9aSHuang Rui 	dwc->tx_de_emphasis = tx_de_emphasis;
87580caf7d2SHuang Rui 
876460d098cSHuang Rui 	dwc->hird_threshold = hird_threshold
877460d098cSHuang Rui 		| (dwc->is_utmi_l1_suspend << 4);
878460d098cSHuang Rui 
8793c9f94acSFelipe Balbi 	ret = dwc3_core_get_phy(dwc);
8803c9f94acSFelipe Balbi 	if (ret)
8813c9f94acSFelipe Balbi 		return ret;
8823c9f94acSFelipe Balbi 
88372246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
88472246da4SFelipe Balbi 	platform_set_drvdata(pdev, dwc);
88572246da4SFelipe Balbi 
88619bacdc9SHeikki Krogerus 	if (!dev->dma_mask) {
887ddff14f1SKishon Vijay Abraham I 		dev->dma_mask = dev->parent->dma_mask;
888ddff14f1SKishon Vijay Abraham I 		dev->dma_parms = dev->parent->dma_parms;
889ddff14f1SKishon Vijay Abraham I 		dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
89019bacdc9SHeikki Krogerus 	}
891ddff14f1SKishon Vijay Abraham I 
892802ca850SChanho Park 	pm_runtime_enable(dev);
893802ca850SChanho Park 	pm_runtime_get_sync(dev);
894802ca850SChanho Park 	pm_runtime_forbid(dev);
89572246da4SFelipe Balbi 
8964fd24483SKishon Vijay Abraham I 	dwc3_cache_hwparams(dwc);
8974fd24483SKishon Vijay Abraham I 
8983921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
8993921426bSFelipe Balbi 	if (ret) {
9003921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
9013921426bSFelipe Balbi 		ret = -ENOMEM;
9023921426bSFelipe Balbi 		goto err0;
9033921426bSFelipe Balbi 	}
9043921426bSFelipe Balbi 
90532a4a135SFelipe Balbi 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
90632a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_HOST;
90732a4a135SFelipe Balbi 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
90832a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
90932a4a135SFelipe Balbi 
91032a4a135SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
91132a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_OTG;
91232a4a135SFelipe Balbi 
91372246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
91472246da4SFelipe Balbi 	if (ret) {
915802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
9163921426bSFelipe Balbi 		goto err0;
91772246da4SFelipe Balbi 	}
91872246da4SFelipe Balbi 
9193088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
9203088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
92157303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb2_generic_phy);
92257303488SKishon Vijay Abraham I 	if (ret < 0)
92357303488SKishon Vijay Abraham I 		goto err1;
92457303488SKishon Vijay Abraham I 
92557303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb3_generic_phy);
92657303488SKishon Vijay Abraham I 	if (ret < 0)
92757303488SKishon Vijay Abraham I 		goto err_usb2phy_power;
9283088f108SKishon Vijay Abraham I 
929f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
930f122d33eSFelipe Balbi 	if (ret) {
931f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
93257303488SKishon Vijay Abraham I 		goto err_usb3phy_power;
933f122d33eSFelipe Balbi 	}
934f122d33eSFelipe Balbi 
9355f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
9365f94adfeSFelipe Balbi 	if (ret)
937f122d33eSFelipe Balbi 		goto err2;
93872246da4SFelipe Balbi 
93972246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
94072246da4SFelipe Balbi 	if (ret) {
941802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
942f122d33eSFelipe Balbi 		goto err3;
94372246da4SFelipe Balbi 	}
94472246da4SFelipe Balbi 
945802ca850SChanho Park 	pm_runtime_allow(dev);
94672246da4SFelipe Balbi 
94772246da4SFelipe Balbi 	return 0;
94872246da4SFelipe Balbi 
949f122d33eSFelipe Balbi err3:
9505f94adfeSFelipe Balbi 	dwc3_core_exit_mode(dwc);
95172246da4SFelipe Balbi 
952f122d33eSFelipe Balbi err2:
953f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
954f122d33eSFelipe Balbi 
95557303488SKishon Vijay Abraham I err_usb3phy_power:
95657303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
95757303488SKishon Vijay Abraham I 
95857303488SKishon Vijay Abraham I err_usb2phy_power:
95957303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
96057303488SKishon Vijay Abraham I 
961802ca850SChanho Park err1:
962501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
963501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
96472246da4SFelipe Balbi 	dwc3_core_exit(dwc);
96572246da4SFelipe Balbi 
9663921426bSFelipe Balbi err0:
9673921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
9683921426bSFelipe Balbi 
96972246da4SFelipe Balbi 	return ret;
97072246da4SFelipe Balbi }
97172246da4SFelipe Balbi 
972fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
97372246da4SFelipe Balbi {
97472246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
97572246da4SFelipe Balbi 
976dc99f16fSFelipe Balbi 	dwc3_debugfs_exit(dwc);
977dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
978dc99f16fSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
979dc99f16fSFelipe Balbi 	dwc3_free_event_buffers(dwc);
980dc99f16fSFelipe Balbi 
9818ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
9828ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
98357303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
98457303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
9858ba007a9SKishon Vijay Abraham I 
98672246da4SFelipe Balbi 	dwc3_core_exit(dwc);
98772246da4SFelipe Balbi 
9887415f17cSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
9897415f17cSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
9907415f17cSFelipe Balbi 
99172246da4SFelipe Balbi 	return 0;
99272246da4SFelipe Balbi }
99372246da4SFelipe Balbi 
9947415f17cSFelipe Balbi #ifdef CONFIG_PM_SLEEP
9957415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
9967415f17cSFelipe Balbi {
9977415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
9987415f17cSFelipe Balbi 	unsigned long	flags;
9997415f17cSFelipe Balbi 
10007415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
10017415f17cSFelipe Balbi 
1002a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
1003a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
1004a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
10057415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
10067415f17cSFelipe Balbi 		/* FALLTHROUGH */
1007a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
10087415f17cSFelipe Balbi 	default:
10090b0231aaSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
10107415f17cSFelipe Balbi 		break;
10117415f17cSFelipe Balbi 	}
10127415f17cSFelipe Balbi 
10137415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
10147415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
10157415f17cSFelipe Balbi 
10167415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
10177415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
101857303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
101957303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
10207415f17cSFelipe Balbi 
10217415f17cSFelipe Balbi 	return 0;
10227415f17cSFelipe Balbi }
10237415f17cSFelipe Balbi 
10247415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
10257415f17cSFelipe Balbi {
10267415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
10277415f17cSFelipe Balbi 	unsigned long	flags;
102857303488SKishon Vijay Abraham I 	int		ret;
10297415f17cSFelipe Balbi 
10307415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
10317415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
103257303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
103357303488SKishon Vijay Abraham I 	if (ret < 0)
103457303488SKishon Vijay Abraham I 		return ret;
103557303488SKishon Vijay Abraham I 
103657303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
103757303488SKishon Vijay Abraham I 	if (ret < 0)
103857303488SKishon Vijay Abraham I 		goto err_usb2phy_init;
10397415f17cSFelipe Balbi 
10407415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
10417415f17cSFelipe Balbi 
10420b0231aaSFelipe Balbi 	dwc3_event_buffers_setup(dwc);
10437415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
10447415f17cSFelipe Balbi 
1045a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
1046a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
1047a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
10487415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
10497415f17cSFelipe Balbi 		/* FALLTHROUGH */
1050a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
10517415f17cSFelipe Balbi 	default:
10527415f17cSFelipe Balbi 		/* do nothing */
10537415f17cSFelipe Balbi 		break;
10547415f17cSFelipe Balbi 	}
10557415f17cSFelipe Balbi 
10567415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
10577415f17cSFelipe Balbi 
10587415f17cSFelipe Balbi 	pm_runtime_disable(dev);
10597415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
10607415f17cSFelipe Balbi 	pm_runtime_enable(dev);
10617415f17cSFelipe Balbi 
10627415f17cSFelipe Balbi 	return 0;
106357303488SKishon Vijay Abraham I 
106457303488SKishon Vijay Abraham I err_usb2phy_init:
106557303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
106657303488SKishon Vijay Abraham I 
106757303488SKishon Vijay Abraham I 	return ret;
10687415f17cSFelipe Balbi }
10697415f17cSFelipe Balbi 
10707415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
10717415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
10727415f17cSFelipe Balbi };
10737415f17cSFelipe Balbi 
10747415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
10757415f17cSFelipe Balbi #else
10767415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
10777415f17cSFelipe Balbi #endif
10787415f17cSFelipe Balbi 
10795088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
10805088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
10815088b6f5SKishon Vijay Abraham I 	{
108222a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
108322a5aa17SFelipe Balbi 	},
108422a5aa17SFelipe Balbi 	{
10855088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
10865088b6f5SKishon Vijay Abraham I 	},
10875088b6f5SKishon Vijay Abraham I 	{ },
10885088b6f5SKishon Vijay Abraham I };
10895088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
10905088b6f5SKishon Vijay Abraham I #endif
10915088b6f5SKishon Vijay Abraham I 
1092404905a6SHeikki Krogerus #ifdef CONFIG_ACPI
1093404905a6SHeikki Krogerus 
1094404905a6SHeikki Krogerus #define ACPI_ID_INTEL_BSW	"808622B7"
1095404905a6SHeikki Krogerus 
1096404905a6SHeikki Krogerus static const struct acpi_device_id dwc3_acpi_match[] = {
1097404905a6SHeikki Krogerus 	{ ACPI_ID_INTEL_BSW, 0 },
1098404905a6SHeikki Krogerus 	{ },
1099404905a6SHeikki Krogerus };
1100404905a6SHeikki Krogerus MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
1101404905a6SHeikki Krogerus #endif
1102404905a6SHeikki Krogerus 
110372246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
110472246da4SFelipe Balbi 	.probe		= dwc3_probe,
11057690417dSBill Pemberton 	.remove		= dwc3_remove,
110672246da4SFelipe Balbi 	.driver		= {
110772246da4SFelipe Balbi 		.name	= "dwc3",
11085088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
1109404905a6SHeikki Krogerus 		.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
11107415f17cSFelipe Balbi 		.pm	= DWC3_PM_OPS,
111172246da4SFelipe Balbi 	},
111272246da4SFelipe Balbi };
111372246da4SFelipe Balbi 
1114b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
1115b1116dccSTobias Klauser 
11167ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
111772246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
11185945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
111972246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
1120