xref: /openbmc/linux/drivers/usb/dwc3/core.c (revision 8ba007a9)
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  *
972246da4SFelipe Balbi  * Redistribution and use in source and binary forms, with or without
1072246da4SFelipe Balbi  * modification, are permitted provided that the following conditions
1172246da4SFelipe Balbi  * are met:
1272246da4SFelipe Balbi  * 1. Redistributions of source code must retain the above copyright
1372246da4SFelipe Balbi  *    notice, this list of conditions, and the following disclaimer,
1472246da4SFelipe Balbi  *    without modification.
1572246da4SFelipe Balbi  * 2. Redistributions in binary form must reproduce the above copyright
1672246da4SFelipe Balbi  *    notice, this list of conditions and the following disclaimer in the
1772246da4SFelipe Balbi  *    documentation and/or other materials provided with the distribution.
1872246da4SFelipe Balbi  * 3. The names of the above-listed copyright holders may not be used
1972246da4SFelipe Balbi  *    to endorse or promote products derived from this software without
2072246da4SFelipe Balbi  *    specific prior written permission.
2172246da4SFelipe Balbi  *
2272246da4SFelipe Balbi  * ALTERNATIVELY, this software may be distributed under the terms of the
2372246da4SFelipe Balbi  * GNU General Public License ("GPL") version 2, as published by the Free
2472246da4SFelipe Balbi  * Software Foundation.
2572246da4SFelipe Balbi  *
2672246da4SFelipe Balbi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2772246da4SFelipe Balbi  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2872246da4SFelipe Balbi  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2972246da4SFelipe Balbi  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
3072246da4SFelipe Balbi  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
3172246da4SFelipe Balbi  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3272246da4SFelipe Balbi  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3372246da4SFelipe Balbi  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3472246da4SFelipe Balbi  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3572246da4SFelipe Balbi  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3672246da4SFelipe Balbi  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3772246da4SFelipe Balbi  */
3872246da4SFelipe Balbi 
39a72e658bSFelipe Balbi #include <linux/module.h>
4072246da4SFelipe Balbi #include <linux/kernel.h>
4172246da4SFelipe Balbi #include <linux/slab.h>
4272246da4SFelipe Balbi #include <linux/spinlock.h>
4372246da4SFelipe Balbi #include <linux/platform_device.h>
4472246da4SFelipe Balbi #include <linux/pm_runtime.h>
4572246da4SFelipe Balbi #include <linux/interrupt.h>
4672246da4SFelipe Balbi #include <linux/ioport.h>
4772246da4SFelipe Balbi #include <linux/io.h>
4872246da4SFelipe Balbi #include <linux/list.h>
4972246da4SFelipe Balbi #include <linux/delay.h>
5072246da4SFelipe Balbi #include <linux/dma-mapping.h>
51457e84b6SFelipe Balbi #include <linux/of.h>
5272246da4SFelipe Balbi 
5351e1e7bcSFelipe Balbi #include <linux/usb/otg.h>
5472246da4SFelipe Balbi #include <linux/usb/ch9.h>
5572246da4SFelipe Balbi #include <linux/usb/gadget.h>
5672246da4SFelipe Balbi 
5772246da4SFelipe Balbi #include "core.h"
5872246da4SFelipe Balbi #include "gadget.h"
5972246da4SFelipe Balbi #include "io.h"
6072246da4SFelipe Balbi 
6172246da4SFelipe Balbi #include "debug.h"
6272246da4SFelipe Balbi 
636c167fc9SFelipe Balbi static char *maximum_speed = "super";
646c167fc9SFelipe Balbi module_param(maximum_speed, charp, 0);
656c167fc9SFelipe Balbi MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
666c167fc9SFelipe Balbi 
678300dd23SFelipe Balbi /* -------------------------------------------------------------------------- */
688300dd23SFelipe Balbi 
693140e8cbSSebastian Andrzej Siewior void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
703140e8cbSSebastian Andrzej Siewior {
713140e8cbSSebastian Andrzej Siewior 	u32 reg;
723140e8cbSSebastian Andrzej Siewior 
733140e8cbSSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
743140e8cbSSebastian Andrzej Siewior 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
753140e8cbSSebastian Andrzej Siewior 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
763140e8cbSSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
773140e8cbSSebastian Andrzej Siewior }
788300dd23SFelipe Balbi 
7972246da4SFelipe Balbi /**
8072246da4SFelipe Balbi  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
8172246da4SFelipe Balbi  * @dwc: pointer to our context structure
8272246da4SFelipe Balbi  */
8372246da4SFelipe Balbi static void dwc3_core_soft_reset(struct dwc3 *dwc)
8472246da4SFelipe Balbi {
8572246da4SFelipe Balbi 	u32		reg;
8672246da4SFelipe Balbi 
8772246da4SFelipe Balbi 	/* Before Resetting PHY, put Core in Reset */
8872246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
8972246da4SFelipe Balbi 	reg |= DWC3_GCTL_CORESOFTRESET;
9072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
9172246da4SFelipe Balbi 
9272246da4SFelipe Balbi 	/* Assert USB3 PHY reset */
9372246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
9472246da4SFelipe Balbi 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
9572246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
9672246da4SFelipe Balbi 
9772246da4SFelipe Balbi 	/* Assert USB2 PHY reset */
9872246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
9972246da4SFelipe Balbi 	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
10072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
10172246da4SFelipe Balbi 
10251e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb2_phy);
10351e1e7bcSFelipe Balbi 	usb_phy_init(dwc->usb3_phy);
10472246da4SFelipe Balbi 	mdelay(100);
10572246da4SFelipe Balbi 
10672246da4SFelipe Balbi 	/* Clear USB3 PHY reset */
10772246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
10872246da4SFelipe Balbi 	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
10972246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
11072246da4SFelipe Balbi 
11172246da4SFelipe Balbi 	/* Clear USB2 PHY reset */
11272246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
11372246da4SFelipe Balbi 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
11472246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
11572246da4SFelipe Balbi 
11645627ac6SPratyush Anand 	mdelay(100);
11745627ac6SPratyush Anand 
11872246da4SFelipe Balbi 	/* After PHYs are stable we can take Core out of reset state */
11972246da4SFelipe Balbi 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
12072246da4SFelipe Balbi 	reg &= ~DWC3_GCTL_CORESOFTRESET;
12172246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
12272246da4SFelipe Balbi }
12372246da4SFelipe Balbi 
12472246da4SFelipe Balbi /**
12572246da4SFelipe Balbi  * dwc3_free_one_event_buffer - Frees one event buffer
12672246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
12772246da4SFelipe Balbi  * @evt: Pointer to event buffer to be freed
12872246da4SFelipe Balbi  */
12972246da4SFelipe Balbi static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
13072246da4SFelipe Balbi 		struct dwc3_event_buffer *evt)
13172246da4SFelipe Balbi {
13272246da4SFelipe Balbi 	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
13372246da4SFelipe Balbi }
13472246da4SFelipe Balbi 
13572246da4SFelipe Balbi /**
1361d046793SPaul Zimmerman  * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
13772246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
13872246da4SFelipe Balbi  * @length: size of the event buffer
13972246da4SFelipe Balbi  *
1401d046793SPaul Zimmerman  * Returns a pointer to the allocated event buffer structure on success
14172246da4SFelipe Balbi  * otherwise ERR_PTR(errno).
14272246da4SFelipe Balbi  */
14341ac7b3aSBill Pemberton static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
14472246da4SFelipe Balbi {
14572246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
14672246da4SFelipe Balbi 
147380f0d28SFelipe Balbi 	evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
14872246da4SFelipe Balbi 	if (!evt)
14972246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
15072246da4SFelipe Balbi 
15172246da4SFelipe Balbi 	evt->dwc	= dwc;
15272246da4SFelipe Balbi 	evt->length	= length;
15372246da4SFelipe Balbi 	evt->buf	= dma_alloc_coherent(dwc->dev, length,
15472246da4SFelipe Balbi 			&evt->dma, GFP_KERNEL);
155e32672f0SFelipe Balbi 	if (!evt->buf)
15672246da4SFelipe Balbi 		return ERR_PTR(-ENOMEM);
15772246da4SFelipe Balbi 
15872246da4SFelipe Balbi 	return evt;
15972246da4SFelipe Balbi }
16072246da4SFelipe Balbi 
16172246da4SFelipe Balbi /**
16272246da4SFelipe Balbi  * dwc3_free_event_buffers - frees all allocated event buffers
16372246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
16472246da4SFelipe Balbi  */
16572246da4SFelipe Balbi static void dwc3_free_event_buffers(struct dwc3 *dwc)
16672246da4SFelipe Balbi {
16772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
16872246da4SFelipe Balbi 	int i;
16972246da4SFelipe Balbi 
1709f622b2aSFelipe Balbi 	for (i = 0; i < dwc->num_event_buffers; i++) {
17172246da4SFelipe Balbi 		evt = dwc->ev_buffs[i];
17264b6c8a7SAnton Tikhomirov 		if (evt)
17372246da4SFelipe Balbi 			dwc3_free_one_event_buffer(dwc, evt);
17472246da4SFelipe Balbi 	}
17572246da4SFelipe Balbi }
17672246da4SFelipe Balbi 
17772246da4SFelipe Balbi /**
17872246da4SFelipe Balbi  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
1791d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
18072246da4SFelipe Balbi  * @length: size of event buffer
18172246da4SFelipe Balbi  *
1821d046793SPaul Zimmerman  * Returns 0 on success otherwise negative errno. In the error case, dwc
18372246da4SFelipe Balbi  * may contain some buffers allocated but not all which were requested.
18472246da4SFelipe Balbi  */
18541ac7b3aSBill Pemberton static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
18672246da4SFelipe Balbi {
1879f622b2aSFelipe Balbi 	int			num;
18872246da4SFelipe Balbi 	int			i;
18972246da4SFelipe Balbi 
1909f622b2aSFelipe Balbi 	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
1919f622b2aSFelipe Balbi 	dwc->num_event_buffers = num;
1929f622b2aSFelipe Balbi 
193380f0d28SFelipe Balbi 	dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
194380f0d28SFelipe Balbi 			GFP_KERNEL);
195457d3f21SFelipe Balbi 	if (!dwc->ev_buffs) {
196457d3f21SFelipe Balbi 		dev_err(dwc->dev, "can't allocate event buffers array\n");
197457d3f21SFelipe Balbi 		return -ENOMEM;
198457d3f21SFelipe Balbi 	}
199457d3f21SFelipe Balbi 
20072246da4SFelipe Balbi 	for (i = 0; i < num; i++) {
20172246da4SFelipe Balbi 		struct dwc3_event_buffer	*evt;
20272246da4SFelipe Balbi 
20372246da4SFelipe Balbi 		evt = dwc3_alloc_one_event_buffer(dwc, length);
20472246da4SFelipe Balbi 		if (IS_ERR(evt)) {
20572246da4SFelipe Balbi 			dev_err(dwc->dev, "can't allocate event buffer\n");
20672246da4SFelipe Balbi 			return PTR_ERR(evt);
20772246da4SFelipe Balbi 		}
20872246da4SFelipe Balbi 		dwc->ev_buffs[i] = evt;
20972246da4SFelipe Balbi 	}
21072246da4SFelipe Balbi 
21172246da4SFelipe Balbi 	return 0;
21272246da4SFelipe Balbi }
21372246da4SFelipe Balbi 
21472246da4SFelipe Balbi /**
21572246da4SFelipe Balbi  * dwc3_event_buffers_setup - setup our allocated event buffers
2161d046793SPaul Zimmerman  * @dwc: pointer to our controller context structure
21772246da4SFelipe Balbi  *
21872246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
21972246da4SFelipe Balbi  */
2207acd85e0SPaul Zimmerman static int dwc3_event_buffers_setup(struct dwc3 *dwc)
22172246da4SFelipe Balbi {
22272246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
22372246da4SFelipe Balbi 	int				n;
22472246da4SFelipe Balbi 
2259f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
22672246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
22772246da4SFelipe Balbi 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
22872246da4SFelipe Balbi 				evt->buf, (unsigned long long) evt->dma,
22972246da4SFelipe Balbi 				evt->length);
23072246da4SFelipe Balbi 
2317acd85e0SPaul Zimmerman 		evt->lpos = 0;
2327acd85e0SPaul Zimmerman 
23372246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
23472246da4SFelipe Balbi 				lower_32_bits(evt->dma));
23572246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
23672246da4SFelipe Balbi 				upper_32_bits(evt->dma));
23772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
23872246da4SFelipe Balbi 				evt->length & 0xffff);
23972246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
24072246da4SFelipe Balbi 	}
24172246da4SFelipe Balbi 
24272246da4SFelipe Balbi 	return 0;
24372246da4SFelipe Balbi }
24472246da4SFelipe Balbi 
24572246da4SFelipe Balbi static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
24672246da4SFelipe Balbi {
24772246da4SFelipe Balbi 	struct dwc3_event_buffer	*evt;
24872246da4SFelipe Balbi 	int				n;
24972246da4SFelipe Balbi 
2509f622b2aSFelipe Balbi 	for (n = 0; n < dwc->num_event_buffers; n++) {
25172246da4SFelipe Balbi 		evt = dwc->ev_buffs[n];
2527acd85e0SPaul Zimmerman 
2537acd85e0SPaul Zimmerman 		evt->lpos = 0;
2547acd85e0SPaul Zimmerman 
25572246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
25672246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
25772246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
25872246da4SFelipe Balbi 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
25972246da4SFelipe Balbi 	}
26072246da4SFelipe Balbi }
26172246da4SFelipe Balbi 
26241ac7b3aSBill Pemberton static void dwc3_cache_hwparams(struct dwc3 *dwc)
26326ceca97SFelipe Balbi {
26426ceca97SFelipe Balbi 	struct dwc3_hwparams	*parms = &dwc->hwparams;
26526ceca97SFelipe Balbi 
26626ceca97SFelipe Balbi 	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
26726ceca97SFelipe Balbi 	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
26826ceca97SFelipe Balbi 	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
26926ceca97SFelipe Balbi 	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
27026ceca97SFelipe Balbi 	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
27126ceca97SFelipe Balbi 	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
27226ceca97SFelipe Balbi 	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
27326ceca97SFelipe Balbi 	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
27426ceca97SFelipe Balbi 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
27526ceca97SFelipe Balbi }
27626ceca97SFelipe Balbi 
27772246da4SFelipe Balbi /**
27872246da4SFelipe Balbi  * dwc3_core_init - Low-level initialization of DWC3 Core
27972246da4SFelipe Balbi  * @dwc: Pointer to our controller context structure
28072246da4SFelipe Balbi  *
28172246da4SFelipe Balbi  * Returns 0 on success otherwise negative errno.
28272246da4SFelipe Balbi  */
28341ac7b3aSBill Pemberton static int dwc3_core_init(struct dwc3 *dwc)
28472246da4SFelipe Balbi {
28572246da4SFelipe Balbi 	unsigned long		timeout;
28672246da4SFelipe Balbi 	u32			reg;
28772246da4SFelipe Balbi 	int			ret;
28872246da4SFelipe Balbi 
2897650bd74SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
2907650bd74SSebastian Andrzej Siewior 	/* This should read as U3 followed by revision number */
2917650bd74SSebastian Andrzej Siewior 	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
2927650bd74SSebastian Andrzej Siewior 		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
2937650bd74SSebastian Andrzej Siewior 		ret = -ENODEV;
2947650bd74SSebastian Andrzej Siewior 		goto err0;
2957650bd74SSebastian Andrzej Siewior 	}
296248b122bSFelipe Balbi 	dwc->revision = reg;
2977650bd74SSebastian Andrzej Siewior 
29872246da4SFelipe Balbi 	/* issue device SoftReset too */
29972246da4SFelipe Balbi 	timeout = jiffies + msecs_to_jiffies(500);
30072246da4SFelipe Balbi 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
30172246da4SFelipe Balbi 	do {
30272246da4SFelipe Balbi 		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
30372246da4SFelipe Balbi 		if (!(reg & DWC3_DCTL_CSFTRST))
30472246da4SFelipe Balbi 			break;
30572246da4SFelipe Balbi 
30672246da4SFelipe Balbi 		if (time_after(jiffies, timeout)) {
30772246da4SFelipe Balbi 			dev_err(dwc->dev, "Reset Timed Out\n");
30872246da4SFelipe Balbi 			ret = -ETIMEDOUT;
30972246da4SFelipe Balbi 			goto err0;
31072246da4SFelipe Balbi 		}
31172246da4SFelipe Balbi 
31272246da4SFelipe Balbi 		cpu_relax();
31372246da4SFelipe Balbi 	} while (true);
31472246da4SFelipe Balbi 
31558a0f23fSPratyush Anand 	dwc3_core_soft_reset(dwc);
31658a0f23fSPratyush Anand 
3174878a028SSebastian Andrzej Siewior 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
3183e87c42aSPaul Zimmerman 	reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
3194878a028SSebastian Andrzej Siewior 	reg &= ~DWC3_GCTL_DISSCRAMBLE;
3204878a028SSebastian Andrzej Siewior 
321164d7731SSebastian Andrzej Siewior 	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
3224878a028SSebastian Andrzej Siewior 	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
3234878a028SSebastian Andrzej Siewior 		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
3244878a028SSebastian Andrzej Siewior 		break;
3254878a028SSebastian Andrzej Siewior 	default:
3264878a028SSebastian Andrzej Siewior 		dev_dbg(dwc->dev, "No power optimization available\n");
3274878a028SSebastian Andrzej Siewior 	}
3284878a028SSebastian Andrzej Siewior 
3294878a028SSebastian Andrzej Siewior 	/*
3304878a028SSebastian Andrzej Siewior 	 * WORKAROUND: DWC3 revisions <1.90a have a bug
3311d046793SPaul Zimmerman 	 * where the device can fail to connect at SuperSpeed
3324878a028SSebastian Andrzej Siewior 	 * and falls back to high-speed mode which causes
3331d046793SPaul Zimmerman 	 * the device to enter a Connect/Disconnect loop
3344878a028SSebastian Andrzej Siewior 	 */
3354878a028SSebastian Andrzej Siewior 	if (dwc->revision < DWC3_REVISION_190A)
3364878a028SSebastian Andrzej Siewior 		reg |= DWC3_GCTL_U2RSTECN;
3374878a028SSebastian Andrzej Siewior 
3384878a028SSebastian Andrzej Siewior 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
3394878a028SSebastian Andrzej Siewior 
34072246da4SFelipe Balbi 	ret = dwc3_event_buffers_setup(dwc);
34172246da4SFelipe Balbi 	if (ret) {
34272246da4SFelipe Balbi 		dev_err(dwc->dev, "failed to setup event buffers\n");
3433921426bSFelipe Balbi 		goto err0;
34472246da4SFelipe Balbi 	}
34572246da4SFelipe Balbi 
34672246da4SFelipe Balbi 	return 0;
34772246da4SFelipe Balbi 
34872246da4SFelipe Balbi err0:
34972246da4SFelipe Balbi 	return ret;
35072246da4SFelipe Balbi }
35172246da4SFelipe Balbi 
35272246da4SFelipe Balbi static void dwc3_core_exit(struct dwc3 *dwc)
35372246da4SFelipe Balbi {
35472246da4SFelipe Balbi 	dwc3_event_buffers_cleanup(dwc);
35501b8daf7SVivek Gautam 
35601b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb2_phy);
35701b8daf7SVivek Gautam 	usb_phy_shutdown(dwc->usb3_phy);
35872246da4SFelipe Balbi }
35972246da4SFelipe Balbi 
36072246da4SFelipe Balbi #define DWC3_ALIGN_MASK		(16 - 1)
36172246da4SFelipe Balbi 
36241ac7b3aSBill Pemberton static int dwc3_probe(struct platform_device *pdev)
36372246da4SFelipe Balbi {
364457e84b6SFelipe Balbi 	struct device_node	*node = pdev->dev.of_node;
36572246da4SFelipe Balbi 	struct resource		*res;
36672246da4SFelipe Balbi 	struct dwc3		*dwc;
367802ca850SChanho Park 	struct device		*dev = &pdev->dev;
3680949e99bSFelipe Balbi 
36972246da4SFelipe Balbi 	int			ret = -ENOMEM;
3700949e99bSFelipe Balbi 
3710949e99bSFelipe Balbi 	void __iomem		*regs;
37272246da4SFelipe Balbi 	void			*mem;
37372246da4SFelipe Balbi 
3740949e99bSFelipe Balbi 	u8			mode;
3750949e99bSFelipe Balbi 
376802ca850SChanho Park 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
37772246da4SFelipe Balbi 	if (!mem) {
378802ca850SChanho Park 		dev_err(dev, "not enough memory\n");
379802ca850SChanho Park 		return -ENOMEM;
38072246da4SFelipe Balbi 	}
38172246da4SFelipe Balbi 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
38272246da4SFelipe Balbi 	dwc->mem = mem;
38372246da4SFelipe Balbi 
38451249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
38572246da4SFelipe Balbi 	if (!res) {
38651249dcaSIdo Shayevitz 		dev_err(dev, "missing IRQ\n");
387802ca850SChanho Park 		return -ENODEV;
38872246da4SFelipe Balbi 	}
389066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].start = res->start;
390066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].end = res->end;
391066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].flags = res->flags;
392066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[1].name = res->name;
39372246da4SFelipe Balbi 
39451249dcaSIdo Shayevitz 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
39551249dcaSIdo Shayevitz 	if (!res) {
39651249dcaSIdo Shayevitz 		dev_err(dev, "missing memory resource\n");
39751249dcaSIdo Shayevitz 		return -ENODEV;
39851249dcaSIdo Shayevitz 	}
399066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].start = res->start;
40051249dcaSIdo Shayevitz 	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
40151249dcaSIdo Shayevitz 					DWC3_XHCI_REGS_END;
402066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].flags = res->flags;
403066618bcSKishon Vijay Abraham I 	dwc->xhci_resources[0].name = res->name;
404d07e8819SFelipe Balbi 
40551249dcaSIdo Shayevitz 	 /*
40651249dcaSIdo Shayevitz 	  * Request memory region but exclude xHCI regs,
40751249dcaSIdo Shayevitz 	  * since it will be requested by the xhci-plat driver.
40851249dcaSIdo Shayevitz 	  */
40951249dcaSIdo Shayevitz 	res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
41051249dcaSIdo Shayevitz 			resource_size(res) - DWC3_GLOBALS_REGS_START,
411802ca850SChanho Park 			dev_name(dev));
41272246da4SFelipe Balbi 	if (!res) {
413802ca850SChanho Park 		dev_err(dev, "can't request mem region\n");
414802ca850SChanho Park 		return -ENOMEM;
41572246da4SFelipe Balbi 	}
41672246da4SFelipe Balbi 
417b7e38aa6SFelipe Balbi 	regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
41872246da4SFelipe Balbi 	if (!regs) {
419802ca850SChanho Park 		dev_err(dev, "ioremap failed\n");
420802ca850SChanho Park 		return -ENOMEM;
42172246da4SFelipe Balbi 	}
42272246da4SFelipe Balbi 
42351e1e7bcSFelipe Balbi 	dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
42451e1e7bcSFelipe Balbi 	if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
42551e1e7bcSFelipe Balbi 		dev_err(dev, "no usb2 phy configured\n");
42651e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
42751e1e7bcSFelipe Balbi 	}
42851e1e7bcSFelipe Balbi 
42951e1e7bcSFelipe Balbi 	dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
43051e1e7bcSFelipe Balbi 	if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
43151e1e7bcSFelipe Balbi 		dev_err(dev, "no usb3 phy configured\n");
43251e1e7bcSFelipe Balbi 		return -EPROBE_DEFER;
43351e1e7bcSFelipe Balbi 	}
43451e1e7bcSFelipe Balbi 
435*8ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 0);
436*8ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 0);
437*8ba007a9SKishon Vijay Abraham I 
43872246da4SFelipe Balbi 	spin_lock_init(&dwc->lock);
43972246da4SFelipe Balbi 	platform_set_drvdata(pdev, dwc);
44072246da4SFelipe Balbi 
44172246da4SFelipe Balbi 	dwc->regs	= regs;
44272246da4SFelipe Balbi 	dwc->regs_size	= resource_size(res);
443802ca850SChanho Park 	dwc->dev	= dev;
44472246da4SFelipe Balbi 
4456c167fc9SFelipe Balbi 	if (!strncmp("super", maximum_speed, 5))
4466c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
4476c167fc9SFelipe Balbi 	else if (!strncmp("high", maximum_speed, 4))
4486c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
4496c167fc9SFelipe Balbi 	else if (!strncmp("full", maximum_speed, 4))
4506c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
4516c167fc9SFelipe Balbi 	else if (!strncmp("low", maximum_speed, 3))
4526c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
4536c167fc9SFelipe Balbi 	else
4546c167fc9SFelipe Balbi 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
4556c167fc9SFelipe Balbi 
456457e84b6SFelipe Balbi 	if (of_get_property(node, "tx-fifo-resize", NULL))
457457e84b6SFelipe Balbi 		dwc->needs_fifo_resize = true;
458457e84b6SFelipe Balbi 
459802ca850SChanho Park 	pm_runtime_enable(dev);
460802ca850SChanho Park 	pm_runtime_get_sync(dev);
461802ca850SChanho Park 	pm_runtime_forbid(dev);
46272246da4SFelipe Balbi 
4634fd24483SKishon Vijay Abraham I 	dwc3_cache_hwparams(dwc);
4644fd24483SKishon Vijay Abraham I 
4653921426bSFelipe Balbi 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
4663921426bSFelipe Balbi 	if (ret) {
4673921426bSFelipe Balbi 		dev_err(dwc->dev, "failed to allocate event buffers\n");
4683921426bSFelipe Balbi 		ret = -ENOMEM;
4693921426bSFelipe Balbi 		goto err0;
4703921426bSFelipe Balbi 	}
4713921426bSFelipe Balbi 
47272246da4SFelipe Balbi 	ret = dwc3_core_init(dwc);
47372246da4SFelipe Balbi 	if (ret) {
474802ca850SChanho Park 		dev_err(dev, "failed to initialize core\n");
4753921426bSFelipe Balbi 		goto err0;
47672246da4SFelipe Balbi 	}
47772246da4SFelipe Balbi 
4780949e99bSFelipe Balbi 	mode = DWC3_MODE(dwc->hwparams.hwparams0);
4790949e99bSFelipe Balbi 
4800949e99bSFelipe Balbi 	switch (mode) {
4810949e99bSFelipe Balbi 	case DWC3_MODE_DEVICE:
4823140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
48372246da4SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
48472246da4SFelipe Balbi 		if (ret) {
485802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
486802ca850SChanho Park 			goto err1;
48772246da4SFelipe Balbi 		}
4880949e99bSFelipe Balbi 		break;
489d07e8819SFelipe Balbi 	case DWC3_MODE_HOST:
4903140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
491d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
492d07e8819SFelipe Balbi 		if (ret) {
493802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
494802ca850SChanho Park 			goto err1;
49572246da4SFelipe Balbi 		}
496d07e8819SFelipe Balbi 		break;
497d07e8819SFelipe Balbi 	case DWC3_MODE_DRD:
4983140e8cbSSebastian Andrzej Siewior 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
499d07e8819SFelipe Balbi 		ret = dwc3_host_init(dwc);
500d07e8819SFelipe Balbi 		if (ret) {
501802ca850SChanho Park 			dev_err(dev, "failed to initialize host\n");
502802ca850SChanho Park 			goto err1;
503d07e8819SFelipe Balbi 		}
504d07e8819SFelipe Balbi 
505d07e8819SFelipe Balbi 		ret = dwc3_gadget_init(dwc);
506d07e8819SFelipe Balbi 		if (ret) {
507802ca850SChanho Park 			dev_err(dev, "failed to initialize gadget\n");
508802ca850SChanho Park 			goto err1;
509d07e8819SFelipe Balbi 		}
510d07e8819SFelipe Balbi 		break;
5110949e99bSFelipe Balbi 	default:
512802ca850SChanho Park 		dev_err(dev, "Unsupported mode of operation %d\n", mode);
513802ca850SChanho Park 		goto err1;
51472246da4SFelipe Balbi 	}
5150949e99bSFelipe Balbi 	dwc->mode = mode;
51672246da4SFelipe Balbi 
51772246da4SFelipe Balbi 	ret = dwc3_debugfs_init(dwc);
51872246da4SFelipe Balbi 	if (ret) {
519802ca850SChanho Park 		dev_err(dev, "failed to initialize debugfs\n");
520802ca850SChanho Park 		goto err2;
52172246da4SFelipe Balbi 	}
52272246da4SFelipe Balbi 
523802ca850SChanho Park 	pm_runtime_allow(dev);
52472246da4SFelipe Balbi 
52572246da4SFelipe Balbi 	return 0;
52672246da4SFelipe Balbi 
527802ca850SChanho Park err2:
5280949e99bSFelipe Balbi 	switch (mode) {
5290949e99bSFelipe Balbi 	case DWC3_MODE_DEVICE:
53072246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5310949e99bSFelipe Balbi 		break;
532d07e8819SFelipe Balbi 	case DWC3_MODE_HOST:
533d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
534d07e8819SFelipe Balbi 		break;
535d07e8819SFelipe Balbi 	case DWC3_MODE_DRD:
536d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
537d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
538d07e8819SFelipe Balbi 		break;
5390949e99bSFelipe Balbi 	default:
5400949e99bSFelipe Balbi 		/* do nothing */
5410949e99bSFelipe Balbi 		break;
5420949e99bSFelipe Balbi 	}
54372246da4SFelipe Balbi 
544802ca850SChanho Park err1:
54572246da4SFelipe Balbi 	dwc3_core_exit(dwc);
54672246da4SFelipe Balbi 
5473921426bSFelipe Balbi err0:
5483921426bSFelipe Balbi 	dwc3_free_event_buffers(dwc);
5493921426bSFelipe Balbi 
55072246da4SFelipe Balbi 	return ret;
55172246da4SFelipe Balbi }
55272246da4SFelipe Balbi 
553fb4e98abSBill Pemberton static int dwc3_remove(struct platform_device *pdev)
55472246da4SFelipe Balbi {
55572246da4SFelipe Balbi 	struct dwc3	*dwc = platform_get_drvdata(pdev);
55672246da4SFelipe Balbi 	struct resource	*res;
55772246da4SFelipe Balbi 
55872246da4SFelipe Balbi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
55972246da4SFelipe Balbi 
560*8ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb2_phy, 1);
561*8ba007a9SKishon Vijay Abraham I 	usb_phy_set_suspend(dwc->usb3_phy, 1);
562*8ba007a9SKishon Vijay Abraham I 
56372246da4SFelipe Balbi 	pm_runtime_put(&pdev->dev);
56472246da4SFelipe Balbi 	pm_runtime_disable(&pdev->dev);
56572246da4SFelipe Balbi 
56672246da4SFelipe Balbi 	dwc3_debugfs_exit(dwc);
56772246da4SFelipe Balbi 
5680949e99bSFelipe Balbi 	switch (dwc->mode) {
5690949e99bSFelipe Balbi 	case DWC3_MODE_DEVICE:
57072246da4SFelipe Balbi 		dwc3_gadget_exit(dwc);
5710949e99bSFelipe Balbi 		break;
572d07e8819SFelipe Balbi 	case DWC3_MODE_HOST:
573d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
574d07e8819SFelipe Balbi 		break;
575d07e8819SFelipe Balbi 	case DWC3_MODE_DRD:
576d07e8819SFelipe Balbi 		dwc3_host_exit(dwc);
577d07e8819SFelipe Balbi 		dwc3_gadget_exit(dwc);
578d07e8819SFelipe Balbi 		break;
5790949e99bSFelipe Balbi 	default:
5800949e99bSFelipe Balbi 		/* do nothing */
5810949e99bSFelipe Balbi 		break;
5820949e99bSFelipe Balbi 	}
58372246da4SFelipe Balbi 
58472246da4SFelipe Balbi 	dwc3_core_exit(dwc);
58572246da4SFelipe Balbi 
58672246da4SFelipe Balbi 	return 0;
58772246da4SFelipe Balbi }
58872246da4SFelipe Balbi 
58972246da4SFelipe Balbi static struct platform_driver dwc3_driver = {
59072246da4SFelipe Balbi 	.probe		= dwc3_probe,
5917690417dSBill Pemberton 	.remove		= dwc3_remove,
59272246da4SFelipe Balbi 	.driver		= {
59372246da4SFelipe Balbi 		.name	= "dwc3",
59472246da4SFelipe Balbi 	},
59572246da4SFelipe Balbi };
59672246da4SFelipe Balbi 
597b1116dccSTobias Klauser module_platform_driver(dwc3_driver);
598b1116dccSTobias Klauser 
5997ae4fc4dSSebastian Andrzej Siewior MODULE_ALIAS("platform:dwc3");
60072246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
60172246da4SFelipe Balbi MODULE_LICENSE("Dual BSD/GPL");
60272246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
603