xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 0ffcaf37)
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 
22a72e658bSFelipe Balbi #include <linux/module.h>
2372246da4SFelipe Balbi #include <linux/kernel.h>
2472246da4SFelipe Balbi #include <linux/slab.h>
2572246da4SFelipe Balbi #include <linux/spinlock.h>
2672246da4SFelipe Balbi #include <linux/platform_device.h>
2772246da4SFelipe Balbi #include <linux/pm_runtime.h>
2872246da4SFelipe Balbi #include <linux/interrupt.h>
2972246da4SFelipe Balbi #include <linux/ioport.h>
3072246da4SFelipe Balbi #include <linux/io.h>
3172246da4SFelipe Balbi #include <linux/list.h>
3272246da4SFelipe Balbi #include <linux/delay.h>
3372246da4SFelipe Balbi #include <linux/dma-mapping.h>
34457e84b6SFelipe Balbi #include <linux/of.h>
3572246da4SFelipe Balbi 
3672246da4SFelipe Balbi #include <linux/usb/ch9.h>
3772246da4SFelipe Balbi #include <linux/usb/gadget.h>
38f7e846f0SFelipe Balbi #include <linux/usb/of.h>
39a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
4072246da4SFelipe Balbi 
416462cbd5SFelipe Balbi #include "platform_data.h"
4272246da4SFelipe Balbi #include "core.h"
4372246da4SFelipe Balbi #include "gadget.h"
4472246da4SFelipe Balbi #include "io.h"
4572246da4SFelipe Balbi 
4672246da4SFelipe Balbi #include "debug.h"
4772246da4SFelipe Balbi 
488300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
498300dd23SFelipe Balbi 
503140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
513140e8cbSSebastian Andrzej Siewior {
523140e8cbSSebastian Andrzej Siewior 	u32 reg;
533140e8cbSSebastian Andrzej Siewior 
543140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
553140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
563140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
573140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
583140e8cbSSebastian Andrzej Siewior }
598300dd23SFelipe Balbi 
6072246da4SFelipe Balbi /**
6172246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
6272246da4SFelipe Balbi  * @dwc: pointer to our context structure
6372246da4SFelipe Balbi  */
6472246da4SFelipe Balbi static void dwc3_core_soft_reset(struct dwc3 *dwc)
6572246da4SFelipe Balbi {
6672246da4SFelipe Balbi 	u32		reg;
6772246da4SFelipe Balbi 
6872246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
6972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
7072246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
7172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
7272246da4SFelipe Balbi 
7372246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
7472246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
7572246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
7672246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
7772246da4SFelipe Balbi 
7872246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
7972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
8072246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
8172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
8272246da4SFelipe Balbi 
8351e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
8451e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
8572246da4SFelipe Balbi 	mdelay(100);
8672246da4SFelipe Balbi 
8772246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
8872246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
8972246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
9072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
9172246da4SFelipe Balbi 
9272246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
9372246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
9472246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
9572246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
9672246da4SFelipe Balbi 
9745627ac6SPratyush Anand 	mdelay(100);
9845627ac6SPratyush Anand 
9972246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
10072246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
10172246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
10272246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
10372246da4SFelipe Balbi }
10472246da4SFelipe Balbi 
10572246da4SFelipe Balbi /**
10672246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
10772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
10872246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
10972246da4SFelipe Balbi  */
11072246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
11172246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
11272246da4SFelipe Balbi {
11372246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
11472246da4SFelipe Balbi }
11572246da4SFelipe Balbi 
11672246da4SFelipe Balbi /**
1171d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
11872246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
11972246da4SFelipe Balbi  * @length: size of the event buffer
12072246da4SFelipe Balbi  *
1211d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
12272246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
12372246da4SFelipe Balbi  */
12467d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
12567d0b500SFelipe Balbi 		unsigned length)
12672246da4SFelipe Balbi {
12772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
12872246da4SFelipe Balbi 
129380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
13072246da4SFelipe Balbi 	if (!evt)
13172246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
13272246da4SFelipe Balbi 
13372246da4SFelipe Balbi 	evt->dwc	= dwc;
13472246da4SFelipe Balbi 	evt->length	= length;
13572246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
13672246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
137e32672f0SFelipe Balbi 	if (!evt->buf)
13872246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
13972246da4SFelipe Balbi 
14072246da4SFelipe Balbi 	return evt;
14172246da4SFelipe Balbi }
14272246da4SFelipe Balbi 
14372246da4SFelipe Balbi /**
14472246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
14572246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
14672246da4SFelipe Balbi  */
14772246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
14872246da4SFelipe Balbi {
14972246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
15072246da4SFelipe Balbi 	int i;
15172246da4SFelipe Balbi 
1529f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
15372246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
15464b6c8a7SAnton Tikhomirov 		if (evt)
15572246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
15672246da4SFelipe Balbi 	}
15772246da4SFelipe Balbi }
15872246da4SFelipe Balbi 
15972246da4SFelipe Balbi /**
16072246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
1611d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
16272246da4SFelipe Balbi  * @length: size of event buffer
16372246da4SFelipe Balbi  *
1641d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
16572246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
16672246da4SFelipe Balbi  */
16741ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
16872246da4SFelipe Balbi {
1699f622b2aSFelipe Balbi 	int			num;
17072246da4SFelipe Balbi 	int			i;
17172246da4SFelipe Balbi 
1729f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
1739f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
1749f622b2aSFelipe Balbi 
175380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
176380f0d28SFelipe Balbi 			GFP_KERNEL);
177457d3f21SFelipe Balbi 	if (!dwc->ev_buffs) {
178457d3f21SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffers array\n");
179457d3f21SFelipe Balbi 		return -ENOMEM;
180457d3f21SFelipe Balbi 	}
181457d3f21SFelipe Balbi 
18272246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
18372246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
18472246da4SFelipe Balbi 
18572246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
18672246da4SFelipe Balbi 		if (IS_ERR(evt)) {
18772246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
18872246da4SFelipe Balbi 			return PTR_ERR(evt);
18972246da4SFelipe Balbi 		}
19072246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
19172246da4SFelipe Balbi 	}
19272246da4SFelipe Balbi 
19372246da4SFelipe Balbi 	return 0;
19472246da4SFelipe Balbi }
19572246da4SFelipe Balbi 
19672246da4SFelipe Balbi /**
19772246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
1981d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
19972246da4SFelipe Balbi  *
20072246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
20172246da4SFelipe Balbi  */
2027acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
20372246da4SFelipe Balbi {
20472246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
20572246da4SFelipe Balbi 	int				n;
20672246da4SFelipe Balbi 
2079f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
20872246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
20972246da4SFelipe Balbi 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
21072246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
21172246da4SFelipe Balbi 				evt->length);
21272246da4SFelipe Balbi 
2137acd85e0SPaul Zimmerman 		evt->lpos = 0;
2147acd85e0SPaul Zimmerman 
21572246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
21672246da4SFelipe Balbi 				lower_32_bits(evt->dma));
21772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
21872246da4SFelipe Balbi 				upper_32_bits(evt->dma));
21972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
22068d6a01bSFelipe Balbi 				DWC3_GEVNTSIZ_SIZE(evt->length));
22172246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
22272246da4SFelipe Balbi 	}
22372246da4SFelipe Balbi 
22472246da4SFelipe Balbi 	return 0;
22572246da4SFelipe Balbi }
22672246da4SFelipe Balbi 
22772246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
22872246da4SFelipe Balbi {
22972246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
23072246da4SFelipe Balbi 	int				n;
23172246da4SFelipe Balbi 
2329f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
23372246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2347acd85e0SPaul Zimmerman 
2357acd85e0SPaul Zimmerman 		evt->lpos = 0;
2367acd85e0SPaul Zimmerman 
23772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
23872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
23968d6a01bSFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
24068d6a01bSFelipe Balbi 				| DWC3_GEVNTSIZ_SIZE(0));
24172246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
24272246da4SFelipe Balbi 	}
24372246da4SFelipe Balbi }
24472246da4SFelipe Balbi 
2450ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
2460ffcaf37SFelipe Balbi {
2470ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
2480ffcaf37SFelipe Balbi 		return 0;
2490ffcaf37SFelipe Balbi 
2500ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
2510ffcaf37SFelipe Balbi 		return 0;
2520ffcaf37SFelipe Balbi 
2530ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
2540ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
2550ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
2560ffcaf37SFelipe Balbi 		return -ENOMEM;
2570ffcaf37SFelipe Balbi 
2580ffcaf37SFelipe Balbi 	return 0;
2590ffcaf37SFelipe Balbi }
2600ffcaf37SFelipe Balbi 
2610ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
2620ffcaf37SFelipe Balbi {
2630ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
2640ffcaf37SFelipe Balbi 	u32 param;
2650ffcaf37SFelipe Balbi 	int ret;
2660ffcaf37SFelipe Balbi 
2670ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
2680ffcaf37SFelipe Balbi 		return 0;
2690ffcaf37SFelipe Balbi 
2700ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
2710ffcaf37SFelipe Balbi 		return 0;
2720ffcaf37SFelipe Balbi 
2730ffcaf37SFelipe Balbi 	 /* should never fall here */
2740ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
2750ffcaf37SFelipe Balbi 		return 0;
2760ffcaf37SFelipe Balbi 
2770ffcaf37SFelipe Balbi 	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
2780ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
2790ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
2800ffcaf37SFelipe Balbi 	if (dma_mapping_error(dwc->dev, scratch_addr)) {
2810ffcaf37SFelipe Balbi 		dev_err(dwc->dev, "failed to map scratch buffer\n");
2820ffcaf37SFelipe Balbi 		ret = -EFAULT;
2830ffcaf37SFelipe Balbi 		goto err0;
2840ffcaf37SFelipe Balbi 	}
2850ffcaf37SFelipe Balbi 
2860ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
2870ffcaf37SFelipe Balbi 
2880ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
2890ffcaf37SFelipe Balbi 
2900ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
2910ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
2920ffcaf37SFelipe Balbi 	if (ret < 0)
2930ffcaf37SFelipe Balbi 		goto err1;
2940ffcaf37SFelipe Balbi 
2950ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
2960ffcaf37SFelipe Balbi 
2970ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
2980ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
2990ffcaf37SFelipe Balbi 	if (ret < 0)
3000ffcaf37SFelipe Balbi 		goto err1;
3010ffcaf37SFelipe Balbi 
3020ffcaf37SFelipe Balbi 	return 0;
3030ffcaf37SFelipe Balbi 
3040ffcaf37SFelipe Balbi err1:
3050ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3060ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3070ffcaf37SFelipe Balbi 
3080ffcaf37SFelipe Balbi err0:
3090ffcaf37SFelipe Balbi 	return ret;
3100ffcaf37SFelipe Balbi }
3110ffcaf37SFelipe Balbi 
3120ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
3130ffcaf37SFelipe Balbi {
3140ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3150ffcaf37SFelipe Balbi 		return;
3160ffcaf37SFelipe Balbi 
3170ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3180ffcaf37SFelipe Balbi 		return;
3190ffcaf37SFelipe Balbi 
3200ffcaf37SFelipe Balbi 	 /* should never fall here */
3210ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3220ffcaf37SFelipe Balbi 		return;
3230ffcaf37SFelipe Balbi 
3240ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3250ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3260ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
3270ffcaf37SFelipe Balbi }
3280ffcaf37SFelipe Balbi 
329789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
330789451f6SFelipe Balbi {
331789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
332789451f6SFelipe Balbi 
333789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
334789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
335789451f6SFelipe Balbi 
336789451f6SFelipe Balbi 	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
337789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
338789451f6SFelipe Balbi }
339789451f6SFelipe Balbi 
34041ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
34126ceca97SFelipe Balbi {
34226ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
34326ceca97SFelipe Balbi 
34426ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
34526ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
34626ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
34726ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
34826ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
34926ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
35026ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
35126ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
35226ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
35326ceca97SFelipe Balbi }
35426ceca97SFelipe Balbi 
35572246da4SFelipe Balbi /**
35672246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
35772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
35872246da4SFelipe Balbi  *
35972246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
36072246da4SFelipe Balbi  */
36141ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
36272246da4SFelipe Balbi {
36372246da4SFelipe Balbi 	unsigned long		timeout;
3640ffcaf37SFelipe Balbi 	u32			hwparams4 = dwc->hwparams.hwparams4;
36572246da4SFelipe Balbi 	u32			reg;
36672246da4SFelipe Balbi 	int			ret;
36772246da4SFelipe Balbi 
3687650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
3697650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
3707650bd74SSebastian Andrzej Siewior 	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
3717650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
3727650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
3737650bd74SSebastian Andrzej Siewior 		goto err0;
3747650bd74SSebastian Andrzej Siewior 	}
375248b122bSFelipe Balbi 	dwc->revision = reg;
3767650bd74SSebastian Andrzej Siewior 
37772246da4SFelipe Balbi 	/* issue device SoftReset too */
37872246da4SFelipe Balbi 	timeout = jiffies + msecs_to_jiffies(500);
37972246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
38072246da4SFelipe Balbi 	do {
38172246da4SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
38272246da4SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
38372246da4SFelipe Balbi 			break;
38472246da4SFelipe Balbi 
38572246da4SFelipe Balbi 		if (time_after(jiffies, timeout)) {
38672246da4SFelipe Balbi 			dev_err(dwc->dev, "Reset Timed Out\n");
38772246da4SFelipe Balbi 			ret = -ETIMEDOUT;
38872246da4SFelipe Balbi 			goto err0;
38972246da4SFelipe Balbi 		}
39072246da4SFelipe Balbi 
39172246da4SFelipe Balbi 		cpu_relax();
39272246da4SFelipe Balbi 	} while (true);
39372246da4SFelipe Balbi 
39458a0f23fSPratyush Anand 	dwc3_core_soft_reset(dwc);
39558a0f23fSPratyush Anand 
3964878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
3973e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
3984878a028SSebastian Andrzej Siewior 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
3994878a028SSebastian Andrzej Siewior 
400164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
4014878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
40232a4a135SFelipe Balbi 		/**
40332a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
40432a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
40532a4a135SFelipe Balbi 		 *
40632a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
40732a4a135SFelipe Balbi 		 * configurations.
40832a4a135SFelipe Balbi 		 *
40932a4a135SFelipe Balbi 		 * Refers to:
41032a4a135SFelipe Balbi 		 *
41132a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
41232a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
41332a4a135SFelipe Balbi 		 */
41432a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
41532a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
41632a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
41732a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
41832a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
41932a4a135SFelipe Balbi 		else
4204878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
4214878a028SSebastian Andrzej Siewior 		break;
4220ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
4230ffcaf37SFelipe Balbi 		/* enable hibernation here */
4240ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
4250ffcaf37SFelipe Balbi 		break;
4264878a028SSebastian Andrzej Siewior 	default:
4274878a028SSebastian Andrzej Siewior 		dev_dbg(dwc->dev, "No power optimization available\n");
4284878a028SSebastian Andrzej Siewior 	}
4294878a028SSebastian Andrzej Siewior 
4304878a028SSebastian Andrzej Siewior 	/*
4314878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
4321d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
4334878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
4341d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
4354878a028SSebastian Andrzej Siewior 	 */
4364878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
4374878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
4384878a028SSebastian Andrzej Siewior 
439789451f6SFelipe Balbi 	dwc3_core_num_eps(dwc);
440789451f6SFelipe Balbi 
4414878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
4424878a028SSebastian Andrzej Siewior 
4430ffcaf37SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
4440ffcaf37SFelipe Balbi 	if (ret)
4450ffcaf37SFelipe Balbi 		goto err1;
4460ffcaf37SFelipe Balbi 
4470ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
4480ffcaf37SFelipe Balbi 	if (ret)
4490ffcaf37SFelipe Balbi 		goto err2;
4500ffcaf37SFelipe Balbi 
45172246da4SFelipe Balbi 	return 0;
45272246da4SFelipe Balbi 
4530ffcaf37SFelipe Balbi err2:
4540ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
4550ffcaf37SFelipe Balbi 
4560ffcaf37SFelipe Balbi err1:
4570ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
4580ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
4590ffcaf37SFelipe Balbi 
46072246da4SFelipe Balbi err0:
46172246da4SFelipe Balbi 	return ret;
46272246da4SFelipe Balbi }
46372246da4SFelipe Balbi 
46472246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
46572246da4SFelipe Balbi {
4660ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
46701b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
46801b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
46972246da4SFelipe Balbi }
47072246da4SFelipe Balbi 
47172246da4SFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
47272246da4SFelipe Balbi 
47341ac7b3aSBill Pemberton static int dwc3_probe(struct platform_device *pdev)
47472246da4SFelipe Balbi {
475941ea361SFelipe Balbi 	struct device		*dev = &pdev->dev;
476941ea361SFelipe Balbi 	struct dwc3_platform_data *pdata = dev_get_platdata(dev);
477941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
47872246da4SFelipe Balbi 	struct resource		*res;
47972246da4SFelipe Balbi 	struct dwc3		*dwc;
4800949e99bSFelipe Balbi 
48172246da4SFelipe Balbi 	int			ret = -ENOMEM;
4820949e99bSFelipe Balbi 
4830949e99bSFelipe Balbi 	void __iomem		*regs;
48472246da4SFelipe Balbi 	void			*mem;
48572246da4SFelipe Balbi 
486802ca850SChanho Park 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
48772246da4SFelipe Balbi 	if (!mem) {
488802ca850SChanho Park 		dev_err(dev, "not enough memory\n");
489802ca850SChanho Park 		return -ENOMEM;
49072246da4SFelipe Balbi 	}
49172246da4SFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
49272246da4SFelipe Balbi 	dwc->mem = mem;
49372246da4SFelipe Balbi 
49451249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
49572246da4SFelipe Balbi 	if (!res) {
49651249dcaSIdo Shayevitz 		dev_err(dev, "missing IRQ\n");
497802ca850SChanho Park 		return -ENODEV;
49872246da4SFelipe Balbi 	}
499066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].start = res->start;
500066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].end = res->end;
501066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].flags = res->flags;
502066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].name = res->name;
50372246da4SFelipe Balbi 
50451249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
50551249dcaSIdo Shayevitz 	if (!res) {
50651249dcaSIdo Shayevitz 		dev_err(dev, "missing memory resource\n");
50751249dcaSIdo Shayevitz 		return -ENODEV;
50851249dcaSIdo Shayevitz 	}
50972246da4SFelipe Balbi 
5105088b6f5SKishon Vijay Abraham I 	if (node) {
511f7e846f0SFelipe Balbi 		dwc->maximum_speed = of_usb_get_maximum_speed(node);
512f7e846f0SFelipe Balbi 
5135088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
5145088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
5156462cbd5SFelipe Balbi 
5166462cbd5SFelipe Balbi 		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
517a45c82b8SRuchika Kharwar 		dwc->dr_mode = of_usb_get_dr_mode(node);
518bb674907SFelipe Balbi 	} else if (pdata) {
519f7e846f0SFelipe Balbi 		dwc->maximum_speed = pdata->maximum_speed;
520f7e846f0SFelipe Balbi 
52151e1e7bcSFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
5225088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
5236462cbd5SFelipe Balbi 
5246462cbd5SFelipe Balbi 		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
525a45c82b8SRuchika Kharwar 		dwc->dr_mode = pdata->dr_mode;
526bb674907SFelipe Balbi 	} else {
527bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
528bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
5295088b6f5SKishon Vijay Abraham I 	}
5305088b6f5SKishon Vijay Abraham I 
531f7e846f0SFelipe Balbi 	/* default to superspeed if no maximum_speed passed */
532f7e846f0SFelipe Balbi 	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
533f7e846f0SFelipe Balbi 		dwc->maximum_speed = USB_SPEED_SUPER;
534f7e846f0SFelipe Balbi 
535d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
536d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
537d105e7f8SFelipe Balbi 
538d105e7f8SFelipe Balbi 		/*
539d105e7f8SFelipe Balbi 		 * if -ENXIO is returned, it means PHY layer wasn't
540d105e7f8SFelipe Balbi 		 * enabled, so it makes no sense to return -EPROBE_DEFER
541d105e7f8SFelipe Balbi 		 * in that case, since no PHY driver will ever probe.
542d105e7f8SFelipe Balbi 		 */
543d105e7f8SFelipe Balbi 		if (ret == -ENXIO)
544d105e7f8SFelipe Balbi 			return ret;
545d105e7f8SFelipe Balbi 
54651e1e7bcSFelipe Balbi 		dev_err(dev, "no usb2 phy configured\n");
54751e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
54851e1e7bcSFelipe Balbi 	}
54951e1e7bcSFelipe Balbi 
550d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
551315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
552d105e7f8SFelipe Balbi 
553d105e7f8SFelipe Balbi 		/*
554d105e7f8SFelipe Balbi 		 * if -ENXIO is returned, it means PHY layer wasn't
555d105e7f8SFelipe Balbi 		 * enabled, so it makes no sense to return -EPROBE_DEFER
556d105e7f8SFelipe Balbi 		 * in that case, since no PHY driver will ever probe.
557d105e7f8SFelipe Balbi 		 */
558d105e7f8SFelipe Balbi 		if (ret == -ENXIO)
559d105e7f8SFelipe Balbi 			return ret;
560d105e7f8SFelipe Balbi 
56151e1e7bcSFelipe Balbi 		dev_err(dev, "no usb3 phy configured\n");
56251e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
56351e1e7bcSFelipe Balbi 	}
56451e1e7bcSFelipe Balbi 
5652e112345SIvan T. Ivanov 	dwc->xhci_resources[0].start = res->start;
5662e112345SIvan T. Ivanov 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
5672e112345SIvan T. Ivanov 					DWC3_XHCI_REGS_END;
5682e112345SIvan T. Ivanov 	dwc->xhci_resources[0].flags = res->flags;
5692e112345SIvan T. Ivanov 	dwc->xhci_resources[0].name = res->name;
5702e112345SIvan T. Ivanov 
5712e112345SIvan T. Ivanov 	res->start += DWC3_GLOBALS_REGS_START;
5722e112345SIvan T. Ivanov 
5732e112345SIvan T. Ivanov 	/*
5742e112345SIvan T. Ivanov 	 * Request memory region but exclude xHCI regs,
5752e112345SIvan T. Ivanov 	 * since it will be requested by the xhci-plat driver.
5762e112345SIvan T. Ivanov 	 */
5772e112345SIvan T. Ivanov 	regs = devm_ioremap_resource(dev, res);
5782e112345SIvan T. Ivanov 	if (IS_ERR(regs))
5792e112345SIvan T. Ivanov 		return PTR_ERR(regs);
5802e112345SIvan T. Ivanov 
58172246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
58272246da4SFelipe Balbi 	platform_set_drvdata(pdev, dwc);
58372246da4SFelipe Balbi 
58472246da4SFelipe Balbi 	dwc->regs	= regs;
58572246da4SFelipe Balbi 	dwc->regs_size	= resource_size(res);
586802ca850SChanho Park 	dwc->dev	= dev;
58772246da4SFelipe Balbi 
588ddff14f1SKishon Vijay Abraham I 	dev->dma_mask	= dev->parent->dma_mask;
589ddff14f1SKishon Vijay Abraham I 	dev->dma_parms	= dev->parent->dma_parms;
590ddff14f1SKishon Vijay Abraham I 	dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
591ddff14f1SKishon Vijay Abraham I 
592802ca850SChanho Park 	pm_runtime_enable(dev);
593802ca850SChanho Park 	pm_runtime_get_sync(dev);
594802ca850SChanho Park 	pm_runtime_forbid(dev);
59572246da4SFelipe Balbi 
5964fd24483SKishon Vijay Abraham I 	dwc3_cache_hwparams(dwc);
5974fd24483SKishon Vijay Abraham I 
5983921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
5993921426bSFelipe Balbi 	if (ret) {
6003921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
6013921426bSFelipe Balbi 		ret = -ENOMEM;
6023921426bSFelipe Balbi 		goto err0;
6033921426bSFelipe Balbi 	}
6043921426bSFelipe Balbi 
60532a4a135SFelipe Balbi 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
60632a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_HOST;
60732a4a135SFelipe Balbi 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
60832a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
60932a4a135SFelipe Balbi 
61032a4a135SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
61132a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_OTG;
61232a4a135SFelipe Balbi 
61372246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
61472246da4SFelipe Balbi 	if (ret) {
615802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
6163921426bSFelipe Balbi 		goto err0;
61772246da4SFelipe Balbi 	}
61872246da4SFelipe Balbi 
6193088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
6203088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
6213088f108SKishon Vijay Abraham I 
622f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
623f122d33eSFelipe Balbi 	if (ret) {
624f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
625f122d33eSFelipe Balbi 		goto err1;
626f122d33eSFelipe Balbi 	}
627f122d33eSFelipe Balbi 
628a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
629a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
6303140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
63172246da4SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
63272246da4SFelipe Balbi 		if (ret) {
633802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
634f122d33eSFelipe Balbi 			goto err2;
63572246da4SFelipe Balbi 		}
6360949e99bSFelipe Balbi 		break;
637a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
6383140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
639d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
640d07e8819SFelipe Balbi 		if (ret) {
641802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
642f122d33eSFelipe Balbi 			goto err2;
64372246da4SFelipe Balbi 		}
644d07e8819SFelipe Balbi 		break;
645a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
6463140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
647d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
648d07e8819SFelipe Balbi 		if (ret) {
649802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
650f122d33eSFelipe Balbi 			goto err2;
651d07e8819SFelipe Balbi 		}
652d07e8819SFelipe Balbi 
653d07e8819SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
654d07e8819SFelipe Balbi 		if (ret) {
655802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
656f122d33eSFelipe Balbi 			goto err2;
657d07e8819SFelipe Balbi 		}
658d07e8819SFelipe Balbi 		break;
6590949e99bSFelipe Balbi 	default:
660a45c82b8SRuchika Kharwar 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
661f122d33eSFelipe Balbi 		goto err2;
66272246da4SFelipe Balbi 	}
66372246da4SFelipe Balbi 
66472246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
66572246da4SFelipe Balbi 	if (ret) {
666802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
667f122d33eSFelipe Balbi 		goto err3;
66872246da4SFelipe Balbi 	}
66972246da4SFelipe Balbi 
670802ca850SChanho Park 	pm_runtime_allow(dev);
67172246da4SFelipe Balbi 
67272246da4SFelipe Balbi 	return 0;
67372246da4SFelipe Balbi 
674f122d33eSFelipe Balbi err3:
675a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
676a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
67772246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
6780949e99bSFelipe Balbi 		break;
679a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
680d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
681d07e8819SFelipe Balbi 		break;
682a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
683d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
684d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
685d07e8819SFelipe Balbi 		break;
6860949e99bSFelipe Balbi 	default:
6870949e99bSFelipe Balbi 		/* do nothing */
6880949e99bSFelipe Balbi 		break;
6890949e99bSFelipe Balbi 	}
69072246da4SFelipe Balbi 
691f122d33eSFelipe Balbi err2:
692f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
693f122d33eSFelipe Balbi 
694802ca850SChanho Park err1:
695501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
696501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
69772246da4SFelipe Balbi 	dwc3_core_exit(dwc);
69872246da4SFelipe Balbi 
6993921426bSFelipe Balbi err0:
7003921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
7013921426bSFelipe Balbi 
70272246da4SFelipe Balbi 	return ret;
70372246da4SFelipe Balbi }
70472246da4SFelipe Balbi 
705fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
70672246da4SFelipe Balbi {
70772246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
70872246da4SFelipe Balbi 
7098ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
7108ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
7118ba007a9SKishon Vijay Abraham I 
71216b972a5SFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
71372246da4SFelipe Balbi 	pm_runtime_disable(&pdev->dev);
71472246da4SFelipe Balbi 
71572246da4SFelipe Balbi 	dwc3_debugfs_exit(dwc);
71672246da4SFelipe Balbi 
717a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
718a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
71972246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
7200949e99bSFelipe Balbi 		break;
721a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
722d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
723d07e8819SFelipe Balbi 		break;
724a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
725d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
726d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
727d07e8819SFelipe Balbi 		break;
7280949e99bSFelipe Balbi 	default:
7290949e99bSFelipe Balbi 		/* do nothing */
7300949e99bSFelipe Balbi 		break;
7310949e99bSFelipe Balbi 	}
73272246da4SFelipe Balbi 
733f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
734d9b4330aSFelipe Balbi 	dwc3_free_event_buffers(dwc);
73572246da4SFelipe Balbi 	dwc3_core_exit(dwc);
73672246da4SFelipe Balbi 
73772246da4SFelipe Balbi 	return 0;
73872246da4SFelipe Balbi }
73972246da4SFelipe Balbi 
74019fda7cdSJingoo Han #ifdef CONFIG_PM_SLEEP
7417415f17cSFelipe Balbi static int dwc3_prepare(struct device *dev)
7427415f17cSFelipe Balbi {
7437415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
7447415f17cSFelipe Balbi 	unsigned long	flags;
7457415f17cSFelipe Balbi 
7467415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
7477415f17cSFelipe Balbi 
748a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
749a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
750a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
7517415f17cSFelipe Balbi 		dwc3_gadget_prepare(dwc);
7527415f17cSFelipe Balbi 		/* FALLTHROUGH */
753a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
7547415f17cSFelipe Balbi 	default:
7557415f17cSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
7567415f17cSFelipe Balbi 		break;
7577415f17cSFelipe Balbi 	}
7587415f17cSFelipe Balbi 
7597415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
7607415f17cSFelipe Balbi 
7617415f17cSFelipe Balbi 	return 0;
7627415f17cSFelipe Balbi }
7637415f17cSFelipe Balbi 
7647415f17cSFelipe Balbi static void dwc3_complete(struct device *dev)
7657415f17cSFelipe Balbi {
7667415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
7677415f17cSFelipe Balbi 	unsigned long	flags;
7687415f17cSFelipe Balbi 
7697415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
7707415f17cSFelipe Balbi 
771a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
772a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
773a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
7747415f17cSFelipe Balbi 		dwc3_gadget_complete(dwc);
7757415f17cSFelipe Balbi 		/* FALLTHROUGH */
776a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
7777415f17cSFelipe Balbi 	default:
7787415f17cSFelipe Balbi 		dwc3_event_buffers_setup(dwc);
7797415f17cSFelipe Balbi 		break;
7807415f17cSFelipe Balbi 	}
7817415f17cSFelipe Balbi 
7827415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
7837415f17cSFelipe Balbi }
7847415f17cSFelipe Balbi 
7857415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
7867415f17cSFelipe Balbi {
7877415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
7887415f17cSFelipe Balbi 	unsigned long	flags;
7897415f17cSFelipe Balbi 
7907415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
7917415f17cSFelipe Balbi 
792a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
793a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
794a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
7957415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
7967415f17cSFelipe Balbi 		/* FALLTHROUGH */
797a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
7987415f17cSFelipe Balbi 	default:
7997415f17cSFelipe Balbi 		/* do nothing */
8007415f17cSFelipe Balbi 		break;
8017415f17cSFelipe Balbi 	}
8027415f17cSFelipe Balbi 
8037415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
8047415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
8057415f17cSFelipe Balbi 
8067415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
8077415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
8087415f17cSFelipe Balbi 
8097415f17cSFelipe Balbi 	return 0;
8107415f17cSFelipe Balbi }
8117415f17cSFelipe Balbi 
8127415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
8137415f17cSFelipe Balbi {
8147415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
8157415f17cSFelipe Balbi 	unsigned long	flags;
8167415f17cSFelipe Balbi 
8177415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
8187415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
8197415f17cSFelipe Balbi 
8207415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
8217415f17cSFelipe Balbi 
8227415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
8237415f17cSFelipe Balbi 
824a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
825a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
826a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
8277415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
8287415f17cSFelipe Balbi 		/* FALLTHROUGH */
829a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
8307415f17cSFelipe Balbi 	default:
8317415f17cSFelipe Balbi 		/* do nothing */
8327415f17cSFelipe Balbi 		break;
8337415f17cSFelipe Balbi 	}
8347415f17cSFelipe Balbi 
8357415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
8367415f17cSFelipe Balbi 
8377415f17cSFelipe Balbi 	pm_runtime_disable(dev);
8387415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
8397415f17cSFelipe Balbi 	pm_runtime_enable(dev);
8407415f17cSFelipe Balbi 
8417415f17cSFelipe Balbi 	return 0;
8427415f17cSFelipe Balbi }
8437415f17cSFelipe Balbi 
8447415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
8457415f17cSFelipe Balbi 	.prepare	= dwc3_prepare,
8467415f17cSFelipe Balbi 	.complete	= dwc3_complete,
8477415f17cSFelipe Balbi 
8487415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
8497415f17cSFelipe Balbi };
8507415f17cSFelipe Balbi 
8517415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
8527415f17cSFelipe Balbi #else
8537415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
8547415f17cSFelipe Balbi #endif
8557415f17cSFelipe Balbi 
8565088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
8575088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
8585088b6f5SKishon Vijay Abraham I 	{
85922a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
86022a5aa17SFelipe Balbi 	},
86122a5aa17SFelipe Balbi 	{
8625088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
8635088b6f5SKishon Vijay Abraham I 	},
8645088b6f5SKishon Vijay Abraham I 	{ },
8655088b6f5SKishon Vijay Abraham I };
8665088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
8675088b6f5SKishon Vijay Abraham I #endif
8685088b6f5SKishon Vijay Abraham I 
86972246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
87072246da4SFelipe Balbi 	.probe		= dwc3_probe,
8717690417dSBill Pemberton 	.remove		= dwc3_remove,
87272246da4SFelipe Balbi 	.driver		= {
87372246da4SFelipe Balbi 		.name	= "dwc3",
8745088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
8757415f17cSFelipe Balbi 		.pm	= DWC3_PM_OPS,
87672246da4SFelipe Balbi 	},
87772246da4SFelipe Balbi };
87872246da4SFelipe Balbi 
879b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
880b1116dccSTobias Klauser 
8817ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
88272246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
8835945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
88472246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
885