xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 19bacdc9)
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>
3672246da4SFelipe Balbi 
3772246da4SFelipe Balbi #include <linux/usb/ch9.h>
3872246da4SFelipe Balbi #include <linux/usb/gadget.h>
39f7e846f0SFelipe Balbi #include <linux/usb/of.h>
40a45c82b8SRuchika Kharwar #include <linux/usb/otg.h>
4172246da4SFelipe Balbi 
426462cbd5SFelipe Balbi #include "platform_data.h"
4372246da4SFelipe Balbi #include "core.h"
4472246da4SFelipe Balbi #include "gadget.h"
4572246da4SFelipe Balbi #include "io.h"
4672246da4SFelipe Balbi 
4772246da4SFelipe Balbi #include "debug.h"
4872246da4SFelipe Balbi 
498300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
508300dd23SFelipe Balbi 
513140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
523140e8cbSSebastian Andrzej Siewior {
533140e8cbSSebastian Andrzej Siewior 	u32 reg;
543140e8cbSSebastian Andrzej Siewior 
553140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
563140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
573140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
583140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
593140e8cbSSebastian Andrzej Siewior }
608300dd23SFelipe Balbi 
6172246da4SFelipe Balbi /**
6272246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
6372246da4SFelipe Balbi  * @dwc: pointer to our context structure
6472246da4SFelipe Balbi  */
6557303488SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc)
6672246da4SFelipe Balbi {
6772246da4SFelipe Balbi 	u32		reg;
6857303488SKishon Vijay Abraham I 	int		ret;
6972246da4SFelipe Balbi 
7072246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
7172246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
7272246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
7372246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
7472246da4SFelipe Balbi 
7572246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
7672246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
7772246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
7872246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
7972246da4SFelipe Balbi 
8072246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
8172246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
8272246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
8372246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
8472246da4SFelipe Balbi 
8551e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
8651e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
8757303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
8857303488SKishon Vijay Abraham I 	if (ret < 0)
8957303488SKishon Vijay Abraham I 		return ret;
9057303488SKishon Vijay Abraham I 
9157303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
9257303488SKishon Vijay Abraham I 	if (ret < 0) {
9357303488SKishon Vijay Abraham I 		phy_exit(dwc->usb2_generic_phy);
9457303488SKishon Vijay Abraham I 		return ret;
9557303488SKishon Vijay Abraham I 	}
9672246da4SFelipe Balbi 	mdelay(100);
9772246da4SFelipe Balbi 
9872246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
9972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
10072246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
10172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
10272246da4SFelipe Balbi 
10372246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
10472246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
10572246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
10672246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
10772246da4SFelipe Balbi 
10845627ac6SPratyush Anand 	mdelay(100);
10945627ac6SPratyush Anand 
11072246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
11172246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
11272246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
11372246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
11457303488SKishon Vijay Abraham I 
11557303488SKishon Vijay Abraham I 	return 0;
11672246da4SFelipe Balbi }
11772246da4SFelipe Balbi 
11872246da4SFelipe Balbi /**
11972246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
12072246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
12172246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
12272246da4SFelipe Balbi  */
12372246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
12472246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
12572246da4SFelipe Balbi {
12672246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
12772246da4SFelipe Balbi }
12872246da4SFelipe Balbi 
12972246da4SFelipe Balbi /**
1301d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
13172246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
13272246da4SFelipe Balbi  * @length: size of the event buffer
13372246da4SFelipe Balbi  *
1341d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
13572246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
13672246da4SFelipe Balbi  */
13767d0b500SFelipe Balbi static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
13867d0b500SFelipe Balbi 		unsigned length)
13972246da4SFelipe Balbi {
14072246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
14172246da4SFelipe Balbi 
142380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
14372246da4SFelipe Balbi 	if (!evt)
14472246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
14572246da4SFelipe Balbi 
14672246da4SFelipe Balbi 	evt->dwc	= dwc;
14772246da4SFelipe Balbi 	evt->length	= length;
14872246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
14972246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
150e32672f0SFelipe Balbi 	if (!evt->buf)
15172246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
15272246da4SFelipe Balbi 
15372246da4SFelipe Balbi 	return evt;
15472246da4SFelipe Balbi }
15572246da4SFelipe Balbi 
15672246da4SFelipe Balbi /**
15772246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
15872246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
15972246da4SFelipe Balbi  */
16072246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
16172246da4SFelipe Balbi {
16272246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
16372246da4SFelipe Balbi 	int i;
16472246da4SFelipe Balbi 
1659f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
16672246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
16764b6c8a7SAnton Tikhomirov 		if (evt)
16872246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
16972246da4SFelipe Balbi 	}
17072246da4SFelipe Balbi }
17172246da4SFelipe Balbi 
17272246da4SFelipe Balbi /**
17372246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
1741d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
17572246da4SFelipe Balbi  * @length: size of event buffer
17672246da4SFelipe Balbi  *
1771d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
17872246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
17972246da4SFelipe Balbi  */
18041ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
18172246da4SFelipe Balbi {
1829f622b2aSFelipe Balbi 	int			num;
18372246da4SFelipe Balbi 	int			i;
18472246da4SFelipe Balbi 
1859f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
1869f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
1879f622b2aSFelipe Balbi 
188380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
189380f0d28SFelipe Balbi 			GFP_KERNEL);
190734d5a53SJingoo Han 	if (!dwc->ev_buffs)
191457d3f21SFelipe Balbi 		return -ENOMEM;
192457d3f21SFelipe Balbi 
19372246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
19472246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
19572246da4SFelipe Balbi 
19672246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
19772246da4SFelipe Balbi 		if (IS_ERR(evt)) {
19872246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
19972246da4SFelipe Balbi 			return PTR_ERR(evt);
20072246da4SFelipe Balbi 		}
20172246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
20272246da4SFelipe Balbi 	}
20372246da4SFelipe Balbi 
20472246da4SFelipe Balbi 	return 0;
20572246da4SFelipe Balbi }
20672246da4SFelipe Balbi 
20772246da4SFelipe Balbi /**
20872246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
2091d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
21072246da4SFelipe Balbi  *
21172246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
21272246da4SFelipe Balbi  */
2137acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
21472246da4SFelipe Balbi {
21572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
21672246da4SFelipe Balbi 	int				n;
21772246da4SFelipe Balbi 
2189f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
21972246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
22072246da4SFelipe Balbi 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
22172246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
22272246da4SFelipe Balbi 				evt->length);
22372246da4SFelipe Balbi 
2247acd85e0SPaul Zimmerman 		evt->lpos = 0;
2257acd85e0SPaul Zimmerman 
22672246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
22772246da4SFelipe Balbi 				lower_32_bits(evt->dma));
22872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
22972246da4SFelipe Balbi 				upper_32_bits(evt->dma));
23072246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
23168d6a01bSFelipe Balbi 				DWC3_GEVNTSIZ_SIZE(evt->length));
23272246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
23372246da4SFelipe Balbi 	}
23472246da4SFelipe Balbi 
23572246da4SFelipe Balbi 	return 0;
23672246da4SFelipe Balbi }
23772246da4SFelipe Balbi 
23872246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
23972246da4SFelipe Balbi {
24072246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
24172246da4SFelipe Balbi 	int				n;
24272246da4SFelipe Balbi 
2439f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
24472246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2457acd85e0SPaul Zimmerman 
2467acd85e0SPaul Zimmerman 		evt->lpos = 0;
2477acd85e0SPaul Zimmerman 
24872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
24972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
25068d6a01bSFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
25168d6a01bSFelipe Balbi 				| DWC3_GEVNTSIZ_SIZE(0));
25272246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
25372246da4SFelipe Balbi 	}
25472246da4SFelipe Balbi }
25572246da4SFelipe Balbi 
2560ffcaf37SFelipe Balbi static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
2570ffcaf37SFelipe Balbi {
2580ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
2590ffcaf37SFelipe Balbi 		return 0;
2600ffcaf37SFelipe Balbi 
2610ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
2620ffcaf37SFelipe Balbi 		return 0;
2630ffcaf37SFelipe Balbi 
2640ffcaf37SFelipe Balbi 	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
2650ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
2660ffcaf37SFelipe Balbi 	if (!dwc->scratchbuf)
2670ffcaf37SFelipe Balbi 		return -ENOMEM;
2680ffcaf37SFelipe Balbi 
2690ffcaf37SFelipe Balbi 	return 0;
2700ffcaf37SFelipe Balbi }
2710ffcaf37SFelipe Balbi 
2720ffcaf37SFelipe Balbi static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
2730ffcaf37SFelipe Balbi {
2740ffcaf37SFelipe Balbi 	dma_addr_t scratch_addr;
2750ffcaf37SFelipe Balbi 	u32 param;
2760ffcaf37SFelipe Balbi 	int ret;
2770ffcaf37SFelipe Balbi 
2780ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
2790ffcaf37SFelipe Balbi 		return 0;
2800ffcaf37SFelipe Balbi 
2810ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
2820ffcaf37SFelipe Balbi 		return 0;
2830ffcaf37SFelipe Balbi 
2840ffcaf37SFelipe Balbi 	 /* should never fall here */
2850ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
2860ffcaf37SFelipe Balbi 		return 0;
2870ffcaf37SFelipe Balbi 
2880ffcaf37SFelipe Balbi 	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
2890ffcaf37SFelipe Balbi 			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
2900ffcaf37SFelipe Balbi 			DMA_BIDIRECTIONAL);
2910ffcaf37SFelipe Balbi 	if (dma_mapping_error(dwc->dev, scratch_addr)) {
2920ffcaf37SFelipe Balbi 		dev_err(dwc->dev, "failed to map scratch buffer\n");
2930ffcaf37SFelipe Balbi 		ret = -EFAULT;
2940ffcaf37SFelipe Balbi 		goto err0;
2950ffcaf37SFelipe Balbi 	}
2960ffcaf37SFelipe Balbi 
2970ffcaf37SFelipe Balbi 	dwc->scratch_addr = scratch_addr;
2980ffcaf37SFelipe Balbi 
2990ffcaf37SFelipe Balbi 	param = lower_32_bits(scratch_addr);
3000ffcaf37SFelipe Balbi 
3010ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3020ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
3030ffcaf37SFelipe Balbi 	if (ret < 0)
3040ffcaf37SFelipe Balbi 		goto err1;
3050ffcaf37SFelipe Balbi 
3060ffcaf37SFelipe Balbi 	param = upper_32_bits(scratch_addr);
3070ffcaf37SFelipe Balbi 
3080ffcaf37SFelipe Balbi 	ret = dwc3_send_gadget_generic_command(dwc,
3090ffcaf37SFelipe Balbi 			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
3100ffcaf37SFelipe Balbi 	if (ret < 0)
3110ffcaf37SFelipe Balbi 		goto err1;
3120ffcaf37SFelipe Balbi 
3130ffcaf37SFelipe Balbi 	return 0;
3140ffcaf37SFelipe Balbi 
3150ffcaf37SFelipe Balbi err1:
3160ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3170ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3180ffcaf37SFelipe Balbi 
3190ffcaf37SFelipe Balbi err0:
3200ffcaf37SFelipe Balbi 	return ret;
3210ffcaf37SFelipe Balbi }
3220ffcaf37SFelipe Balbi 
3230ffcaf37SFelipe Balbi static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
3240ffcaf37SFelipe Balbi {
3250ffcaf37SFelipe Balbi 	if (!dwc->has_hibernation)
3260ffcaf37SFelipe Balbi 		return;
3270ffcaf37SFelipe Balbi 
3280ffcaf37SFelipe Balbi 	if (!dwc->nr_scratch)
3290ffcaf37SFelipe Balbi 		return;
3300ffcaf37SFelipe Balbi 
3310ffcaf37SFelipe Balbi 	 /* should never fall here */
3320ffcaf37SFelipe Balbi 	if (!WARN_ON(dwc->scratchbuf))
3330ffcaf37SFelipe Balbi 		return;
3340ffcaf37SFelipe Balbi 
3350ffcaf37SFelipe Balbi 	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
3360ffcaf37SFelipe Balbi 			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
3370ffcaf37SFelipe Balbi 	kfree(dwc->scratchbuf);
3380ffcaf37SFelipe Balbi }
3390ffcaf37SFelipe Balbi 
340789451f6SFelipe Balbi static void dwc3_core_num_eps(struct dwc3 *dwc)
341789451f6SFelipe Balbi {
342789451f6SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
343789451f6SFelipe Balbi 
344789451f6SFelipe Balbi 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
345789451f6SFelipe Balbi 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
346789451f6SFelipe Balbi 
347789451f6SFelipe Balbi 	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
348789451f6SFelipe Balbi 			dwc->num_in_eps, dwc->num_out_eps);
349789451f6SFelipe Balbi }
350789451f6SFelipe Balbi 
35141ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
35226ceca97SFelipe Balbi {
35326ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
35426ceca97SFelipe Balbi 
35526ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
35626ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
35726ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
35826ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
35926ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
36026ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
36126ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
36226ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
36326ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
36426ceca97SFelipe Balbi }
36526ceca97SFelipe Balbi 
36672246da4SFelipe Balbi /**
36772246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
36872246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
36972246da4SFelipe Balbi  *
37072246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
37172246da4SFelipe Balbi  */
37241ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
37372246da4SFelipe Balbi {
37472246da4SFelipe Balbi 	unsigned long		timeout;
3750ffcaf37SFelipe Balbi 	u32			hwparams4 = dwc->hwparams.hwparams4;
37672246da4SFelipe Balbi 	u32			reg;
37772246da4SFelipe Balbi 	int			ret;
37872246da4SFelipe Balbi 
3797650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
3807650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
3817650bd74SSebastian Andrzej Siewior 	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
3827650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
3837650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
3847650bd74SSebastian Andrzej Siewior 		goto err0;
3857650bd74SSebastian Andrzej Siewior 	}
386248b122bSFelipe Balbi 	dwc->revision = reg;
3877650bd74SSebastian Andrzej Siewior 
388fa0ea13eSFelipe Balbi 	/*
389fa0ea13eSFelipe Balbi 	 * Write Linux Version Code to our GUID register so it's easy to figure
390fa0ea13eSFelipe Balbi 	 * out which kernel version a bug was found.
391fa0ea13eSFelipe Balbi 	 */
392fa0ea13eSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
393fa0ea13eSFelipe Balbi 
3940e1e5c47SPaul Zimmerman 	/* Handle USB2.0-only core configuration */
3950e1e5c47SPaul Zimmerman 	if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
3960e1e5c47SPaul Zimmerman 			DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
3970e1e5c47SPaul Zimmerman 		if (dwc->maximum_speed == USB_SPEED_SUPER)
3980e1e5c47SPaul Zimmerman 			dwc->maximum_speed = USB_SPEED_HIGH;
3990e1e5c47SPaul Zimmerman 	}
4000e1e5c47SPaul Zimmerman 
40172246da4SFelipe Balbi 	/* issue device SoftReset too */
40272246da4SFelipe Balbi 	timeout = jiffies + msecs_to_jiffies(500);
40372246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
40472246da4SFelipe Balbi 	do {
40572246da4SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
40672246da4SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
40772246da4SFelipe Balbi 			break;
40872246da4SFelipe Balbi 
40972246da4SFelipe Balbi 		if (time_after(jiffies, timeout)) {
41072246da4SFelipe Balbi 			dev_err(dwc->dev, "Reset Timed Out\n");
41172246da4SFelipe Balbi 			ret = -ETIMEDOUT;
41272246da4SFelipe Balbi 			goto err0;
41372246da4SFelipe Balbi 		}
41472246da4SFelipe Balbi 
41572246da4SFelipe Balbi 		cpu_relax();
41672246da4SFelipe Balbi 	} while (true);
41772246da4SFelipe Balbi 
41857303488SKishon Vijay Abraham I 	ret = dwc3_core_soft_reset(dwc);
41957303488SKishon Vijay Abraham I 	if (ret)
42057303488SKishon Vijay Abraham I 		goto err0;
42158a0f23fSPratyush Anand 
4224878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
4233e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
4244878a028SSebastian Andrzej Siewior 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
4254878a028SSebastian Andrzej Siewior 
426164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
4274878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
42832a4a135SFelipe Balbi 		/**
42932a4a135SFelipe Balbi 		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
43032a4a135SFelipe Balbi 		 * issue which would cause xHCI compliance tests to fail.
43132a4a135SFelipe Balbi 		 *
43232a4a135SFelipe Balbi 		 * Because of that we cannot enable clock gating on such
43332a4a135SFelipe Balbi 		 * configurations.
43432a4a135SFelipe Balbi 		 *
43532a4a135SFelipe Balbi 		 * Refers to:
43632a4a135SFelipe Balbi 		 *
43732a4a135SFelipe Balbi 		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
43832a4a135SFelipe Balbi 		 * SOF/ITP Mode Used
43932a4a135SFelipe Balbi 		 */
44032a4a135SFelipe Balbi 		if ((dwc->dr_mode == USB_DR_MODE_HOST ||
44132a4a135SFelipe Balbi 				dwc->dr_mode == USB_DR_MODE_OTG) &&
44232a4a135SFelipe Balbi 				(dwc->revision >= DWC3_REVISION_210A &&
44332a4a135SFelipe Balbi 				dwc->revision <= DWC3_REVISION_250A))
44432a4a135SFelipe Balbi 			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
44532a4a135SFelipe Balbi 		else
4464878a028SSebastian Andrzej Siewior 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
4474878a028SSebastian Andrzej Siewior 		break;
4480ffcaf37SFelipe Balbi 	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
4490ffcaf37SFelipe Balbi 		/* enable hibernation here */
4500ffcaf37SFelipe Balbi 		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
4510ffcaf37SFelipe Balbi 		break;
4524878a028SSebastian Andrzej Siewior 	default:
4534878a028SSebastian Andrzej Siewior 		dev_dbg(dwc->dev, "No power optimization available\n");
4544878a028SSebastian Andrzej Siewior 	}
4554878a028SSebastian Andrzej Siewior 
4564878a028SSebastian Andrzej Siewior 	/*
4574878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
4581d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
4594878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
4601d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
4614878a028SSebastian Andrzej Siewior 	 */
4624878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
4634878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
4644878a028SSebastian Andrzej Siewior 
465789451f6SFelipe Balbi 	dwc3_core_num_eps(dwc);
466789451f6SFelipe Balbi 
4674878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
4684878a028SSebastian Andrzej Siewior 
4690ffcaf37SFelipe Balbi 	ret = dwc3_alloc_scratch_buffers(dwc);
4700ffcaf37SFelipe Balbi 	if (ret)
4710ffcaf37SFelipe Balbi 		goto err1;
4720ffcaf37SFelipe Balbi 
4730ffcaf37SFelipe Balbi 	ret = dwc3_setup_scratch_buffers(dwc);
4740ffcaf37SFelipe Balbi 	if (ret)
4750ffcaf37SFelipe Balbi 		goto err2;
4760ffcaf37SFelipe Balbi 
47772246da4SFelipe Balbi 	return 0;
47872246da4SFelipe Balbi 
4790ffcaf37SFelipe Balbi err2:
4800ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
4810ffcaf37SFelipe Balbi 
4820ffcaf37SFelipe Balbi err1:
4830ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
4840ffcaf37SFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
48557303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
48657303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
4870ffcaf37SFelipe Balbi 
48872246da4SFelipe Balbi err0:
48972246da4SFelipe Balbi 	return ret;
49072246da4SFelipe Balbi }
49172246da4SFelipe Balbi 
49272246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
49372246da4SFelipe Balbi {
4940ffcaf37SFelipe Balbi 	dwc3_free_scratch_buffers(dwc);
49501b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
49601b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
49757303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
49857303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
49972246da4SFelipe Balbi }
50072246da4SFelipe Balbi 
5013c9f94acSFelipe Balbi static int dwc3_core_get_phy(struct dwc3 *dwc)
50272246da4SFelipe Balbi {
5033c9f94acSFelipe Balbi 	struct device		*dev = dwc->dev;
504941ea361SFelipe Balbi 	struct device_node	*node = dev->of_node;
5053c9f94acSFelipe Balbi 	int ret;
50672246da4SFelipe Balbi 
5075088b6f5SKishon Vijay Abraham I 	if (node) {
5085088b6f5SKishon Vijay Abraham I 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
5095088b6f5SKishon Vijay Abraham I 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
510bb674907SFelipe Balbi 	} else {
511bb674907SFelipe Balbi 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
512bb674907SFelipe Balbi 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
5135088b6f5SKishon Vijay Abraham I 	}
5145088b6f5SKishon Vijay Abraham I 
515d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb2_phy)) {
516d105e7f8SFelipe Balbi 		ret = PTR_ERR(dwc->usb2_phy);
517122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
518122f06e6SKishon Vijay Abraham I 			dwc->usb2_phy = NULL;
519122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
520d105e7f8SFelipe Balbi 			return ret;
521122f06e6SKishon Vijay Abraham I 		} else {
52251e1e7bcSFelipe Balbi 			dev_err(dev, "no usb2 phy configured\n");
523122f06e6SKishon Vijay Abraham I 			return ret;
524122f06e6SKishon Vijay Abraham I 		}
52551e1e7bcSFelipe Balbi 	}
52651e1e7bcSFelipe Balbi 
527d105e7f8SFelipe Balbi 	if (IS_ERR(dwc->usb3_phy)) {
528315955d7SRuchika Kharwar 		ret = PTR_ERR(dwc->usb3_phy);
529122f06e6SKishon Vijay Abraham I 		if (ret == -ENXIO || ret == -ENODEV) {
530122f06e6SKishon Vijay Abraham I 			dwc->usb3_phy = NULL;
531122f06e6SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
532d105e7f8SFelipe Balbi 			return ret;
533122f06e6SKishon Vijay Abraham I 		} else {
53451e1e7bcSFelipe Balbi 			dev_err(dev, "no usb3 phy configured\n");
535122f06e6SKishon Vijay Abraham I 			return ret;
536122f06e6SKishon Vijay Abraham I 		}
53751e1e7bcSFelipe Balbi 	}
53851e1e7bcSFelipe Balbi 
53957303488SKishon Vijay Abraham I 	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
54057303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb2_generic_phy)) {
54157303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb2_generic_phy);
54257303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
54357303488SKishon Vijay Abraham I 			dwc->usb2_generic_phy = NULL;
54457303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
54557303488SKishon Vijay Abraham I 			return ret;
54657303488SKishon Vijay Abraham I 		} else {
54757303488SKishon Vijay Abraham I 			dev_err(dev, "no usb2 phy configured\n");
54857303488SKishon Vijay Abraham I 			return ret;
54957303488SKishon Vijay Abraham I 		}
55057303488SKishon Vijay Abraham I 	}
55157303488SKishon Vijay Abraham I 
55257303488SKishon Vijay Abraham I 	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
55357303488SKishon Vijay Abraham I 	if (IS_ERR(dwc->usb3_generic_phy)) {
55457303488SKishon Vijay Abraham I 		ret = PTR_ERR(dwc->usb3_generic_phy);
55557303488SKishon Vijay Abraham I 		if (ret == -ENOSYS || ret == -ENODEV) {
55657303488SKishon Vijay Abraham I 			dwc->usb3_generic_phy = NULL;
55757303488SKishon Vijay Abraham I 		} else if (ret == -EPROBE_DEFER) {
55857303488SKishon Vijay Abraham I 			return ret;
55957303488SKishon Vijay Abraham I 		} else {
56057303488SKishon Vijay Abraham I 			dev_err(dev, "no usb3 phy configured\n");
56157303488SKishon Vijay Abraham I 			return ret;
56257303488SKishon Vijay Abraham I 		}
56357303488SKishon Vijay Abraham I 	}
56457303488SKishon Vijay Abraham I 
5653c9f94acSFelipe Balbi 	return 0;
5663c9f94acSFelipe Balbi }
5673c9f94acSFelipe Balbi 
5685f94adfeSFelipe Balbi static int dwc3_core_init_mode(struct dwc3 *dwc)
5695f94adfeSFelipe Balbi {
5705f94adfeSFelipe Balbi 	struct device *dev = dwc->dev;
5715f94adfeSFelipe Balbi 	int ret;
5725f94adfeSFelipe Balbi 
5735f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
5745f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
5755f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
5765f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
5775f94adfeSFelipe Balbi 		if (ret) {
5785f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
5795f94adfeSFelipe Balbi 			return ret;
5805f94adfeSFelipe Balbi 		}
5815f94adfeSFelipe Balbi 		break;
5825f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
5835f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
5845f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
5855f94adfeSFelipe Balbi 		if (ret) {
5865f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
5875f94adfeSFelipe Balbi 			return ret;
5885f94adfeSFelipe Balbi 		}
5895f94adfeSFelipe Balbi 		break;
5905f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
5915f94adfeSFelipe Balbi 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
5925f94adfeSFelipe Balbi 		ret = dwc3_host_init(dwc);
5935f94adfeSFelipe Balbi 		if (ret) {
5945f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize host\n");
5955f94adfeSFelipe Balbi 			return ret;
5965f94adfeSFelipe Balbi 		}
5975f94adfeSFelipe Balbi 
5985f94adfeSFelipe Balbi 		ret = dwc3_gadget_init(dwc);
5995f94adfeSFelipe Balbi 		if (ret) {
6005f94adfeSFelipe Balbi 			dev_err(dev, "failed to initialize gadget\n");
6015f94adfeSFelipe Balbi 			return ret;
6025f94adfeSFelipe Balbi 		}
6035f94adfeSFelipe Balbi 		break;
6045f94adfeSFelipe Balbi 	default:
6055f94adfeSFelipe Balbi 		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
6065f94adfeSFelipe Balbi 		return -EINVAL;
6075f94adfeSFelipe Balbi 	}
6085f94adfeSFelipe Balbi 
6095f94adfeSFelipe Balbi 	return 0;
6105f94adfeSFelipe Balbi }
6115f94adfeSFelipe Balbi 
6125f94adfeSFelipe Balbi static void dwc3_core_exit_mode(struct dwc3 *dwc)
6135f94adfeSFelipe Balbi {
6145f94adfeSFelipe Balbi 	switch (dwc->dr_mode) {
6155f94adfeSFelipe Balbi 	case USB_DR_MODE_PERIPHERAL:
6165f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
6175f94adfeSFelipe Balbi 		break;
6185f94adfeSFelipe Balbi 	case USB_DR_MODE_HOST:
6195f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
6205f94adfeSFelipe Balbi 		break;
6215f94adfeSFelipe Balbi 	case USB_DR_MODE_OTG:
6225f94adfeSFelipe Balbi 		dwc3_host_exit(dwc);
6235f94adfeSFelipe Balbi 		dwc3_gadget_exit(dwc);
6245f94adfeSFelipe Balbi 		break;
6255f94adfeSFelipe Balbi 	default:
6265f94adfeSFelipe Balbi 		/* do nothing */
6275f94adfeSFelipe Balbi 		break;
6285f94adfeSFelipe Balbi 	}
6295f94adfeSFelipe Balbi }
6305f94adfeSFelipe Balbi 
6313c9f94acSFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
6323c9f94acSFelipe Balbi 
6333c9f94acSFelipe Balbi static int dwc3_probe(struct platform_device *pdev)
6343c9f94acSFelipe Balbi {
6353c9f94acSFelipe Balbi 	struct device		*dev = &pdev->dev;
6363c9f94acSFelipe Balbi 	struct dwc3_platform_data *pdata = dev_get_platdata(dev);
6373c9f94acSFelipe Balbi 	struct device_node	*node = dev->of_node;
6383c9f94acSFelipe Balbi 	struct resource		*res;
6393c9f94acSFelipe Balbi 	struct dwc3		*dwc;
6403c9f94acSFelipe Balbi 
641b09e99eeSAndy Shevchenko 	int			ret;
6423c9f94acSFelipe Balbi 
6433c9f94acSFelipe Balbi 	void __iomem		*regs;
6443c9f94acSFelipe Balbi 	void			*mem;
6453c9f94acSFelipe Balbi 
6463c9f94acSFelipe Balbi 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
647734d5a53SJingoo Han 	if (!mem)
6483c9f94acSFelipe Balbi 		return -ENOMEM;
649734d5a53SJingoo Han 
6503c9f94acSFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
6513c9f94acSFelipe Balbi 	dwc->mem = mem;
6523c9f94acSFelipe Balbi 	dwc->dev = dev;
6533c9f94acSFelipe Balbi 
6543c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
6553c9f94acSFelipe Balbi 	if (!res) {
6563c9f94acSFelipe Balbi 		dev_err(dev, "missing IRQ\n");
6573c9f94acSFelipe Balbi 		return -ENODEV;
6583c9f94acSFelipe Balbi 	}
6593c9f94acSFelipe Balbi 	dwc->xhci_resources[1].start = res->start;
6603c9f94acSFelipe Balbi 	dwc->xhci_resources[1].end = res->end;
6613c9f94acSFelipe Balbi 	dwc->xhci_resources[1].flags = res->flags;
6623c9f94acSFelipe Balbi 	dwc->xhci_resources[1].name = res->name;
6633c9f94acSFelipe Balbi 
6643c9f94acSFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6653c9f94acSFelipe Balbi 	if (!res) {
6663c9f94acSFelipe Balbi 		dev_err(dev, "missing memory resource\n");
6673c9f94acSFelipe Balbi 		return -ENODEV;
6683c9f94acSFelipe Balbi 	}
6693c9f94acSFelipe Balbi 
670f32a5e23SVivek Gautam 	dwc->xhci_resources[0].start = res->start;
671f32a5e23SVivek Gautam 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
672f32a5e23SVivek Gautam 					DWC3_XHCI_REGS_END;
673f32a5e23SVivek Gautam 	dwc->xhci_resources[0].flags = res->flags;
674f32a5e23SVivek Gautam 	dwc->xhci_resources[0].name = res->name;
675f32a5e23SVivek Gautam 
676f32a5e23SVivek Gautam 	res->start += DWC3_GLOBALS_REGS_START;
677f32a5e23SVivek Gautam 
678f32a5e23SVivek Gautam 	/*
679f32a5e23SVivek Gautam 	 * Request memory region but exclude xHCI regs,
680f32a5e23SVivek Gautam 	 * since it will be requested by the xhci-plat driver.
681f32a5e23SVivek Gautam 	 */
682f32a5e23SVivek Gautam 	regs = devm_ioremap_resource(dev, res);
683f32a5e23SVivek Gautam 	if (IS_ERR(regs))
684f32a5e23SVivek Gautam 		return PTR_ERR(regs);
685f32a5e23SVivek Gautam 
686f32a5e23SVivek Gautam 	dwc->regs	= regs;
687f32a5e23SVivek Gautam 	dwc->regs_size	= resource_size(res);
688f32a5e23SVivek Gautam 	/*
689f32a5e23SVivek Gautam 	 * restore res->start back to its original value so that,
690f32a5e23SVivek Gautam 	 * in case the probe is deferred, we don't end up getting error in
691f32a5e23SVivek Gautam 	 * request the memory region the next time probe is called.
692f32a5e23SVivek Gautam 	 */
693f32a5e23SVivek Gautam 	res->start -= DWC3_GLOBALS_REGS_START;
694f32a5e23SVivek Gautam 
6953c9f94acSFelipe Balbi 	if (node) {
6963c9f94acSFelipe Balbi 		dwc->maximum_speed = of_usb_get_maximum_speed(node);
6973c9f94acSFelipe Balbi 
6983c9f94acSFelipe Balbi 		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
6993c9f94acSFelipe Balbi 		dwc->dr_mode = of_usb_get_dr_mode(node);
7003c9f94acSFelipe Balbi 	} else if (pdata) {
7013c9f94acSFelipe Balbi 		dwc->maximum_speed = pdata->maximum_speed;
7023c9f94acSFelipe Balbi 
7033c9f94acSFelipe Balbi 		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
7043c9f94acSFelipe Balbi 		dwc->dr_mode = pdata->dr_mode;
7053c9f94acSFelipe Balbi 	}
7063c9f94acSFelipe Balbi 
7073c9f94acSFelipe Balbi 	/* default to superspeed if no maximum_speed passed */
7083c9f94acSFelipe Balbi 	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
7093c9f94acSFelipe Balbi 		dwc->maximum_speed = USB_SPEED_SUPER;
7103c9f94acSFelipe Balbi 
7113c9f94acSFelipe Balbi 	ret = dwc3_core_get_phy(dwc);
7123c9f94acSFelipe Balbi 	if (ret)
7133c9f94acSFelipe Balbi 		return ret;
7143c9f94acSFelipe Balbi 
71572246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
71672246da4SFelipe Balbi 	platform_set_drvdata(pdev, dwc);
71772246da4SFelipe Balbi 
718*19bacdc9SHeikki Krogerus 	if (!dev->dma_mask) {
719ddff14f1SKishon Vijay Abraham I 		dev->dma_mask = dev->parent->dma_mask;
720ddff14f1SKishon Vijay Abraham I 		dev->dma_parms = dev->parent->dma_parms;
721ddff14f1SKishon Vijay Abraham I 		dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
722*19bacdc9SHeikki Krogerus 	}
723ddff14f1SKishon Vijay Abraham I 
724802ca850SChanho Park 	pm_runtime_enable(dev);
725802ca850SChanho Park 	pm_runtime_get_sync(dev);
726802ca850SChanho Park 	pm_runtime_forbid(dev);
72772246da4SFelipe Balbi 
7284fd24483SKishon Vijay Abraham I 	dwc3_cache_hwparams(dwc);
7294fd24483SKishon Vijay Abraham I 
7303921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
7313921426bSFelipe Balbi 	if (ret) {
7323921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
7333921426bSFelipe Balbi 		ret = -ENOMEM;
7343921426bSFelipe Balbi 		goto err0;
7353921426bSFelipe Balbi 	}
7363921426bSFelipe Balbi 
73732a4a135SFelipe Balbi 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
73832a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_HOST;
73932a4a135SFelipe Balbi 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
74032a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
74132a4a135SFelipe Balbi 
74232a4a135SFelipe Balbi 	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
74332a4a135SFelipe Balbi 		dwc->dr_mode = USB_DR_MODE_OTG;
74432a4a135SFelipe Balbi 
74572246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
74672246da4SFelipe Balbi 	if (ret) {
747802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
7483921426bSFelipe Balbi 		goto err0;
74972246da4SFelipe Balbi 	}
75072246da4SFelipe Balbi 
7513088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
7523088f108SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
75357303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb2_generic_phy);
75457303488SKishon Vijay Abraham I 	if (ret < 0)
75557303488SKishon Vijay Abraham I 		goto err1;
75657303488SKishon Vijay Abraham I 
75757303488SKishon Vijay Abraham I 	ret = phy_power_on(dwc->usb3_generic_phy);
75857303488SKishon Vijay Abraham I 	if (ret < 0)
75957303488SKishon Vijay Abraham I 		goto err_usb2phy_power;
7603088f108SKishon Vijay Abraham I 
761f122d33eSFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
762f122d33eSFelipe Balbi 	if (ret) {
763f122d33eSFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
76457303488SKishon Vijay Abraham I 		goto err_usb3phy_power;
765f122d33eSFelipe Balbi 	}
766f122d33eSFelipe Balbi 
7675f94adfeSFelipe Balbi 	ret = dwc3_core_init_mode(dwc);
7685f94adfeSFelipe Balbi 	if (ret)
769f122d33eSFelipe Balbi 		goto err2;
77072246da4SFelipe Balbi 
77172246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
77272246da4SFelipe Balbi 	if (ret) {
773802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
774f122d33eSFelipe Balbi 		goto err3;
77572246da4SFelipe Balbi 	}
77672246da4SFelipe Balbi 
777802ca850SChanho Park 	pm_runtime_allow(dev);
77872246da4SFelipe Balbi 
77972246da4SFelipe Balbi 	return 0;
78072246da4SFelipe Balbi 
781f122d33eSFelipe Balbi err3:
7825f94adfeSFelipe Balbi 	dwc3_core_exit_mode(dwc);
78372246da4SFelipe Balbi 
784f122d33eSFelipe Balbi err2:
785f122d33eSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
786f122d33eSFelipe Balbi 
78757303488SKishon Vijay Abraham I err_usb3phy_power:
78857303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
78957303488SKishon Vijay Abraham I 
79057303488SKishon Vijay Abraham I err_usb2phy_power:
79157303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
79257303488SKishon Vijay Abraham I 
793802ca850SChanho Park err1:
794501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
795501fae51SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
79672246da4SFelipe Balbi 	dwc3_core_exit(dwc);
79772246da4SFelipe Balbi 
7983921426bSFelipe Balbi err0:
7993921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
8003921426bSFelipe Balbi 
80172246da4SFelipe Balbi 	return ret;
80272246da4SFelipe Balbi }
80372246da4SFelipe Balbi 
804fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
80572246da4SFelipe Balbi {
80672246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
80772246da4SFelipe Balbi 
808dc99f16fSFelipe Balbi 	dwc3_debugfs_exit(dwc);
809dc99f16fSFelipe Balbi 	dwc3_core_exit_mode(dwc);
810dc99f16fSFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
811dc99f16fSFelipe Balbi 	dwc3_free_event_buffers(dwc);
812dc99f16fSFelipe Balbi 
8138ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
8148ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
81557303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb2_generic_phy);
81657303488SKishon Vijay Abraham I 	phy_power_off(dwc->usb3_generic_phy);
8178ba007a9SKishon Vijay Abraham I 
81872246da4SFelipe Balbi 	dwc3_core_exit(dwc);
81972246da4SFelipe Balbi 
8207415f17cSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
8217415f17cSFelipe Balbi 	pm_runtime_disable(&pdev->dev);
8227415f17cSFelipe Balbi 
82372246da4SFelipe Balbi 	return 0;
82472246da4SFelipe Balbi }
82572246da4SFelipe Balbi 
8267415f17cSFelipe Balbi #ifdef CONFIG_PM_SLEEP
8277415f17cSFelipe Balbi static int dwc3_prepare(struct device *dev)
8287415f17cSFelipe Balbi {
8297415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
8307415f17cSFelipe Balbi 	unsigned long	flags;
8317415f17cSFelipe Balbi 
8327415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
8337415f17cSFelipe Balbi 
834a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
835a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
836a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
8377415f17cSFelipe Balbi 		dwc3_gadget_prepare(dwc);
8387415f17cSFelipe Balbi 		/* FALLTHROUGH */
839a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
8407415f17cSFelipe Balbi 	default:
8417415f17cSFelipe Balbi 		dwc3_event_buffers_cleanup(dwc);
8427415f17cSFelipe Balbi 		break;
8437415f17cSFelipe Balbi 	}
8447415f17cSFelipe Balbi 
8457415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
8467415f17cSFelipe Balbi 
8477415f17cSFelipe Balbi 	return 0;
8487415f17cSFelipe Balbi }
8497415f17cSFelipe Balbi 
8507415f17cSFelipe Balbi static void dwc3_complete(struct device *dev)
8517415f17cSFelipe Balbi {
8527415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
8537415f17cSFelipe Balbi 	unsigned long	flags;
8547415f17cSFelipe Balbi 
8557415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
8567415f17cSFelipe Balbi 
857f45e5f00SRoger Quadros 	dwc3_event_buffers_setup(dwc);
858a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
859a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
860a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
8617415f17cSFelipe Balbi 		dwc3_gadget_complete(dwc);
8627415f17cSFelipe Balbi 		/* FALLTHROUGH */
863a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
8647415f17cSFelipe Balbi 	default:
8657415f17cSFelipe Balbi 		break;
8667415f17cSFelipe Balbi 	}
8677415f17cSFelipe Balbi 
8687415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
8697415f17cSFelipe Balbi }
8707415f17cSFelipe Balbi 
8717415f17cSFelipe Balbi static int dwc3_suspend(struct device *dev)
8727415f17cSFelipe Balbi {
8737415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
8747415f17cSFelipe Balbi 	unsigned long	flags;
8757415f17cSFelipe Balbi 
8767415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
8777415f17cSFelipe Balbi 
878a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
879a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
880a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
8817415f17cSFelipe Balbi 		dwc3_gadget_suspend(dwc);
8827415f17cSFelipe Balbi 		/* FALLTHROUGH */
883a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
8847415f17cSFelipe Balbi 	default:
8857415f17cSFelipe Balbi 		/* do nothing */
8867415f17cSFelipe Balbi 		break;
8877415f17cSFelipe Balbi 	}
8887415f17cSFelipe Balbi 
8897415f17cSFelipe Balbi 	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
8907415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
8917415f17cSFelipe Balbi 
8927415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb3_phy);
8937415f17cSFelipe Balbi 	usb_phy_shutdown(dwc->usb2_phy);
89457303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
89557303488SKishon Vijay Abraham I 	phy_exit(dwc->usb3_generic_phy);
8967415f17cSFelipe Balbi 
8977415f17cSFelipe Balbi 	return 0;
8987415f17cSFelipe Balbi }
8997415f17cSFelipe Balbi 
9007415f17cSFelipe Balbi static int dwc3_resume(struct device *dev)
9017415f17cSFelipe Balbi {
9027415f17cSFelipe Balbi 	struct dwc3	*dwc = dev_get_drvdata(dev);
9037415f17cSFelipe Balbi 	unsigned long	flags;
90457303488SKishon Vijay Abraham I 	int		ret;
9057415f17cSFelipe Balbi 
9067415f17cSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
9077415f17cSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
90857303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb2_generic_phy);
90957303488SKishon Vijay Abraham I 	if (ret < 0)
91057303488SKishon Vijay Abraham I 		return ret;
91157303488SKishon Vijay Abraham I 
91257303488SKishon Vijay Abraham I 	ret = phy_init(dwc->usb3_generic_phy);
91357303488SKishon Vijay Abraham I 	if (ret < 0)
91457303488SKishon Vijay Abraham I 		goto err_usb2phy_init;
9157415f17cSFelipe Balbi 
9167415f17cSFelipe Balbi 	spin_lock_irqsave(&dwc->lock, flags);
9177415f17cSFelipe Balbi 
9187415f17cSFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
9197415f17cSFelipe Balbi 
920a45c82b8SRuchika Kharwar 	switch (dwc->dr_mode) {
921a45c82b8SRuchika Kharwar 	case USB_DR_MODE_PERIPHERAL:
922a45c82b8SRuchika Kharwar 	case USB_DR_MODE_OTG:
9237415f17cSFelipe Balbi 		dwc3_gadget_resume(dwc);
9247415f17cSFelipe Balbi 		/* FALLTHROUGH */
925a45c82b8SRuchika Kharwar 	case USB_DR_MODE_HOST:
9267415f17cSFelipe Balbi 	default:
9277415f17cSFelipe Balbi 		/* do nothing */
9287415f17cSFelipe Balbi 		break;
9297415f17cSFelipe Balbi 	}
9307415f17cSFelipe Balbi 
9317415f17cSFelipe Balbi 	spin_unlock_irqrestore(&dwc->lock, flags);
9327415f17cSFelipe Balbi 
9337415f17cSFelipe Balbi 	pm_runtime_disable(dev);
9347415f17cSFelipe Balbi 	pm_runtime_set_active(dev);
9357415f17cSFelipe Balbi 	pm_runtime_enable(dev);
9367415f17cSFelipe Balbi 
9377415f17cSFelipe Balbi 	return 0;
93857303488SKishon Vijay Abraham I 
93957303488SKishon Vijay Abraham I err_usb2phy_init:
94057303488SKishon Vijay Abraham I 	phy_exit(dwc->usb2_generic_phy);
94157303488SKishon Vijay Abraham I 
94257303488SKishon Vijay Abraham I 	return ret;
9437415f17cSFelipe Balbi }
9447415f17cSFelipe Balbi 
9457415f17cSFelipe Balbi static const struct dev_pm_ops dwc3_dev_pm_ops = {
9467415f17cSFelipe Balbi 	.prepare	= dwc3_prepare,
9477415f17cSFelipe Balbi 	.complete	= dwc3_complete,
9487415f17cSFelipe Balbi 
9497415f17cSFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
9507415f17cSFelipe Balbi };
9517415f17cSFelipe Balbi 
9527415f17cSFelipe Balbi #define DWC3_PM_OPS	&(dwc3_dev_pm_ops)
9537415f17cSFelipe Balbi #else
9547415f17cSFelipe Balbi #define DWC3_PM_OPS	NULL
9557415f17cSFelipe Balbi #endif
9567415f17cSFelipe Balbi 
9575088b6f5SKishon Vijay Abraham I #ifdef CONFIG_OF
9585088b6f5SKishon Vijay Abraham I static const struct of_device_id of_dwc3_match[] = {
9595088b6f5SKishon Vijay Abraham I 	{
96022a5aa17SFelipe Balbi 		.compatible = "snps,dwc3"
96122a5aa17SFelipe Balbi 	},
96222a5aa17SFelipe Balbi 	{
9635088b6f5SKishon Vijay Abraham I 		.compatible = "synopsys,dwc3"
9645088b6f5SKishon Vijay Abraham I 	},
9655088b6f5SKishon Vijay Abraham I 	{ },
9665088b6f5SKishon Vijay Abraham I };
9675088b6f5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, of_dwc3_match);
9685088b6f5SKishon Vijay Abraham I #endif
9695088b6f5SKishon Vijay Abraham I 
97072246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
97172246da4SFelipe Balbi 	.probe		= dwc3_probe,
9727690417dSBill Pemberton 	.remove		= dwc3_remove,
97372246da4SFelipe Balbi 	.driver		= {
97472246da4SFelipe Balbi 		.name	= "dwc3",
9755088b6f5SKishon Vijay Abraham I 		.of_match_table	= of_match_ptr(of_dwc3_match),
9767415f17cSFelipe Balbi 		.pm	= DWC3_PM_OPS,
97772246da4SFelipe Balbi 	},
97872246da4SFelipe Balbi };
97972246da4SFelipe Balbi 
980b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
981b1116dccSTobias Klauser 
9827ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
98372246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
9845945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
98572246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
986