From: Jens Wiklander <jens.wiklander@linaro.org>
To: u-boot@lists.denx.de, Marek Vasut <marex@denx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>,
Andre Przywara <andre.przywara@arm.com>,
Andrew Goodbody <andrew.goodbody@linaro.org>,
Anshul Dalal <anshuld@ti.com>, Bin Meng <bmeng.cn@gmail.com>,
Casey Connolly <casey.connolly@linaro.org>,
Chunfeng Yun <chunfeng.yun@mediatek.com>,
Eddie Cai <eddie.cai.linux@gmail.com>,
GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com>,
Ion Agorria <ion@agorria.com>,
Junhui Liu <junhui.liu@pigmoral.tech>,
Kongyang Liu <seashell11234455@gmail.com>,
Lukasz Majewski <lukma@denx.de>,
Mattijs Korpershoek <mkorpershoek@kernel.org>,
Neil Armstrong <neil.armstrong@linaro.org>,
Patrice Chotard <patrice.chotard@foss.st.com>,
Quentin Schulz <quentin.schulz@cherry.de>,
Rasmus Villemoes <ravi@prevas.dk>,
Ryder Lee <ryder.lee@mediatek.com>,
Simon Glass <sjg@chromium.org>,
Stephan Gerhold <stephan.gerhold@linaro.org>,
Svyatoslav Ryhel <clamor95@gmail.com>,
Tom Rini <trini@konsulko.com>,
Varadarajan Narayanan <quic_varada@quicinc.com>,
Weijie Gao <weijie.gao@mediatek.com>,
Zixun LI <admin@hifiphile.com>,
Jerome Forissier <jerome.forissier@arm.com>,
Jens Wiklander <jens.wiklander@linaro.org>
Subject: [RFC PATCH v2 01/64] usb: dwc3: restore to original v3.19-rc1 kernel import
Date: Thu, 7 May 2026 11:27:08 +0200 [thread overview]
Message-ID: <20260507092843.358908-2-jens.wiklander@linaro.org> (raw)
In-Reply-To: <20260507092843.358908-1-jens.wiklander@linaro.org>
Restore the dwc3 source files to the state of the original import in
commit 85d5e7075f33 ("usb: dwc3: add dwc3 folder from linux kernel to
u-boot").
The following files are preserved accross the import:
Makefile Kconfig dwc3-meson-g12a.c dwc3-meson-gxl.c dwc3-omap.c
dwc3-uniphier.c dwc3-generic.h dwc3-generic.c dwc3-generic-sti.c
dwc3-layerscape.c ti_usb_phy.c
Note that this is a raw import and doesn't build.
A fixup commit at the end of the series fixes that.
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
---
drivers/usb/dwc3/core.c | 1002 +++++++++++++---------------
drivers/usb/dwc3/core.h | 171 ++---
drivers/usb/dwc3/debug.c | 32 +
drivers/usb/dwc3/debug.h | 228 +++++++
drivers/usb/dwc3/dwc3-am62.c | 125 ----
drivers/usb/dwc3/ep0.c | 217 +++---
drivers/usb/dwc3/gadget.c | 482 +++++++------
drivers/usb/dwc3/gadget.h | 16 +-
drivers/usb/dwc3/io.h | 54 +-
drivers/usb/dwc3/linux-compat.h | 16 -
drivers/usb/dwc3/platform_data.h | 47 ++
drivers/usb/dwc3/samsung_usb_phy.c | 77 ---
12 files changed, 1211 insertions(+), 1256 deletions(-)
create mode 100644 drivers/usb/dwc3/debug.c
create mode 100644 drivers/usb/dwc3/debug.h
delete mode 100644 drivers/usb/dwc3/dwc3-am62.c
delete mode 100644 drivers/usb/dwc3/linux-compat.h
create mode 100644 drivers/usb/dwc3/platform_data.h
delete mode 100644 drivers/usb/dwc3/samsung_usb_phy.c
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 847fa1f82c37..25ddc39efad8 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1,48 +1,55 @@
-// SPDX-License-Identifier: GPL-2.0
/**
* core.c - DesignWare USB3 DRD Controller Core file
*
- * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/core.c) and ported
- * to uboot.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * commit cd72f890d2 : usb: dwc3: core: enable phy suspend quirk on non-FPGA
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <clk.h>
-#include <cpu_func.h>
-#include <malloc.h>
-#include <dwc3-uboot.h>
-#include <dm/device_compat.h>
-#include <dm/devres.h>
-#include <linux/bug.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/iopoll.h>
-#include <linux/ioport.h>
-#include <dm.h>
-#include <generic-phy.h>
+#include <linux/of.h>
+#include <linux/acpi.h>
+
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <linux/bitfield.h>
-#include <linux/math64.h>
-#include <linux/time.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include "platform_data.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
-#include "linux-compat.h"
+#include "debug.h"
-static LIST_HEAD(dwc3_list);
/* -------------------------------------------------------------------------- */
-static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
u32 reg;
@@ -59,6 +66,7 @@ static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
static int dwc3_core_soft_reset(struct dwc3 *dwc)
{
u32 reg;
+ int ret;
/* Before Resetting PHY, put Core in Reset */
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
@@ -75,6 +83,17 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ usb_phy_init(dwc->usb2_phy);
+ usb_phy_init(dwc->usb3_phy);
+ ret = phy_init(dwc->usb2_generic_phy);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_init(dwc->usb3_generic_phy);
+ if (ret < 0) {
+ phy_exit(dwc->usb2_generic_phy);
+ return ret;
+ }
mdelay(100);
/* Clear USB3 PHY reset */
@@ -97,94 +116,6 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
return 0;
}
-/*
- * dwc3_frame_length_adjustment - Adjusts frame length if required
- * @dwc3: Pointer to our controller context structure
- * @fladj: Value of GFLADJ_30MHZ to adjust frame length
- */
-static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
-{
- u32 reg;
-
- if (dwc->revision < DWC3_REVISION_250A)
- return;
-
- if (fladj == 0)
- return;
-
- reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
- reg &= ~DWC3_GFLADJ_30MHZ_MASK;
- reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
- dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
-}
-
-/**
- * dwc3_ref_clk_period - Reference clock period configuration
- * Default reference clock period depends on hardware
- * configuration. For systems with reference clock that differs
- * from the default, this will set clock period in DWC3_GUCTL
- * register.
- * @dwc: Pointer to our controller context structure
- * @ref_clk_per: reference clock period in ns
- */
-static void dwc3_ref_clk_period(struct dwc3 *dwc)
-{
- unsigned long period;
- unsigned long fladj;
- unsigned long decr;
- unsigned long rate;
- u32 reg;
-
- if (dwc->ref_clk) {
- rate = clk_get_rate(dwc->ref_clk);
- if (!rate)
- return;
- period = NSEC_PER_SEC / rate;
- } else {
- return;
- }
-
- reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
- reg &= ~DWC3_GUCTL_REFCLKPER_MASK;
- reg |= FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, period);
- dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
-
- if (dwc->revision <= DWC3_REVISION_250A)
- return;
-
- /*
- * The calculation below is
- *
- * 125000 * (NSEC_PER_SEC / (rate * period) - 1)
- *
- * but rearranged for fixed-point arithmetic. The division must be
- * 64-bit because 125000 * NSEC_PER_SEC doesn't fit in 32 bits (and
- * neither does rate * period).
- *
- * Note that rate * period ~= NSEC_PER_SECOND, minus the number of
- * nanoseconds of error caused by the truncation which happened during
- * the division when calculating rate or period (whichever one was
- * derived from the other). We first calculate the relative error, then
- * scale it to units of 8 ppm.
- */
- fladj = div64_u64(125000ULL * NSEC_PER_SEC, (u64)rate * period);
- fladj -= 125000;
-
- /*
- * The documented 240MHz constant is scaled by 2 to get PLS1 as well.
- */
- decr = 480000000 / rate;
-
- reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
- reg &= ~DWC3_GFLADJ_REFCLK_FLADJ_MASK
- & ~DWC3_GFLADJ_240MHZDECR
- & ~DWC3_GFLADJ_240MHZDECR_PLS1;
- reg |= FIELD_PREP(DWC3_GFLADJ_REFCLK_FLADJ_MASK, fladj)
- | FIELD_PREP(DWC3_GFLADJ_240MHZDECR, decr >> 1)
- | FIELD_PREP(DWC3_GFLADJ_240MHZDECR_PLS1, decr & 1);
- dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
-}
-
/**
* dwc3_free_one_event_buffer - Frees one event buffer
* @dwc: Pointer to our controller context structure
@@ -193,7 +124,7 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
struct dwc3_event_buffer *evt)
{
- dma_free_coherent(evt->buf);
+ dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
}
/**
@@ -209,20 +140,17 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
{
struct dwc3_event_buffer *evt;
- evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt),
- GFP_KERNEL);
+ evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
if (!evt)
return ERR_PTR(-ENOMEM);
evt->dwc = dwc;
evt->length = length;
- evt->buf = dma_alloc_coherent(length,
- (unsigned long *)&evt->dma);
+ evt->buf = dma_alloc_coherent(dwc->dev, length,
+ &evt->dma, GFP_KERNEL);
if (!evt->buf)
return ERR_PTR(-ENOMEM);
- dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
-
return evt;
}
@@ -258,8 +186,8 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
dwc->num_event_buffers = num;
- dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE,
- sizeof(*dwc->ev_buffs) * num);
+ dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
+ GFP_KERNEL);
if (!dwc->ev_buffs)
return -ENOMEM;
@@ -354,9 +282,13 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
if (!dwc->nr_scratch)
return 0;
- scratch_addr = dma_map_single(dwc->scratchbuf,
- dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
- DMA_BIDIRECTIONAL);
+ /* should never fall here */
+ if (!WARN_ON(dwc->scratchbuf))
+ return 0;
+
+ scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
+ dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
+ DMA_BIDIRECTIONAL);
if (dma_mapping_error(dwc->dev, scratch_addr)) {
dev_err(dwc->dev, "failed to map scratch buffer\n");
ret = -EFAULT;
@@ -382,8 +314,8 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
return 0;
err1:
- dma_unmap_single(scratch_addr, dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
- DMA_BIDIRECTIONAL);
+ dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
+ DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
err0:
return ret;
@@ -397,8 +329,12 @@ static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
if (!dwc->nr_scratch)
return;
- dma_unmap_single(dwc->scratch_addr, dwc->nr_scratch *
- DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
+ /* should never fall here */
+ if (!WARN_ON(dwc->scratchbuf))
+ return;
+
+ dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
+ DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
kfree(dwc->scratchbuf);
}
@@ -428,34 +364,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
}
-static void dwc3_hsphy_mode_setup(struct dwc3 *dwc)
-{
- enum usb_phy_interface hsphy_mode = dwc->hsphy_mode;
- u32 reg;
-
- /* Set dwc3 usb2 phy config */
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-
- switch (hsphy_mode) {
- case USBPHY_INTERFACE_MODE_UTMI:
- reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
- DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
- reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
- DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
- break;
- case USBPHY_INTERFACE_MODE_UTMIW:
- reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
- DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
- reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
- DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
- break;
- default:
- break;
- }
-
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
-}
-
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
@@ -499,13 +407,8 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_u3_susphy_quirk)
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
- if (dwc->dis_del_phy_power_chg_quirk)
- reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
-
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
- dwc3_hsphy_mode_setup(dwc);
-
mdelay(100);
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -522,64 +425,11 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
- if (dwc->dis_enblslpm_quirk)
- reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
-
- if (dwc->dis_u2_freeclk_exists_quirk)
- reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
-
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
mdelay(100);
}
-/* set global incr burst type configuration registers */
-static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
-{
- struct udevice *dev = dwc->dev;
- u32 cfg;
-
- if (!dwc->incrx_size)
- return;
-
- cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
-
- /* Enable Undefined Length INCR Burst and Enable INCRx Burst */
- cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
- if (dwc->incrx_mode)
- cfg |= DWC3_GSBUSCFG0_INCRBRSTENA;
- switch (dwc->incrx_size) {
- case 256:
- cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA;
- break;
- case 128:
- cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA;
- break;
- case 64:
- cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA;
- break;
- case 32:
- cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA;
- break;
- case 16:
- cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA;
- break;
- case 8:
- cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA;
- break;
- case 4:
- cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA;
- break;
- case 1:
- break;
- default:
- dev_err(dev, "Invalid property\n");
- break;
- }
-
- dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
-}
-
/**
* dwc3_core_init - Low-level initialization of DWC3 Core
* @dwc: Pointer to our controller context structure
@@ -588,20 +438,26 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
*/
static int dwc3_core_init(struct dwc3 *dwc)
{
+ unsigned long timeout;
u32 hwparams4 = dwc->hwparams.hwparams4;
u32 reg;
int ret;
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
/* This should read as U3 followed by revision number */
- if ((reg & DWC3_GSNPSID_MASK) != 0x55330000 &&
- (reg & DWC3_GSNPSID_MASK) != 0x33310000) {
+ if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
ret = -ENODEV;
goto err0;
}
dwc->revision = reg;
+ /*
+ * Write Linux Version Code to our GUID register so it's easy to figure
+ * out which kernel version a bug was found.
+ */
+ dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
+
/* Handle USB2.0-only core configuration */
if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
@@ -610,17 +466,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
}
/* issue device SoftReset too */
+ timeout = jiffies + msecs_to_jiffies(500);
dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
- ret = read_poll_timeout(dwc3_readl, reg,
- !(reg & DWC3_DCTL_CSFTRST),
- 1, 5000, dwc->regs, DWC3_DCTL);
- if (ret) {
- dev_err(dwc->dev, "Reset Timed Out\n");
- ret = -ETIMEDOUT;
- goto err0;
- }
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (!(reg & DWC3_DCTL_CSFTRST))
+ break;
- dwc3_phy_setup(dwc);
+ if (time_after(jiffies, timeout)) {
+ dev_err(dwc->dev, "Reset Timed Out\n");
+ ret = -ETIMEDOUT;
+ goto err0;
+ }
+
+ cpu_relax();
+ } while (true);
ret = dwc3_core_soft_reset(dwc);
if (ret)
@@ -671,9 +531,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc->is_fpga = true;
}
- if(dwc->disable_scramble_quirk && !dwc->is_fpga)
- WARN(true,
- "disable_scramble cannot be used on non-FPGA builds\n");
+ WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
+ "disable_scramble cannot be used on non-FPGA builds\n");
if (dwc->disable_scramble_quirk && dwc->is_fpga)
reg |= DWC3_GCTL_DISSCRAMBLE;
@@ -696,27 +555,27 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ dwc3_phy_setup(dwc);
+
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
- goto err0;
+ goto err1;
ret = dwc3_setup_scratch_buffers(dwc);
if (ret)
- goto err1;
-
- /* Adjust Frame Length */
- dwc3_frame_length_adjustment(dwc, dwc->fladj);
-
- /* Adjust Reference Clock Period */
- dwc3_ref_clk_period(dwc);
-
- dwc3_set_incr_burst_type(dwc);
+ goto err2;
return 0;
-err1:
+err2:
dwc3_free_scratch_buffers(dwc);
+err1:
+ usb_phy_shutdown(dwc->usb2_phy);
+ usb_phy_shutdown(dwc->usb3_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
+
err0:
return ret;
}
@@ -724,10 +583,82 @@ err0:
static void dwc3_core_exit(struct dwc3 *dwc)
{
dwc3_free_scratch_buffers(dwc);
+ usb_phy_shutdown(dwc->usb2_phy);
+ usb_phy_shutdown(dwc->usb3_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
+}
+
+static int dwc3_core_get_phy(struct dwc3 *dwc)
+{
+ struct device *dev = dwc->dev;
+ struct device_node *node = dev->of_node;
+ int ret;
+
+ if (node) {
+ dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
+ dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+ } else {
+ dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+ dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+ }
+
+ if (IS_ERR(dwc->usb2_phy)) {
+ ret = PTR_ERR(dwc->usb2_phy);
+ if (ret == -ENXIO || ret == -ENODEV) {
+ dwc->usb2_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev, "no usb2 phy configured\n");
+ return ret;
+ }
+ }
+
+ if (IS_ERR(dwc->usb3_phy)) {
+ ret = PTR_ERR(dwc->usb3_phy);
+ if (ret == -ENXIO || ret == -ENODEV) {
+ dwc->usb3_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev, "no usb3 phy configured\n");
+ return ret;
+ }
+ }
+
+ dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
+ if (IS_ERR(dwc->usb2_generic_phy)) {
+ ret = PTR_ERR(dwc->usb2_generic_phy);
+ if (ret == -ENOSYS || ret == -ENODEV) {
+ dwc->usb2_generic_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev, "no usb2 phy configured\n");
+ return ret;
+ }
+ }
+
+ dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
+ if (IS_ERR(dwc->usb3_generic_phy)) {
+ ret = PTR_ERR(dwc->usb3_generic_phy);
+ if (ret == -ENOSYS || ret == -ENODEV) {
+ dwc->usb3_generic_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev, "no usb3 phy configured\n");
+ return ret;
+ }
+ }
+
+ return 0;
}
static int dwc3_core_init_mode(struct dwc3 *dwc)
{
+ struct device *dev = dwc->dev;
int ret;
switch (dwc->dr_mode) {
@@ -735,7 +666,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(dwc->dev, "failed to initialize gadget\n");
+ dev_err(dev, "failed to initialize gadget\n");
return ret;
}
break;
@@ -743,7 +674,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
- dev_err(dwc->dev, "failed to initialize host\n");
+ dev_err(dev, "failed to initialize host\n");
return ret;
}
break;
@@ -751,39 +682,24 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
- dev_err(dwc->dev, "failed to initialize host\n");
+ dev_err(dev, "failed to initialize host\n");
return ret;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(dwc->dev, "failed to initialize gadget\n");
+ dev_err(dev, "failed to initialize gadget\n");
return ret;
}
break;
default:
- dev_err(dwc->dev,
- "Unsupported mode of operation %d\n", dwc->dr_mode);
+ dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
return -EINVAL;
}
return 0;
}
-static void dwc3_gadget_run(struct dwc3 *dwc)
-{
- dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_RUN_STOP);
- mdelay(100);
-}
-
-static void dwc3_core_stop(struct dwc3 *dwc)
-{
- u32 reg;
-
- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
- dwc3_writel(dwc->regs, DWC3_DCTL, reg & ~(DWC3_DCTL_RUN_STOP));
-}
-
static void dwc3_core_exit_mode(struct dwc3 *dwc)
{
switch (dwc->dr_mode) {
@@ -801,50 +717,74 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
/* do nothing */
break;
}
-
- /*
- * switch back to peripheral mode
- * This enables the phy to enter idle and then, if enabled, suspend.
- */
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
- dwc3_gadget_run(dwc);
}
#define DWC3_ALIGN_MASK (16 - 1)
-/**
- * dwc3_uboot_init - dwc3 core uboot initialization code
- * @dwc3_dev: struct dwc3_device containing initialization data
- *
- * Entry point for dwc3 driver (equivalent to dwc3_probe in linux
- * kernel driver). Pointer to dwc3_device should be passed containing
- * base address and other initialization data. Returns '0' on success and
- * a negative value on failure.
- *
- * Generally called from board_usb_init() implemented in board file.
- */
-int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
+static int dwc3_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
+ struct dwc3_platform_data *pdata = dev_get_platdata(dev);
+ struct device_node *node = dev->of_node;
+ struct resource *res;
struct dwc3 *dwc;
- struct device *dev = NULL;
u8 lpm_nyet_threshold;
u8 tx_de_emphasis;
u8 hird_threshold;
int ret;
+ void __iomem *regs;
void *mem;
- mem = devm_kzalloc((struct udevice *)dev,
- sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+ mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem)
return -ENOMEM;
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
+ dwc->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "missing IRQ\n");
+ return -ENODEV;
+ }
+ dwc->xhci_resources[1].start = res->start;
+ dwc->xhci_resources[1].end = res->end;
+ dwc->xhci_resources[1].flags = res->flags;
+ dwc->xhci_resources[1].name = res->name;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+
+ dwc->xhci_resources[0].start = res->start;
+ dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+ DWC3_XHCI_REGS_END;
+ dwc->xhci_resources[0].flags = res->flags;
+ dwc->xhci_resources[0].name = res->name;
- dwc->regs = (void *)(uintptr_t)(dwc3_dev->base +
- DWC3_GLOBALS_REGS_START);
+ res->start += DWC3_GLOBALS_REGS_START;
+
+ /*
+ * Request memory region but exclude xHCI regs,
+ * since it will be requested by the xhci-plat driver.
+ */
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ dwc->regs = regs;
+ dwc->regs_size = resource_size(res);
+ /*
+ * restore res->start back to its original value so that,
+ * in case the probe is deferred, we don't end up getting error in
+ * request the memory region the next time probe is called.
+ */
+ res->start -= DWC3_GLOBALS_REGS_START;
/* default to highest possible threshold */
lpm_nyet_threshold = 0xff;
@@ -858,35 +798,73 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
*/
hird_threshold = 12;
- dwc->maximum_speed = dwc3_dev->maximum_speed;
- dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum;
- if (dwc3_dev->lpm_nyet_threshold)
- lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold;
- dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend;
- if (dwc3_dev->hird_threshold)
- hird_threshold = dwc3_dev->hird_threshold;
-
- dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize;
- dwc->dr_mode = dwc3_dev->dr_mode;
-
- dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk;
- dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk;
- dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk;
- dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk;
- dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk;
- dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk;
- dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk;
- dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk;
- dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk;
- dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk;
- dwc->dis_del_phy_power_chg_quirk = dwc3_dev->dis_del_phy_power_chg_quirk;
- dwc->dis_tx_ipgap_linecheck_quirk = dwc3_dev->dis_tx_ipgap_linecheck_quirk;
- dwc->dis_enblslpm_quirk = dwc3_dev->dis_enblslpm_quirk;
- dwc->dis_u2_freeclk_exists_quirk = dwc3_dev->dis_u2_freeclk_exists_quirk;
-
- dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk;
- if (dwc3_dev->tx_de_emphasis)
- tx_de_emphasis = dwc3_dev->tx_de_emphasis;
+ if (node) {
+ dwc->maximum_speed = of_usb_get_maximum_speed(node);
+ dwc->has_lpm_erratum = of_property_read_bool(node,
+ "snps,has-lpm-erratum");
+ of_property_read_u8(node, "snps,lpm-nyet-threshold",
+ &lpm_nyet_threshold);
+ dwc->is_utmi_l1_suspend = of_property_read_bool(node,
+ "snps,is-utmi-l1-suspend");
+ of_property_read_u8(node, "snps,hird-threshold",
+ &hird_threshold);
+
+ dwc->needs_fifo_resize = of_property_read_bool(node,
+ "tx-fifo-resize");
+ dwc->dr_mode = of_usb_get_dr_mode(node);
+
+ dwc->disable_scramble_quirk = of_property_read_bool(node,
+ "snps,disable_scramble_quirk");
+ dwc->u2exit_lfps_quirk = of_property_read_bool(node,
+ "snps,u2exit_lfps_quirk");
+ dwc->u2ss_inp3_quirk = of_property_read_bool(node,
+ "snps,u2ss_inp3_quirk");
+ dwc->req_p1p2p3_quirk = of_property_read_bool(node,
+ "snps,req_p1p2p3_quirk");
+ dwc->del_p1p2p3_quirk = of_property_read_bool(node,
+ "snps,del_p1p2p3_quirk");
+ dwc->del_phy_power_chg_quirk = of_property_read_bool(node,
+ "snps,del_phy_power_chg_quirk");
+ dwc->lfps_filter_quirk = of_property_read_bool(node,
+ "snps,lfps_filter_quirk");
+ dwc->rx_detect_poll_quirk = of_property_read_bool(node,
+ "snps,rx_detect_poll_quirk");
+ dwc->dis_u3_susphy_quirk = of_property_read_bool(node,
+ "snps,dis_u3_susphy_quirk");
+ dwc->dis_u2_susphy_quirk = of_property_read_bool(node,
+ "snps,dis_u2_susphy_quirk");
+
+ dwc->tx_de_emphasis_quirk = of_property_read_bool(node,
+ "snps,tx_de_emphasis_quirk");
+ of_property_read_u8(node, "snps,tx_de_emphasis",
+ &tx_de_emphasis);
+ } else if (pdata) {
+ dwc->maximum_speed = pdata->maximum_speed;
+ dwc->has_lpm_erratum = pdata->has_lpm_erratum;
+ if (pdata->lpm_nyet_threshold)
+ lpm_nyet_threshold = pdata->lpm_nyet_threshold;
+ dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
+ if (pdata->hird_threshold)
+ hird_threshold = pdata->hird_threshold;
+
+ dwc->needs_fifo_resize = pdata->tx_fifo_resize;
+ dwc->dr_mode = pdata->dr_mode;
+
+ dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
+ dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
+ dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
+ dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
+ dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
+ dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
+ dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
+ dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
+ dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
+ dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
+
+ dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
+ if (pdata->tx_de_emphasis)
+ tx_de_emphasis = pdata->tx_de_emphasis;
+ }
/* default to superspeed if no maximum_speed passed */
if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
@@ -898,21 +876,35 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
dwc->hird_threshold = hird_threshold
| (dwc->is_utmi_l1_suspend << 4);
- dwc->hsphy_mode = dwc3_dev->hsphy_mode;
+ ret = dwc3_core_get_phy(dwc);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&dwc->lock);
+ platform_set_drvdata(pdev, dwc);
- dwc->index = dwc3_dev->index;
+ if (!dev->dma_mask) {
+ dev->dma_mask = dev->parent->dma_mask;
+ dev->dma_parms = dev->parent->dma_parms;
+ dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
+ }
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ pm_runtime_forbid(dev);
dwc3_cache_hwparams(dwc);
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err0;
}
- if (!IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+ if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
dwc->dr_mode = USB_DR_MODE_HOST;
- else if (!IS_ENABLED(CONFIG_USB_HOST))
+ else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
@@ -920,28 +912,55 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
ret = dwc3_core_init(dwc);
if (ret) {
- dev_err(dwc->dev, "failed to initialize core\n");
+ dev_err(dev, "failed to initialize core\n");
goto err0;
}
+ usb_phy_set_suspend(dwc->usb2_phy, 0);
+ usb_phy_set_suspend(dwc->usb3_phy, 0);
+ ret = phy_power_on(dwc->usb2_generic_phy);
+ if (ret < 0)
+ goto err1;
+
+ ret = phy_power_on(dwc->usb3_generic_phy);
+ if (ret < 0)
+ goto err_usb2phy_power;
+
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
- goto err1;
+ goto err_usb3phy_power;
}
ret = dwc3_core_init_mode(dwc);
if (ret)
goto err2;
- list_add_tail(&dwc->list, &dwc3_list);
+ ret = dwc3_debugfs_init(dwc);
+ if (ret) {
+ dev_err(dev, "failed to initialize debugfs\n");
+ goto err3;
+ }
+
+ pm_runtime_allow(dev);
return 0;
+err3:
+ dwc3_core_exit_mode(dwc);
+
err2:
dwc3_event_buffers_cleanup(dwc);
+err_usb3phy_power:
+ phy_power_off(dwc->usb3_generic_phy);
+
+err_usb2phy_power:
+ phy_power_off(dwc->usb2_generic_phy);
+
err1:
+ usb_phy_set_suspend(dwc->usb2_phy, 1);
+ usb_phy_set_suspend(dwc->usb3_phy, 1);
dwc3_core_exit(dwc);
err0:
@@ -950,276 +969,151 @@ err0:
return ret;
}
-/**
- * dwc3_uboot_exit - dwc3 core uboot cleanup code
- * @index: index of this controller
- *
- * Performs cleanup of memory allocated in dwc3_uboot_init and other misc
- * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller
- * should be passed and should match with the index passed in
- * dwc3_device during init.
- *
- * Generally called from board file.
- */
-void dwc3_uboot_exit(int index)
-{
- struct dwc3 *dwc;
-
- list_for_each_entry(dwc, &dwc3_list, list) {
- if (dwc->index != index)
- continue;
-
- dwc3_core_exit_mode(dwc);
- dwc3_event_buffers_cleanup(dwc);
- dwc3_free_event_buffers(dwc);
- dwc3_core_exit(dwc);
- list_del(&dwc->list);
- kfree(dwc->mem);
- break;
- }
-}
-
-MODULE_ALIAS("platform:dwc3");
-MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
-
-#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
-__weak int dwc3_uboot_interrupt_status(struct udevice *dev)
+static int dwc3_remove(struct platform_device *pdev)
{
- return 1;
-}
+ struct dwc3 *dwc = platform_get_drvdata(pdev);
-/**
- * dm_usb_gadget_handle_interrupts - handle dwc3 core interrupt
- * @dev: device of this controller
- *
- * Invokes dwc3 gadget interrupts.
- *
- * Generally called from board file.
- */
-int dm_usb_gadget_handle_interrupts(struct udevice *dev)
-{
- struct dwc3 *dwc = NULL;
+ dwc3_debugfs_exit(dwc);
+ dwc3_core_exit_mode(dwc);
+ dwc3_event_buffers_cleanup(dwc);
+ dwc3_free_event_buffers(dwc);
- if (!dwc3_uboot_interrupt_status(dev))
- return 0;
+ usb_phy_set_suspend(dwc->usb2_phy, 1);
+ usb_phy_set_suspend(dwc->usb3_phy, 1);
+ phy_power_off(dwc->usb2_generic_phy);
+ phy_power_off(dwc->usb3_generic_phy);
- list_for_each_entry(dwc, &dwc3_list, list) {
- if (dwc->dev != dev)
- continue;
+ dwc3_core_exit(dwc);
- dwc3_gadget_uboot_handle_interrupt(dwc);
- break;
- }
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
-#endif
-#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB)
-int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys)
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_suspend(struct device *dev)
{
- int ret;
-
- ret = generic_phy_get_bulk(dev, phys);
- if (ret)
- return ret;
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ unsigned long flags;
- ret = generic_phy_init_bulk(phys);
- if (ret)
- return ret;
+ spin_lock_irqsave(&dwc->lock, flags);
- ret = generic_phy_power_on_bulk(phys);
- if (ret)
- generic_phy_exit_bulk(phys);
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ case USB_DR_MODE_OTG:
+ dwc3_gadget_suspend(dwc);
+ /* FALLTHROUGH */
+ case USB_DR_MODE_HOST:
+ default:
+ dwc3_event_buffers_cleanup(dwc);
+ break;
+ }
- return ret;
-}
+ dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
+ spin_unlock_irqrestore(&dwc->lock, flags);
-int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys)
-{
- int ret;
+ usb_phy_shutdown(dwc->usb3_phy);
+ usb_phy_shutdown(dwc->usb2_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
- ret = generic_phy_power_off_bulk(phys);
- ret |= generic_phy_exit_bulk(phys);
- return ret;
+ return 0;
}
-#endif
-#if CONFIG_IS_ENABLED(DM_USB)
-void dwc3_of_parse(struct dwc3 *dwc)
+static int dwc3_resume(struct device *dev)
{
- const u8 *tmp;
- struct udevice *dev = dwc->dev;
- u8 lpm_nyet_threshold;
- u8 tx_de_emphasis;
- u8 hird_threshold;
- u32 val;
- int i;
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ unsigned long flags;
+ int ret;
- /* default to highest possible threshold */
- lpm_nyet_threshold = 0xff;
-
- /* default to -3.5dB de-emphasis */
- tx_de_emphasis = 1;
-
- /*
- * default to assert utmi_sleep_n and use maximum allowed HIRD
- * threshold value of 0b1100
- */
- hird_threshold = 12;
-
- dwc->hsphy_mode = usb_get_phy_mode(dev_ofnode(dev));
-
- dwc->has_lpm_erratum = dev_read_bool(dev,
- "snps,has-lpm-erratum");
- tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1);
- if (tmp)
- lpm_nyet_threshold = *tmp;
-
- dwc->is_utmi_l1_suspend = dev_read_bool(dev,
- "snps,is-utmi-l1-suspend");
- tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1);
- if (tmp)
- hird_threshold = *tmp;
-
- dwc->disable_scramble_quirk = dev_read_bool(dev,
- "snps,disable_scramble_quirk");
- dwc->u2exit_lfps_quirk = dev_read_bool(dev,
- "snps,u2exit_lfps_quirk");
- dwc->u2ss_inp3_quirk = dev_read_bool(dev,
- "snps,u2ss_inp3_quirk");
- dwc->req_p1p2p3_quirk = dev_read_bool(dev,
- "snps,req_p1p2p3_quirk");
- dwc->del_p1p2p3_quirk = dev_read_bool(dev,
- "snps,del_p1p2p3_quirk");
- dwc->del_phy_power_chg_quirk = dev_read_bool(dev,
- "snps,del_phy_power_chg_quirk");
- dwc->lfps_filter_quirk = dev_read_bool(dev,
- "snps,lfps_filter_quirk");
- dwc->rx_detect_poll_quirk = dev_read_bool(dev,
- "snps,rx_detect_poll_quirk");
- dwc->dis_u3_susphy_quirk = dev_read_bool(dev,
- "snps,dis_u3_susphy_quirk");
- dwc->dis_u2_susphy_quirk = dev_read_bool(dev,
- "snps,dis_u2_susphy_quirk");
- dwc->dis_del_phy_power_chg_quirk = dev_read_bool(dev,
- "snps,dis-del-phy-power-chg-quirk");
- dwc->dis_tx_ipgap_linecheck_quirk = dev_read_bool(dev,
- "snps,dis-tx-ipgap-linecheck-quirk");
- dwc->dis_enblslpm_quirk = dev_read_bool(dev,
- "snps,dis_enblslpm_quirk");
- dwc->dis_u2_freeclk_exists_quirk = dev_read_bool(dev,
- "snps,dis-u2-freeclk-exists-quirk");
- dwc->tx_de_emphasis_quirk = dev_read_bool(dev,
- "snps,tx_de_emphasis_quirk");
- tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1);
- if (tmp)
- tx_de_emphasis = *tmp;
-
- dwc->lpm_nyet_threshold = lpm_nyet_threshold;
- dwc->tx_de_emphasis = tx_de_emphasis;
-
- dwc->hird_threshold = hird_threshold
- | (dwc->is_utmi_l1_suspend << 4);
-
- dev_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj);
-
- /*
- * Handle property "snps,incr-burst-type-adjustment".
- * Get the number of value from this property:
- * result <= 0, means this property is not supported.
- * result = 1, means INCRx burst mode supported.
- * result > 1, means undefined length burst mode supported.
- */
- dwc->incrx_mode = INCRX_BURST_MODE;
- dwc->incrx_size = 0;
- for (i = 0; i < 8; i++) {
- if (dev_read_u32_index(dev, "snps,incr-burst-type-adjustment",
- i, &val))
- break;
-
- dwc->incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE;
- dwc->incrx_size = max(dwc->incrx_size, val);
- }
-}
-
-int dwc3_init(struct dwc3 *dwc)
-{
- int ret;
- u32 reg;
+ usb_phy_init(dwc->usb3_phy);
+ usb_phy_init(dwc->usb2_phy);
+ ret = phy_init(dwc->usb2_generic_phy);
+ if (ret < 0)
+ return ret;
- dwc3_cache_hwparams(dwc);
+ ret = phy_init(dwc->usb3_generic_phy);
+ if (ret < 0)
+ goto err_usb2phy_init;
- ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
- if (ret) {
- dev_err(dwc->dev, "failed to allocate event buffers\n");
- return -ENOMEM;
- }
+ spin_lock_irqsave(&dwc->lock, flags);
- ret = dwc3_core_init(dwc);
- if (ret) {
- dev_err(dwc->dev, "failed to initialize core\n");
- goto core_fail;
- }
+ dwc3_event_buffers_setup(dwc);
+ dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
- ret = dwc3_event_buffers_setup(dwc);
- if (ret) {
- dev_err(dwc->dev, "failed to setup event buffers\n");
- goto event_fail;
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ case USB_DR_MODE_OTG:
+ dwc3_gadget_resume(dwc);
+ /* FALLTHROUGH */
+ case USB_DR_MODE_HOST:
+ default:
+ /* do nothing */
+ break;
}
- if (dwc->revision >= DWC3_REVISION_250A) {
- reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
+ spin_unlock_irqrestore(&dwc->lock, flags);
- /*
- * Enable hardware control of sending remote wakeup
- * in HS when the device is in the L1 state.
- */
- if (dwc->revision >= DWC3_REVISION_290A)
- reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
- if (dwc->dis_tx_ipgap_linecheck_quirk)
- reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
+ return 0;
- dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
- }
+err_usb2phy_init:
+ phy_exit(dwc->usb2_generic_phy);
- if (dwc->dr_mode == USB_DR_MODE_HOST ||
- dwc->dr_mode == USB_DR_MODE_OTG) {
- reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+ return ret;
+}
- reg |= DWC3_GUCTL_HSTINAUTORETRY;
+static const struct dev_pm_ops dwc3_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
+};
- dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
- }
+#define DWC3_PM_OPS &(dwc3_dev_pm_ops)
+#else
+#define DWC3_PM_OPS NULL
+#endif
- ret = dwc3_core_init_mode(dwc);
- if (ret)
- goto mode_fail;
+#ifdef CONFIG_OF
+static const struct of_device_id of_dwc3_match[] = {
+ {
+ .compatible = "snps,dwc3"
+ },
+ {
+ .compatible = "synopsys,dwc3"
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_match);
+#endif
- return 0;
+#ifdef CONFIG_ACPI
-mode_fail:
- dwc3_event_buffers_cleanup(dwc);
+#define ACPI_ID_INTEL_BSW "808622B7"
-event_fail:
- dwc3_core_exit(dwc);
+static const struct acpi_device_id dwc3_acpi_match[] = {
+ { ACPI_ID_INTEL_BSW, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
+#endif
-core_fail:
- dwc3_free_event_buffers(dwc);
+static struct platform_driver dwc3_driver = {
+ .probe = dwc3_probe,
+ .remove = dwc3_remove,
+ .driver = {
+ .name = "dwc3",
+ .of_match_table = of_match_ptr(of_dwc3_match),
+ .acpi_match_table = ACPI_PTR(dwc3_acpi_match),
+ .pm = DWC3_PM_OPS,
+ },
+};
- return ret;
-}
+module_platform_driver(dwc3_driver);
-void dwc3_remove(struct dwc3 *dwc)
-{
- dwc3_core_exit_mode(dwc);
- dwc3_event_buffers_cleanup(dwc);
- dwc3_free_event_buffers(dwc);
- dwc3_core_stop(dwc);
- dwc3_core_exit(dwc);
- kfree(dwc->mem);
-}
-#endif
+MODULE_ALIAS("platform:dwc3");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b572ea340c8c..4bb9aa696ede 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1,28 +1,37 @@
-/* SPDX-License-Identifier: GPL-2.0 */
/**
* core.h - DesignWare USB3 DRD Core Header
*
- * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/core.h) and ported
- * to uboot.
- *
- * commit 460d098cb6 : usb: dwc3: make HIRD threshold configurable
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __DRIVERS_USB_DWC3_CORE_H
#define __DRIVERS_USB_DWC3_CORE_H
-#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
-#include <linux/usb/phy.h>
+
+#include <linux/phy/phy.h>
#define DWC3_MSG_MAX 500
@@ -75,7 +84,6 @@
#define DWC3_GCTL 0xc110
#define DWC3_GEVTEN 0xc114
#define DWC3_GSTS 0xc118
-#define DWC3_GUCTL1 0xc11c
#define DWC3_GSNPSID 0xc120
#define DWC3_GGPIO 0xc124
#define DWC3_GUID 0xc128
@@ -115,7 +123,6 @@
#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
#define DWC3_GHWPARAMS8 0xc600
-#define DWC3_GFLADJ 0xc630
/* Device Registers */
#define DWC3_DCFG 0xc700
@@ -139,17 +146,6 @@
/* Bit fields */
-/* Global SoC Bus Configuration INCRx Register 0 */
-#define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */
-#define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */
-#define DWC3_GSBUSCFG0_INCR64BRSTENA (1 << 5) /* INCR64 burst */
-#define DWC3_GSBUSCFG0_INCR32BRSTENA (1 << 4) /* INCR32 burst */
-#define DWC3_GSBUSCFG0_INCR16BRSTENA (1 << 3) /* INCR16 burst */
-#define DWC3_GSBUSCFG0_INCR8BRSTENA (1 << 2) /* INCR8 burst */
-#define DWC3_GSBUSCFG0_INCR4BRSTENA (1 << 1) /* INCR4 burst */
-#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */
-#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff
-
/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
#define DWC3_GCTL_U2RSTECN (1 << 16)
@@ -174,26 +170,9 @@
#define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1)
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
-/* Global User Control Register */
-#define DWC3_GUCTL_HSTINAUTORETRY BIT(14)
-
-/* Global User Control 1 Register */
-#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
-#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
-
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
-#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS (1 << 30)
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
-#define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8)
-#define DWC3_GUSB2PHYCFG_PHYIF(n) ((n) << 3)
-#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
-#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) ((n) << 10)
-#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
-#define USBTRDTIM_UTMI_8_BIT 9
-#define USBTRDTIM_UTMI_16_BIT 5
-#define UTMI_PHYIF_16_BIT 1
-#define UTMI_PHYIF_8_BIT 0
/* Global USB3 PIPE Control Register */
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
@@ -245,17 +224,6 @@
/* Global HWPARAMS6 Register */
#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
-/* Global Frame Length Adjustment Register */
-#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
-#define DWC3_GFLADJ_30MHZ_MASK 0x3f
-#define DWC3_GFLADJ_REFCLK_FLADJ_MASK GENMASK(21, 8)
-#define DWC3_GFLADJ_240MHZDECR GENMASK(30, 24)
-#define DWC3_GFLADJ_240MHZDECR_PLS1 BIT(31)
-
-/* Global User Control Register*/
-#define DWC3_GUCTL_REFCLKPER_MASK 0xffc00000
-#define DWC3_GUCTL_REFCLKPER_SEL 22
-
/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -405,8 +373,6 @@
#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0)
#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0)
-#define DWC3_DEPCMD_CMD(x) ((x) & 0xf)
-
/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
#define DWC3_DALEPENA_EP(n) (1 << n)
@@ -436,7 +402,7 @@ struct dwc3_event_buffer {
unsigned int count;
unsigned int flags;
-#define DWC3_EVENT_PENDING (1UL << 0)
+#define DWC3_EVENT_PENDING BIT(0)
dma_addr_t dma;
@@ -670,7 +636,6 @@ struct dwc3_scratchpad_array {
* @ep0_trb: dma address of ep0_trb
* @ep0_usb_req: dummy req used while handling STD USB requests
* @ep0_bounce_addr: dma address of ep0_bounce
- * @setup_buf_addr: dma address of setup_buf
* @scratch_addr: dma address of scratchbuf
* @lock: for synchronizing
* @dev: pointer to our struct device
@@ -678,19 +643,18 @@ struct dwc3_scratchpad_array {
* @event_buffer_list: a list of event buffers
* @gadget: device side representation of the peripheral controller
* @gadget_driver: pointer to the gadget driver
- * @ref_clk: reference clock
* @regs: base address for our registers
* @regs_size: address space size
- * @ref_clk_per: reference clock period configuration
* @nr_scratch: number of scratch buffers
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
* @dr_mode: requested mode of operation
- * @hsphy_mode: UTMI phy mode, one of following:
- * - USBPHY_INTERFACE_MODE_UTMI
- * - USBPHY_INTERFACE_MODE_UTMIW
+ * @usb2_phy: pointer to USB2 PHY
+ * @usb3_phy: pointer to USB3 PHY
+ * @usb2_generic_phy: pointer to USB2 PHY
+ * @usb3_generic_phy: pointer to USB3 PHY
* @dcfg: saved contents of DCFG register
* @gctl: saved contents of GCTL register
* @isoch_delay: wValue from Set Isochronous Delay request;
@@ -719,8 +683,8 @@ struct dwc3_scratchpad_array {
* @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
* there's now way for software to detect this in runtime.
* @is_utmi_l1_suspend: the core asserts output signal
- * 0 - utmi_sleep_n
- * 1 - utmi_l1_suspend_n
+ * 0 - utmi_sleep_n
+ * 1 - utmi_l1_suspend_n
* @is_selfpowered: true when we are selfpowered
* @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
@@ -741,12 +705,10 @@ struct dwc3_scratchpad_array {
* @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
* @tx_de_emphasis: Tx de-emphasis value
- * 0 - -6dB de-emphasis
- * 1 - -3.5dB de-emphasis
- * 2 - No de-emphasis
- * 3 - Reserved
- * @index: index of _this_ controller
- * @list: to maintain the list of dwc3 controllers
+ * 0 - -6dB de-emphasis
+ * 1 - -3.5dB de-emphasis
+ * 2 - No de-emphasis
+ * 3 - Reserved
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -758,17 +720,12 @@ struct dwc3 {
dma_addr_t ep0_trb_addr;
dma_addr_t ep0_bounce_addr;
dma_addr_t scratch_addr;
- dma_addr_t setup_buf_addr;
struct dwc3_request ep0_usb_req;
/* device lock */
spinlock_t lock;
-#if defined(__UBOOT__) && CONFIG_IS_ENABLED(DM_USB)
- struct udevice *dev;
-#else
struct device *dev;
-#endif
struct platform_device *xhci;
struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
@@ -779,13 +736,16 @@ struct dwc3 {
struct usb_gadget gadget;
struct usb_gadget_driver *gadget_driver;
- struct clk *ref_clk;
+ struct usb_phy *usb2_phy;
+ struct usb_phy *usb3_phy;
+
+ struct phy *usb2_generic_phy;
+ struct phy *usb3_generic_phy;
void __iomem *regs;
size_t regs_size;
enum usb_dr_mode dr_mode;
- enum usb_phy_interface hsphy_mode;
/* used for suspend/resume */
u32 dcfg;
@@ -816,7 +776,6 @@ struct dwc3 {
#define DWC3_REVISION_260A 0x5533260a
#define DWC3_REVISION_270A 0x5533270a
#define DWC3_REVISION_280A 0x5533280a
-#define DWC3_REVISION_290A 0x5533290a
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@@ -843,10 +802,6 @@ struct dwc3 {
u8 test_mode_nr;
u8 lpm_nyet_threshold;
u8 hird_threshold;
- u32 fladj;
- u32 ref_clk_per;
- u8 incrx_mode;
- u32 incrx_size;
unsigned delayed_status:1;
unsigned ep0_bounced:1;
@@ -873,20 +828,11 @@ struct dwc3 {
unsigned rx_detect_poll_quirk:1;
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
- unsigned dis_del_phy_power_chg_quirk:1;
- unsigned dis_tx_ipgap_linecheck_quirk:1;
- unsigned dis_enblslpm_quirk:1;
- unsigned dis_u2_freeclk_exists_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
- int index;
- struct list_head list;
};
-#define INCRX_BURST_MODE 0
-#define INCRX_UNDEF_LENGTH_BURST_MODE 1
-
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@@ -904,30 +850,6 @@ struct dwc3_event_type {
#define DWC3_DEPEVT_STREAMEVT 0x06
#define DWC3_DEPEVT_EPCMDCMPLT 0x07
-/**
- * dwc3_ep_event_string - returns event name
- * @event: then event code
- */
-static inline const char *dwc3_ep_event_string(u8 event)
-{
- switch (event) {
- case DWC3_DEPEVT_XFERCOMPLETE:
- return "Transfer Complete";
- case DWC3_DEPEVT_XFERINPROGRESS:
- return "Transfer In-Progress";
- case DWC3_DEPEVT_XFERNOTREADY:
- return "Transfer Not Ready";
- case DWC3_DEPEVT_RXTXFIFOEVT:
- return "FIFO";
- case DWC3_DEPEVT_STREAMEVT:
- return "Stream";
- case DWC3_DEPEVT_EPCMDCMPLT:
- return "Endpoint Command Complete";
- }
-
- return "UNKNOWN";
-}
-
/**
* struct dwc3_event_depvt - Device Endpoint Events
* @one_bit: indicates this is an endpoint event (not used)
@@ -1057,17 +979,20 @@ struct dwc3_gadget_ep_cmd_params {
#define DWC3_HAS_OTG BIT(3)
/* prototypes */
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
-void dwc3_of_parse(struct dwc3 *dwc);
-int dwc3_init(struct dwc3 *dwc);
-void dwc3_remove(struct dwc3 *dwc);
+#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_host_init(struct dwc3 *dwc);
+void dwc3_host_exit(struct dwc3 *dwc);
+#else
static inline int dwc3_host_init(struct dwc3 *dwc)
{ return 0; }
static inline void dwc3_host_exit(struct dwc3 *dwc)
{ }
+#endif
-#ifdef CONFIG_USB_DWC3_GADGET
+#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
@@ -1097,4 +1022,20 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
{ return 0; }
#endif
+/* power management interface */
+#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
+int dwc3_gadget_suspend(struct dwc3 *dwc);
+int dwc3_gadget_resume(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+ return 0;
+}
+
+static inline int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+ return 0;
+}
+#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
+
#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debug.c b/drivers/usb/dwc3/debug.c
new file mode 100644
index 000000000000..0be6885bc370
--- /dev/null
+++ b/drivers/usb/dwc3/debug.c
@@ -0,0 +1,32 @@
+/**
+ * debug.c - DesignWare USB3 DRD Controller Debug/Trace Support
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "debug.h"
+
+void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ trace(&vaf);
+
+ va_end(args);
+}
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
new file mode 100644
index 000000000000..07fbc2d94fd4
--- /dev/null
+++ b/drivers/usb/dwc3/debug.h
@@ -0,0 +1,228 @@
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DWC3_DEBUG_H
+#define __DWC3_DEBUG_H
+
+#include "core.h"
+
+/**
+ * dwc3_gadget_ep_cmd_string - returns endpoint command string
+ * @cmd: command code
+ */
+static inline const char *
+dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ case DWC3_DEPCMD_DEPSTARTCFG:
+ return "Start New Configuration";
+ case DWC3_DEPCMD_ENDTRANSFER:
+ return "End Transfer";
+ case DWC3_DEPCMD_UPDATETRANSFER:
+ return "Update Transfer";
+ case DWC3_DEPCMD_STARTTRANSFER:
+ return "Start Transfer";
+ case DWC3_DEPCMD_CLEARSTALL:
+ return "Clear Stall";
+ case DWC3_DEPCMD_SETSTALL:
+ return "Set Stall";
+ case DWC3_DEPCMD_GETEPSTATE:
+ return "Get Endpoint State";
+ case DWC3_DEPCMD_SETTRANSFRESOURCE:
+ return "Set Endpoint Transfer Resource";
+ case DWC3_DEPCMD_SETEPCONFIG:
+ return "Set Endpoint Configuration";
+ default:
+ return "UNKNOWN command";
+ }
+}
+
+/**
+ * dwc3_gadget_generic_cmd_string - returns generic command string
+ * @cmd: command code
+ */
+static inline const char *
+dwc3_gadget_generic_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ case DWC3_DGCMD_SET_LMP:
+ return "Set LMP";
+ case DWC3_DGCMD_SET_PERIODIC_PAR:
+ return "Set Periodic Parameters";
+ case DWC3_DGCMD_XMIT_FUNCTION:
+ return "Transmit Function Wake Device Notification";
+ case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
+ return "Set Scratchpad Buffer Array Address Lo";
+ case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
+ return "Set Scratchpad Buffer Array Address Hi";
+ case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
+ return "Selected FIFO Flush";
+ case DWC3_DGCMD_ALL_FIFO_FLUSH:
+ return "All FIFO Flush";
+ case DWC3_DGCMD_SET_ENDPOINT_NRDY:
+ return "Set Endpoint NRDY";
+ case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
+ return "Run SoC Bus Loopback Test";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/**
+ * dwc3_gadget_link_string - returns link name
+ * @link_state: link state code
+ */
+static inline const char *
+dwc3_gadget_link_string(enum dwc3_link_state link_state)
+{
+ switch (link_state) {
+ case DWC3_LINK_STATE_U0:
+ return "U0";
+ case DWC3_LINK_STATE_U1:
+ return "U1";
+ case DWC3_LINK_STATE_U2:
+ return "U2";
+ case DWC3_LINK_STATE_U3:
+ return "U3";
+ case DWC3_LINK_STATE_SS_DIS:
+ return "SS.Disabled";
+ case DWC3_LINK_STATE_RX_DET:
+ return "RX.Detect";
+ case DWC3_LINK_STATE_SS_INACT:
+ return "SS.Inactive";
+ case DWC3_LINK_STATE_POLL:
+ return "Polling";
+ case DWC3_LINK_STATE_RECOV:
+ return "Recovery";
+ case DWC3_LINK_STATE_HRESET:
+ return "Hot Reset";
+ case DWC3_LINK_STATE_CMPLY:
+ return "Compliance";
+ case DWC3_LINK_STATE_LPBK:
+ return "Loopback";
+ case DWC3_LINK_STATE_RESET:
+ return "Reset";
+ case DWC3_LINK_STATE_RESUME:
+ return "Resume";
+ default:
+ return "UNKNOWN link state\n";
+ }
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_string(u8 event)
+{
+ switch (event) {
+ case DWC3_DEVICE_EVENT_DISCONNECT:
+ return "Disconnect";
+ case DWC3_DEVICE_EVENT_RESET:
+ return "Reset";
+ case DWC3_DEVICE_EVENT_CONNECT_DONE:
+ return "Connection Done";
+ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+ return "Link Status Change";
+ case DWC3_DEVICE_EVENT_WAKEUP:
+ return "WakeUp";
+ case DWC3_DEVICE_EVENT_EOPF:
+ return "End-Of-Frame";
+ case DWC3_DEVICE_EVENT_SOF:
+ return "Start-Of-Frame";
+ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+ return "Erratic Error";
+ case DWC3_DEVICE_EVENT_CMD_CMPL:
+ return "Command Complete";
+ case DWC3_DEVICE_EVENT_OVERFLOW:
+ return "Overflow";
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(u8 event)
+{
+ switch (event) {
+ case DWC3_DEPEVT_XFERCOMPLETE:
+ return "Transfer Complete";
+ case DWC3_DEPEVT_XFERINPROGRESS:
+ return "Transfer In-Progress";
+ case DWC3_DEPEVT_XFERNOTREADY:
+ return "Transfer Not Ready";
+ case DWC3_DEPEVT_RXTXFIFOEVT:
+ return "FIFO";
+ case DWC3_DEPEVT_STREAMEVT:
+ return "Stream";
+ case DWC3_DEPEVT_EPCMDCMPLT:
+ return "Endpoint Command Complete";
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * dwc3_gadget_event_type_string - return event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_type_string(u8 event)
+{
+ switch (event) {
+ case DWC3_DEVICE_EVENT_DISCONNECT:
+ return "Disconnect";
+ case DWC3_DEVICE_EVENT_RESET:
+ return "Reset";
+ case DWC3_DEVICE_EVENT_CONNECT_DONE:
+ return "Connect Done";
+ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+ return "Link Status Change";
+ case DWC3_DEVICE_EVENT_WAKEUP:
+ return "Wake-Up";
+ case DWC3_DEVICE_EVENT_HIBER_REQ:
+ return "Hibernation";
+ case DWC3_DEVICE_EVENT_EOPF:
+ return "End of Periodic Frame";
+ case DWC3_DEVICE_EVENT_SOF:
+ return "Start of Frame";
+ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+ return "Erratic Error";
+ case DWC3_DEVICE_EVENT_CMD_CMPL:
+ return "Command Complete";
+ case DWC3_DEVICE_EVENT_OVERFLOW:
+ return "Overflow";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
+
+#ifdef CONFIG_DEBUG_FS
+extern int dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline int dwc3_debugfs_init(struct dwc3 *d)
+{ return 0; }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{ }
+#endif
+#endif /* __DWC3_DEBUG_H */
diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c
deleted file mode 100644
index 99519602eb2c..000000000000
--- a/drivers/usb/dwc3/dwc3-am62.c
+++ /dev/null
@@ -1,125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * TI AM62 specific glue layer for DWC3
- */
-
-#include <dm.h>
-#include <dm/device_compat.h>
-#include <regmap.h>
-#include <syscon.h>
-#include <asm/io.h>
-
-#include "dwc3-generic.h"
-
-#define USBSS_MODE_CONTROL 0x1c
-#define USBSS_PHY_CONFIG 0x8
-#define USBSS_PHY_VBUS_SEL_MASK GENMASK(2, 1)
-#define USBSS_PHY_VBUS_SEL_SHIFT 1
-#define USBSS_MODE_VALID BIT(0)
-#define PHY_PLL_REFCLK_MASK GENMASK(3, 0)
-static const int dwc3_ti_am62_rate_table[] = { /* in KHZ */
- 9600,
- 10000,
- 12000,
- 19200,
- 20000,
- 24000,
- 25000,
- 26000,
- 38400,
- 40000,
- 58000,
- 50000,
- 52000,
-};
-
-static void dwc3_ti_am62_glue_configure(struct udevice *dev, int index,
- enum usb_dr_mode mode)
-{
- struct clk usb2_refclk;
- int rate_code, i, ret;
- unsigned long rate;
- u32 reg;
- void *usbss;
- bool vbus_divider;
- struct regmap *syscon;
- struct ofnode_phandle_args args;
-
- usbss = dev_remap_addr_index(dev, 0);
- if (IS_ERR(usbss)) {
- dev_err(dev, "can't map IOMEM resource\n");
- return;
- }
-
- ret = clk_get_by_name(dev, "ref", &usb2_refclk);
- if (ret) {
- dev_err(dev, "can't get usb2_refclk\n");
- return;
- }
-
- /* Calculate the rate code */
- rate = clk_get_rate(&usb2_refclk);
- rate /= 1000; /* To KHz */
- for (i = 0; i < ARRAY_SIZE(dwc3_ti_am62_rate_table); i++) {
- if (dwc3_ti_am62_rate_table[i] == rate)
- break;
- }
-
- if (i == ARRAY_SIZE(dwc3_ti_am62_rate_table)) {
- dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
- return;
- }
-
- rate_code = i;
-
- /* Read the syscon property */
- syscon = syscon_regmap_lookup_by_phandle(dev, "ti,syscon-phy-pll-refclk");
- if (IS_ERR(syscon)) {
- dev_err(dev, "unable to get ti,syscon-phy-pll-refclk regmap\n");
- return;
- }
-
- ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "ti,syscon-phy-pll-refclk", NULL, 1,
- 0, &args);
- if (ret)
- return;
-
- /* Program PHY PLL refclk by reading syscon property */
- ret = regmap_update_bits(syscon, args.args[0], PHY_PLL_REFCLK_MASK, rate_code);
- if (ret) {
- dev_err(dev, "failed to set phy pll reference clock rate\n");
- return;
- }
-
- /* VBUS divider select */
- reg = readl(usbss + USBSS_PHY_CONFIG);
- vbus_divider = dev_read_bool(dev, "ti,vbus-divider");
- if (vbus_divider)
- reg |= 1 << USBSS_PHY_VBUS_SEL_SHIFT;
-
- writel(reg, usbss + USBSS_PHY_CONFIG);
-
- /* Set mode valid */
- reg = readl(usbss + USBSS_MODE_CONTROL);
- reg |= USBSS_MODE_VALID;
- writel(reg, usbss + USBSS_MODE_CONTROL);
-}
-
-struct dwc3_glue_ops ti_am62_ops = {
- .glue_configure = dwc3_ti_am62_glue_configure,
-};
-
-static const struct udevice_id dwc3_am62_match[] = {
- { .compatible = "ti,am62-usb", .data = (ulong)&ti_am62_ops },
- { /* sentinel */ }
-};
-
-U_BOOT_DRIVER(dwc3_am62_wrapper) = {
- .name = "dwc3-am62",
- .id = UCLASS_SIMPLE_BUS,
- .of_match = dwc3_am62_match,
- .bind = dwc3_glue_bind,
- .probe = dwc3_glue_probe,
- .remove = dwc3_glue_remove,
- .plat_auto = sizeof(struct dwc3_glue_data),
-};
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 680756532f0d..1bc77a3b4997 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -1,34 +1,40 @@
-// SPDX-License-Identifier: GPL-2.0
/**
* ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
*
- * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/ep0.c) and ported
- * to uboot.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * commit c00552ebaf : Merge 3.18-rc7 into usb-next
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
-#include <cpu_func.h>
-#include <dm.h>
-#include <dm/device_compat.h>
-#include <linux/bug.h>
+
#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/list.h>
+#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include "core.h"
+#include "debug.h"
#include "gadget.h"
#include "io.h"
-#include "linux-compat.h"
-
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
struct dwc3_ep *dep, struct dwc3_request *req);
@@ -50,7 +56,7 @@ static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
}
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
- u32 len, u32 type, unsigned chain)
+ u32 len, u32 type)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_trb *trb;
@@ -60,14 +66,11 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
dep = dwc->eps[epnum];
if (dep->flags & DWC3_EP_BUSY) {
- dev_vdbg(dwc->dev, "%s still busy\n", dep->name);
+ dwc3_trace(trace_dwc3_ep0, "%s still busy", dep->name);
return 0;
}
- trb = &dwc->ep0_trb[dep->free_slot];
-
- if (chain)
- dep->free_slot++;
+ trb = dwc->ep0_trb;
trb->bpl = lower_32_bits(buf_dma);
trb->bph = upper_32_bits(buf_dma);
@@ -75,28 +78,21 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
trb->ctrl = type;
trb->ctrl |= (DWC3_TRB_CTRL_HWO
+ | DWC3_TRB_CTRL_LST
+ | DWC3_TRB_CTRL_IOC
| DWC3_TRB_CTRL_ISP_IMI);
- if (chain)
- trb->ctrl |= DWC3_TRB_CTRL_CHN;
- else
- trb->ctrl |= (DWC3_TRB_CTRL_IOC
- | DWC3_TRB_CTRL_LST);
-
- dwc3_flush_cache((uintptr_t)buf_dma, len);
- dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
-
- if (chain)
- return 0;
-
memset(¶ms, 0, sizeof(params));
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
+ trace_dwc3_prepare_trb(dep, trb);
+
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_STARTTRANSFER, ¶ms);
if (ret < 0) {
- dev_dbg(dwc->dev, "%s STARTTRANSFER failed", dep->name);
+ dwc3_trace(trace_dwc3_ep0, "%s STARTTRANSFER failed",
+ dep->name);
return ret;
}
@@ -161,7 +157,8 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
if (dwc->ep0state == EP0_STATUS_PHASE)
__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
else
- dev_dbg(dwc->dev, "too early for delayed status");
+ dwc3_trace(trace_dwc3_ep0,
+ "too early for delayed status");
return 0;
}
@@ -225,7 +222,8 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
spin_lock_irqsave(&dwc->lock, flags);
if (!dep->endpoint.desc) {
- dev_dbg(dwc->dev, "trying to queue request %p to disabled %s",
+ dwc3_trace(trace_dwc3_ep0,
+ "trying to queue request %p to disabled %s",
request, dep->name);
ret = -ESHUTDOWN;
goto out;
@@ -237,9 +235,10 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
goto out;
}
- dev_vdbg(dwc->dev, "queueing request %p to %s length %d state '%s\n'",
- request, dep->name, request->length,
- dwc3_ep0_state_string(dwc->ep0state));
+ dwc3_trace(trace_dwc3_ep0,
+ "queueing request %p to %s length %d state '%s'",
+ request, dep->name, request->length,
+ dwc3_ep0_state_string(dwc->ep0state));
ret = __dwc3_gadget_ep0_queue(dep, req);
@@ -286,6 +285,8 @@ int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int ret;
@@ -301,7 +302,7 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
int ret;
ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
- DWC3_TRBCTL_CONTROL_SETUP, 0);
+ DWC3_TRBCTL_CONTROL_SETUP);
WARN_ON(ret < 0);
}
@@ -380,7 +381,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
dep = dwc->eps[0];
dwc->ep0_usb_req.dep = dep;
dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
- dwc->ep0_usb_req.request.buf = (void *)(uintptr_t)dwc->setup_buf_addr;
+ dwc->ep0_usb_req.request.buf = dwc->setup_buf;
dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
@@ -504,12 +505,13 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
addr = le16_to_cpu(ctrl->wValue);
if (addr > 127) {
- dev_dbg(dwc->dev, "invalid device address %d", addr);
+ dwc3_trace(trace_dwc3_ep0, "invalid device address %d", addr);
return -EINVAL;
}
if (state == USB_STATE_CONFIGURED) {
- dev_dbg(dwc->dev, "trying to set address when configured");
+ dwc3_trace(trace_dwc3_ep0,
+ "trying to set address when configured");
return -EINVAL;
}
@@ -574,7 +576,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->resize_fifos = true;
- dev_dbg(dwc->dev, "resize FIFOs flag SET");
+ dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
}
break;
@@ -639,10 +641,12 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
struct dwc3_ep *dep;
enum usb_device_state state = dwc->gadget.state;
u16 wLength;
+ u16 wValue;
if (state == USB_STATE_DEFAULT)
return -EINVAL;
+ wValue = le16_to_cpu(ctrl->wValue);
wLength = le16_to_cpu(ctrl->wLength);
if (wLength != 6) {
@@ -662,7 +666,7 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dep = dwc->eps[0];
dwc->ep0_usb_req.dep = dep;
dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
- dwc->ep0_usb_req.request.buf = (void *)(uintptr_t)dwc->setup_buf_addr;
+ dwc->ep0_usb_req.request.buf = dwc->setup_buf;
dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
@@ -696,35 +700,35 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
switch (ctrl->bRequest) {
case USB_REQ_GET_STATUS:
- dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_GET_STATUS");
ret = dwc3_ep0_handle_status(dwc, ctrl);
break;
case USB_REQ_CLEAR_FEATURE:
- dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_CLEAR_FEATURE");
ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
break;
case USB_REQ_SET_FEATURE:
- dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_FEATURE");
ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
break;
case USB_REQ_SET_ADDRESS:
- dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ADDRESS");
ret = dwc3_ep0_set_address(dwc, ctrl);
break;
case USB_REQ_SET_CONFIGURATION:
- dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_CONFIGURATION");
ret = dwc3_ep0_set_config(dwc, ctrl);
break;
case USB_REQ_SET_SEL:
- dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_SEL");
ret = dwc3_ep0_set_sel(dwc, ctrl);
break;
case USB_REQ_SET_ISOCH_DELAY:
- dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
break;
default:
- dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
+ dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
ret = dwc3_ep0_delegate_req(dwc, ctrl);
break;
}
@@ -742,7 +746,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
if (!dwc->gadget_driver)
goto out;
- dwc3_invalidate_cache((uintptr_t)ctrl, sizeof(*ctrl));
+ trace_dwc3_ctrl_req(ctrl);
len = le16_to_cpu(ctrl->wLength);
if (!len) {
@@ -775,10 +779,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
struct usb_request *ur;
struct dwc3_trb *trb;
struct dwc3_ep *ep0;
- unsigned transfer_size = 0;
- unsigned maxp;
- void *buf;
- u32 transferred = 0;
+ u32 transferred;
u32 status;
u32 length;
u8 epnum;
@@ -790,50 +791,34 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
trb = dwc->ep0_trb;
+ trace_dwc3_complete_trb(ep0, trb);
+
r = next_request(&ep0->request_list);
if (!r)
return;
- dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
-
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (status == DWC3_TRBSTS_SETUP_PENDING) {
- dev_dbg(dwc->dev, "Setup Pending received");
- dwc3_gadget_giveback(ep0, r, -ECONNRESET);
+ dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
+
+ if (r)
+ dwc3_gadget_giveback(ep0, r, -ECONNRESET);
+
return;
}
ur = &r->request;
- buf = ur->buf;
length = trb->size & DWC3_TRB_SIZE_MASK;
- maxp = ep0->endpoint.maxpacket;
-
if (dwc->ep0_bounced) {
- /*
- * Handle the first TRB before handling the bounce buffer if
- * the request length is greater than the bounce buffer size.
- */
- if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
- transfer_size = (ur->length / maxp) * maxp;
- transferred = transfer_size - length;
- buf = (u8 *)buf + transferred;
- ur->actual += transferred;
+ unsigned transfer_size = ur->length;
+ unsigned maxp = ep0->endpoint.maxpacket;
- trb++;
- dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
- length = trb->size & DWC3_TRB_SIZE_MASK;
-
- ep0->free_slot = 0;
- }
-
- transfer_size = roundup((ur->length - transfer_size),
- maxp);
- transferred = min_t(u32, ur->length - transferred,
- transfer_size - length);
- dwc3_flush_cache((uintptr_t)dwc->ep0_bounce, DWC3_EP0_BOUNCE_SIZE);
- memcpy(buf, dwc->ep0_bounce, transferred);
+ transfer_size += (maxp - (transfer_size % maxp));
+ transferred = min_t(u32, ur->length,
+ transfer_size - length);
+ memcpy(ur->buf, dwc->ep0_bounce, transferred);
} else {
transferred = ur->length - length;
}
@@ -855,7 +840,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
ret = dwc3_ep0_start_trans(dwc, epnum,
dwc->ctrl_req_addr, 0,
- DWC3_TRBCTL_CONTROL_DATA, 0);
+ DWC3_TRBCTL_CONTROL_DATA);
WARN_ON(ret < 0);
}
}
@@ -872,6 +857,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
dep = dwc->eps[0];
trb = dwc->ep0_trb;
+ trace_dwc3_complete_trb(dep, trb);
+
if (!list_empty(&dep->request_list)) {
r = next_request(&dep->request_list);
@@ -883,7 +870,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
if (ret < 0) {
- dev_dbg(dwc->dev, "Invalid Test #%d",
+ dwc3_trace(trace_dwc3_ep0, "Invalid Test #%d",
dwc->test_mode_nr);
dwc3_ep0_stall_and_restart(dwc);
return;
@@ -892,7 +879,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (status == DWC3_TRBSTS_SETUP_PENDING)
- dev_dbg(dwc->dev, "Setup Pending received");
+ dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
@@ -909,17 +896,17 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
switch (dwc->ep0state) {
case EP0_SETUP_PHASE:
- dev_vdbg(dwc->dev, "Setup Phase\n");
+ dwc3_trace(trace_dwc3_ep0, "Setup Phase");
dwc3_ep0_inspect_setup(dwc, event);
break;
case EP0_DATA_PHASE:
- dev_vdbg(dwc->dev, "Data Phase\n");
+ dwc3_trace(trace_dwc3_ep0, "Data Phase");
dwc3_ep0_complete_data(dwc, event);
break;
case EP0_STATUS_PHASE:
- dev_vdbg(dwc->dev, "Status Phase\n");
+ dwc3_trace(trace_dwc3_ep0, "Status Phase");
dwc3_ep0_complete_status(dwc, event);
break;
default:
@@ -936,11 +923,11 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
if (req->request.length == 0) {
ret = dwc3_ep0_start_trans(dwc, dep->number,
- dwc->ctrl_req_addr, 0,
- DWC3_TRBCTL_CONTROL_DATA, 0);
- } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
- (dep->number == 0)) {
- u32 transfer_size = 0;
+ dwc->ctrl_req_addr, 0,
+ DWC3_TRBCTL_CONTROL_DATA);
+ } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
+ && (dep->number == 0)) {
+ u32 transfer_size;
u32 maxpacket;
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
@@ -950,18 +937,10 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
return;
}
- maxpacket = dep->endpoint.maxpacket;
- if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
- transfer_size = (req->request.length / maxpacket) *
- maxpacket;
- ret = dwc3_ep0_start_trans(dwc, dep->number,
- req->request.dma,
- transfer_size,
- DWC3_TRBCTL_CONTROL_DATA, 1);
- }
+ WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
- transfer_size = roundup((req->request.length - transfer_size),
- maxpacket);
+ maxpacket = dep->endpoint.maxpacket;
+ transfer_size = roundup(req->request.length, maxpacket);
dwc->ep0_bounced = true;
@@ -971,8 +950,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
* TRBs to handle the transfer.
*/
ret = dwc3_ep0_start_trans(dwc, dep->number,
- dwc->ep0_bounce_addr, transfer_size,
- DWC3_TRBCTL_CONTROL_DATA, 0);
+ dwc->ep0_bounce_addr, transfer_size,
+ DWC3_TRBCTL_CONTROL_DATA);
} else {
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
dep->number);
@@ -982,8 +961,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
}
ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
- req->request.length,
- DWC3_TRBCTL_CONTROL_DATA, 0);
+ req->request.length, DWC3_TRBCTL_CONTROL_DATA);
}
WARN_ON(ret < 0);
@@ -998,13 +976,13 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
: DWC3_TRBCTL_CONTROL_STATUS2;
return dwc3_ep0_start_trans(dwc, dep->number,
- dwc->ctrl_req_addr, 0, type, 0);
+ dwc->ctrl_req_addr, 0, type);
}
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
{
if (dwc->resize_fifos) {
- dev_dbg(dwc->dev, "Resizing FIFOs");
+ dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
dwc3_gadget_resize_tx_fifos(dwc);
dwc->resize_fifos = 0;
}
@@ -1045,7 +1023,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
switch (event->status) {
case DEPEVT_STATUS_CONTROL_DATA:
- dev_vdbg(dwc->dev, "Control Data\n");
+ dwc3_trace(trace_dwc3_ep0, "Control Data");
/*
* We already have a DATA transfer in the controller's cache,
@@ -1059,7 +1037,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
if (dwc->ep0_expect_in != event->endpoint_number) {
struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in];
- dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
+ dwc3_trace(trace_dwc3_ep0,
+ "Wrong direction for Data phase");
dwc3_ep0_end_control_data(dwc, dep);
dwc3_ep0_stall_and_restart(dwc);
return;
@@ -1071,13 +1050,13 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS)
return;
- dev_vdbg(dwc->dev, "Control Status\n");
+ dwc3_trace(trace_dwc3_ep0, "Control Status");
dwc->ep0state = EP0_STATUS_PHASE;
if (dwc->delayed_status) {
WARN_ON_ONCE(event->endpoint_number != 1);
- dev_vdbg(dwc->dev, "Delayed Status\n");
+ dwc3_trace(trace_dwc3_ep0, "Delayed Status");
return;
}
@@ -1090,10 +1069,10 @@ void dwc3_ep0_interrupt(struct dwc3 *dwc,
{
u8 epnum = event->endpoint_number;
- dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
- dwc3_ep_event_string(event->endpoint_event),
- epnum >> 1, (epnum & 1) ? "in" : "out",
- dwc3_ep0_state_string(dwc->ep0state));
+ dwc3_trace(trace_dwc3_ep0, "%s while ep%d%s in state '%s'",
+ dwc3_ep_event_string(event->endpoint_event),
+ epnum >> 1, (epnum & 1) ? "in" : "out",
+ dwc3_ep0_state_string(dwc->ep0state));
switch (event->endpoint_event) {
case DWC3_DEPEVT_XFERCOMPLETE:
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2b01113d54cd..f03b136ecfce 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1,39 +1,40 @@
-// SPDX-License-Identifier: GPL-2.0
/**
* gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
*
- * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/gadget.c) and ported
- * to uboot.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * commit 8e74475b0e : usb: dwc3: gadget: use udc-core's reset notifier
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
-#include <cpu_func.h>
-#include <log.h>
-#include <malloc.h>
-#include <dm.h>
-#include <dm/device_compat.h>
-#include <dm/devres.h>
-#include <linux/bug.h>
+#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/list.h>
-#include <linux/printk.h>
+#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include "debug.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
-#include "linux-compat.h"
-
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
@@ -167,6 +168,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
{
int last_fifo_depth = 0;
+ int ram1_depth;
int fifo_size;
int mdwidth;
int num;
@@ -174,6 +176,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
if (!dwc->needs_fifo_resize)
return 0;
+ ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
/* MDWIDTH is represented in bits, we need it in bytes */
@@ -231,38 +234,40 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status)
{
struct dwc3 *dwc = dep->dwc;
+ int i;
if (req->queued) {
- dep->busy_slot++;
- /*
- * Skip LINK TRB. We can't use req->trb and check for
- * DWC3_TRBCTL_LINK_TRB because it points the TRB we
- * just completed (not the LINK TRB).
- */
- if (((dep->busy_slot & DWC3_TRB_MASK) ==
- DWC3_TRB_NUM- 1) &&
- usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ i = 0;
+ do {
dep->busy_slot++;
+ /*
+ * Skip LINK TRB. We can't use req->trb and check for
+ * DWC3_TRBCTL_LINK_TRB because it points the TRB we
+ * just completed (not the LINK TRB).
+ */
+ if (((dep->busy_slot & DWC3_TRB_MASK) ==
+ DWC3_TRB_NUM- 1) &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ dep->busy_slot++;
+ } while(++i < req->request.num_mapped_sgs);
req->queued = false;
}
-
list_del(&req->list);
req->trb = NULL;
- if (req->request.dma && req->request.length)
- dwc3_flush_cache((uintptr_t)req->request.dma, req->request.length);
if (req->request.status == -EINPROGRESS)
req->request.status = status;
if (dwc->ep0_bounced && dep->number == 0)
dwc->ep0_bounced = false;
- else if (req->request.dma)
+ else
usb_gadget_unmap_request(&dwc->gadget, &req->request,
req->direction);
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
req, dep->name, req->request.actual,
req->request.length, status);
+ trace_dwc3_gadget_giveback(req);
spin_unlock(&dwc->lock);
usb_gadget_giveback_request(&dep->endpoint, &req->request);
@@ -274,6 +279,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
u32 timeout = 500;
u32 reg;
+ trace_dwc3_gadget_generic_cmd(cmd, param);
+
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
@@ -299,38 +306,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
+ struct dwc3_ep *dep = dwc->eps[ep];
u32 timeout = 500;
- u32 saved_config = 0;
u32 reg;
- int ret = -EINVAL;
-
- /*
- * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or
- * GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an
- * endpoint command.
- *
- * Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY
- * settings. Restore them after the command is completed.
- *
- * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
- */
- if (dwc->gadget.speed <= USB_SPEED_HIGH ||
- DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER) {
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
- if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
- saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
- reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
- }
-
- if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) {
- saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM;
- reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
- }
-
- if (saved_config)
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
- }
+ trace_dwc3_gadget_ep_cmd(dep, cmd, params);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
@@ -342,8 +322,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
if (!(reg & DWC3_DEPCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
DWC3_DEPCMD_STATUS(reg));
- ret = 0;
- break;
+ return 0;
}
/*
@@ -351,21 +330,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
* interrupt context.
*/
timeout--;
- if (!timeout) {
- ret = -ETIMEDOUT;
- break;
- }
+ if (!timeout)
+ return -ETIMEDOUT;
udelay(1);
} while (1);
-
- if (saved_config) {
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
- reg |= saved_config;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
- }
-
- return ret;
}
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
@@ -378,15 +347,17 @@ static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
{
+ struct dwc3 *dwc = dep->dwc;
+
if (dep->trb_pool)
return 0;
if (dep->number == 0 || dep->number == 1)
return 0;
- dep->trb_pool = dma_alloc_coherent(sizeof(struct dwc3_trb) *
- DWC3_TRB_NUM,
- (unsigned long *)&dep->trb_pool_dma);
+ dep->trb_pool = dma_alloc_coherent(dwc->dev,
+ sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+ &dep->trb_pool_dma, GFP_KERNEL);
if (!dep->trb_pool) {
dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
dep->name);
@@ -398,7 +369,10 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
static void dwc3_free_trb_pool(struct dwc3_ep *dep)
{
- dma_free_coherent(dep->trb_pool);
+ struct dwc3 *dwc = dep->dwc;
+
+ dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+ dep->trb_pool, dep->trb_pool_dma);
dep->trb_pool = NULL;
dep->trb_pool_dma = 0;
@@ -640,6 +614,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
struct dwc3_ep *dep;
+ struct dwc3 *dwc;
unsigned long flags;
int ret;
@@ -654,9 +629,10 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
}
dep = to_dwc3_ep(ep);
+ dwc = dep->dwc;
if (dep->flags & DWC3_EP_ENABLED) {
- WARN(true, "%s is already enabled\n",
+ dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
dep->name);
return 0;
}
@@ -675,7 +651,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
strlcat(dep->name, "-int", sizeof(dep->name));
break;
default:
- dev_err(dep->dwc->dev, "invalid endpoint transfer type\n");
+ dev_err(dwc->dev, "invalid endpoint transfer type\n");
}
spin_lock_irqsave(&dwc->lock, flags);
@@ -688,6 +664,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
static int dwc3_gadget_ep_disable(struct usb_ep *ep)
{
struct dwc3_ep *dep;
+ struct dwc3 *dwc;
unsigned long flags;
int ret;
@@ -697,9 +674,10 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
}
dep = to_dwc3_ep(ep);
+ dwc = dep->dwc;
if (!(dep->flags & DWC3_EP_ENABLED)) {
- WARN(true, "%s is already disabled\n",
+ dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
dep->name);
return 0;
}
@@ -728,6 +706,8 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
req->epnum = dep->number;
req->dep = dep;
+ trace_dwc3_alloc_request(req);
+
return &req->request;
}
@@ -736,6 +716,7 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
{
struct dwc3_request *req = to_dwc3_request(request);
+ trace_dwc3_free_request(req);
kfree(req);
}
@@ -748,11 +729,14 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, dma_addr_t dma,
unsigned length, unsigned last, unsigned chain, unsigned node)
{
+ struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
- dev_vdbg(dep->dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
- dep->name, req, (unsigned long long)dma,
- length, last ? " last" : "", chain ? " chain" : "");
+ dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+ dep->name, req, (unsigned long long) dma,
+ length, last ? " last" : "",
+ chain ? " chain" : "");
+
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
@@ -815,8 +799,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->ctrl |= DWC3_TRB_CTRL_HWO;
- dwc3_flush_cache((uintptr_t)dma, length);
- dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
+ trace_dwc3_prepare_trb(dep, trb);
}
/*
@@ -833,6 +816,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
struct dwc3_request *req, *n;
u32 trbs_left;
u32 max;
+ unsigned int last_one = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
@@ -882,14 +866,59 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
list_for_each_entry_safe(req, n, &dep->request_list, list) {
unsigned length;
dma_addr_t dma;
+ last_one = false;
- dma = req->request.dma;
- length = req->request.length;
+ if (req->request.num_mapped_sgs > 0) {
+ struct usb_request *request = &req->request;
+ struct scatterlist *sg = request->sg;
+ struct scatterlist *s;
+ int i;
- dwc3_prepare_one_trb(dep, req, dma, length,
- true, false, 0);
+ for_each_sg(sg, s, request->num_mapped_sgs, i) {
+ unsigned chain = true;
- break;
+ length = sg_dma_len(s);
+ dma = sg_dma_address(s);
+
+ if (i == (request->num_mapped_sgs - 1) ||
+ sg_is_last(s)) {
+ if (list_is_last(&req->list,
+ &dep->request_list))
+ last_one = true;
+ chain = false;
+ }
+
+ trbs_left--;
+ if (!trbs_left)
+ last_one = true;
+
+ if (last_one)
+ chain = false;
+
+ dwc3_prepare_one_trb(dep, req, dma, length,
+ last_one, chain, i);
+
+ if (last_one)
+ break;
+ }
+ } else {
+ dma = req->request.dma;
+ length = req->request.length;
+ trbs_left--;
+
+ if (!trbs_left)
+ last_one = 1;
+
+ /* Is this the last request? */
+ if (list_is_last(&req->list, &dep->request_list))
+ last_one = 1;
+
+ dwc3_prepare_one_trb(dep, req, dma, length,
+ last_one, false, 0);
+
+ if (last_one)
+ break;
+ }
}
}
@@ -1007,14 +1036,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
req->direction = dep->direction;
req->epnum = dep->number;
- /*
- * DWC3 hangs on OUT requests smaller than maxpacket size,
- * so HACK the request length
- */
- if (dep->direction == 0 &&
- req->request.length < dep->endpoint.maxpacket)
- req->request.length = dep->endpoint.maxpacket;
-
/*
* We only add to our list of requests now and
* start consuming the list once we get XferNotReady
@@ -1094,6 +1115,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (ret && ret != -EBUSY) {
+ struct dwc3 *dwc = dep->dwc;
+
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
}
@@ -1107,6 +1130,7 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
{
struct dwc3_request *req = to_dwc3_request(request);
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
unsigned long flags;
@@ -1114,22 +1138,21 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
spin_lock_irqsave(&dwc->lock, flags);
if (!dep->endpoint.desc) {
- dev_dbg(dep->dwc->dev,
- "trying to queue request %p to disabled %s\n", request,
- ep->name);
+ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+ request, ep->name);
ret = -ESHUTDOWN;
goto out;
}
- if (req->dep != dep) {
- WARN(true, "request %p belongs to '%s'\n", request,
- req->dep->name);
+ if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
+ request, req->dep->name)) {
ret = -EINVAL;
goto out;
}
- dev_vdbg(dep->dwc->dev, "queing request %p to %s length %d\n",
- request, ep->name, request->length);
+ dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
+ request, ep->name, request->length);
+ trace_dwc3_ep_queue(req);
ret = __dwc3_gadget_ep_queue(dep, req);
@@ -1151,6 +1174,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
unsigned long flags;
int ret = 0;
+ trace_dwc3_ep_dequeue(req);
+
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry(r, &dep->request_list, list) {
@@ -1229,6 +1254,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
unsigned long flags;
@@ -1244,6 +1270,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int ret;
@@ -1359,9 +1386,9 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
}
/* poll until Link State changes to ON */
- timeout = 1000;
+ timeout = jiffies + msecs_to_jiffies(100);
- while (timeout--) {
+ while (!time_after(jiffies, timeout)) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
/* in HS, means ON */
@@ -1486,6 +1513,9 @@ static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
}
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
+
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
@@ -1493,14 +1523,24 @@ static int dwc3_gadget_start(struct usb_gadget *g,
struct dwc3_ep *dep;
unsigned long flags;
int ret = 0;
+ int irq;
u32 reg;
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+ IRQF_SHARED, "dwc3", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ irq, ret);
+ goto err0;
+ }
+
spin_lock_irqsave(&dwc->lock, flags);
if (dwc->gadget_driver) {
dev_err(dwc->dev, "%s is already bound to %s\n",
dwc->gadget.name,
- dwc->gadget_driver->function);
+ dwc->gadget_driver->driver.name);
ret = -EBUSY;
goto err1;
}
@@ -1584,6 +1624,9 @@ err2:
err1:
spin_unlock_irqrestore(&dwc->lock, flags);
+ free_irq(irq, dwc);
+
+err0:
return ret;
}
@@ -1591,6 +1634,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
+ int irq;
spin_lock_irqsave(&dwc->lock, flags);
@@ -1602,56 +1646,10 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
spin_unlock_irqrestore(&dwc->lock, flags);
- return 0;
-}
-
-static struct usb_ep *dwc3_find_ep(struct usb_gadget *gadget, const char *name)
-{
- struct usb_ep *ep;
-
- list_for_each_entry(ep, &gadget->ep_list, ep_list)
- if (!strcmp(ep->name, name))
- return ep;
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ free_irq(irq, dwc);
- return NULL;
-}
-
-static struct
-usb_ep *dwc3_gadget_match_ep(struct usb_gadget *gadget,
- struct usb_endpoint_descriptor *desc,
- struct usb_ss_ep_comp_descriptor *comp_desc)
-{
- /*
- * First try standard, common configuration: ep1in-bulk,
- * ep2out-bulk, ep3in-int to match other udc drivers to avoid
- * confusion in already deployed software (endpoint numbers
- * hardcoded in userspace software/drivers)
- */
- if (usb_endpoint_is_bulk_in(desc))
- return dwc3_find_ep(gadget, "ep1in");
- if (usb_endpoint_is_bulk_out(desc))
- return dwc3_find_ep(gadget, "ep2out");
- if (usb_endpoint_is_int_in(desc)) {
- /*
- * Special workaround for NXP UUU tool in SPL.
- *
- * The tool expects the interrupt-in endpoint to be ep1in,
- * otherwise it crashes. This is a result of the previous
- * hard-coded EP setup in drivers/usb/gadget/epautoconf.c
- * which did special-case EP allocation for SPL builds,
- * and which was since converted to this callback, but
- * without the special-case EP allocation in SPL part.
- *
- * This reinstates the SPL part in an isolated manner,
- * only for NXP iMX SoCs, only for SPL builds, and only
- * for the ep1in interrupt-in endpoint.
- */
- if (IS_ENABLED(CONFIG_MACH_IMX) && IS_ENABLED(CONFIG_XPL_BUILD))
- return dwc3_find_ep(gadget, "ep1in");
- return dwc3_find_ep(gadget, "ep3in");
- }
-
- return NULL;
+ return 0;
}
static const struct usb_gadget_ops dwc3_gadget_ops = {
@@ -1661,7 +1659,6 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
- .match_ep = dwc3_gadget_match_ep,
};
/* -------------------------------------------------------------------------- */
@@ -1700,7 +1697,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
} else {
int ret;
- usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
+ usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);
dep->endpoint.max_streams = 15;
dep->endpoint.ops = &dwc3_gadget_ep_ops;
list_add_tail(&dep->endpoint.ep_list,
@@ -1776,6 +1773,8 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
unsigned int s_pkt = 0;
unsigned int trb_status;
+ trace_dwc3_complete_trb(dep, trb);
+
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
/*
* We continue despite the error. There is not much we
@@ -1850,23 +1849,35 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
struct dwc3_request *req;
struct dwc3_trb *trb;
unsigned int slot;
+ unsigned int i;
+ int ret;
- req = next_request(&dep->req_queued);
- if (!req) {
- WARN_ON_ONCE(1);
- return 1;
- }
+ do {
+ req = next_request(&dep->req_queued);
+ if (!req) {
+ WARN_ON_ONCE(1);
+ return 1;
+ }
+ i = 0;
+ do {
+ slot = req->start_slot + i;
+ if ((slot == DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ slot++;
+ slot %= DWC3_TRB_NUM;
+ trb = &dep->trb_pool[slot];
+
+ ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+ event, status);
+ if (ret)
+ break;
+ }while (++i < req->request.num_mapped_sgs);
- slot = req->start_slot;
- if ((slot == DWC3_TRB_NUM - 1) &&
- usb_endpoint_xfer_isoc(dep->endpoint.desc))
- slot++;
- slot %= DWC3_TRB_NUM;
- trb = &dep->trb_pool[slot];
+ dwc3_gadget_giveback(dep, req, status);
- dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
- __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
- dwc3_gadget_giveback(dep, req, status);
+ if (ret)
+ break;
+ } while (1);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
@@ -2299,8 +2310,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
* BESL value in the LPM token is less than or equal to LPM
* NYET threshold.
*/
- if (dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum)
- WARN(true, "LPM Erratum not available on dwc3 revisisions < 2.40a\n");
+ WARN_ONCE(dwc->revision < DWC3_REVISION_240A
+ && dwc->has_lpm_erratum,
+ "LPM Erratum not available on dwc3 revisisions < 2.40a\n");
if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A)
reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold);
@@ -2449,7 +2461,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
- unsigned int is_ss = evtinfo & (1UL << 4);
+ unsigned int is_ss = evtinfo & BIT(4);
/**
* WORKAROUND: DWC3 revison 2.20a with hibernation support
@@ -2487,10 +2499,10 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
dwc3_gadget_wakeup_interrupt(dwc);
break;
case DWC3_DEVICE_EVENT_HIBER_REQ:
- if (!dwc->has_hibernation) {
- WARN(1 ,"unexpected hibernation event\n");
+ if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
+ "unexpected hibernation event\n"))
break;
- }
+
dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
@@ -2519,6 +2531,8 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
static void dwc3_process_event_entry(struct dwc3 *dwc,
const union dwc3_event *event)
{
+ trace_dwc3_event(event->raw);
+
/* Endpoint IRQ, handle it and return early */
if (event->type.is_devspec == 0) {
/* depevt */
@@ -2551,8 +2565,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
while (left > 0) {
union dwc3_event event;
- dwc3_invalidate_cache((uintptr_t)evt->buf, evt->length);
-
event.raw = *(u32 *) (evt->buf + evt->lpos);
dwc3_process_event_entry(dwc, &event);
@@ -2656,31 +2668,31 @@ int dwc3_gadget_init(struct dwc3 *dwc)
{
int ret;
- dwc->ctrl_req = dma_alloc_coherent(sizeof(*dwc->ctrl_req),
- (unsigned long *)&dwc->ctrl_req_addr);
+ dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ &dwc->ctrl_req_addr, GFP_KERNEL);
if (!dwc->ctrl_req) {
dev_err(dwc->dev, "failed to allocate ctrl request\n");
ret = -ENOMEM;
goto err0;
}
- dwc->ep0_trb = dma_alloc_coherent(sizeof(*dwc->ep0_trb) * 2,
- (unsigned long *)&dwc->ep0_trb_addr);
+ dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ &dwc->ep0_trb_addr, GFP_KERNEL);
if (!dwc->ep0_trb) {
dev_err(dwc->dev, "failed to allocate ep0 trb\n");
ret = -ENOMEM;
goto err1;
}
- dwc->setup_buf = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE,
- (unsigned long *)&dwc->setup_buf_addr);
+ dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
if (!dwc->setup_buf) {
ret = -ENOMEM;
goto err2;
}
- dwc->ep0_bounce = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE,
- (unsigned long *)&dwc->ep0_bounce_addr);
+ dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
+ DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
+ GFP_KERNEL);
if (!dwc->ep0_bounce) {
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
ret = -ENOMEM;
@@ -2690,6 +2702,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
+ dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
/*
@@ -2707,7 +2720,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
if (ret)
goto err4;
- ret = usb_add_gadget_udc((struct device *)dwc->dev, &dwc->gadget);
+ ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
goto err4;
@@ -2717,16 +2730,19 @@ int dwc3_gadget_init(struct dwc3 *dwc)
err4:
dwc3_gadget_free_endpoints(dwc);
- dma_free_coherent(dwc->ep0_bounce);
+ dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+ dwc->ep0_bounce, dwc->ep0_bounce_addr);
err3:
- dma_free_coherent(dwc->setup_buf);
+ kfree(dwc->setup_buf);
err2:
- dma_free_coherent(dwc->ep0_trb);
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ dwc->ep0_trb, dwc->ep0_trb_addr);
err1:
- dma_free_coherent(dwc->ctrl_req);
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ dwc->ctrl_req, dwc->ctrl_req_addr);
err0:
return ret;
@@ -2740,37 +2756,69 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dwc3_gadget_free_endpoints(dwc);
- dma_free_coherent(dwc->ep0_bounce);
+ dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+ dwc->ep0_bounce, dwc->ep0_bounce_addr);
- dma_free_coherent(dwc->setup_buf);
+ kfree(dwc->setup_buf);
- dma_free_coherent(dwc->ep0_trb);
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ dwc->ep0_trb, dwc->ep0_trb_addr);
- dma_free_coherent(dwc->ctrl_req);
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ dwc->ctrl_req, dwc->ctrl_req_addr);
}
-/**
- * dwc3_gadget_uboot_handle_interrupt - handle dwc3 gadget interrupt
- * @dwc: struct dwce *
- *
- * Handles ep0 and gadget interrupt
- *
- * Should be called from dwc3 core.
- */
-void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc)
+int dwc3_gadget_suspend(struct dwc3 *dwc)
{
- int ret = dwc3_interrupt(0, dwc);
+ if (dwc->pullups_connected) {
+ dwc3_gadget_disable_irq(dwc);
+ dwc3_gadget_run_stop(dwc, true, true);
+ }
- if (ret == IRQ_WAKE_THREAD) {
- int i;
- struct dwc3_event_buffer *evt;
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+ __dwc3_gadget_ep_disable(dwc->eps[1]);
- dwc3_thread_interrupt(0, dwc);
+ dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
- /* Clean + Invalidate the buffers after touching them */
- for (i = 0; i < dwc->num_event_buffers; i++) {
- evt = dwc->ev_buffs[i];
- dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
- }
+ return 0;
+}
+
+int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ int ret;
+
+ /* Start with SuperSpeed Default */
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+ false);
+ if (ret)
+ goto err0;
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+ false);
+ if (ret)
+ goto err1;
+
+ /* begin to receive SETUP packets */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+
+ dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
+
+ if (dwc->pullups_connected) {
+ dwc3_gadget_enable_irq(dwc);
+ dwc3_gadget_run_stop(dwc, true, false);
}
+
+ return 0;
+
+err1:
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+ return ret;
}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index f28a9755dcb3..18ae3eaa8b6f 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -1,18 +1,19 @@
-/* SPDX-License-Identifier: GPL-2.0 */
/**
* gadget.h - DesignWare USB3 DRD Gadget Header
*
- * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/gadget.h) and ported
- * to uboot.
- *
- * commit 7a60855972 : usb: dwc3: gadget: fix set_halt() bug with pending
- transfers
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __DRIVERS_USB_DWC3_GADGET_H
@@ -86,7 +87,6 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
-void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index c1ab02881424..6a79c8e66bbc 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -1,29 +1,32 @@
-/* SPDX-License-Identifier: GPL-2.0 */
/**
* io.h - DesignWare USB3 DRD IO Header
*
- * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/io.h) and ported
- * to uboot.
- *
- * commit 2c4cbe6e5a : usb: dwc3: add tracepoints to aid debugging
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __DRIVERS_USB_DWC3_IO_H
#define __DRIVERS_USB_DWC3_IO_H
-#include <cpu_func.h>
-#include <asm/io.h>
+#include <linux/io.h>
+#include "trace.h"
+#include "debug.h"
+#include "core.h"
-#define CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
- unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
+ u32 offs = offset - DWC3_GLOBALS_REGS_START;
u32 value;
/*
@@ -33,12 +36,20 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset)
*/
value = readl(base + offs);
+ /*
+ * When tracing we want to make it easy to find the correct address on
+ * documentation, so we revert it back to the proper addresses, the
+ * same way they are described on SNPS documentation
+ */
+ dwc3_trace(trace_dwc3_readl, "addr %p value %08x",
+ base - DWC3_GLOBALS_REGS_START + offset, value);
+
return value;
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
- unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
+ u32 offs = offset - DWC3_GLOBALS_REGS_START;
/*
* We requested the mem region starting from the Globals address
@@ -46,21 +57,14 @@ static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
* However, the offsets are given starting from xHCI address space.
*/
writel(value, base + offs);
-}
-
-static inline void dwc3_flush_cache(uintptr_t addr, int length)
-{
- uintptr_t start_addr = (uintptr_t)addr & ~(CACHELINE_SIZE - 1);
- uintptr_t end_addr = ALIGN((uintptr_t)addr + length, CACHELINE_SIZE);
- flush_dcache_range((unsigned long)start_addr, (unsigned long)end_addr);
+ /*
+ * When tracing we want to make it easy to find the correct address on
+ * documentation, so we revert it back to the proper addresses, the
+ * same way they are described on SNPS documentation
+ */
+ dwc3_trace(trace_dwc3_writel, "addr %p value %08x",
+ base - DWC3_GLOBALS_REGS_START + offset, value);
}
-static inline void dwc3_invalidate_cache(uintptr_t addr, int length)
-{
- uintptr_t start_addr = (uintptr_t)addr & ~(CACHELINE_SIZE - 1);
- uintptr_t end_addr = ALIGN((uintptr_t)addr + length, CACHELINE_SIZE);
-
- invalidate_dcache_range((unsigned long)start_addr, (unsigned long)end_addr);
-}
#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h
deleted file mode 100644
index 563f8727cdde..000000000000
--- a/drivers/usb/dwc3/linux-compat.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/**
- * linux-compat.h - DesignWare USB3 Linux Compatibiltiy Adapter Header
- *
- * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
- *
- * Authors: Kishon Vijay Abraham I <kishon@ti.com>
- *
- */
-
-#ifndef __DWC3_LINUX_COMPAT__
-#define __DWC3_LINUX_COMPAT__
-
-#define dev_WARN(dev, format, arg...) debug(format, ##arg)
-
-#endif
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
new file mode 100644
index 000000000000..a3a3b6d5668c
--- /dev/null
+++ b/drivers/usb/dwc3/platform_data.h
@@ -0,0 +1,47 @@
+/**
+ * platform_data.h - USB DWC3 Platform Data Support
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+
+struct dwc3_platform_data {
+ enum usb_device_speed maximum_speed;
+ enum usb_dr_mode dr_mode;
+ bool tx_fifo_resize;
+
+ unsigned is_utmi_l1_suspend:1;
+ u8 hird_threshold;
+
+ u8 lpm_nyet_threshold;
+
+ unsigned disable_scramble_quirk:1;
+ unsigned has_lpm_erratum:1;
+ unsigned u2exit_lfps_quirk:1;
+ unsigned u2ss_inp3_quirk:1;
+ unsigned req_p1p2p3_quirk:1;
+ unsigned del_p1p2p3_quirk:1;
+ unsigned del_phy_power_chg_quirk:1;
+ unsigned lfps_filter_quirk:1;
+ unsigned rx_detect_poll_quirk:1;
+ unsigned dis_u3_susphy_quirk:1;
+ unsigned dis_u2_susphy_quirk:1;
+
+ unsigned tx_de_emphasis_quirk:1;
+ unsigned tx_de_emphasis:2;
+};
diff --git a/drivers/usb/dwc3/samsung_usb_phy.c b/drivers/usb/dwc3/samsung_usb_phy.c
deleted file mode 100644
index 3563070cb85d..000000000000
--- a/drivers/usb/dwc3/samsung_usb_phy.c
+++ /dev/null
@@ -1,77 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/**
- * samsung_usb_phy.c - DesignWare USB3 (DWC3) PHY handling file
- *
- * Copyright (C) 2015 Samsung Electronics
- *
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- */
-
-#include <asm/io.h>
-#include <asm/arch/power.h>
-#include <asm/arch/xhci-exynos.h>
-#include <linux/delay.h>
-
-void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
-{
- u32 reg;
-
- /* Reset USB 3.0 PHY */
- writel(0x0, &phy->phy_reg0);
-
- clrbits_le32(&phy->phy_param0,
- /* Select PHY CLK source */
- PHYPARAM0_REF_USE_PAD |
- /* Set Loss-of-Signal Detector sensitivity */
- PHYPARAM0_REF_LOSLEVEL_MASK);
- setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
-
- writel(0x0, &phy->phy_resume);
-
- /*
- * Setting the Frame length Adj value[6:1] to default 0x20
- * See xHCI 1.0 spec, 5.2.4
- */
- setbits_le32(&phy->link_system,
- LINKSYSTEM_XHCI_VERSION_CONTROL |
- LINKSYSTEM_FLADJ(0x20));
-
- /* Set Tx De-Emphasis level */
- clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
- setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
-
- setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
-
- /* PHYTEST POWERDOWN Control */
- clrbits_le32(&phy->phy_test,
- PHYTEST_POWERDOWN_SSP |
- PHYTEST_POWERDOWN_HSP);
-
- /* UTMI Power Control */
- writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
-
- /* Use core clock from main PLL */
- reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
- /* Default 24Mhz crystal clock */
- PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
- PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
- PHYCLKRST_SSC_REFCLKSEL(0) |
- /* Force PortReset of PHY */
- PHYCLKRST_PORTRESET |
- /* Digital power supply in normal operating mode */
- PHYCLKRST_RETENABLEN |
- /* Enable ref clock for SS function */
- PHYCLKRST_REF_SSP_EN |
- /* Enable spread spectrum */
- PHYCLKRST_SSC_EN |
- /* Power down HS Bias and PLL blocks in suspend mode */
- PHYCLKRST_COMMONONN;
-
- writel(reg, &phy->phy_clk_rst);
-
- /* giving time to Phy clock to settle before resetting */
- udelay(10);
-
- reg &= ~PHYCLKRST_PORTRESET;
- writel(reg, &phy->phy_clk_rst);
-}
--
2.43.0
next prev parent reply other threads:[~2026-05-07 9:29 UTC|newest]
Thread overview: 102+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-07 9:27 [RFC PATCH v2 00/64] drivers: usb: dwc3: sync code with Linux v6.16-rc7 Jens Wiklander
2026-05-07 9:27 ` Jens Wiklander [this message]
2026-05-08 15:40 ` [RFC PATCH v2 01/64] usb: dwc3: restore to original v3.19-rc1 kernel import Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 02/64] usb: dwc3: import from kernel v3.19 Jens Wiklander
2026-05-08 15:25 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 03/64] usb: dwc3: import from kernel v4.0 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 04/64] usb: dwc3: import from kernel v4.1 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 05/64] usb: dwc3: import from kernel v4.2 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 06/64] usb: dwc3: import from kernel v4.3 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 07/64] usb: dwc3: import from kernel v4.4 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 08/64] usb: dwc3: import from kernel v4.5 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 09/64] usb: dwc3: import from kernel v4.6 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 10/64] usb: dwc3: import from kernel v4.7 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 11/64] usb: dwc3: import from kernel v4.8 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 12/64] usb: dwc3: import from kernel v4.9 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 13/64] usb: dwc3: import from kernel v4.10 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 14/64] usb: dwc3: import from kernel v4.11 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 15/64] usb: dwc3: import from kernel v4.12 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 16/64] usb: dwc3: import from kernel v4.13 Jens Wiklander
2026-05-08 15:26 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 17/64] usb: dwc3: import from kernel v4.14 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 18/64] usb: dwc3: import from kernel v4.15 Jens Wiklander
2026-05-08 15:27 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 19/64] usb: dwc3: import from kernel v4.16 Jens Wiklander
2026-05-08 15:28 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 20/64] usb: dwc3: import from kernel v4.17 Jens Wiklander
2026-05-08 15:28 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 21/64] usb: dwc3: import from kernel v4.18 Jens Wiklander
2026-05-08 15:28 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 22/64] usb: dwc3: import from kernel v4.19 Jens Wiklander
2026-05-08 15:28 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 23/64] usb: dwc3: import from kernel v4.20 Jens Wiklander
2026-05-08 15:28 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 24/64] usb: dwc3: import from kernel v5.0 Jens Wiklander
2026-05-08 15:31 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 25/64] usb: dwc3: import from kernel v5.1 Jens Wiklander
2026-05-08 15:31 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 26/64] usb: dwc3: import from kernel v5.2 Jens Wiklander
2026-05-08 15:31 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 27/64] usb: dwc3: import from kernel v5.3 Jens Wiklander
2026-05-08 15:31 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 28/64] usb: dwc3: import from kernel v5.4 Jens Wiklander
2026-05-08 15:31 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 29/64] usb: dwc3: import from kernel v5.5 Jens Wiklander
2026-05-08 15:31 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 30/64] usb: dwc3: import from kernel v5.6 Jens Wiklander
2026-05-08 15:36 ` Simon Glass
2026-05-07 9:27 ` [RFC PATCH v2 31/64] usb: dwc3: import from kernel v5.7 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 32/64] usb: dwc3: import from kernel v5.8 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 33/64] usb: dwc3: import from kernel v5.9 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 34/64] usb: dwc3: import from kernel v5.10 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 35/64] usb: dwc3: import from kernel v5.11 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 36/64] usb: dwc3: import from kernel v5.12 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 37/64] usb: dwc3: import from kernel v5.13 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 38/64] usb: dwc3: import from kernel v5.14 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 39/64] usb: dwc3: import from kernel v5.15 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 40/64] usb: dwc3: import from kernel v5.16 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 41/64] usb: dwc3: import from kernel v5.17 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 42/64] usb: dwc3: import from kernel v5.18 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 43/64] usb: dwc3: import from kernel v5.19 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 44/64] usb: dwc3: import from kernel v6.0 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 45/64] usb: dwc3: import from kernel v6.1 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 46/64] usb: dwc3: import from kernel v6.2 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 47/64] usb: dwc3: import from kernel v6.3 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 48/64] usb: dwc3: import from kernel v6.4 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 49/64] usb: dwc3: import from kernel v6.5 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 50/64] usb: dwc3: import from kernel v6.6 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 51/64] usb: dwc3: import from kernel v6.7 Jens Wiklander
2026-05-07 9:27 ` [RFC PATCH v2 52/64] usb: dwc3: import from kernel v6.8 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 53/64] usb: dwc3: import from kernel v6.9 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 54/64] usb: dwc3: import from kernel v6.10 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 55/64] usb: dwc3: import from kernel v6.11 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 56/64] usb: dwc3: import from kernel v6.12 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 57/64] usb: dwc3: import from kernel v6.13 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 58/64] usb: dwc3: import from kernel v6.14 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 59/64] usb: dwc3: import from kernel v6.15 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 60/64] usb: dwc3: import from kernel v6.16-rc7 Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 61/64] usb: host: re-import xhci-ext-caps.h " Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 62/64] usb: gadget: re-import epautoconf.c " Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 63/64] usb: udc: re-import udc-core.c " Jens Wiklander
2026-05-07 9:28 ` [RFC PATCH v2 64/64] usb: fix build after resync of DWC3 with " Jens Wiklander
2026-05-11 8:25 ` Anshul Dalal
2026-05-08 15:42 ` [RFC PATCH v2 00/64] drivers: usb: dwc3: sync code with Linux v6.16-rc7 Simon Glass
2026-05-08 16:03 ` Tom Rini
2026-05-11 13:13 ` Simon Glass
2026-05-11 6:31 ` Michal Simek
2026-05-11 8:27 ` Anshul Dalal
2026-05-11 14:58 ` Tom Rini
2026-05-12 14:52 ` Alexey Charkov
2026-05-14 11:49 ` Michal Simek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260507092843.358908-2-jens.wiklander@linaro.org \
--to=jens.wiklander@linaro.org \
--cc=GSS_MTK_Uboot_upstream@mediatek.com \
--cc=admin@hifiphile.com \
--cc=andre.przywara@arm.com \
--cc=andrew.goodbody@linaro.org \
--cc=anshuld@ti.com \
--cc=bmeng.cn@gmail.com \
--cc=casey.connolly@linaro.org \
--cc=chunfeng.yun@mediatek.com \
--cc=clamor95@gmail.com \
--cc=eddie.cai.linux@gmail.com \
--cc=ilias.apalodimas@linaro.org \
--cc=ion@agorria.com \
--cc=jerome.forissier@arm.com \
--cc=junhui.liu@pigmoral.tech \
--cc=lukma@denx.de \
--cc=marex@denx.de \
--cc=mkorpershoek@kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=patrice.chotard@foss.st.com \
--cc=quentin.schulz@cherry.de \
--cc=quic_varada@quicinc.com \
--cc=ravi@prevas.dk \
--cc=ryder.lee@mediatek.com \
--cc=seashell11234455@gmail.com \
--cc=sjg@chromium.org \
--cc=stephan.gerhold@linaro.org \
--cc=trini@konsulko.com \
--cc=u-boot@lists.denx.de \
--cc=weijie.gao@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.