diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2023-04-19 08:59:15 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2023-04-19 08:59:15 +0200 |
commit | e0f1115ebb757cebbc0cf7dd92a586e3dad19b77 (patch) | |
tree | f694ff849990cbfa962f49954266b5aa6eadf7eb /drivers | |
parent | d5a06d4800305af6740cde3894d8f4b65b26b392 (diff) | |
parent | 0a73158341d5d3ef1e79e0d77a177121ef502930 (diff) | |
download | barebox-e0f1115ebb757cebbc0cf7dd92a586e3dad19b77.tar.gz barebox-e0f1115ebb757cebbc0cf7dd92a586e3dad19b77.tar.xz |
Merge branch 'for-next/usb'
Diffstat (limited to 'drivers')
83 files changed, 6105 insertions, 2522 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index efbffcdddb..f00be99cdc 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -405,6 +405,23 @@ int register_driver(struct driver *drv) } EXPORT_SYMBOL(register_driver); +void unregister_driver(struct driver *drv) +{ + struct device *dev; + + list_del(&drv->list); + list_del(&drv->bus_list); + + bus_for_each_device(drv->bus, dev) { + if (dev->driver == drv) { + drv->bus->remove(dev); + dev->driver = NULL; + list_del(&dev->active); + INIT_LIST_HEAD(&dev->active); + } + } +} + struct resource *dev_get_resource(struct device *dev, unsigned long type, int num) { diff --git a/drivers/input/usb_kbd.c b/drivers/input/usb_kbd.c index d950bd5039..86b48db2a7 100644 --- a/drivers/input/usb_kbd.c +++ b/drivers/input/usb_kbd.c @@ -10,7 +10,7 @@ #include <init.h> #include <clock.h> #include <poller.h> -#include <usb/usb.h> +#include <linux/usb/usb.h> #include <string.h> #include <dma.h> #include <input/input.h> diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 2d7114e5b1..9d34beab0d 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -3,8 +3,8 @@ #include <init.h> #include <net.h> #include <linux/phy.h> -#include <usb/usb.h> -#include <usb/usbnet.h> +#include <linux/usb/usb.h> +#include <linux/usb/usbnet.h> #include <errno.h> #include <malloc.h> #include <asm/byteorder.h> diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index fddb187144..318eb9be02 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -8,8 +8,8 @@ #include <init.h> #include <net.h> #include <linux/phy.h> -#include <usb/usb.h> -#include <usb/usbnet.h> +#include <linux/usb/usb.h> +#include <linux/usb/usbnet.h> #include <errno.h> #include <malloc.h> #include <poller.h> diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0928887784..2511c524cd 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -8,8 +8,8 @@ #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/phy.h> -#include <usb/usb.h> -#include <usb/usbnet.h> +#include <linux/usb/usb.h> +#include <linux/usb/usbnet.h> #include "r8152.h" #define R8152_TX_BURST_SIZE 512 diff --git a/drivers/net/usb/r8152_fw.c b/drivers/net/usb/r8152_fw.c index ee5f7c48e4..a6d61ac0d6 100644 --- a/drivers/net/usb/r8152_fw.c +++ b/drivers/net/usb/r8152_fw.c @@ -2,8 +2,8 @@ /* Copyright (c) 2015 Realtek Semiconductor Corp. All rights reserved. */ #include <common.h> -#include <usb/usb.h> -#include <usb/usbnet.h> +#include <linux/usb/usb.h> +#include <linux/usb/usbnet.h> #include "r8152.h" static const u8 r8152b_pla_patch_a[] = { diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 3c5bd1e4ee..b6f81cfab8 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -5,8 +5,8 @@ #include <command.h> #include <init.h> #include <net.h> -#include <usb/usb.h> -#include <usb/usbnet.h> +#include <linux/usb/usb.h> +#include <linux/usb/usbnet.h> #include <malloc.h> #include <asm/byteorder.h> #include <errno.h> diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 4818079523..3c3da3171b 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include <common.h> -#include <usb/usb.h> -#include <usb/usbnet.h> +#include <linux/usb/usb.h> +#include <linux/usb/usbnet.h> #include <asm/byteorder.h> #include <errno.h> #include <malloc.h> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index e0d7d7818c..c664894cdd 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c @@ -13,7 +13,7 @@ #include <malloc.h> #include <of_device.h> #include <of.h> -#include <usb/phy.h> +#include <linux/usb/phy.h> #define PHY_CTRL0 0x0 diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index d3a7847ee8..1a23f35b95 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -11,7 +11,7 @@ #include <common.h> #include <malloc.h> #include <linux/phy/phy.h> -#include <usb/phy.h> +#include <linux/usb/phy.h> static LIST_HEAD(phy_provider_list); static int phy_ida; @@ -203,6 +203,21 @@ int phy_power_off(struct phy *phy) return 0; } +int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode) +{ + int ret; + + if (!phy || !phy->ops->set_mode) + return 0; + + ret = phy->ops->set_mode(phy, mode, submode); + if (!ret) + phy->attrs.mode = mode; + + return ret; +} +EXPORT_SYMBOL_GPL(phy_set_mode_ext); + struct usb_phy *phy_to_usbphy(struct phy *phy) { if (!phy) diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index db4ccef920..3ccbc7b902 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -14,7 +14,7 @@ #include <linux/phy/phy.h> #include <linux/reset.h> #include <linux/math64.h> -#include <usb/phy.h> +#include <linux/usb/phy.h> #define STM32_USBPHYC_PLL 0x0 #define STM32_USBPHYC_MISC 0x8 diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index ab7d65389c..1f77d430a6 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -11,7 +11,7 @@ #include <errno.h> #include <driver.h> #include <malloc.h> -#include <usb/phy.h> +#include <linux/usb/phy.h> #include <linux/phy/phy.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 65869efd3f..bd5dff954e 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -12,7 +12,7 @@ #include <errno.h> #include <driver.h> #include <malloc.h> -#include <usb/phy.h> +#include <linux/usb/phy.h> #include <linux/phy/phy.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/phy/usb-nop-xceiv.c b/drivers/phy/usb-nop-xceiv.c index 7fa412cab6..80141f9def 100644 --- a/drivers/phy/usb-nop-xceiv.c +++ b/drivers/phy/usb-nop-xceiv.c @@ -9,7 +9,7 @@ #include <errno.h> #include <driver.h> #include <malloc.h> -#include <usb/phy.h> +#include <linux/usb/phy.h> #include <linux/phy/phy.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/usb/core/common.c b/drivers/usb/core/common.c index d562b963be..61ccc13024 100644 --- a/drivers/usb/core/common.c +++ b/drivers/usb/core/common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include <common.h> -#include <usb/ch9.h> +#include <linux/usb/ch9.h> static const char *const speed_names[] = { [USB_SPEED_UNKNOWN] = "UNKNOWN", diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8c85b93420..650af0e884 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -9,9 +9,9 @@ #include <init.h> #include <malloc.h> #include <errno.h> -#include <usb/phy.h> -#include <usb/usb.h> -#include <usb/usb_defs.h> +#include <linux/usb/phy.h> +#include <linux/usb/usb.h> +#include <linux/usb/usb_defs.h> #include "usb.h" diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index acf95320c0..25203c6064 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -4,8 +4,8 @@ */ #include <common.h> -#include <usb/usb.h> -#include <usb/phy.h> +#include <linux/usb/usb.h> +#include <linux/usb/phy.h> #include <of.h> static const char *usb_dr_modes[] = { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index a974614c06..178ddbbca5 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -38,8 +38,8 @@ #include <init.h> #include <dma.h> -#include <usb/usb.h> -#include <usb/ch9.h> +#include <linux/usb/usb.h> +#include <linux/usb/ch9.h> #include "usb.h" diff --git a/drivers/usb/dwc2/dwc2.h b/drivers/usb/dwc2/dwc2.h index 3ecc359f8b..15d4b69759 100644 --- a/drivers/usb/dwc2/dwc2.h +++ b/drivers/usb/dwc2/dwc2.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include <usb/usb.h> -#include <usb/usb_defs.h> -#include <usb/gadget.h> +#include <linux/usb/usb.h> +#include <linux/usb/usb_defs.h> +#include <linux/usb/gadget.h> #include <linux/phy/phy.h> #include "regs.h" diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 7070485410..028f3c877a 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <dma.h> -#include <usb/gadget.h> +#include <linux/usb/gadget.h> #include "dwc2.h" #define to_dwc2 gadget_to_dwc2 @@ -2533,8 +2533,7 @@ static int dwc2_gadget_udc_start(struct usb_gadget *gadget, return 0; } -static int dwc2_gadget_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) +static int dwc2_gadget_udc_stop(struct usb_gadget *gadget) { struct dwc2 *dwc2 = to_dwc2(gadget); unsigned long flags = 0; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a3388d4dd6..314346fd31 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0-only -/** +// SPDX-License-Identifier: GPL-2.0 +/* * core.c - DesignWare USB3 DRD Controller Core file * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -16,10 +16,11 @@ #include <init.h> #include <linux/reset.h> -#include "gadget.h" #include "core.h" +#include "gadget.h" #include "io.h" +#include "debug.h" #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ @@ -67,8 +68,10 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc) * mode. If the controller supports DRD but the dr_mode is not * specified or set to OTG, then set the mode to peripheral. */ - if (mode == USB_DR_MODE_OTG && - dwc->revision >= DWC3_REVISION_330A) + if (mode == USB_DR_MODE_OTG && !dwc->edev && + (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) || + !of_property_read_bool(dwc->dev->of_node, "usb-role-switch")) && + !DWC3_VER_IS_PRIOR(DWC3, 330A)) mode = USB_DR_MODE_PERIPHERAL; } @@ -95,25 +98,28 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } +u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) +{ + struct dwc3 *dwc = dep->dwc; + u32 reg; + + dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE, + DWC3_GDBGFIFOSPACE_NUM(dep->number) | + DWC3_GDBGFIFOSPACE_TYPE(type)); + + reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE); + + return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); +} + /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ -static int dwc3_core_soft_reset(struct dwc3 *dwc) +int dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; int retries = 1000; - int ret; - - 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; - } /* * We're resetting only the device side because, if we're in host mode, @@ -125,33 +131,94 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= DWC3_DCTL_CSFTRST; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + reg &= ~DWC3_DCTL_RUN_STOP; + dwc3_gadget_dctl_write_safe(dwc, reg); + + /* + * For DWC_usb31 controller 1.90a and later, the DCTL.CSFRST bit + * is cleared only after all the clocks are synchronized. This can + * take a little more than 50ms. Set the polling rate at 20ms + * for 10 times instead. + */ + if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32)) + retries = 10; do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) goto done; - udelay(1); + if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32)) + mdelay(20); + else + udelay(1); } while (--retries); - phy_exit(dwc->usb3_generic_phy); - phy_exit(dwc->usb2_generic_phy); - + dev_warn(dwc->dev, "DWC3 controller soft reset failed.\n"); return -ETIMEDOUT; done: /* - * For DWC_usb31 controller, once DWC3_DCTL_CSFTRST bit is cleared, - * we must wait at least 50ms before accessing the PHY domain - * (synchronization delay). DWC_usb31 programming guide section 1.3.2. + * For DWC_usb31 controller 1.80a and prior, once DCTL.CSFRST bit + * is cleared, we must wait at least 50ms before accessing the PHY + * domain (synchronization delay). */ - if (dwc3_is_usb31(dwc)) + if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A)) mdelay(50); return 0; } +/* + * dwc3_frame_length_adjustment - Adjusts frame length if required + * @dwc3: Pointer to our controller context structure + */ +static void dwc3_frame_length_adjustment(struct dwc3 *dwc) +{ + u32 reg; + u32 dft; + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + + if (dwc->fladj == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; + if (dft != dwc->fladj) { + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->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 + */ +static void dwc3_ref_clk_period(struct dwc3 *dwc) +{ + u32 reg; + u32 dft; + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + + if (dwc->fladj == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); +} + /** * dwc3_free_one_event_buffer - Frees one event buffer * @dwc: Pointer to our controller context structure @@ -160,7 +227,7 @@ done: static void dwc3_free_one_event_buffer(struct dwc3 *dwc, struct dwc3_event_buffer *evt) { - dma_free_coherent(evt->buf, 0, sizeof(dma_addr_t)); + dma_free_coherent(evt->buf, evt->dma, evt->length); } /** @@ -172,16 +239,20 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, * otherwise ERR_PTR(errno). */ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, - unsigned length) + unsigned int length) { struct dwc3_event_buffer *evt; - evt = xzalloc(sizeof(*evt)); + evt = kzalloc(sizeof(*evt), GFP_KERNEL); if (!evt) return ERR_PTR(-ENOMEM); evt->dwc = dwc; evt->length = length; + evt->cache = kzalloc(length, GFP_KERNEL); + if (!evt->cache) + return ERR_PTR(-ENOMEM); + evt->buf = dma_alloc_coherent(length, &evt->dma); if (!evt->buf) return ERR_PTR(-ENOMEM); @@ -210,7 +281,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) * Returns 0 on success otherwise negative errno. In the error case, dwc * may contain some buffers allocated but not all which were requested. */ -static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) +static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length) { struct dwc3_event_buffer *evt; @@ -230,7 +301,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) * * Returns 0 on success otherwise negative errno. */ -static int dwc3_event_buffers_setup(struct dwc3 *dwc) +int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; @@ -247,8 +318,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) return 0; } - -static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) +void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; @@ -291,11 +361,15 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) if (!dwc->nr_scratch) 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"); + /* should never fall here */ + if (!WARN_ON(dwc->scratchbuf)) + return 0; + + scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf, + dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dwc->sysdev, scratch_addr)) { + dev_err(dwc->sysdev, "failed to map scratch buffer\n"); ret = -EFAULT; goto err0; } @@ -319,33 +393,28 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) return 0; err1: - dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * - DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); + dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * + DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); err0: return ret; } -/* - * dwc3_frame_length_adjustment - Adjusts frame length if required - * @dwc3: Pointer to our controller context structure - */ -static void dwc3_frame_length_adjustment(struct dwc3 *dwc) +static void dwc3_free_scratch_buffers(struct dwc3 *dwc) { - u32 reg; - u32 dft; + if (!dwc->has_hibernation) + return; - if (dwc->revision < DWC3_REVISION_250A) + if (!dwc->nr_scratch) return; - if (dwc->fladj == 0) + /* should never fall here */ + if (!WARN_ON(dwc->scratchbuf)) return; - reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); - dft = reg & DWC3_GFLADJ_30MHZ_MASK; - reg &= ~DWC3_GFLADJ_30MHZ_MASK; - reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; - dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); + dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * + DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); + kfree(dwc->scratchbuf); } static void dwc3_core_num_eps(struct dwc3 *dwc) @@ -368,6 +437,9 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); + + if (DWC3_IP_IS(DWC32)) + parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9); } static int dwc3_core_ulpi_init(struct dwc3 *dwc) @@ -396,8 +468,11 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc) */ static int dwc3_phy_setup(struct dwc3 *dwc) { + unsigned int hw_mode; u32 reg; + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); /* @@ -412,9 +487,17 @@ static int dwc3_phy_setup(struct dwc3 *dwc) * will be '0' when the core is reset. Application needs to set it * to '1' after the core initialization is completed. */ - if (dwc->revision > DWC3_REVISION_194A) + if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) reg |= DWC3_GUSB3PIPECTL_SUSPHY; + /* + * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after + * power-on reset, and it can be set after core initialization, which is + * after device soft-reset during initialization. + */ + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; @@ -465,9 +548,8 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) break; } - /* FALLTHROUGH */ + fallthrough; case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI: - /* FALLTHROUGH */ default: break; } @@ -495,9 +577,17 @@ static int dwc3_phy_setup(struct dwc3 *dwc) * be '0' when the core is reset. Application needs to set it to * '1' after the core initialization is completed. */ - if (dwc->revision > DWC3_REVISION_194A) + if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) reg |= DWC3_GUSB2PHYCFG_SUSPHY; + /* + * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after + * power-on reset, and it can be set after core initialization, which is + * after device soft-reset during initialization. + */ + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + if (dwc->dis_u2_susphy_quirk) reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; @@ -506,7 +596,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) else reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; - if (dwc->dis_u2_freeclk_exists_quirk) + if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); @@ -518,14 +608,17 @@ static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - + 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); - clk_bulk_disable(dwc->num_clks, dwc->clks); - dwc3_free_event_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); + + reset_control_assert(dwc->reset); } static bool dwc3_core_is_valid(struct dwc3 *dwc) @@ -533,15 +626,13 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); + dwc->ip = DWC3_GSNPS_ID(reg); /* This should read as U3 followed by revision number */ - if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) { - /* Detected DWC_usb3 IP */ + if (DWC3_IP_IS(DWC3)) { dwc->revision = reg; - } else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) { - /* Detected DWC_usb31 IP */ + } else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) { dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER); - dwc->revision |= DWC3_REVISION_IS_DWC31; dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE); } else { return false; @@ -574,8 +665,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) */ if ((dwc->dr_mode == USB_DR_MODE_HOST || dwc->dr_mode == USB_DR_MODE_OTG) && - (dwc->revision >= DWC3_REVISION_210A && - dwc->revision <= DWC3_REVISION_250A)) + DWC3_VER_IS_WITHIN(DWC3, 210A, 250A)) reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; else reg &= ~DWC3_GCTL_DSBLCLKGTNG; @@ -601,8 +691,8 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) dwc->is_fpga = true; } - WARN(dwc->disable_scramble_quirk && !dwc->is_fpga, - "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; @@ -618,13 +708,14 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) * and falls back to high-speed mode which causes * the device to enter a Connect/Disconnect loop */ - if (dwc->revision < DWC3_REVISION_190A) + if (DWC3_VER_IS_PRIOR(DWC3, 190A)) reg |= DWC3_GCTL_U2RSTECN; dwc3_writel(dwc->regs, DWC3_GCTL, reg); } static int dwc3_core_get_phy(struct dwc3 *dwc); +static int dwc3_core_ulpi_init(struct dwc3 *dwc); /* set global incr burst type configuration registers */ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) @@ -636,7 +727,7 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) u32 incrx_size; u32 *vals; u32 cfg; - int ntype = 0; + int ntype; int ret; int i; @@ -649,24 +740,19 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) * result = 1, means INCRx burst mode supported. * result > 1, means undefined length burst mode supported. */ - of_find_property(dev->of_node, "snps,incr-burst-type-adjustment", - &ntype); - - ntype /= sizeof(u32); - + ntype = of_property_count_elems_of_size(dev->of_node, + "snps,incr-burst-type-adjustment", + sizeof(u32)); if (ntype <= 0) return; vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL); - if (!vals) { - dev_err(dev, "Error to get memory\n"); + if (!vals) return; - } /* Get INCR burst type, and parse it */ ret = of_property_read_u32_array(dev->of_node, - "snps,incr-burst-type-adjustment", - vals, ntype); + "snps,incr-burst-type-adjustment", vals, ntype); if (ret) { kfree(vals); dev_err(dev, "Error to get property\n"); @@ -733,14 +819,11 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) */ static int dwc3_core_init(struct dwc3 *dwc) { + unsigned int hw_mode; u32 reg; int ret; - if (!dwc3_core_is_valid(dwc)) { - dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); - ret = -ENODEV; - goto err0; - } + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); /* * Write Linux Version Code to our GUID register so it's easy to figure @@ -748,21 +831,19 @@ static int dwc3_core_init(struct dwc3 *dwc) */ dwc3_writel(dwc->regs, DWC3_GUID, 0xdeadbeef); - /* Handle USB2.0-only core configuration */ - if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == - DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { - if (dwc->maximum_speed == USB_SPEED_SUPER) - dwc->maximum_speed = USB_SPEED_HIGH; - } - ret = dwc3_phy_setup(dwc); if (ret) goto err0; if (!dwc->ulpi_ready) { ret = dwc3_core_ulpi_init(dwc); - if (ret) + if (ret) { + if (ret == -ETIMEDOUT) { + dwc3_core_soft_reset(dwc); + ret = -EPROBE_DEFER; + } goto err0; + } dwc->ulpi_ready = true; } @@ -773,34 +854,66 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc->phys_ready = true; } + usb_phy_init(dwc->usb2_phy); + usb_phy_init(dwc->usb3_phy); + ret = phy_init(dwc->usb2_generic_phy); + if (ret < 0) + goto err0a; + + ret = phy_init(dwc->usb3_generic_phy); + if (ret < 0) { + phy_exit(dwc->usb2_generic_phy); + goto err0a; + } + ret = dwc3_core_soft_reset(dwc); if (ret) - goto err0a; + goto err1; + + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && + !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { + if (!dwc->dis_u3_susphy_quirk) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + } + + if (!dwc->dis_u2_susphy_quirk) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + } dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); ret = dwc3_setup_scratch_buffers(dwc); if (ret) - goto err0a; + goto err1; /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); + /* Adjust Reference Clock Period */ + dwc3_ref_clk_period(dwc); + dwc3_set_incr_burst_type(dwc); + 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; + goto err2; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) - goto err2; + goto err3; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err3; + goto err4; } /* @@ -808,25 +921,57 @@ static int dwc3_core_init(struct dwc3 *dwc) * the DWC_usb3 controller. It is NOT available in the * DWC_usb31 controller. */ - if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) { + if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); reg |= DWC3_GUCTL2_RST_ACTBITLATER; dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); } - if (dwc->revision >= DWC3_REVISION_250A) { + /* + * When configured in HOST mode, after issuing U3/L2 exit controller + * fails to send proper CRC checksum in CRC5 feild. Because of this + * behaviour Transaction Error is generated, resulting in reset and + * re-enumeration of usb device attached. All the termsel, xcvrsel, + * opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1 + * will correct this problem. This option is to support certain + * legacy ULPI PHYs. + */ + if (dwc->resume_hs_terminations) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); + reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST; + dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); + } + + if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); /* * Enable hardware control of sending remote wakeup * in HS when the device is in the L1 state. */ - if (dwc->revision >= DWC3_REVISION_290A) + if (!DWC3_VER_IS_PRIOR(DWC3, 290A)) reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW; + /* + * Decouple USB 2.0 L1 & L2 events which will allow for + * gadget driver to only receive U3/L2 suspend & wakeup + * events and prevent the more frequent L1 LPM transitions + * from interrupting the driver. + */ + if (!DWC3_VER_IS_PRIOR(DWC3, 300A)) + reg |= DWC3_GUCTL1_DEV_DECOUPLE_L1L2_EVT; + if (dwc->dis_tx_ipgap_linecheck_quirk) reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; + if (dwc->parkmode_disable_ss_quirk) + reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; + + if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && + (dwc->maximum_speed == USB_SPEED_HIGH || + dwc->maximum_speed == USB_SPEED_FULL)) + reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; + dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } @@ -850,7 +995,7 @@ static int dwc3_core_init(struct dwc3 *dwc) * Must config both number of packets and max burst settings to enable * RX and/or TX threshold. */ - if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) { + if (!DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) { u8 rx_thr_num = dwc->rx_thr_num_pkt_prd; u8 rx_maxburst = dwc->rx_max_burst_prd; u8 tx_thr_num = dwc->tx_thr_num_pkt_prd; @@ -885,14 +1030,25 @@ static int dwc3_core_init(struct dwc3 *dwc) return 0; -err3: +err4: phy_power_off(dwc->usb3_generic_phy); -err2: + +err3: phy_power_off(dwc->usb2_generic_phy); + +err2: + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); + 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); + err0a: + dwc3_ulpi_exit(dwc); + err0: return ret; } @@ -905,33 +1061,25 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) dwc->usb2_generic_phy = phy_get(dev, "usb2-phy"); if (IS_ERR(dwc->usb2_generic_phy)) { ret = PTR_ERR(dwc->usb2_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) { + 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; - } + else + return dev_err_probe(dev, ret, "no usb2 phy configured\n"); } dwc->usb3_generic_phy = phy_get(dev, "usb3-phy"); if (IS_ERR(dwc->usb3_generic_phy)) { ret = PTR_ERR(dwc->usb3_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) { + 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; - } + else + return dev_err_probe(dev, ret, "no usb3 phy configured\n"); } return 0; } -static int dwc3_set_mode(void *ctx, enum usb_dr_mode mode) +static int dwc3_set_dr_mode(void *ctx, enum usb_dr_mode mode) { struct dwc3 *dwc = ctx; struct device *dev = dwc->dev; @@ -941,24 +1089,29 @@ static int dwc3_set_mode(void *ctx, enum usb_dr_mode mode) case USB_DR_MODE_PERIPHERAL: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); +// if (dwc->usb2_phy) +// otg_set_vbus(dwc->usb2_phy->otg, false); + phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); + ret = dwc3_gadget_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize gadget\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to initialize gadget\n"); break; case USB_DR_MODE_HOST: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); +// if (dwc->usb2_phy) +// otg_set_vbus(dwc->usb2_phy->otg, true); + phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); + phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); + ret = dwc3_host_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize host\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to initialize host\n"); break; default: + dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); return -EINVAL; } @@ -968,9 +1121,27 @@ static int dwc3_set_mode(void *ctx, enum usb_dr_mode mode) static int dwc3_core_init_mode(struct dwc3 *dwc) { if (dwc->dr_mode == USB_DR_MODE_OTG) - return usb_register_otg_device(dwc->dev, dwc3_set_mode, dwc); + return usb_register_otg_device(dwc->dev, dwc3_set_dr_mode, dwc); else - return dwc3_set_mode(dwc, dwc->dr_mode); + return dwc3_set_dr_mode(dwc, dwc->dr_mode); +} + +static void dwc3_core_exit_mode(struct dwc3 *dwc) +{ + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_gadget_exit(dwc); + break; + case USB_DR_MODE_HOST: + dwc3_host_exit(dwc); + break; + default: + /* do nothing */ + break; + } + + /* de-assert DRVVBUS for HOST and OTG mode */ + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); } static void dwc3_get_properties(struct dwc3 *dwc) @@ -979,9 +1150,14 @@ static void dwc3_get_properties(struct dwc3 *dwc) u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; + u8 rx_thr_num_pkt_prd = 0; + u8 rx_max_burst_prd = 0; + u8 tx_thr_num_pkt_prd = 0; + u8 tx_max_burst_prd = 0; + u8 tx_fifo_resize_max_num; /* default to highest possible threshold */ - lpm_nyet_threshold = 0xff; + lpm_nyet_threshold = 0xf; /* default to -3.5dB de-emphasis */ tx_de_emphasis = 1; @@ -992,41 +1168,142 @@ static void dwc3_get_properties(struct dwc3 *dwc) */ hird_threshold = 12; + /* + * default to a TXFIFO size large enough to fit 6 max packets. This + * allows for systems with larger bus latencies to have some headroom + * for endpoints that have a large bMaxBurst value. + */ + tx_fifo_resize_max_num = 6; + dwc->maximum_speed = of_usb_get_maximum_speed(dev->of_node, NULL); +// dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); dwc->dr_mode = of_usb_get_dr_mode(dev->of_node, NULL); dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node, NULL); + dwc->sysdev_is_parent = of_property_read_bool(dev->of_node, + "linux,sysdev_is_parent"); + if (dwc->sysdev_is_parent) + dwc->sysdev = dwc->dev->parent; + else + dwc->sysdev = dwc->dev; + + dwc->has_lpm_erratum = of_property_read_bool(dev->of_node, + "snps,has-lpm-erratum"); + of_property_read_u8(dev->of_node, "snps,lpm-nyet-threshold", + &lpm_nyet_threshold); + dwc->is_utmi_l1_suspend = of_property_read_bool(dev->of_node, + "snps,is-utmi-l1-suspend"); + of_property_read_u8(dev->of_node, "snps,hird-threshold", + &hird_threshold); + dwc->dis_start_transfer_quirk = of_property_read_bool(dev->of_node, + "snps,dis-start-transfer-quirk"); + dwc->usb3_lpm_capable = of_property_read_bool(dev->of_node, + "snps,usb3_lpm_capable"); + dwc->usb2_lpm_disable = of_property_read_bool(dev->of_node, + "snps,usb2-lpm-disable"); + dwc->usb2_gadget_lpm_disable = of_property_read_bool(dev->of_node, + "snps,usb2-gadget-lpm-disable"); + of_property_read_u8(dev->of_node, "snps,rx-thr-num-pkt-prd", + &rx_thr_num_pkt_prd); + of_property_read_u8(dev->of_node, "snps,rx-max-burst-prd", + &rx_max_burst_prd); + of_property_read_u8(dev->of_node, "snps,tx-thr-num-pkt-prd", + &tx_thr_num_pkt_prd); + of_property_read_u8(dev->of_node, "snps,tx-max-burst-prd", + &tx_max_burst_prd); + dwc->do_fifo_resize = of_property_read_bool(dev->of_node, + "tx-fifo-resize"); + if (dwc->do_fifo_resize) + of_property_read_u8(dev->of_node, "tx-fifo-max-num", + &tx_fifo_resize_max_num); + + dwc->disable_scramble_quirk = of_property_read_bool(dev->of_node, + "snps,disable_scramble_quirk"); + dwc->u2exit_lfps_quirk = of_property_read_bool(dev->of_node, + "snps,u2exit_lfps_quirk"); + dwc->u2ss_inp3_quirk = of_property_read_bool(dev->of_node, + "snps,u2ss_inp3_quirk"); + dwc->req_p1p2p3_quirk = of_property_read_bool(dev->of_node, + "snps,req_p1p2p3_quirk"); + dwc->del_p1p2p3_quirk = of_property_read_bool(dev->of_node, + "snps,del_p1p2p3_quirk"); + dwc->del_phy_power_chg_quirk = of_property_read_bool(dev->of_node, + "snps,del_phy_power_chg_quirk"); + dwc->lfps_filter_quirk = of_property_read_bool(dev->of_node, + "snps,lfps_filter_quirk"); + dwc->rx_detect_poll_quirk = of_property_read_bool(dev->of_node, + "snps,rx_detect_poll_quirk"); + dwc->dis_u3_susphy_quirk = of_property_read_bool(dev->of_node, + "snps,dis_u3_susphy_quirk"); + dwc->dis_u2_susphy_quirk = of_property_read_bool(dev->of_node, + "snps,dis_u2_susphy_quirk"); + dwc->dis_enblslpm_quirk = of_property_read_bool(dev->of_node, + "snps,dis_enblslpm_quirk"); + dwc->dis_u1_entry_quirk = of_property_read_bool(dev->of_node, + "snps,dis-u1-entry-quirk"); + dwc->dis_u2_entry_quirk = of_property_read_bool(dev->of_node, + "snps,dis-u2-entry-quirk"); + dwc->dis_rxdet_inp3_quirk = of_property_read_bool(dev->of_node, + "snps,dis_rxdet_inp3_quirk"); dwc->dis_u2_freeclk_exists_quirk = of_property_read_bool(dev->of_node, - "snps,dis-u2-freeclk-exists-quirk"); + "snps,dis-u2-freeclk-exists-quirk"); + dwc->dis_del_phy_power_chg_quirk = of_property_read_bool(dev->of_node, + "snps,dis-del-phy-power-chg-quirk"); + dwc->dis_tx_ipgap_linecheck_quirk = of_property_read_bool(dev->of_node, + "snps,dis-tx-ipgap-linecheck-quirk"); + dwc->resume_hs_terminations = of_property_read_bool(dev->of_node, + "snps,resume-hs-terminations"); + dwc->parkmode_disable_ss_quirk = of_property_read_bool(dev->of_node, + "snps,parkmode-disable-ss-quirk"); + dwc->gfladj_refclk_lpm_sel = of_property_read_bool(dev->of_node, + "snps,gfladj-refclk-lpm-sel-quirk"); + + dwc->tx_de_emphasis_quirk = of_property_read_bool(dev->of_node, + "snps,tx_de_emphasis_quirk"); + of_property_read_u8(dev->of_node, "snps,tx_de_emphasis", + &tx_de_emphasis); + of_property_read_string(dev->of_node, "snps,hsphy_interface", + &dwc->hsphy_interface); + of_property_read_u32(dev->of_node, "snps,quirk-frame-length-adjustment", + &dwc->fladj); + of_property_read_u32(dev->of_node, "snps,ref-clock-period-ns", + &dwc->ref_clk_per); + + dwc->dis_metastability_quirk = of_property_read_bool(dev->of_node, + "snps,dis_metastability_quirk"); + + dwc->dis_split_quirk = of_property_read_bool(dev->of_node, + "snps,dis-split-quirk"); + dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; - if (of_get_property(dev->of_node, "snps,dis_rxdet_inp3_quirk", - NULL)) - dwc->dis_rxdet_inp3_quirk = 1; + dwc->hird_threshold = hird_threshold; - of_property_read_u32_array(dev->of_node, - "snps,quirk-frame-length-adjustment", - &dwc->fladj, 1); + dwc->rx_thr_num_pkt_prd = rx_thr_num_pkt_prd; + dwc->rx_max_burst_prd = rx_max_burst_prd; - dwc->hird_threshold = hird_threshold - | (dwc->is_utmi_l1_suspend << 4); + dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; + dwc->tx_max_burst_prd = tx_max_burst_prd; dwc->imod_interval = 0; + + dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; } /* check whether the core supports IMOD */ bool dwc3_has_imod(struct dwc3 *dwc) { - return ((dwc3_is_usb3(dwc) && - dwc->revision >= DWC3_REVISION_300A) || - (dwc3_is_usb31(dwc) && - dwc->revision >= DWC3_USB31_REVISION_120A)); + return DWC3_VER_IS_WITHIN(DWC3, 300A, ANY) || + DWC3_VER_IS_WITHIN(DWC31, 120A, ANY) || + DWC3_IP_IS(DWC32); } static void dwc3_check_params(struct dwc3 *dwc) { struct device *dev = dwc->dev; + unsigned int hwparam_gen = + DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3); /* Check for proper value of imod_interval */ if (dwc->imod_interval && !dwc3_has_imod(dwc)) { @@ -1042,54 +1319,85 @@ static void dwc3_check_params(struct dwc3 *dwc) * affected version. */ if (!dwc->imod_interval && - (dwc->revision == DWC3_REVISION_300A)) + DWC3_VER_IS(DWC3, 300A)) dwc->imod_interval = 1; /* Check the maximum_speed parameter */ switch (dwc->maximum_speed) { - case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: + break; case USB_SPEED_SUPER: + if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) + dev_warn(dev, "UDC doesn't support Gen 1\n"); + break; case USB_SPEED_SUPER_PLUS: + if ((DWC3_IP_IS(DWC32) && + hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) || + (!DWC3_IP_IS(DWC32) && + hwparam_gen != DWC3_GHWPARAMS3_SSPHY_IFC_GEN2)) + dev_warn(dev, "UDC doesn't support SSP\n"); break; default: dev_err(dev, "invalid maximum_speed parameter %d\n", dwc->maximum_speed); - /* fall through */ + fallthrough; case USB_SPEED_UNKNOWN: - /* default to superspeed */ - dwc->maximum_speed = USB_SPEED_SUPER; - - /* - * default to superspeed plus if we are capable. - */ - if (dwc3_is_usb31(dwc) && - (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == - DWC3_GHWPARAMS3_SSPHY_IFC_GEN2)) + switch (hwparam_gen) { + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2: dwc->maximum_speed = USB_SPEED_SUPER_PLUS; - + break; + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1: + if (DWC3_IP_IS(DWC32)) + dwc->maximum_speed = USB_SPEED_SUPER_PLUS; + else + dwc->maximum_speed = USB_SPEED_SUPER; + break; + case DWC3_GHWPARAMS3_SSPHY_IFC_DIS: + dwc->maximum_speed = USB_SPEED_HIGH; + break; + default: + dwc->maximum_speed = USB_SPEED_SUPER; + break; + } break; } -} - -static void dwc3_coresoft_reset(struct dwc3 *dwc) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg |= DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* - * Similar reset sequence in U-Boot has a 100ms delay here. In - * practice reset sequence seem to work as expected even - * without a delay. + * Currently the controller does not have visibility into the HW + * parameter to determine the maximum number of lanes the HW supports. + * If the number of lanes is not specified in the device property, then + * set the default to support dual-lane for DWC_usb32 and single-lane + * for DWC_usb31 for super-speed-plus. */ - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg &= ~DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); + if (dwc->maximum_speed == USB_SPEED_SUPER_PLUS) { + switch (dwc->max_ssp_rate) { + case USB_SSP_GEN_2x1: + if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_GEN1) + dev_warn(dev, "UDC only supports Gen 1\n"); + break; + case USB_SSP_GEN_1x2: + case USB_SSP_GEN_2x2: + if (DWC3_IP_IS(DWC31)) + dev_warn(dev, "UDC only supports single lane\n"); + break; + case USB_SSP_GEN_UNKNOWN: + default: + switch (hwparam_gen) { + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2: + if (DWC3_IP_IS(DWC32)) + dwc->max_ssp_rate = USB_SSP_GEN_2x2; + else + dwc->max_ssp_rate = USB_SSP_GEN_2x1; + break; + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1: + if (DWC3_IP_IS(DWC32)) + dwc->max_ssp_rate = USB_SSP_GEN_1x2; + break; + } + break; + } + } } static int dwc3_probe(struct device *dev) @@ -1127,7 +1435,12 @@ static int dwc3_probe(struct device *dev) mdelay(1); reset_control_deassert(dwc->reset); - dwc3_coresoft_reset(dwc); + if (!dwc3_core_is_valid(dwc)) { + dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); + return -ENODEV; + } + + dwc3_core_soft_reset(dwc); dwc3_cache_hwparams(dwc); @@ -1165,8 +1478,11 @@ static void dwc3_remove(struct device *dev) { struct dwc3 *dwc = dev->priv; + dwc3_core_exit_mode(dwc); dwc3_core_exit(dwc); clk_bulk_put(dwc->num_clks, dwc->clks); + dwc3_free_event_buffers(dwc); + dwc3_free_scratch_buffers(dwc); } static const struct of_device_id of_dwc3_match[] = { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5ad1fea8e0..52853a4370 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0-only +/* SPDX-License-Identifier: GPL-2.0 */ /* * core.h - DesignWare USB3 DRD Core Header * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -12,9 +12,11 @@ #define __DRIVERS_USB_DWC3_CORE_H #include <linux/spinlock.h> -#include <usb/usb.h> -#include <usb/phy.h> -#include <usb/gadget.h> +#include <linux/usb/usb.h> +#include <linux/usb/phy.h> +#include <linux/usb/gadget.h> +#include <linux/mutex.h> +#include <linux/completion.h> #define DWC3_MSG_MAX 500 @@ -40,7 +42,7 @@ #define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3 #define DWC3_DEVICE_EVENT_WAKEUP 4 #define DWC3_DEVICE_EVENT_HIBER_REQ 5 -#define DWC3_DEVICE_EVENT_EOPF 6 +#define DWC3_DEVICE_EVENT_SUSPEND 6 #define DWC3_DEVICE_EVENT_SOF 7 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9 #define DWC3_DEVICE_EVENT_CMD_CMPL 10 @@ -55,6 +57,7 @@ #define DWC3_GEVNTCOUNT_EHB BIT(31) #define DWC3_GSNPSID_MASK 0xffff0000 #define DWC3_GSNPSREV_MASK 0xffff +#define DWC3_GSNPS_ID(p) (((p) & DWC3_GSNPSID_MASK) >> 16) /* DWC3 registers memory space boundries */ #define DWC3_XHCI_REGS_START 0x0 @@ -123,7 +126,9 @@ #define DWC3_GEVNTCOUNT(n) (0xc40c + ((n) * 0x10)) #define DWC3_GHWPARAMS8 0xc600 +#define DWC3_GUCTL3 0xc60c #define DWC3_GFLADJ 0xc630 +#define DWC3_GHWPARAMS9 0xc6e0 /* Device Registers */ #define DWC3_DCFG 0xc700 @@ -133,6 +138,7 @@ #define DWC3_DGCMDPAR 0xc710 #define DWC3_DGCMD 0xc714 #define DWC3_DALEPENA 0xc720 +#define DWC3_DCFG1 0xc740 /* DWC_usb32 only */ #define DWC3_DEP_BASE(n) (0xc800 + ((n) * 0x10)) #define DWC3_DEPCMDPAR2 0x00 @@ -210,6 +216,7 @@ /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) +#define DWC3_GCTL_PWRDNSCALE_MASK GENMASK(31, 19) #define DWC3_GCTL_U2RSTECN BIT(16) #define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6) #define DWC3_GCTL_CLK_BUS (0) @@ -236,8 +243,12 @@ #define DWC3_GUCTL_HSTINAUTORETRY BIT(14) /* Global User Control 1 Register */ +#define DWC3_GUCTL1_DEV_DECOUPLE_L1L2_EVT BIT(31) #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) -#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) +#define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) +#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) +#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) +#define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10) /* Global Status Register */ #define DWC3_GSTS_OTG_IP BIT(10) @@ -268,6 +279,7 @@ /* Global USB2 PHY Vendor Control Register */ #define DWC3_GUSB2PHYACC_NEWREGREQ BIT(25) +#define DWC3_GUSB2PHYACC_DONE BIT(24) #define DWC3_GUSB2PHYACC_BUSY BIT(23) #define DWC3_GUSB2PHYACC_WRITE BIT(22) #define DWC3_GUSB2PHYACC_ADDR(n) (n << 16) @@ -292,10 +304,14 @@ /* Global TX Fifo Size Register */ #define DWC31_GTXFIFOSIZ_TXFRAMNUM BIT(15) /* DWC_usb31 only */ -#define DWC31_GTXFIFOSIZ_TXFDEF(n) ((n) & 0x7fff) /* DWC_usb31 only */ -#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) +#define DWC31_GTXFIFOSIZ_TXFDEP(n) ((n) & 0x7fff) /* DWC_usb31 only */ +#define DWC3_GTXFIFOSIZ_TXFDEP(n) ((n) & 0xffff) #define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) +/* Global RX Fifo Size Register */ +#define DWC31_GRXFIFOSIZ_RXFDEP(n) ((n) & 0x7fff) /* DWC_usb31 only */ +#define DWC3_GRXFIFOSIZ_RXFDEP(n) ((n) & 0xffff) + /* Global Event Size Registers */ #define DWC3_GEVNTSIZ_INTMASK BIT(31) #define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff) @@ -346,18 +362,38 @@ #define DWC3_GHWPARAMS6_SRPSUPPORT BIT(10) #define DWC3_GHWPARAMS6_EN_FPGA BIT(7) +/* DWC_usb32 only */ +#define DWC3_GHWPARAMS6_MDWIDTH(n) ((n) & (0x3 << 8)) + /* Global HWPARAMS7 Register */ #define DWC3_GHWPARAMS7_RAM1_DEPTH(n) ((n) & 0xffff) #define DWC3_GHWPARAMS7_RAM2_DEPTH(n) (((n) >> 16) & 0xffff) +/* Global HWPARAMS9 Register */ +#define DWC3_GHWPARAMS9_DEV_TXF_FLUSH_BYPASS BIT(0) +#define DWC3_GHWPARAMS9_DEV_MST BIT(1) + /* Global Frame Length Adjustment Register */ #define DWC3_GFLADJ_30MHZ_SDBND_SEL BIT(7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f +#define DWC3_GFLADJ_REFCLK_FLADJ_MASK GENMASK(21, 8) +#define DWC3_GFLADJ_REFCLK_LPM_SEL BIT(23) +#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 /* Global User Control Register 2 */ #define DWC3_GUCTL2_RST_ACTBITLATER BIT(14) +/* Global User Control Register 3 */ +#define DWC3_GUCTL3_SPLITDISABLE BIT(14) + /* Device Configuration Register */ +#define DWC3_DCFG_NUMLANES(n) (((n) & 0x3) << 30) /* DWC_usb32 only */ + #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -366,13 +402,12 @@ #define DWC3_DCFG_SUPERSPEED (4 << 0) #define DWC3_DCFG_HIGHSPEED (0 << 0) #define DWC3_DCFG_FULLSPEED BIT(0) -#define DWC3_DCFG_LOWSPEED (2 << 0) -#define DWC3_DCFG_FULLSPEED1 (3 << 0) #define DWC3_DCFG_NUMP_SHIFT 17 #define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f) #define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT) #define DWC3_DCFG_LPM_CAP BIT(22) +#define DWC3_DCFG_IGNSTRMPP BIT(23) /* Device Control Register */ #define DWC3_DCTL_RUN_STOP BIT(31) @@ -394,8 +429,7 @@ #define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) /* These apply for core versions 1.94a and later */ -#define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf) -#define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20) +#define DWC3_DCTL_NYET_THRES(n) (((n) & 0xf) << 20) #define DWC3_DCTL_KEEP_CONNECT BIT(19) #define DWC3_DCTL_L1_HIBER_EN BIT(18) @@ -425,7 +459,7 @@ #define DWC3_DEVTEN_CMDCMPLTEN BIT(10) #define DWC3_DEVTEN_ERRTICERREN BIT(9) #define DWC3_DEVTEN_SOFEN BIT(7) -#define DWC3_DEVTEN_EOPFEN BIT(6) +#define DWC3_DEVTEN_U3L2L1SUSPEN BIT(6) #define DWC3_DEVTEN_HIBERNATIONREQEVTEN BIT(5) #define DWC3_DEVTEN_WKUPEVTEN BIT(4) #define DWC3_DEVTEN_ULSTCNGEN BIT(3) @@ -433,6 +467,8 @@ #define DWC3_DEVTEN_USBRSTEN BIT(1) #define DWC3_DEVTEN_DISCONNEVTEN BIT(0) +#define DWC3_DSTS_CONNLANES(n) (((n) >> 30) & 0x3) /* DWC_usb32 only */ + /* Device Status Register */ #define DWC3_DSTS_DCNRD BIT(29) @@ -460,8 +496,6 @@ #define DWC3_DSTS_SUPERSPEED (4 << 0) #define DWC3_DSTS_HIGHSPEED (0 << 0) #define DWC3_DSTS_FULLSPEED BIT(0) -#define DWC3_DSTS_LOWSPEED (2 << 0) -#define DWC3_DSTS_FULLSPEED1 (3 << 0) /* Device Generic Command Register */ #define DWC3_DGCMD_SET_LMP 0x01 @@ -475,6 +509,7 @@ #define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09 #define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c +#define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 #define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F) @@ -517,6 +552,9 @@ /* The EP number goes 0..31 so ep0 is always out and ep1 is always in */ #define DWC3_DALEPENA_EP(n) BIT(n) +/* DWC_usb32 DCFG1 config */ +#define DWC3_DCFG1_DIS_MST_ENH BIT(1) + #define DWC3_DEPCMD_TYPE_CONTROL 0 #define DWC3_DEPCMD_TYPE_ISOC 1 #define DWC3_DEPCMD_TYPE_BULK 2 @@ -602,16 +640,26 @@ struct dwc3_trb; /** * struct dwc3_event_buffer - Software event buffer representation * @buf: _THE_ buffer + * @cache: The buffer cache used in the threaded interrupt * @length: size of this buffer * @lpos: event offset + * @count: cache of last read event count register + * @flags: flags related to this event buffer * @dma: dma_addr_t * @dwc: pointer to DWC controller */ struct dwc3_event_buffer { void *buf; - unsigned length; + void *cache; + unsigned int length; unsigned int lpos; + unsigned int count; + unsigned int flags; + +#define DWC3_EVENT_PENDING BIT(0) + dma_addr_t dma; + struct dwc3 *dwc; }; @@ -622,57 +670,66 @@ struct dwc3_event_buffer { #define DWC3_EP_DIRECTION_RX false #define DWC3_TRB_NUM 256 -#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1) /** * struct dwc3_ep - device side endpoint representation * @endpoint: usb endpoint - * @pending_list: list of requests for this endpoint + * @cancelled_list: list of cancelled requests for this endpoint + * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint + * @regs: pointer to first endpoint register * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool - * @free_slot: next slot which is going to be used - * @busy_slot: first slot which is owned by HW - * @desc: usb_endpoint_descriptor pointer + * @trb_enqueue: enqueue 'pointer' into TRB array + * @trb_dequeue: dequeue 'pointer' into TRB array * @dwc: pointer to DWC controller * @saved_state: ep state saved during hibernation * @flags: endpoint flags (wedged, stalled, ...) - * @current_trb: index of current used trb * @number: endpoint number (1 - 15) * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK * @resource_index: Resource transfer index + * @frame_number: set to the frame number we want this transfer to start (ISOC) * @interval: the interval on which the ISOC transfer is started * @name: a human readable name e.g. ep1out-bulk * @direction: true for TX, false for RX * @stream_capable: true when streams are enabled + * @combo_num: the test combination BIT[15:14] of the frame number to test + * isochronous START TRANSFER command failure workaround + * @start_cmd_status: the status of testing START TRANSFER command with + * combo_num = 'b00 */ struct dwc3_ep { - struct usb_ep endpoint; - struct list_head cancelled_list; - struct list_head pending_list; - struct list_head started_list; - - void __iomem *regs; - - struct dwc3_trb *trb_pool; - dma_addr_t trb_pool_dma; - u32 free_slot; - u32 busy_slot; - const struct usb_ss_ep_comp_descriptor *comp_desc; - struct dwc3 *dwc; - - u32 saved_state; - unsigned flags; + struct usb_ep endpoint; + struct list_head cancelled_list; + struct list_head pending_list; + struct list_head started_list; + + void __iomem *regs; + + struct dwc3_trb *trb_pool; + dma_addr_t trb_pool_dma; + struct dwc3 *dwc; + + u32 saved_state; + unsigned int flags; #define DWC3_EP_ENABLED BIT(0) -#define DWC3_EP_STALL BIT(1) -#define DWC3_EP_WEDGE BIT(2) -#define DWC3_EP_TRANSFER_STARTED BIT(3) -#define DWC3_EP_PENDING_REQUEST BIT(4) +#define DWC3_EP_STALL BIT(1) +#define DWC3_EP_WEDGE BIT(2) +#define DWC3_EP_TRANSFER_STARTED BIT(3) +#define DWC3_EP_END_TRANSFER_PENDING BIT(4) +#define DWC3_EP_PENDING_REQUEST BIT(5) +#define DWC3_EP_DELAY_START BIT(6) +#define DWC3_EP_WAIT_TRANSFER_COMPLETE BIT(7) +#define DWC3_EP_IGNORE_NEXT_NOSTREAM BIT(8) +#define DWC3_EP_FORCE_RESTART_STREAM BIT(9) +#define DWC3_EP_FIRST_STREAM_PRIMED BIT(10) +#define DWC3_EP_PENDING_CLEAR_STALL BIT(11) +#define DWC3_EP_TXFIFO_RESIZED BIT(12) +#define DWC3_EP_DELAY_STOP BIT(13) /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN BIT(31) - unsigned current_trb; /* * IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will * use a u8 type here. If anybody decides to increase number of TRBs to @@ -682,23 +739,23 @@ struct dwc3_ep { * By using u8 types we ensure that our % operator when incrementing * enqueue and dequeue get optimized away by the compiler. */ - u8 trb_enqueue; - u8 trb_dequeue; + u8 trb_enqueue; + u8 trb_dequeue; - u8 number; - u8 type; - u8 resource_index; - u32 frame_number; - u32 interval; + u8 number; + u8 type; + u8 resource_index; + u32 frame_number; + u32 interval; - char name[20]; + char name[20]; - unsigned direction:1; - unsigned stream_capable:1; + unsigned direction:1; + unsigned stream_capable:1; /* For isochronous START TRANSFER workaround only */ - u8 combo_num; - int start_cmd_status; + u8 combo_num; + int start_cmd_status; }; enum dwc3_phy { @@ -797,6 +854,7 @@ struct dwc3_trb { * @hwparams6: GHWPARAMS6 * @hwparams7: GHWPARAMS7 * @hwparams8: GHWPARAMS8 + * @hwparams9: GHWPARAMS9 */ struct dwc3_hwparams { u32 hwparams0; @@ -808,13 +866,12 @@ struct dwc3_hwparams { u32 hwparams6; u32 hwparams7; u32 hwparams8; + u32 hwparams9; }; /* HWPARAMS0 */ #define DWC3_MODE(n) ((n) & 0x7) -#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8) - /* HWPARAMS1 */ #define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) @@ -829,31 +886,67 @@ struct dwc3_hwparams { /* HWPARAMS7 */ #define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) -struct dwc3_request { - struct usb_request request; - struct list_head list; - struct dwc3_ep *dep; - u32 start_slot; - - unsigned remaining; - - unsigned int status; -#define DWC3_REQUEST_STATUS_QUEUED 0 -#define DWC3_REQUEST_STATUS_STARTED 1 -#define DWC3_REQUEST_STATUS_CANCELLED 2 -#define DWC3_REQUEST_STATUS_COMPLETED 3 -#define DWC3_REQUEST_STATUS_UNKNOWN -1 +/* HWPARAMS9 */ +#define DWC3_MST_CAPABLE(p) (!!((p)->hwparams9 & \ + DWC3_GHWPARAMS9_DEV_MST)) - u8 epnum; +/** + * struct dwc3_request - representation of a transfer request + * @request: struct usb_request to be transferred + * @list: a list_head used for request queueing + * @dep: struct dwc3_ep owning this request + * @sg: pointer to first incomplete sg + * @start_sg: pointer to the sg which should be queued next + * @num_pending_sgs: counter to pending sgs + * @num_queued_sgs: counter to the number of sgs which already got queued + * @remaining: amount of data remaining + * @status: internal dwc3 request status tracking + * @epnum: endpoint number to which this request refers + * @trb: pointer to struct dwc3_trb + * @trb_dma: DMA address of @trb + * @num_trbs: number of TRBs used by this request + * @needs_extra_trb: true when request needs one extra TRB (either due to ZLP + * or unaligned OUT) + * @direction: IN or OUT direction flag + * @mapped: true when request has been dma-mapped + */ +struct dwc3_request { + struct usb_request request; + struct list_head list; + struct dwc3_ep *dep; + struct scatterlist *sg; + struct scatterlist *start_sg; + + unsigned int num_pending_sgs; + unsigned int num_queued_sgs; + unsigned int remaining; + + unsigned int status; +#define DWC3_REQUEST_STATUS_QUEUED 0 +#define DWC3_REQUEST_STATUS_STARTED 1 +#define DWC3_REQUEST_STATUS_DISCONNECTED 2 +#define DWC3_REQUEST_STATUS_DEQUEUED 3 +#define DWC3_REQUEST_STATUS_STALLED 4 +#define DWC3_REQUEST_STATUS_COMPLETED 5 +#define DWC3_REQUEST_STATUS_UNKNOWN -1 + + u8 epnum; struct dwc3_trb *trb; - dma_addr_t trb_dma; + dma_addr_t trb_dma; + + unsigned int num_trbs; - unsigned num_trbs; + unsigned int needs_extra_trb:1; + unsigned int direction:1; + unsigned int mapped:1; +}; - unsigned needs_extra_trb:1; - unsigned direction:1; - unsigned mapped:1; - unsigned queued:1; +/* + * struct dwc3_scratchpad_array - hibernation scratchpad array + * (format defined by hw) + */ +struct dwc3_scratchpad_array { + __le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS]; }; /** @@ -869,6 +962,7 @@ struct dwc3_request { * @scratch_addr: dma address of scratchbuf * @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing + * @mutex: for mode switching * @dev: pointer to our struct device * @sysdev: pointer to the DMA-capable device * @xhci: pointer to our xHCI child @@ -877,12 +971,14 @@ struct dwc3_request { * @eps: endpoint array * @gadget: device side representation of the peripheral controller * @gadget_driver: pointer to the gadget driver - * @clks: array of clocks - * @num_clks: number of clocks + * @bus_clk: clock for accessing the registers + * @ref_clk: reference clock + * @susp_clk: clock used when the SS phy is in low power (S3) state * @reset: reset control * @regs: base address for our registers * @regs_size: address space size * @fladj: frame length adjustment + * @ref_clk_per: reference clock period configuration * @irq_gadget: peripheral controller's IRQ number * @otg_irq: IRQ number for OTG IRQs * @current_otg_role: current role of operation while using the OTG block @@ -891,7 +987,12 @@ struct dwc3_request { * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) - * @revision: revision register contents + * @max_ssp_rate: SuperSpeed Plus maximum signaling rate and lane count + * @gadget_max_speed: maximum gadget speed requested + * @gadget_ssp_rate: Gadget driver's maximum supported SuperSpeed Plus signaling + * rate and lane count. + * @ip: controller's ID + * @revision: controller's version of an IP * @version_type: VERSIONTYPE register contents, a sub release of a revision * @dr_mode: requested mode of operation * @current_dr_role: current role of operation when in dual-role mode @@ -901,6 +1002,10 @@ struct dwc3_request { * @hsphy_mode: UTMI phy mode, one of following: * - USBPHY_INTERFACE_MODE_UTMI * - USBPHY_INTERFACE_MODE_UTMIW + * @role_sw: usb_role_switch handle + * @role_switch_default_mode: default operation mode of controller while + * usb role is USB_ROLE_NONE. + * @usb_psy: pointer to power supply interface. * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY @@ -918,7 +1023,6 @@ struct dwc3_request { * @link_state: link state * @speed: device speed (super, high, full, low) * @hwparams: copy of hwparams registers - * @root: debugfs root folder pointer * @regset: debugfs pointer to regdump file * @dbg_lsp_select: current debug lsp mux register selection * @test_mode: true when we're entering a USB test mode @@ -929,8 +1033,11 @@ struct dwc3_request { * @rx_max_burst_prd: max periodic ESS receive burst size * @tx_thr_num_pkt_prd: periodic ESS transmit packet count * @tx_max_burst_prd: max periodic ESS transmit burst size + * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize + * @clear_stall_protocol: endpoint number that requires a delayed status phase * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise + * @softconnect: true when gadget connect is called, false when disconnect runs * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer @@ -939,17 +1046,19 @@ struct dwc3_request { * @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_fpga: true when we are using the FPGA board * @pending_events: true when we have pending IRQs to be handled + * @do_fifo_resize: true when txfifo resizing is enabled for dwc3 endpoints * @pullups_connected: true when Run/Stop bit is set * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @three_stage_setup: set if we perform a three phase setup * @dis_start_transfer_quirk: set if start_transfer failure SW workaround is * not needed for DWC_usb31 version 1.70a-ea06 and below * @usb3_lpm_capable: set if hadrware supports Link Power Management - * @usb2_lpm_disable: set to disable usb2 lpm + * @usb2_lpm_disable: set to disable usb2 lpm for host + * @usb2_gadget_lpm_disable: set to disable usb2 lpm for gadget * @disable_scramble_quirk: set if we enable the disable scramble quirk * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk @@ -962,7 +1071,11 @@ struct dwc3_request { * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG, * disabling the suspend signal to the PHY. + * @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled. + * @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled. * @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3 + * @async_callbacks: if set, indicate that async callbacks will be used. + * * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists * in GUSB2PHYCFG, specify that USB2 PHY doesn't * provide a free-running PHY clock. @@ -970,55 +1083,89 @@ struct dwc3_request { * change quirk. * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate * check during HS transmit. + * @resume-hs-terminations: Set if we enable quirk for fixing improper crc + * generation after resume from suspend. + * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed + * instances in park mode. * @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 + * 0 - -6dB de-emphasis + * 1 - -3.5dB de-emphasis + * 2 - No de-emphasis + * 3 - Reserved * @dis_metastability_quirk: set to disable metastability quirk. + * @dis_split_quirk: set to disable split boundary. * @imod_interval: set the interrupt moderation interval in 250ns - * increments or 0 to disable. + * increments or 0 to disable. + * @max_cfg_eps: current max number of IN eps used across all USB configs. + * @last_fifo_depth: last fifo depth used to determine next fifo ram start + * address. + * @num_ep_resized: carries the current number endpoints which have had its tx + * fifo resized. + * @debug_root: root debugfs directory for this device to put its files in. */ struct dwc3 { + struct work_struct drd_work; struct dwc3_trb *ep0_trb; - void *bounce; - void *scratchbuf; - u8 *setup_buf; - dma_addr_t ep0_trb_addr; - dma_addr_t bounce_addr; - dma_addr_t scratch_addr; - struct dwc3_request ep0_usb_req; + void *bounce; + void *scratchbuf; + u8 *setup_buf; + dma_addr_t ep0_trb_addr; + dma_addr_t bounce_addr; + dma_addr_t scratch_addr; + struct dwc3_request ep0_usb_req; + struct completion ep0_in_setup; + + /* device lock */ + spinlock_t lock; + + /* mode switching lock */ + struct mutex mutex; struct device *dev; + struct device *sysdev; struct device *xhci; + struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; - struct dwc3_event_buffer *ev_buf; - struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; + struct dwc3_event_buffer *ev_buf; + struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; - struct usb_gadget gadget; - struct usb_gadget_driver *gadget_driver; + struct usb_gadget *gadget; + struct usb_gadget_driver *gadget_driver; struct clk_bulk_data *clks; int num_clks; struct reset_control *reset; + struct usb_phy *usb2_phy; + struct usb_phy *usb3_phy; + struct phy *usb2_generic_phy; struct phy *usb3_generic_phy; bool phys_ready; + + struct ulpi *ulpi; bool ulpi_ready; void __iomem *regs; + size_t regs_size; enum usb_dr_mode dr_mode; u32 current_dr_role; u32 desired_dr_role; + struct extcon_dev *edev; + struct notifier_block edev_nb; enum usb_phy_interface hsphy_mode; + struct usb_role_switch *role_sw; + enum usb_dr_mode role_switch_default_mode; + + struct power_supply *usb_psy; u32 fladj; + u32 ref_clk_per; u32 irq_gadget; u32 otg_irq; u32 current_otg_role; @@ -1027,16 +1174,19 @@ struct dwc3 { u32 nr_scratch; u32 u1u2; u32 maximum_speed; + u32 gadget_max_speed; + enum usb_ssp_rate max_ssp_rate; + enum usb_ssp_rate gadget_ssp_rate; + + u32 ip; + +#define DWC3_IP 0x5533 +#define DWC31_IP 0x3331 +#define DWC32_IP 0x3332 - /* - * All 3.1 IP version constants are greater than the 3.0 IP - * version constants. This works for most version checks in - * dwc3. However, in the future, this may not apply as - * features may be developed on newer versions of the 3.0 IP - * that are not in the 3.1 IP. - */ u32 revision; +#define DWC3_REVISION_ANY 0x0 #define DWC3_REVISION_173A 0x5533173a #define DWC3_REVISION_175A 0x5533175a #define DWC3_REVISION_180A 0x5533180a @@ -1061,18 +1211,20 @@ struct dwc3 { #define DWC3_REVISION_310A 0x5533310a #define DWC3_REVISION_330A 0x5533330a -/* - * NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really - * just so dwc31 revisions are always larger than dwc3. - */ -#define DWC3_REVISION_IS_DWC31 0x80000000 -#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31) -#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) -#define DWC3_USB31_REVISION_160A (0x3136302a | DWC3_REVISION_IS_DWC31) -#define DWC3_USB31_REVISION_170A (0x3137302a | DWC3_REVISION_IS_DWC31) +#define DWC31_REVISION_ANY 0x0 +#define DWC31_REVISION_110A 0x3131302a +#define DWC31_REVISION_120A 0x3132302a +#define DWC31_REVISION_160A 0x3136302a +#define DWC31_REVISION_170A 0x3137302a +#define DWC31_REVISION_180A 0x3138302a +#define DWC31_REVISION_190A 0x3139302a + +#define DWC32_REVISION_ANY 0x0 +#define DWC32_REVISION_100A 0x3130302a u32 version_type; +#define DWC31_VERSIONTYPE_ANY 0x0 #define DWC31_VERSIONTYPE_EA01 0x65613031 #define DWC31_VERSIONTYPE_EA02 0x65613032 #define DWC31_VERSIONTYPE_EA03 0x65613033 @@ -1084,7 +1236,6 @@ struct dwc3 { enum dwc3_ep0_state ep0state; enum dwc3_link_state link_state; - u16 isoch_delay; u16 u2sel; u16 u2pel; u8 u1sel; @@ -1095,6 +1246,7 @@ struct dwc3 { u8 num_eps; struct dwc3_hwparams hwparams; + struct debugfs_regset32 *regset; u32 dbg_lsp_select; @@ -1106,10 +1258,13 @@ struct dwc3 { u8 rx_max_burst_prd; u8 tx_thr_num_pkt_prd; u8 tx_max_burst_prd; + u8 tx_fifo_resize_max_num; + u8 clear_stall_protocol; const char *hsphy_interface; unsigned connected:1; + unsigned softconnect:1; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; @@ -1117,18 +1272,16 @@ struct dwc3 { unsigned sysdev_is_parent:1; unsigned has_lpm_erratum:1; unsigned is_utmi_l1_suspend:1; - unsigned is_selfpowered:1; unsigned is_fpga:1; unsigned pending_events:1; - unsigned needs_fifo_resize:1; + unsigned do_fifo_resize:1; unsigned pullups_connected:1; - unsigned resize_fifos:1; unsigned setup_packet_pending:1; - unsigned start_config_issued:1; unsigned three_stage_setup:1; unsigned dis_start_transfer_quirk:1; unsigned usb3_lpm_capable:1; unsigned usb2_lpm_disable:1; + unsigned usb2_gadget_lpm_disable:1; unsigned disable_scramble_quirk:1; unsigned u2exit_lfps_quirk:1; @@ -1141,17 +1294,30 @@ struct dwc3 { unsigned dis_u3_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; + unsigned dis_u1_entry_quirk:1; + unsigned dis_u2_entry_quirk:1; unsigned dis_rxdet_inp3_quirk:1; unsigned dis_u2_freeclk_exists_quirk:1; unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1; + unsigned resume_hs_terminations:1; + unsigned parkmode_disable_ss_quirk:1; + unsigned gfladj_refclk_lpm_sel:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; unsigned dis_metastability_quirk:1; + unsigned dis_split_quirk:1; + unsigned async_callbacks:1; + u16 imod_interval; + + int max_cfg_eps; + int last_fifo_depth; + int num_ep_resized; + struct dentry *debug_root; }; #define INCRX_BURST_MODE 0 @@ -1175,31 +1341,7 @@ struct dwc3_event_type { #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 + * struct dwc3_event_depevt - Device Endpoint Events * @one_bit: indicates this is an endpoint event (not used) * @endpoint_number: number of the endpoint * @endpoint_event: The event we have: @@ -1238,6 +1380,10 @@ struct dwc3_event_depevt { #define DEPEVT_STREAMEVT_FOUND 1 #define DEPEVT_STREAMEVT_NOTFOUND 2 +/* Stream event parameter */ +#define DEPEVT_STREAM_PRIME 0xfffe +#define DEPEVT_STREAM_NOSTREAM 0x0 + /* Control-only Status */ #define DEPEVT_STATUS_CONTROL_DATA 1 #define DEPEVT_STATUS_CONTROL_STATUS 2 @@ -1264,7 +1410,7 @@ struct dwc3_event_depevt { * 3 - ULStChng * 4 - WkUpEvt * 5 - Reserved - * 6 - EOPF + * 6 - Suspend (EOPF on revisions 2.10a and prior) * 7 - SOF * 8 - Reserved * 9 - ErrticErr @@ -1336,28 +1482,63 @@ struct dwc3_gadget_ep_cmd_params { #define DWC3_HAS_OTG BIT(3) /* prototypes */ -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode); +void dwc3_set_mode(struct dwc3 *dwc, u32 mode); +u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); -/* check whether we are on the DWC_usb3 core */ -static inline bool dwc3_is_usb3(struct dwc3 *dwc) -{ - return !(dwc->revision & DWC3_REVISION_IS_DWC31); -} +#define DWC3_IP_IS(_ip) \ + (dwc->ip == _ip##_IP) + +#define DWC3_VER_IS(_ip, _ver) \ + (DWC3_IP_IS(_ip) && dwc->revision == _ip##_REVISION_##_ver) + +#define DWC3_VER_IS_PRIOR(_ip, _ver) \ + (DWC3_IP_IS(_ip) && dwc->revision < _ip##_REVISION_##_ver) -/* check whether we are on the DWC_usb31 core */ -static inline bool dwc3_is_usb31(struct dwc3 *dwc) +#define DWC3_VER_IS_WITHIN(_ip, _from, _to) \ + (DWC3_IP_IS(_ip) && \ + (int)dwc->revision >= _ip##_REVISION_##_from && \ + (!(_ip##_REVISION_##_to) || \ + dwc->revision <= _ip##_REVISION_##_to)) + +#define DWC3_VER_TYPE_IS_WITHIN(_ip, _ver, _from, _to) \ + (DWC3_VER_IS(_ip, _ver) && \ + dwc->version_type >= _ip##_VERSIONTYPE_##_from && \ + (!(_ip##_VERSIONTYPE_##_to) || \ + dwc->version_type <= _ip##_VERSIONTYPE_##_to)) + +/** + * dwc3_mdwidth - get MDWIDTH value in bits + * @dwc: pointer to our context structure + * + * Return MDWIDTH configuration value in bits. + */ +static inline u32 dwc3_mdwidth(struct dwc3 *dwc) { - return !!(dwc->revision & DWC3_REVISION_IS_DWC31); + u32 mdwidth; + + mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0); + if (DWC3_IP_IS(DWC32)) + mdwidth += DWC3_GHWPARAMS6_MDWIDTH(dwc->hwparams.hwparams6); + + return mdwidth; } bool dwc3_has_imod(struct dwc3 *dwc); +int dwc3_event_buffers_setup(struct dwc3 *dwc); +void dwc3_event_buffers_cleanup(struct dwc3 *dwc); + +int dwc3_core_soft_reset(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 #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) @@ -1366,9 +1547,12 @@ void dwc3_gadget_exit(struct dwc3 *dwc); int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); int dwc3_gadget_get_link_state(struct dwc3 *dwc); int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); -int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, +int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, struct dwc3_gadget_ep_cmd_params *params); -int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param); +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, + u32 param); +void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc); +void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep, int status); #else static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } @@ -1382,9 +1566,14 @@ static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) { return 0; } +static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + struct dwc3_gadget_ep_cmd_params *params) +{ return 0; } static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { return 0; } +static inline void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) +{ } #endif #if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 1494df261d..8bb2c9e3b9 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0-only -/** +/* SPDX-License-Identifier: GPL-2.0 */ +/* * debug.h - DesignWare USB3 DRD Controller Debug Header * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -68,6 +68,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd) return "All FIFO Flush"; case DWC3_DGCMD_SET_ENDPOINT_NRDY: return "Set Endpoint NRDY"; + case DWC3_DGCMD_SET_ENDPOINT_PRIME: + return "Set Endpoint Prime"; case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: return "Run SoC Bus Loopback Test"; default: @@ -112,7 +114,7 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state) case DWC3_LINK_STATE_RESUME: return "Resume"; default: - return "UNKNOWN link state\n"; + return "UNKNOWN link state"; } } @@ -141,7 +143,7 @@ dwc3_gadget_hs_link_string(enum dwc3_link_state link_state) case DWC3_LINK_STATE_RESUME: return "Resume"; default: - return "UNKNOWN link state\n"; + return "UNKNOWN link state"; } } @@ -193,294 +195,54 @@ static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) * dwc3_gadget_event_string - returns event name * @event: the event code */ -static inline const char * -dwc3_gadget_event_string(char *str, const struct dwc3_event_devt *event) +static inline const char *dwc3_gadget_event_string(char *str, size_t size, + const struct dwc3_event_devt *event) { enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK; switch (event->type) { case DWC3_DEVICE_EVENT_DISCONNECT: - sprintf(str, "Disconnect: [%s]", + snprintf(str, size, "Disconnect: [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_RESET: - sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "Reset [%s]", + dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CONNECT_DONE: - sprintf(str, "Connection Done [%s]", + snprintf(str, size, "Connection Done [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: - sprintf(str, "Link Change [%s]", + snprintf(str, size, "Link Change [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_WAKEUP: - sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "WakeUp [%s]", + dwc3_gadget_link_string(state)); break; - case DWC3_DEVICE_EVENT_EOPF: - sprintf(str, "End-Of-Frame [%s]", + case DWC3_DEVICE_EVENT_SUSPEND: + snprintf(str, size, "Suspend [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_SOF: - sprintf(str, "Start-Of-Frame [%s]", + snprintf(str, size, "Start-Of-Frame [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - sprintf(str, "Erratic Error [%s]", + snprintf(str, size, "Erratic Error [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CMD_CMPL: - sprintf(str, "Command Complete [%s]", + snprintf(str, size, "Command Complete [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_OVERFLOW: - sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state)); - break; - default: - sprintf(str, "UNKNOWN"); - } - - return str; -} - -static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str) -{ - switch (t & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: - sprintf(str, "Get Interface Status(Intf = %d, Length = %d)", - i, l); - break; - case USB_RECIP_ENDPOINT: - sprintf(str, "Get Endpoint Status(ep%d%s)", - i & ~USB_DIR_IN, - i & USB_DIR_IN ? "in" : "out"); - break; - } -} - -static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, - __u16 i, char *str) -{ - switch (t & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - sprintf(str, "%s Device Feature(%s%s)", - b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", - ({char *s; - switch (v) { - case USB_DEVICE_SELF_POWERED: - s = "Self Powered"; - break; - case USB_DEVICE_REMOTE_WAKEUP: - s = "Remote Wakeup"; - break; - case USB_DEVICE_TEST_MODE: - s = "Test Mode"; - break; - case USB_DEVICE_U1_ENABLE: - s = "U1 Enable"; - break; - case USB_DEVICE_U2_ENABLE: - s = "U2 Enable"; - break; - case USB_DEVICE_LTM_ENABLE: - s = "LTM Enable"; - break; - default: - s = "UNKNOWN"; - } s; }), - v == USB_DEVICE_TEST_MODE ? - ({ char *s; - switch (i) { - case TEST_J: - s = ": TEST_J"; - break; - case TEST_K: - s = ": TEST_K"; - break; - case TEST_SE0_NAK: - s = ": TEST_SE0_NAK"; - break; - case TEST_PACKET: - s = ": TEST_PACKET"; - break; - case TEST_FORCE_EN: - s = ": TEST_FORCE_EN"; - break; - default: - s = ": UNKNOWN"; - } s; }) : ""); - break; - case USB_RECIP_INTERFACE: - sprintf(str, "%s Interface Feature(%s)", - b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", - v == USB_INTRF_FUNC_SUSPEND ? - "Function Suspend" : "UNKNOWN"); - break; - case USB_RECIP_ENDPOINT: - sprintf(str, "%s Endpoint Feature(%s ep%d%s)", - b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", - v == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN", - i & ~USB_DIR_IN, - i & USB_DIR_IN ? "in" : "out"); - break; - } -} - -static inline void dwc3_decode_set_address(__u16 v, char *str) -{ - sprintf(str, "Set Address(Addr = %02x)", v); -} - -static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v, - __u16 i, __u16 l, char *str) -{ - sprintf(str, "%s %s Descriptor(Index = %d, Length = %d)", - b == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set", - ({ char *s; - switch (v >> 8) { - case USB_DT_DEVICE: - s = "Device"; - break; - case USB_DT_CONFIG: - s = "Configuration"; - break; - case USB_DT_STRING: - s = "String"; - break; - case USB_DT_INTERFACE: - s = "Interface"; - break; - case USB_DT_ENDPOINT: - s = "Endpoint"; - break; - case USB_DT_DEVICE_QUALIFIER: - s = "Device Qualifier"; - break; - case USB_DT_OTHER_SPEED_CONFIG: - s = "Other Speed Config"; - break; - case USB_DT_INTERFACE_POWER: - s = "Interface Power"; - break; - case USB_DT_OTG: - s = "OTG"; - break; - case USB_DT_DEBUG: - s = "Debug"; - break; - case USB_DT_INTERFACE_ASSOCIATION: - s = "Interface Association"; - break; - case USB_DT_BOS: - s = "BOS"; - break; - case USB_DT_DEVICE_CAPABILITY: - s = "Device Capability"; - break; - case USB_DT_PIPE_USAGE: - s = "Pipe Usage"; - break; - case USB_DT_SS_ENDPOINT_COMP: - s = "SS Endpoint Companion"; - break; - case USB_DT_SSP_ISOC_ENDPOINT_COMP: - s = "SSP Isochronous Endpoint Companion"; - break; - default: - s = "UNKNOWN"; - break; - } s; }), v & 0xff, l); -} - - -static inline void dwc3_decode_get_configuration(__u16 l, char *str) -{ - sprintf(str, "Get Configuration(Length = %d)", l); -} - -static inline void dwc3_decode_set_configuration(__u8 v, char *str) -{ - sprintf(str, "Set Configuration(Config = %d)", v); -} - -static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str) -{ - sprintf(str, "Get Interface(Intf = %d, Length = %d)", i, l); -} - -static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str) -{ - sprintf(str, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v); -} - -static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str) -{ - sprintf(str, "Synch Frame(Endpoint = %d, Length = %d)", i, l); -} - -static inline void dwc3_decode_set_sel(__u16 l, char *str) -{ - sprintf(str, "Set SEL(Length = %d)", l); -} - -static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str) -{ - sprintf(str, "Set Isochronous Delay(Delay = %d ns)", v); -} - -/** - * dwc3_decode_ctrl - returns a string represetion of ctrl request - */ -static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, - __u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength) -{ - switch (bRequest) { - case USB_REQ_GET_STATUS: - dwc3_decode_get_status(bRequestType, wIndex, wLength, str); - break; - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - dwc3_decode_set_clear_feature(bRequestType, bRequest, wValue, - wIndex, str); - break; - case USB_REQ_SET_ADDRESS: - dwc3_decode_set_address(wValue, str); - break; - case USB_REQ_GET_DESCRIPTOR: - case USB_REQ_SET_DESCRIPTOR: - dwc3_decode_get_set_descriptor(bRequestType, bRequest, wValue, - wIndex, wLength, str); - break; - case USB_REQ_GET_CONFIGURATION: - dwc3_decode_get_configuration(wLength, str); - break; - case USB_REQ_SET_CONFIGURATION: - dwc3_decode_set_configuration(wValue, str); - break; - case USB_REQ_GET_INTERFACE: - dwc3_decode_get_intf(wIndex, wLength, str); - break; - case USB_REQ_SET_INTERFACE: - dwc3_decode_set_intf(wValue, wIndex, str); - break; - case USB_REQ_SYNCH_FRAME: - dwc3_decode_synch_frame(wIndex, wLength, str); - break; - case USB_REQ_SET_SEL: - dwc3_decode_set_sel(wLength, str); - break; - case USB_REQ_SET_ISOCH_DELAY: - dwc3_decode_set_isoch_delay(wValue, str); + snprintf(str, size, "Overflow [%s]", + dwc3_gadget_link_string(state)); break; default: - sprintf(str, "%02x %02x %02x %02x %02x %02x %02x %02x", - bRequestType, bRequest, - cpu_to_le16(wValue) & 0xff, - cpu_to_le16(wValue) >> 8, - cpu_to_le16(wIndex) & 0xff, - cpu_to_le16(wIndex) >> 8, - cpu_to_le16(wLength) & 0xff, - cpu_to_le16(wLength) >> 8); + snprintf(str, size, "UNKNOWN"); } return str; @@ -490,48 +252,41 @@ static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, * dwc3_ep_event_string - returns event name * @event: then event code */ -static inline const char * -dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, - u32 ep0state) +static inline const char *dwc3_ep_event_string(char *str, size_t size, + const struct dwc3_event_depevt *event, u32 ep0state) { u8 epnum = event->endpoint_number; size_t len; int status; - int ret; - ret = sprintf(str, "ep%d%s: ", epnum >> 1, + len = scnprintf(str, size, "ep%d%s: ", epnum >> 1, (epnum & 1) ? "in" : "out"); - if (ret < 0) - return "UNKNOWN"; status = event->status; switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: - len = strlen(str); - sprintf(str + len, "Transfer Complete (%c%c%c)", + len += scnprintf(str + len, size - len, + "Transfer Complete (%c%c%c)", status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', status & DEPEVT_STATUS_LST ? 'L' : 'l'); - len = strlen(str); - if (epnum <= 1) - sprintf(str + len, " [%s]", dwc3_ep0_state_string(ep0state)); + scnprintf(str + len, size - len, " [%s]", + dwc3_ep0_state_string(ep0state)); break; case DWC3_DEPEVT_XFERINPROGRESS: - len = strlen(str); - - sprintf(str + len, "Transfer In Progress [%d] (%c%c%c)", + scnprintf(str + len, size - len, + "Transfer In Progress [%08x] (%c%c%c)", event->parameters, status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', status & DEPEVT_STATUS_LST ? 'M' : 'm'); break; case DWC3_DEPEVT_XFERNOTREADY: - len = strlen(str); - - sprintf(str + len, "Transfer Not Ready [%d]%s", + len += scnprintf(str + len, size - len, + "Transfer Not Ready [%08x]%s", event->parameters, status & DEPEVT_STATUS_TRANSFER_ACTIVE ? " (Active)" : " (Not Active)"); @@ -542,36 +297,38 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, switch (phase) { case DEPEVT_STATUS_CONTROL_DATA: - strcat(str, " [Data Phase]"); + scnprintf(str + len, size - len, + " [Data Phase]"); break; case DEPEVT_STATUS_CONTROL_STATUS: - strcat(str, " [Status Phase]"); + scnprintf(str + len, size - len, + " [Status Phase]"); } } break; case DWC3_DEPEVT_RXTXFIFOEVT: - strcat(str, "FIFO"); + scnprintf(str + len, size - len, "FIFO"); break; case DWC3_DEPEVT_STREAMEVT: status = event->status; switch (status) { case DEPEVT_STREAMEVT_FOUND: - sprintf(str + ret, " Stream %d Found", + scnprintf(str + len, size - len, " Stream %d Found", event->parameters); break; case DEPEVT_STREAMEVT_NOTFOUND: default: - strcat(str, " Stream Not Found"); + scnprintf(str + len, size - len, " Stream Not Found"); break; } break; case DWC3_DEPEVT_EPCMDCMPLT: - strcat(str, "Endpoint Command Complete"); + scnprintf(str + len, size - len, "Endpoint Command Complete"); break; default: - sprintf(str, "UNKNOWN"); + scnprintf(str + len, size - len, "UNKNOWN"); } return str; @@ -596,8 +353,8 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) 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_SUSPEND: + return "Suspend"; case DWC3_DEVICE_EVENT_SOF: return "Start of Frame"; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: @@ -611,14 +368,17 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) } } -static inline const char *dwc3_decode_event(char *str, u32 event, u32 ep0state) +static inline const char *dwc3_decode_event(char *str, size_t size, u32 event, + u32 ep0state) { - const union dwc3_event evt = (union dwc3_event) event; + union dwc3_event evt; + + memcpy(&evt, &event, sizeof(event)); if (evt.type.is_devspec) - return dwc3_gadget_event_string(str, &evt.devt); + return dwc3_gadget_event_string(str, size, &evt.devt); else - return dwc3_ep_event_string(str, &evt.depevt, ep0state); + return dwc3_ep_event_string(str, size, &evt.depevt, ep0state); } static inline const char *dwc3_ep_cmd_status_string(int status) @@ -653,9 +413,15 @@ static inline const char *dwc3_gadget_generic_cmd_status_string(int status) #ifdef CONFIG_DEBUG_FS -extern void dwc3_debugfs_init(struct dwc3 *); -extern void dwc3_debugfs_exit(struct dwc3 *); +extern void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep); +extern void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep); +extern void dwc3_debugfs_init(struct dwc3 *d); +extern void dwc3_debugfs_exit(struct dwc3 *d); #else +static inline void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep) +{ } +static inline void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep) +{ } static inline void dwc3_debugfs_init(struct dwc3 *d) { } static inline void dwc3_debugfs_exit(struct dwc3 *d) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c0e316e14f..6285566b4b 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -1,26 +1,26 @@ -// SPDX-License-Identifier: GPL-2.0-only -/** +// SPDX-License-Identifier: GPL-2.0 +/* * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling * - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://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. - * - * commit c00552ebaf : Merge 3.18-rc7 into usb-next */ #include <common.h> #include <dma.h> #include <linux/kernel.h> #include <linux/list.h> +#include <linux/completion.h> -#include <usb/gadget.h> +#include <linux/usb/gadget.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" @@ -29,11 +29,10 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, - dma_addr_t buf_dma, u32 len, u32 type, - bool chain) + dma_addr_t buf_dma, u32 len, u32 type, bool chain) { - struct dwc3_trb *trb; - struct dwc3 *dwc; + struct dwc3_trb *trb; + struct dwc3 *dwc; dwc = dep->dwc; trb = &dwc->ep0_trb[dep->trb_enqueue]; @@ -47,67 +46,47 @@ static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl = type; trb->ctrl |= (DWC3_TRB_CTRL_HWO - | DWC3_TRB_CTRL_ISP_IMI); + | 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_TRB_CTRL_LST); } static int dwc3_ep0_start_trans(struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; - struct dwc3 *dwc; - int ret; - - dwc = dep->dwc; + struct dwc3 *dwc; + int ret; - if (dep->flags & DWC3_EP_TRANSFER_STARTED) { - dev_err(dwc->dev, "%s: transfer already started\n", dep->name); + if (dep->flags & DWC3_EP_TRANSFER_STARTED) return 0; - } + + dwc = dep->dwc; memset(¶ms, 0, sizeof(params)); params.param0 = upper_32_bits(dwc->ep0_trb_addr); params.param1 = lower_32_bits(dwc->ep0_trb_addr); ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, ¶ms); - if (ret < 0) { - dev_err(dwc->dev, "%s: STARTTRANSFER failed\n", dep->name); + if (ret < 0) return ret; - } dwc->ep0_next_event = DWC3_EP0_COMPLETE; return 0; } -static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) -{ - switch (state) { - case EP0_UNCONNECTED: - return "Unconnected"; - case EP0_SETUP_PHASE: - return "Setup Phase"; - case EP0_DATA_PHASE: - return "Data Phase"; - case EP0_STATUS_PHASE: - return "Status Phase"; - default: - return "UNKNOWN"; - } -} - static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, - struct dwc3_request *req) + struct dwc3_request *req) { - struct dwc3 *dwc = dep->dwc; + struct dwc3 *dwc = dep->dwc; - req->request.actual = 0; - req->request.status = -EINPROGRESS; - req->epnum = dep->number; + req->request.actual = 0; + req->request.status = -EINPROGRESS; + req->epnum = dep->number; list_add_tail(&req->list, &dep->pending_list); @@ -121,7 +100,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, * IRQ we were waiting for is long gone. */ if (dep->flags & DWC3_EP_PENDING_REQUEST) { - unsigned direction; + unsigned int direction; direction = !!(dep->flags & DWC3_EP0_DIR_IN); @@ -143,16 +122,14 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, * handle it here. */ if (dwc->delayed_status) { - unsigned direction; + unsigned int direction; direction = !dwc->ep0_expect_in; dwc->delayed_status = false; - usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); + usb_gadget_set_state(dwc->gadget, USB_STATE_CONFIGURED); 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\n"); return 0; } @@ -190,7 +167,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, * XferNotReady(STATUS). */ if (dwc->three_stage_setup) { - unsigned direction; + unsigned int direction; direction = dwc->ep0_expect_in; dwc->ep0state = EP0_DATA_PHASE; @@ -205,16 +182,18 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, int dwc3_gadget_ep0_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; - int ret; + struct dwc3_request *req = to_dwc3_request(request); + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + + unsigned long flags; + + int ret; spin_lock_irqsave(&dwc->lock, flags); - if (!dep->endpoint.desc) { - dev_err(dwc->dev, "trying to queue request %p to disabled %s\n", - request, dep->name); + if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) { + dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", + dep->name); ret = -ESHUTDOWN; goto out; } @@ -225,10 +204,6 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request) goto out; } - dev_dbg(dwc->dev, "queueing request %p to %s length %d state '%s'\n", - request, dep->name, request->length, - dwc3_ep0_state_string(dwc->ep0state)); - ret = __dwc3_gadget_ep0_queue(dep, req); out: @@ -237,9 +212,9 @@ out: return ret; } -static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) +void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) { - struct dwc3_ep *dep; + struct dwc3_ep *dep; /* reinitialize physical ep1 */ dep = dwc->eps[1]; @@ -252,20 +227,22 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) dwc->delayed_status = false; if (!list_empty(&dep->pending_list)) { - struct dwc3_request *req; + struct dwc3_request *req; req = next_request(&dep->pending_list); dwc3_gadget_giveback(dep, req, -ECONNRESET); } + dwc->eps[0]->trb_enqueue = 0; + dwc->eps[1]->trb_enqueue = 0; dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } 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; + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; dwc3_ep0_stall_and_restart(dwc); @@ -274,8 +251,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) { - unsigned long flags; - int ret; + unsigned long flags; + int ret; spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep0_set_halt(ep, value); @@ -286,27 +263,49 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) void dwc3_ep0_out_start(struct dwc3 *dwc) { - struct dwc3_ep *dep; - int ret; + struct dwc3_ep *dep; + int ret; + int i; + + complete(&dwc->ep0_in_setup); dep = dwc->eps[0]; dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8, - DWC3_TRBCTL_CONTROL_SETUP, false); + DWC3_TRBCTL_CONTROL_SETUP, false); ret = dwc3_ep0_start_trans(dep); WARN_ON(ret < 0); + for (i = 2; i < DWC3_ENDPOINTS_NUM; i++) { + struct dwc3_ep *dwc3_ep; + + dwc3_ep = dwc->eps[i]; + if (!dwc3_ep) + continue; + + if (!(dwc3_ep->flags & DWC3_EP_DELAY_STOP)) + continue; + + dwc3_ep->flags &= ~DWC3_EP_DELAY_STOP; + if (dwc->connected) + dwc3_stop_active_transfer(dwc3_ep, true, true); + else + dwc3_remove_requests(dwc, dwc3_ep, -ESHUTDOWN); + } } static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) { - struct dwc3_ep *dep; - u32 windex = le16_to_cpu(wIndex_le); - u32 epnum; + struct dwc3_ep *dep; + u32 windex = le16_to_cpu(wIndex_le); + u32 epnum; epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1; if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) epnum |= 1; dep = dwc->eps[epnum]; + if (dep == NULL) + return NULL; + if (dep->flags & DWC3_EP_ENABLED) return dep; @@ -320,14 +319,14 @@ static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) * ch 9.4.5 */ static int dwc3_ep0_handle_status(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl) + struct usb_ctrlrequest *ctrl) { - struct dwc3_ep *dep; - u32 recip; - u32 value; - u32 reg; - u16 usb_status = 0; - __le16 *response_pkt; + struct dwc3_ep *dep; + u32 recip; + u32 value; + u32 reg; + u16 usb_status = 0; + __le16 *response_pkt; /* We don't support PTM_STATUS */ value = le16_to_cpu(ctrl->wValue); @@ -340,7 +339,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, /* * LTM will be set once we know how to set this in HW. */ - usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; + usb_status |= dwc->gadget->is_selfpowered; if ((dwc->speed == DWC3_DSTS_SUPERSPEED) || (dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) { @@ -385,7 +384,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, } static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, - int set) + int set) { u32 reg; @@ -394,6 +393,8 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) return -EINVAL; + if (set && dwc->dis_u1_entry_quirk) + return -EINVAL; reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) @@ -406,15 +407,18 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, } static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state, - int set) + int set) { u32 reg; + if (state != USB_STATE_CONFIGURED) return -EINVAL; if ((dwc->speed != DWC3_DSTS_SUPERSPEED) && (dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS)) return -EINVAL; + if (set && dwc->dis_u2_entry_quirk) + return -EINVAL; reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) @@ -427,7 +431,7 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state, } static int dwc3_ep0_handle_test(struct dwc3 *dwc, enum usb_device_state state, - u32 wIndex, int set) + u32 wIndex, int set) { if ((wIndex & 0xff) != 0) return -EINVAL; @@ -435,11 +439,11 @@ static int dwc3_ep0_handle_test(struct dwc3 *dwc, enum usb_device_state state, return -EINVAL; switch (wIndex >> 8) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: + case USB_TEST_FORCE_ENABLE: dwc->test_mode_nr = wIndex >> 8; dwc->test_mode = true; break; @@ -451,22 +455,22 @@ static int dwc3_ep0_handle_test(struct dwc3 *dwc, enum usb_device_state state, } static int dwc3_ep0_handle_device(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl, int set) + struct usb_ctrlrequest *ctrl, int set) { - enum usb_device_state state; - u32 wValue; - u32 wIndex; - int ret = 0; + enum usb_device_state state; + u32 wValue; + u32 wIndex; + int ret = 0; wValue = le16_to_cpu(ctrl->wValue); wIndex = le16_to_cpu(ctrl->wIndex); - state = dwc->gadget.state; + state = dwc->gadget->state; switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: break; /* - * 9.4.1 says only only for SS, in AddressState only for + * 9.4.1 says only for SS, in AddressState only for * default control pipe */ case USB_DEVICE_U1_ENABLE: @@ -489,10 +493,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, } static int dwc3_ep0_handle_intf(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl, int set) + struct usb_ctrlrequest *ctrl, int set) { - u32 wValue; - int ret = 0; + u32 wValue; + int ret = 0; wValue = le16_to_cpu(ctrl->wValue); @@ -514,11 +518,11 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, } static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl, int set) + struct usb_ctrlrequest *ctrl, int set) { - struct dwc3_ep *dep; - u32 wValue; - int ret; + struct dwc3_ep *dep; + u32 wValue; + int ret; wValue = le16_to_cpu(ctrl->wValue); @@ -534,6 +538,11 @@ static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc, ret = __dwc3_gadget_ep_set_halt(dep, set, true); if (ret) return -EINVAL; + + /* ClearFeature(Halt) may need delayed status */ + if (!set && (dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + return USB_GADGET_DELAYED_STATUS; + break; default: return -EINVAL; @@ -542,12 +551,11 @@ static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc, return 0; } - static int dwc3_ep0_handle_feature(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl, int set) + struct usb_ctrlrequest *ctrl, int set) { - u32 recip; - int ret; + u32 recip; + int ret; recip = ctrl->bRequestType & USB_RECIP_MASK; @@ -570,7 +578,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { - enum usb_device_state state = dwc->gadget.state; + enum usb_device_state state = dwc->gadget->state; u32 addr; u32 reg; @@ -581,7 +589,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) } if (state == USB_STATE_CONFIGURED) { - dev_err(dwc->dev, "trying to set address when configured\n"); + dev_err(dwc->dev, "can't SetAddress() from Configured State\n"); return -EINVAL; } @@ -591,27 +599,28 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc3_writel(dwc->regs, DWC3_DCFG, reg); if (addr) - usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS); + usb_gadget_set_state(dwc->gadget, USB_STATE_ADDRESS); else - usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT); + usb_gadget_set_state(dwc->gadget, USB_STATE_DEFAULT); return 0; } static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { - int ret; + int ret = -EINVAL; - spin_unlock(&dwc->lock); - ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl); - spin_lock(&dwc->lock); + if (dwc->async_callbacks) { + spin_unlock(&dwc->lock); + ret = dwc->gadget_driver->setup(dwc->gadget, ctrl); + spin_lock(&dwc->lock); + } return ret; } -#define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { - enum usb_device_state state = dwc->gadget.state; + enum usb_device_state state = dwc->gadget->state; u32 cfg; int ret; u32 reg; @@ -623,6 +632,8 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return -EINVAL; case USB_STATE_ADDRESS: + dwc3_gadget_clear_tx_fifos(dwc); + ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { @@ -634,7 +645,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) * to change the state on the next usb_ep_queue() */ if (ret == 0) - usb_gadget_set_state(&dwc->gadget, + usb_gadget_set_state(dwc->gadget, USB_STATE_CONFIGURED); /* @@ -642,7 +653,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) * nothing is pending from application. */ reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); + if (!dwc->dis_u1_entry_quirk) + reg |= DWC3_DCTL_ACCEPTU1ENA; + if (!dwc->dis_u2_entry_quirk) + reg |= DWC3_DCTL_ACCEPTU2ENA; dwc3_writel(dwc->regs, DWC3_DCTL, reg); } break; @@ -650,7 +664,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) case USB_STATE_CONFIGURED: ret = dwc3_ep0_delegate_req(dwc, ctrl); if (!cfg && !ret) - usb_gadget_set_state(&dwc->gadget, + usb_gadget_set_state(dwc->gadget, USB_STATE_ADDRESS); break; default: @@ -661,11 +675,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) { - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; - u32 param = 0; - u32 reg; + u32 param = 0; + u32 reg; struct timing { u8 u1sel; @@ -705,9 +719,9 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) 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; + struct dwc3_ep *dep; + enum usb_device_state state = dwc->gadget->state; + u16 wLength; if (state == USB_STATE_DEFAULT) return -EINVAL; @@ -737,12 +751,11 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } -static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl) +static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { - u16 wLength; - u16 wValue; - u16 wIndex; + u16 wLength; + u16 wValue; + u16 wIndex; wValue = le16_to_cpu(ctrl->wValue); wLength = le16_to_cpu(ctrl->wLength); @@ -751,11 +764,7 @@ static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, if (wIndex || wLength) return -EINVAL; - /* - * REVISIT It's unclear from Databook what to do with this - * value. For now, just cache it. - */ - dwc->isoch_delay = wValue; + dwc->gadget->isoch_delay = wValue; return 0; } @@ -766,35 +775,27 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) switch (ctrl->bRequest) { case USB_REQ_GET_STATUS: - dev_dbg(dwc->dev, "USB_REQ_GET_STATUS\n"); ret = dwc3_ep0_handle_status(dwc, ctrl); break; case USB_REQ_CLEAR_FEATURE: - dev_dbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n"); ret = dwc3_ep0_handle_feature(dwc, ctrl, 0); break; case USB_REQ_SET_FEATURE: - dev_dbg(dwc->dev, "USB_REQ_SET_FEATURE\n"); ret = dwc3_ep0_handle_feature(dwc, ctrl, 1); break; case USB_REQ_SET_ADDRESS: - dev_dbg(dwc->dev, "USB_REQ_SET_ADDRESS\n"); ret = dwc3_ep0_set_address(dwc, ctrl); break; case USB_REQ_SET_CONFIGURATION: - dev_dbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n"); ret = dwc3_ep0_set_config(dwc, ctrl); break; case USB_REQ_SET_SEL: - dev_dbg(dwc->dev, "USB_REQ_SET_SEL\n"); ret = dwc3_ep0_set_sel(dwc, ctrl); break; case USB_REQ_SET_ISOCH_DELAY: - dev_dbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n"); ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); break; default: - dev_dbg(dwc->dev, "Forwarding to gadget driver\n"); ret = dwc3_ep0_delegate_req(dwc, ctrl); break; } @@ -803,13 +804,13 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) } static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { struct usb_ctrlrequest *ctrl = (void *) dwc->ep0_trb; int ret = -EINVAL; u32 len; - if (!dwc->gadget_driver) + if (!dwc->gadget_driver || !dwc->softconnect || !dwc->connected) goto out; len = le16_to_cpu(ctrl->wLength); @@ -837,16 +838,16 @@ out: } static void dwc3_ep0_complete_data(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { - struct dwc3_request *r = NULL; - struct usb_request *ur; - struct dwc3_trb *trb; - struct dwc3_ep *ep0; - u32 transferred = 0; - u32 status; - u32 length; - u8 epnum; + struct dwc3_request *r; + struct usb_request *ur; + struct dwc3_trb *trb; + struct dwc3_ep *ep0; + u32 transferred = 0; + u32 status; + u32 length; + u8 epnum; epnum = event->endpoint_number; ep0 = dwc->eps[0]; @@ -860,9 +861,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (status == DWC3_TRBSTS_SETUP_PENDING) { - dev_dbg(dwc->dev, "Setup Pending received\n"); dwc->setup_packet_pending = true; - if (r) dwc3_gadget_giveback(ep0, r, -ECONNRESET); @@ -876,7 +875,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ur->actual += transferred; if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) && - ur->length && ur->zero) || dwc->ep0_bounced) { + ur->length && ur->zero) || dwc->ep0_bounced) { trb++; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; @@ -895,12 +894,12 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, } static void dwc3_ep0_complete_status(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { - struct dwc3_request *r; - struct dwc3_ep *dep; - struct dwc3_trb *trb; - u32 status; + struct dwc3_request *r; + struct dwc3_ep *dep; + struct dwc3_trb *trb; + u32 status; dep = dwc->eps[0]; trb = dwc->ep0_trb; @@ -916,27 +915,25 @@ 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\n", - dwc->test_mode_nr); + dev_err(dwc->dev, "invalid test #%d\n", + dwc->test_mode_nr); dwc3_ep0_stall_and_restart(dwc); return; } } status = DWC3_TRB_SIZE_TRBSTS(trb->size); - if (status == DWC3_TRBSTS_SETUP_PENDING) { - dev_dbg(dwc->dev, "Setup Pending received\n"); + if (status == DWC3_TRBSTS_SETUP_PENDING) dwc->setup_packet_pending = true; - } dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { - struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; + struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; dep->flags &= ~DWC3_EP_TRANSFER_STARTED; dep->resource_index = 0; @@ -944,17 +941,14 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, switch (dwc->ep0state) { case EP0_SETUP_PHASE: - dev_dbg(dwc->dev, "Setup Phase\n"); dwc3_ep0_inspect_setup(dwc, event); break; case EP0_DATA_PHASE: - dev_dbg(dwc->dev, "Data Phase\n"); dwc3_ep0_complete_data(dwc, event); break; case EP0_STATUS_PHASE: - dev_dbg(dwc->dev, "Status Phase\n"); dwc3_ep0_complete_status(dwc, event); break; default: @@ -963,31 +957,29 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, } static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, - struct dwc3_ep *dep, - struct dwc3_request *req) + struct dwc3_ep *dep, struct dwc3_request *req) { - dma_addr_t dma_addr; - int ret; + unsigned int trb_length = 0; + int ret; req->direction = !!dep->number; if (req->request.length == 0) { - dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0, - DWC3_TRBCTL_CONTROL_DATA, false); + if (!req->direction) + trb_length = dep->endpoint.maxpacket; + + dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, trb_length, + DWC3_TRBCTL_CONTROL_DATA, false); ret = dwc3_ep0_start_trans(dep); - } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && - (dep->number == 0)) { - u32 maxpacket; - u32 rem; - - dma_addr = dma_map_single(dwc->dev, req->request.buf, - req->request.length, - dep->number ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(dwc->dev, dma_addr)) - return; + } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) + && (dep->number == 0)) { + u32 maxpacket; + u32 rem; - req->request.dma = dma_addr; + ret = usb_gadget_map_request_by_dev(dwc->sysdev, + &req->request, dep->number); + if (ret) + return; maxpacket = dep->endpoint.maxpacket; rem = req->request.length % maxpacket; @@ -1009,14 +1001,11 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ret = dwc3_ep0_start_trans(dep); } else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && req->request.length && req->request.zero) { - dma_addr = dma_map_single(dwc->dev, req->request.buf, - req->request.length, - dep->number ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(dwc->dev, dma_addr)) - return; - req->request.dma = dma_addr; + ret = usb_gadget_map_request_by_dev(dwc->sysdev, + &req->request, dep->number); + if (ret) + return; /* prepare normal TRB */ dwc3_ep0_prepare_one_trb(dep, req->request.dma, @@ -1026,21 +1015,20 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1]; + if (!req->direction) + trb_length = dep->endpoint.maxpacket; + /* Now prepare one extra TRB to align transfer size */ dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr, - 0, DWC3_TRBCTL_CONTROL_DATA, + trb_length, DWC3_TRBCTL_CONTROL_DATA, false); ret = dwc3_ep0_start_trans(dep); } else { - dma_addr = dma_map_single(dwc->dev, req->request.buf, - req->request.length, - dep->number ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(dwc->dev, dma_addr)) + ret = usb_gadget_map_request_by_dev(dwc->sysdev, + &req->request, dep->number); + if (ret) return; - req->request.dma = dma_addr; - dwc3_ep0_prepare_one_trb(dep, req->request.dma, req->request.length, DWC3_TRBCTL_CONTROL_DATA, false); @@ -1055,8 +1043,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) { - struct dwc3 *dwc = dep->dwc; - u32 type; + struct dwc3 *dwc = dep->dwc; + u32 type; type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3 : DWC3_TRBCTL_CONTROL_STATUS2; @@ -1071,20 +1059,38 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) } static void dwc3_ep0_do_control_status(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { - struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; + struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; __dwc3_ep0_do_control_status(dwc, dep); } -static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) +void dwc3_ep0_send_delayed_status(struct dwc3 *dwc) +{ + unsigned int direction = !dwc->ep0_expect_in; + + dwc->delayed_status = false; + dwc->clear_stall_protocol = 0; + + if (dwc->ep0state != EP0_STATUS_PHASE) + return; + + __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); +} + +void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; - u32 cmd; - int ret; + u32 cmd; + int ret; - if (!dep->resource_index) + /* + * For status/DATA OUT stage, TRB will be queued on ep0 out + * endpoint for which resource index is zero. Hence allow + * queuing ENDXFER command for ep0 out endpoint. + */ + if (!dep->resource_index && dep->number) return; cmd = DWC3_DEPCMD_ENDTRANSFER; @@ -1092,17 +1098,17 @@ static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); - WARN_ON(ret); + WARN_ON_ONCE(ret); dep->resource_index = 0; } static void dwc3_ep0_xfernotready(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { switch (event->status) { case DEPEVT_STATUS_CONTROL_DATA: - dev_dbg(dwc->dev, "Control Data\n"); - + if (!dwc->softconnect || !dwc->connected) + return; /* * We already have a DATA transfer in the controller's cache, * if we receive a XferNotReady(DATA) we will ignore it, unless @@ -1113,9 +1119,9 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, * control endpoint. */ if (dwc->ep0_expect_in != event->endpoint_number) { - struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in]; + struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in]; - dev_dbg(dwc->dev, "Wrong direction for Data phase\n"); + dev_err(dwc->dev, "unexpected direction for Data Phase\n"); dwc3_ep0_end_control_data(dwc, dep); dwc3_ep0_stall_and_restart(dwc); return; @@ -1127,15 +1133,17 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) return; - dev_dbg(dwc->dev, "Control Status\n"); + if (dwc->setup_packet_pending) { + dwc3_ep0_stall_and_restart(dwc); + return; + } dwc->ep0state = EP0_STATUS_PHASE; if (dwc->delayed_status) { struct dwc3_ep *dep = dwc->eps[0]; - WARN_ON(event->endpoint_number != 1); - dev_dbg(dwc->dev, "Delayed Status\n"); + WARN_ON_ONCE(event->endpoint_number != 1); /* * We should handle the delay STATUS phase here if the * request for handling delay STATUS has been queued @@ -1143,7 +1151,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, */ if (!list_empty(&dep->pending_list)) { dwc->delayed_status = false; - usb_gadget_set_state(&dwc->gadget, + usb_gadget_set_state(dwc->gadget, USB_STATE_CONFIGURED); dwc3_ep0_do_control_status(dwc, event); } @@ -1156,14 +1164,10 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, } void dwc3_ep0_interrupt(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { - 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)); + struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; + u8 cmd; switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: @@ -1177,7 +1181,14 @@ void dwc3_ep0_interrupt(struct dwc3 *dwc, case DWC3_DEPEVT_XFERINPROGRESS: case DWC3_DEPEVT_RXTXFIFOEVT: case DWC3_DEPEVT_STREAMEVT: + break; case DWC3_DEPEVT_EPCMDCMPLT: + cmd = DEPEVT_PARAMETER_CMD(event->parameters); + + if (cmd == DWC3_DEPCMD_ENDTRANSFER) { + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; + } break; } } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8ec1268a22..48be74f7e9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1,40 +1,37 @@ -// SPDX-License-Identifier: GPL-2.0-only -/** +// SPDX-License-Identifier: GPL-2.0 +/* * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link * - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://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. - * - * commit 8e74475b0e : usb: dwc3: gadget: use udc-core's reset notifier */ #include <common.h> #include <dma.h> #include <io.h> #include <linux/list.h> -#include <usb/gadget.h> -#include <usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/ch9.h> +#include "debug.h" #include "core.h" #include "gadget.h" +#include "io.h" #define DWC3_ALIGN_FRAME(d, n) (((d)->frame_number + ((d)->interval * (n))) \ & ~((d)->interval - 1)) - /** - * dwc3_gadget_set_test_mode - Enables USB2 Test Modes + * dwc3_gadget_set_test_mode - enables usb2 test modes * @dwc: pointer to our context structure * @mode: the mode to set (J, K SE0 NAK, Force Enable) * - * Caller should take care of locking. This function will - * return 0 on success or -EINVAL if wrong Test Selector - * is passed + * Caller should take care of locking. This function will return 0 on + * success or -EINVAL if wrong Test Selector is passed. */ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) { @@ -44,24 +41,24 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) reg &= ~DWC3_DCTL_TSTCTRL_MASK; switch (mode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: + case USB_TEST_FORCE_ENABLE: reg |= mode << 1; break; default: return -EINVAL; } - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); return 0; } /** - * dwc3_gadget_get_link_state - Gets current state of USB Link + * dwc3_gadget_get_link_state - gets current state of usb link * @dwc: pointer to our context structure * * Caller should take care of locking. This function will @@ -69,7 +66,7 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) */ int dwc3_gadget_get_link_state(struct dwc3 *dwc) { - u32 reg; + u32 reg; reg = dwc3_readl(dwc->regs, DWC3_DSTS); @@ -77,7 +74,7 @@ int dwc3_gadget_get_link_state(struct dwc3 *dwc) } /** - * dwc3_gadget_set_link_state - Sets USB Link to a particular State + * dwc3_gadget_set_link_state - sets usb link to a particular state * @dwc: pointer to our context structure * @state: the state to put link into * @@ -86,14 +83,14 @@ int dwc3_gadget_get_link_state(struct dwc3 *dwc) */ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) { - int retries = 10000; - u32 reg; + int retries = 10000; + u32 reg; /* * Wait until device controller is ready. Only applies to 1.94a and * later RTL. */ - if (dwc->revision >= DWC3_REVISION_194A) { + if (!DWC3_VER_IS_PRIOR(DWC3, 194A)) { while (--retries) { reg = dwc3_readl(dwc->regs, DWC3_DSTS); if (reg & DWC3_DSTS_DCNRD) @@ -109,6 +106,9 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; + /* set no action before sending new link state change */ + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + /* set requested state */ reg |= DWC3_DCTL_ULSTCHNGREQ(state); dwc3_writel(dwc->regs, DWC3_DCTL, reg); @@ -117,7 +117,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) * The following code is racy when called from dwc3_gadget_wakeup, * and is not needed, at least on newer versions */ - if (dwc->revision >= DWC3_REVISION_194A) + if (!DWC3_VER_IS_PRIOR(DWC3, 194A)) return 0; /* wait for a change in DSTS */ @@ -131,8 +131,6 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) udelay(5); } - dev_dbg(dwc->dev, "link state change request timed out\n"); - return -ETIMEDOUT; } @@ -170,10 +168,9 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep) } static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, - struct dwc3_request *req, - int status) + struct dwc3_request *req, int status) { - struct dwc3 *dwc = dep->dwc; + struct dwc3 *dwc = dep->dwc; list_del(&req->list); req->remaining = 0; @@ -182,13 +179,10 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, if (req->request.status == -EINPROGRESS) req->request.status = status; - if (req->request.length == 0) - return; - if (req->trb) dma_unmap_single(dwc->dev, req->request.dma, - req->request.length, - req->direction ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->request.length, + req->direction ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->trb = NULL; } @@ -204,18 +198,13 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, * layers that it has completed. */ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, - int status) + int status) { - struct dwc3 *dwc = dep->dwc; - dwc3_gadget_del_and_unmap_request(dep, req, status); - dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n", - req, dep->name, req->request.actual, - req->request.length, status); req->status = DWC3_REQUEST_STATUS_COMPLETED; spin_unlock(&dwc->lock); - req->request.complete(&dep->endpoint, &req->request); + usb_gadget_giveback_request(&dep->endpoint, &req->request); spin_lock(&dwc->lock); } @@ -228,12 +217,13 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, * Caller should take care of locking. Issue @cmd with a given @param to @dwc * and wait for its completion. */ -int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, + u32 param) { - u32 timeout = 500; - int status = 0; - int ret = 0; - u32 reg; + u32 timeout = 500; + int status = 0; + int ret = 0; + u32 reg; dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); @@ -241,16 +231,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) do { reg = dwc3_readl(dwc->regs, DWC3_DGCMD); if (!(reg & DWC3_DGCMD_CMDACT)) { - dev_dbg(dwc->dev, "%s: Command Complete --> %d\n", - __func__, - DWC3_DGCMD_STATUS(reg)); status = DWC3_DGCMD_STATUS(reg); if (status) ret = -EINVAL; break; } - - udelay(1); } while (--timeout); if (!timeout) { @@ -262,6 +247,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) } static int __dwc3_gadget_wakeup(struct dwc3 *dwc); + /** * dwc3_send_gadget_ep_cmd - issue an endpoint command * @dep: the endpoint to which the command is going to be issued @@ -271,17 +257,17 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc); * Caller should handle locking. This function will issue @cmd with given * @params to @dep and wait for its completion. */ -int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, - struct dwc3_gadget_ep_cmd_params *params) +int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + struct dwc3_gadget_ep_cmd_params *params) { const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; - struct dwc3 *dwc = dep->dwc; - u32 timeout = 1000; - u32 saved_config = 0; - u32 reg; + struct dwc3 *dwc = dep->dwc; + u32 timeout = 5000; + u32 saved_config = 0; + u32 reg; - int cmd_status = 0; - int ret = -EINVAL; + int cmd_status = 0; + int ret = -EINVAL; /* * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or @@ -293,7 +279,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, * * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2 */ - if (dwc->gadget.speed <= USB_SPEED_HIGH) { + 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; @@ -310,21 +297,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, } if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { - int needs_wakeup; + int link_state; - needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 || - dwc->link_state == DWC3_LINK_STATE_U2 || - dwc->link_state == DWC3_LINK_STATE_U3); + /* + * Initiate remote wakeup if the link state is in U3 when + * operating in SS/SSP or L1/L2 when operating in HS/FS. If the + * link state is in U1/U2, no remote wakeup is needed. The Start + * Transfer command will initiate the link recovery. + */ + link_state = dwc3_gadget_get_link_state(dwc); + switch (link_state) { + case DWC3_LINK_STATE_U2: + if (dwc->gadget->speed >= USB_SPEED_SUPER) + break; - if (unlikely(needs_wakeup)) { + fallthrough; + case DWC3_LINK_STATE_U3: ret = __dwc3_gadget_wakeup(dwc); - dev_warn(dwc->dev, "wakeup failed --> %d\n", ret); + dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", + ret); + break; } } - dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0); - dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1); - dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2); + /* + * For some commands such as Update Transfer command, DEPCMDPARn + * registers are reserved. Since the driver often sends Update Transfer + * command, don't write to DEPCMDPARn to avoid register write delays and + * improve performance. + */ + if (DWC3_DEPCMD_CMD(cmd) != DWC3_DEPCMD_UPDATETRANSFER) { + dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0); + dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1); + dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2); + } /* * Synopsys Databook 2.60a states in section 6.3.2.5.6 of that if we're @@ -348,6 +354,14 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, cmd |= DWC3_DEPCMD_CMDACT; dwc3_writel(dep->regs, DWC3_DEPCMD, cmd); + + if (!(cmd & DWC3_DEPCMD_CMDACT) || + (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER && + !(cmd & DWC3_DEPCMD_CMDIOC))) { + ret = 0; + goto skip_status; + } + do { reg = dwc3_readl(dep->regs, DWC3_DEPCMD); if (!(reg & DWC3_DEPCMD_CMDACT)) { @@ -358,6 +372,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, ret = 0; break; case DEPEVT_TRANSFER_NO_RESOURCE: + dev_warn(dwc->dev, "No resource for %s\n", + dep->name); ret = -EINVAL; break; case DEPEVT_TRANSFER_BUS_EXPIRY: @@ -387,9 +403,14 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, cmd_status = -ETIMEDOUT; } - if (ret == 0 && DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { - dep->flags |= DWC3_EP_TRANSFER_STARTED; - dwc3_gadget_ep_get_transfer_index(dep); +skip_status: + + if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { + if (ret == 0) + dep->flags |= DWC3_EP_TRANSFER_STARTED; + + if (ret != -ETIMEDOUT) + dwc3_gadget_ep_get_transfer_index(dep); } if (saved_config) { @@ -399,7 +420,6 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, } return ret; - } static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) @@ -416,8 +436,9 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) * IN transfers due to a mishandled error condition. Synopsys * STAR 9000614252. */ - if (dep->direction && (dwc->revision >= DWC3_REVISION_260A) && - (dwc->gadget.speed >= USB_SPEED_SUPER)) + if (dep->direction && + !DWC3_VER_IS_PRIOR(DWC3, 260A) && + (dwc->gadget->speed >= USB_SPEED_SUPER)) cmd |= DWC3_DEPCMD_CLEARPENDIN; memset(¶ms, 0, sizeof(params)); @@ -426,9 +447,9 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) } static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, - struct dwc3_trb *trb) + struct dwc3_trb *trb) { - u32 offset = (char *) trb - (char *) dep->trb_pool; + u32 offset = (char *) trb - (char *) dep->trb_pool; return dep->trb_pool_dma + offset; } @@ -438,12 +459,11 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep) if (dep->trb_pool) return 0; - dep->trb_pool = dma_alloc_coherent(sizeof(struct dwc3_trb) * - DWC3_TRB_NUM, - &dep->trb_pool_dma); + dep->trb_pool = dma_alloc_coherent(sizeof(struct dwc3_trb) * DWC3_TRB_NUM, + &dep->trb_pool_dma); if (!dep->trb_pool) { dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n", - dep->name); + dep->name); return -ENOMEM; } @@ -452,7 +472,8 @@ 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, 0, sizeof(dma_addr_t)); + dma_free_coherent(dep->trb_pool, dep->trb_pool_dma, + sizeof(struct dwc3_trb) * DWC3_TRB_NUM); dep->trb_pool = NULL; dep->trb_pool_dma = 0; @@ -467,7 +488,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep) params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE, - ¶ms); + ¶ms); } /** @@ -506,10 +527,10 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep) static int dwc3_gadget_start_config(struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; - struct dwc3 *dwc; - u32 cmd; - int i; - int ret; + struct dwc3 *dwc; + u32 cmd; + int i; + int ret; if (dep->number) return 0; @@ -552,9 +573,10 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action) | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)); /* Burst size is only needed in SuperSpeed mode */ - if (dwc->gadget.speed == USB_SPEED_SUPER) { - u32 burst = dep->endpoint.maxburst - 1; - params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); + if (dwc->gadget->speed >= USB_SPEED_SUPER) { + u32 burst = dep->endpoint.maxburst; + + params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1); } params.param0 |= action; @@ -569,6 +591,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action) if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) { params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE + | DWC3_DEPCFG_XFER_COMPLETE_EN | DWC3_DEPCFG_STREAM_EVENT_EN; dep->stream_capable = true; } @@ -592,31 +615,239 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action) params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1); if (desc->bInterval) { - params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1); - dep->interval = 1 << (desc->bInterval - 1); + u8 bInterval_m1; + + /* + * Valid range for DEPCFG.bInterval_m1 is from 0 to 13. + * + * NOTE: The programming guide incorrectly stated bInterval_m1 + * must be set to 0 when operating in fullspeed. Internally the + * controller does not have this limitation. See DWC_usb3x + * programming guide section 3.2.2.1. + */ + bInterval_m1 = min_t(u8, desc->bInterval - 1, 13); + + if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT && + dwc->gadget->speed == USB_SPEED_FULL) + dep->interval = desc->bInterval; + else + dep->interval = 1 << (desc->bInterval - 1); + + params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1); } return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, ¶ms); } /** - * __dwc3_gadget_ep_enable - Initializes a HW endpoint + * dwc3_gadget_calc_tx_fifo_size - calculates the txfifo size value + * @dwc: pointer to the DWC3 context + * @mult: multiplier to be used when calculating the fifo_size + * + * Calculates the size value based on the equation below: + * + * DWC3 revision 280A and prior: + * fifo_size = mult * (max_packet / mdwidth) + 1; + * + * DWC3 revision 290A and onwards: + * fifo_size = mult * ((max_packet + mdwidth)/mdwidth + 1) + 1 + * + * The max packet size is set to 1024, as the txfifo requirements mainly apply + * to super speed USB use cases. However, it is safe to overestimate the fifo + * allocations for other scenarios, i.e. high speed USB. + */ +static int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult) +{ + int max_packet = 1024; + int fifo_size; + int mdwidth; + + mdwidth = dwc3_mdwidth(dwc); + + /* MDWIDTH is represented in bits, we need it in bytes */ + mdwidth >>= 3; + + if (DWC3_VER_IS_PRIOR(DWC3, 290A)) + fifo_size = mult * (max_packet / mdwidth) + 1; + else + fifo_size = mult * ((max_packet + mdwidth) / mdwidth) + 1; + return fifo_size; +} + +/** + * dwc3_gadget_clear_tx_fifos - Clears txfifo allocation + * @dwc: pointer to the DWC3 context + * + * Iterates through all the endpoint registers and clears the previous txfifo + * allocations. + */ +void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) +{ + struct dwc3_ep *dep; + int fifo_depth; + int size; + int num; + + if (!dwc->do_fifo_resize) + return; + + /* Read ep0IN related TXFIFO size */ + dep = dwc->eps[1]; + size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); + if (DWC3_IP_IS(DWC3)) + fifo_depth = DWC3_GTXFIFOSIZ_TXFDEP(size); + else + fifo_depth = DWC31_GTXFIFOSIZ_TXFDEP(size); + + dwc->last_fifo_depth = fifo_depth; + /* Clear existing TXFIFO for all IN eps except ep0 */ + for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); + num += 2) { + dep = dwc->eps[num]; + /* Don't change TXFRAMNUM on usb31 version */ + size = DWC3_IP_IS(DWC3) ? 0 : + dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & + DWC31_GTXFIFOSIZ_TXFRAMNUM; + + dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size); + dep->flags &= ~DWC3_EP_TXFIFO_RESIZED; + } + dwc->num_ep_resized = 0; +} + +/* + * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case + * @dwc: pointer to our context structure + * + * This function will a best effort FIFO allocation in order + * to improve FIFO usage and throughput, while still allowing + * us to enable as many endpoints as possible. + * + * Keep in mind that this operation will be highly dependent + * on the configured size for RAM1 - which contains TxFifo -, + * the amount of endpoints enabled on coreConsultant tool, and + * the width of the Master Bus. + * + * In general, FIFO depths are represented with the following equation: + * + * fifo_size = mult * ((max_packet + mdwidth)/mdwidth + 1) + 1 + * + * In conjunction with dwc3_gadget_check_config(), this resizing logic will + * ensure that all endpoints will have enough internal memory for one max + * packet per endpoint. + */ +static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) +{ + struct dwc3 *dwc = dep->dwc; + int fifo_0_start; + int ram1_depth; + int fifo_size; + int min_depth; + int num_in_ep; + int remaining; + int num_fifos = 1; + int fifo; + int tmp; + + if (!dwc->do_fifo_resize) + return 0; + + /* resize IN endpoints except ep0 */ + if (!usb_endpoint_dir_in(dep->endpoint.desc) || dep->number <= 1) + return 0; + + /* bail if already resized */ + if (dep->flags & DWC3_EP_TXFIFO_RESIZED) + return 0; + + ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); + + if ((dep->endpoint.maxburst > 1 && + usb_endpoint_xfer_bulk(dep->endpoint.desc)) || + usb_endpoint_xfer_isoc(dep->endpoint.desc)) + num_fifos = 3; + + if (dep->endpoint.maxburst > 6 && + (usb_endpoint_xfer_bulk(dep->endpoint.desc) || + usb_endpoint_xfer_isoc(dep->endpoint.desc)) && DWC3_IP_IS(DWC31)) + num_fifos = dwc->tx_fifo_resize_max_num; + + /* FIFO size for a single buffer */ + fifo = dwc3_gadget_calc_tx_fifo_size(dwc, 1); + + /* Calculate the number of remaining EPs w/o any FIFO */ + num_in_ep = dwc->max_cfg_eps; + num_in_ep -= dwc->num_ep_resized; + + /* Reserve at least one FIFO for the number of IN EPs */ + min_depth = num_in_ep * (fifo + 1); + remaining = ram1_depth - min_depth - dwc->last_fifo_depth; + remaining = max_t(int, 0, remaining); + /* + * We've already reserved 1 FIFO per EP, so check what we can fit in + * addition to it. If there is not enough remaining space, allocate + * all the remaining space to the EP. + */ + fifo_size = (num_fifos - 1) * fifo; + if (remaining < fifo_size) + fifo_size = remaining; + + fifo_size += fifo; + /* Last increment according to the TX FIFO size equation */ + fifo_size++; + + /* Check if TXFIFOs start at non-zero addr */ + tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); + fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp); + + fifo_size |= (fifo_0_start + (dwc->last_fifo_depth << 16)); + if (DWC3_IP_IS(DWC3)) + dwc->last_fifo_depth += DWC3_GTXFIFOSIZ_TXFDEP(fifo_size); + else + dwc->last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEP(fifo_size); + + /* Check fifo size allocation doesn't exceed available RAM size. */ + if (dwc->last_fifo_depth >= ram1_depth) { + dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n", + dwc->last_fifo_depth, ram1_depth, + dep->endpoint.name, fifo_size); + if (DWC3_IP_IS(DWC3)) + fifo_size = DWC3_GTXFIFOSIZ_TXFDEP(fifo_size); + else + fifo_size = DWC31_GTXFIFOSIZ_TXFDEP(fifo_size); + + dwc->last_fifo_depth -= fifo_size; + return -ENOMEM; + } + + dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size); + dep->flags |= DWC3_EP_TXFIFO_RESIZED; + dwc->num_ep_resized++; + + return 0; +} + +/** + * __dwc3_gadget_ep_enable - initializes a hw endpoint * @dep: endpoint to be initialized - * @desc: USB Endpoint Descriptor + * @action: one of INIT, MODIFY or RESTORE * - * Caller should take care of locking + * Caller should take care of locking. Execute all necessary commands to + * initialize a HW endpoint so it can be used by a gadget driver. */ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) { const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; - struct dwc3 *dwc = dep->dwc; + struct dwc3 *dwc = dep->dwc; - u32 reg; - int ret; - - dev_dbg(dwc->dev, "Enabling %s\n", dep->name); + u32 reg; + int ret; if (!(dep->flags & DWC3_EP_ENABLED)) { + ret = dwc3_gadget_resize_tx_fifos(dep); + if (ret) + return ret; + ret = dwc3_gadget_start_config(dep); if (ret) return ret; @@ -627,8 +858,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) return ret; if (!(dep->flags & DWC3_EP_ENABLED)) { - struct dwc3_trb *trb_st_hw; - struct dwc3_trb *trb_link; + struct dwc3_trb *trb_st_hw; + struct dwc3_trb *trb_link; dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; @@ -637,12 +868,13 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) reg |= DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); + dep->trb_dequeue = 0; + dep->trb_enqueue = 0; + if (usb_endpoint_xfer_control(desc)) - return 0; + goto out; /* Initialize the TRB ring */ - dep->trb_dequeue = 0; - dep->trb_enqueue = 0; memset_io(dep->trb_pool, 0, sizeof(struct dwc3_trb) * DWC3_TRB_NUM); @@ -650,12 +882,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) trb_st_hw = &dep->trb_pool[0]; trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1]; - memset_io(trb_link, 0, sizeof(*trb_link)); - - trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, - trb_st_hw)); - trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, - trb_st_hw)); + trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); + trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB; trb_link->ctrl |= DWC3_TRB_CTRL_HWO; } @@ -664,10 +892,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) * Issue StartTransfer here with no-op TRB so we can always rely on No * Response Update Transfer command. */ - if ((usb_endpoint_xfer_bulk(desc) && !dep->stream_capable) || + if (usb_endpoint_xfer_bulk(desc) || usb_endpoint_xfer_int(desc)) { struct dwc3_gadget_ep_cmd_params params; - struct dwc3_trb *trb; + struct dwc3_trb *trb; dma_addr_t trb_dma; u32 cmd; @@ -683,47 +911,88 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); if (ret < 0) return ret; + + if (dep->stream_capable) { + /* + * For streams, at start, there maybe a race where the + * host primes the endpoint before the function driver + * queues a request to initiate a stream. In that case, + * the controller will not see the prime to generate the + * ERDY and start stream. To workaround this, issue a + * no-op TRB as normal, but end it immediately. As a + * result, when the function driver queues the request, + * the next START_TRANSFER command will cause the + * controller to generate an ERDY to initiate the + * stream. + */ + dwc3_stop_active_transfer(dep, true, true); + + /* + * All stream eps will reinitiate stream on NoStream + * rejection until we can determine that the host can + * prime after the first transfer. + * + * However, if the controller is capable of + * TXF_FLUSH_BYPASS, then IN direction endpoints will + * automatically restart the stream without the driver + * initiation. + */ + if (!dep->direction || + !(dwc->hwparams.hwparams9 & + DWC3_GHWPARAMS9_DEV_TXF_FLUSH_BYPASS)) + dep->flags |= DWC3_EP_FORCE_RESTART_STREAM; + } } +out: return 0; } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, - bool interrupt); -static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) +void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep, int status) { - struct dwc3_request *req; + struct dwc3_request *req; dwc3_stop_active_transfer(dep, true, false); + /* If endxfer is delayed, avoid unmapping requests */ + if (dep->flags & DWC3_EP_DELAY_STOP) + return; + /* - giveback all requests to gadget driver */ while (!list_empty(&dep->started_list)) { req = next_request(&dep->started_list); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + dwc3_gadget_giveback(dep, req, status); } while (!list_empty(&dep->pending_list)) { req = next_request(&dep->pending_list); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + dwc3_gadget_giveback(dep, req, status); + } + + while (!list_empty(&dep->cancelled_list)) { + req = next_request(&dep->cancelled_list); + + dwc3_gadget_giveback(dep, req, status); } } /** - * __dwc3_gadget_ep_disable - Disables a HW endpoint + * __dwc3_gadget_ep_disable - disables a hw endpoint * @dep: the endpoint to disable * - * This function also removes requests which are currently processed ny the - * hardware and those which are not yet scheduled. + * This function undoes what __dwc3_gadget_ep_enable did and also removes + * requests which are currently being processed by the hardware and those which + * are not yet scheduled. + * * Caller should take care of locking. */ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) { - struct dwc3 *dwc = dep->dwc; - u32 reg; - - dwc3_remove_requests(dwc, dep); + struct dwc3 *dwc = dep->dwc; + u32 reg; + u32 mask; /* make sure HW endpoint isn't stalled */ if (dep->flags & DWC3_EP_STALL) @@ -733,9 +1002,19 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) reg &= ~DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); + dwc3_remove_requests(dwc, dep, -ESHUTDOWN); + dep->stream_capable = false; dep->type = 0; - dep->flags = 0; + mask = DWC3_EP_TXFIFO_RESIZED; + /* + * dwc3_remove_requests() can exit early if DWC3 EP delayed stop is + * set. Do not clear DEP flags, so that the end transfer command will + * be reattempted during the next SETUP stage. + */ + if (dep->flags & DWC3_EP_DELAY_STOP) + mask |= (DWC3_EP_DELAY_STOP | DWC3_EP_TRANSFER_STARTED); + dep->flags &= mask; /* Clear out the ep descriptors for non-ep0 */ if (dep->number > 1) { @@ -749,7 +1028,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) /* -------------------------------------------------------------------------- */ static int dwc3_gadget_ep0_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) + const struct usb_endpoint_descriptor *desc) { return -EINVAL; } @@ -762,12 +1041,12 @@ static int dwc3_gadget_ep0_disable(struct usb_ep *ep) /* -------------------------------------------------------------------------- */ static int dwc3_gadget_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) + const struct usb_endpoint_descriptor *desc) { - struct dwc3_ep *dep; - struct dwc3 *dwc; - unsigned long flags; - int ret; + struct dwc3_ep *dep; + struct dwc3 *dwc; + unsigned long flags; + int ret; if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { pr_debug("dwc3: invalid parameters\n"); @@ -782,11 +1061,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", - dep->name); + if (dev_WARN_ONCE(dwc->dev, dep->flags & DWC3_EP_ENABLED, + "%s is already enabled\n", + dep->name)) return 0; - } spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); @@ -797,10 +1075,10 @@ 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; + struct dwc3_ep *dep; + struct dwc3 *dwc; + unsigned long flags; + int ret; if (!ep) { pr_debug("dwc3: invalid parameters\n"); @@ -810,11 +1088,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", - dep->name); + if (dev_WARN_ONCE(dwc->dev, !(dep->flags & DWC3_EP_ENABLED), + "%s is already disabled\n", + dep->name)) return 0; - } spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_disable(dep); @@ -825,10 +1102,10 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep) { - struct dwc3_request *req; - struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3_request *req; + struct dwc3_ep *dep = to_dwc3_ep(ep); - req = xzalloc(sizeof(*req)); + req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return NULL; @@ -841,9 +1118,9 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep) } static void dwc3_gadget_ep_free_request(struct usb_ep *ep, - struct usb_request *request) + struct usb_request *request) { - struct dwc3_request *req = to_dwc3_request(request); + struct dwc3_request *req = to_dwc3_request(request); kfree(req); } @@ -869,19 +1146,19 @@ static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index) static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) { - struct dwc3_trb *tmp; - u8 trbs_left; + u8 trbs_left; /* - * If enqueue & dequeue are equal than it is either full or empty. - * - * One way to know for sure is if the TRB right before us has HWO bit - * set or not. If it has, then we're definitely full and can't fit any - * more transfers in our ring. + * If the enqueue & dequeue are equal then the TRB ring is either full + * or empty. It's considered full when there are DWC3_TRB_NUM-1 of TRBs + * pending to be processed by the driver. */ if (dep->trb_enqueue == dep->trb_dequeue) { - tmp = dwc3_ep_prev_trb(dep, dep->trb_enqueue); - if (tmp->ctrl & DWC3_TRB_CTRL_HWO) + /* + * If there is any request remained in the started_list at + * this point, that means there is no TRB available. + */ + if (!list_empty(&dep->started_list)) return 0; return DWC3_TRB_NUM - 1; @@ -896,17 +1173,47 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) return trbs_left; } -static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, - dma_addr_t dma, unsigned length, - unsigned chain, unsigned node, - unsigned stream_id, unsigned short_not_ok, - unsigned no_interrupt) +/** + * dwc3_prepare_one_trb - setup one TRB from one request + * @dep: endpoint for which this request is prepared + * @req: dwc3_request pointer + * @trb_length: buffer size of the TRB + * @chain: should this TRB be chained to the next? + * @node: only for isochronous endpoints. First TRB needs different type. + * @use_bounce_buffer: set to use bounce buffer + * @must_interrupt: set to interrupt on TRB completion + */ +static void dwc3_prepare_one_trb(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned int trb_length, + unsigned int chain, unsigned int node, bool use_bounce_buffer, + bool must_interrupt) { - struct dwc3 *dwc = dep->dwc; - struct usb_gadget *gadget = &dwc->gadget; - enum usb_device_speed speed = gadget->speed; + struct dwc3_trb *trb; + dma_addr_t dma; + unsigned int stream_id = req->request.stream_id; + unsigned int short_not_ok = req->request.short_not_ok; + unsigned int no_interrupt = req->request.no_interrupt; + unsigned int is_last = req->request.is_last; + struct dwc3 *dwc = dep->dwc; + struct usb_gadget *gadget = dwc->gadget; + enum usb_device_speed speed = gadget->speed; + + if (use_bounce_buffer) + dma = dep->dwc->bounce_addr; + else + dma = req->request.dma; + + trb = &dep->trb_pool[dep->trb_enqueue]; - trb->size = DWC3_TRB_SIZE_LENGTH(length); + if (!req->trb) { + dwc3_gadget_move_started_request(req); + req->trb = trb; + req->trb_dma = dwc3_trb_dma_offset(dep, trb); + } + + req->num_trbs++; + + trb->size = DWC3_TRB_SIZE_LENGTH(trb_length); trb->bpl = lower_32_bits(dma); trb->bph = upper_32_bits(dma); @@ -946,10 +1253,10 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, unsigned int mult = 2; unsigned int maxp = usb_endpoint_maxp(ep->desc); - if (length <= (2 * maxp)) + if (req->request.length <= (2 * maxp)) mult--; - if (length <= maxp) + if (req->request.length <= maxp) mult--; trb->size |= DWC3_TRB_SIZE_PCM1(mult); @@ -958,8 +1265,8 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; } - /* always enable Interrupt on Missed ISOC */ - trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; + if (!no_interrupt && !chain) + trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; break; case USB_ENDPOINT_XFER_BULK: @@ -972,7 +1279,7 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, * checked it already :) */ dev_warn(dwc->dev, "Unknown endpoint type %d\n", - usb_endpoint_type(dep->endpoint.desc)); + usb_endpoint_type(dep->endpoint.desc)); } /* @@ -987,149 +1294,197 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; } - if ((!no_interrupt && !chain) || - (dwc3_calc_trbs_left(dep) == 1)) + /* All TRBs setup for MST must set CSP=1 when LST=0 */ + if (dep->stream_capable && DWC3_MST_CAPABLE(&dwc->hwparams)) + trb->ctrl |= DWC3_TRB_CTRL_CSP; + + if ((!no_interrupt && !chain) || must_interrupt) trb->ctrl |= DWC3_TRB_CTRL_IOC; if (chain) trb->ctrl |= DWC3_TRB_CTRL_CHN; + else if (dep->stream_capable && is_last && + !DWC3_MST_CAPABLE(&dwc->hwparams)) + trb->ctrl |= DWC3_TRB_CTRL_LST; if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable) trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id); + /* + * As per data book 4.2.3.2TRB Control Bit Rules section + * + * The controller autonomously checks the HWO field of a TRB to determine if the + * entire TRB is valid. Therefore, software must ensure that the rest of the TRB + * is valid before setting the HWO field to '1'. In most systems, this means that + * software must update the fourth DWORD of a TRB last. + * + * However there is a possibility of CPU re-ordering here which can cause + * controller to observe the HWO bit set prematurely. + * Add a write memory barrier to prevent CPU re-ordering. + */ + /* wmb() FIXME */ trb->ctrl |= DWC3_TRB_CTRL_HWO; dwc3_ep_inc_enq(dep); } -/** - * dwc3_prepare_one_trb - setup one TRB from one request - * @dep: endpoint for which this request is prepared - * @req: dwc3_request pointer - * @chain: should this TRB be chained to the next? - * @node: only for isochronous endpoints. First TRB needs different type. - */ -static void dwc3_prepare_one_trb(struct dwc3_ep *dep, - struct dwc3_request *req, - unsigned chain, unsigned node) +static bool dwc3_needs_extra_trb(struct dwc3_ep *dep, struct dwc3_request *req) { - struct dwc3_trb *trb; - unsigned int length; - dma_addr_t dma; - unsigned stream_id = req->request.stream_id; - unsigned short_not_ok = req->request.short_not_ok; - unsigned no_interrupt = req->request.no_interrupt; - - length = req->request.length; - dma = req->request.dma; - - trb = &dep->trb_pool[dep->trb_enqueue]; - - if (!req->trb) { - dwc3_gadget_move_started_request(req); - req->trb = trb; - req->trb_dma = dwc3_trb_dma_offset(dep, trb); - } + unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); + unsigned int rem = req->request.length % maxp; - req->num_trbs++; + if ((req->request.length && req->request.zero && !rem && + !usb_endpoint_xfer_isoc(dep->endpoint.desc)) || + (!req->direction && rem)) + return true; - __dwc3_prepare_one_trb(dep, trb, dma, length, chain, node, - stream_id, short_not_ok, no_interrupt); + return false; } -static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req) +/** + * dwc3_prepare_last_sg - prepare TRBs for the last SG entry + * @dep: The endpoint that the request belongs to + * @req: The request to prepare + * @entry_length: The last SG entry size + * @node: Indicates whether this is not the first entry (for isoc only) + * + * Return the number of TRBs prepared. + */ +static int dwc3_prepare_last_sg(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned int entry_length, + unsigned int node) { - unsigned int length = req->request.length; unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); - unsigned int rem = length % maxp; + unsigned int rem = req->request.length % maxp; + unsigned int num_trbs = 1; - if ((!length || rem) && usb_endpoint_dir_out(dep->endpoint.desc)) { - struct dwc3 *dwc = dep->dwc; - struct dwc3_trb *trb; + if (dwc3_needs_extra_trb(dep, req)) + num_trbs++; - req->needs_extra_trb = true; + if (dwc3_calc_trbs_left(dep) < num_trbs) + return 0; - /* prepare normal TRB */ - dwc3_prepare_one_trb(dep, req, true, 0); + req->needs_extra_trb = num_trbs > 1; - /* Now prepare one extra TRB to align transfer size */ - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; - __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem, - false, 1, req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt); - } else if (req->request.zero && req->request.length && - (IS_ALIGNED(req->request.length, maxp))) { - struct dwc3 *dwc = dep->dwc; - struct dwc3_trb *trb; + /* Prepare a normal TRB */ + if (req->direction || req->request.length) + dwc3_prepare_one_trb(dep, req, entry_length, + req->needs_extra_trb, node, false, false); - req->needs_extra_trb = true; + /* Prepare extra TRBs for ZLP and MPS OUT transfer alignment */ + if ((!req->direction && !req->request.length) || req->needs_extra_trb) + dwc3_prepare_one_trb(dep, req, + req->direction ? 0 : maxp - rem, + false, 1, true, false); - /* prepare normal TRB */ - dwc3_prepare_one_trb(dep, req, true, 0); + return num_trbs; +} - /* Now prepare one extra TRB to handle ZLP */ - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; - __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0, - false, 1, req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt); - } else { - dwc3_prepare_one_trb(dep, req, false, 0); - } +static int dwc3_prepare_trbs_linear(struct dwc3_ep *dep, + struct dwc3_request *req) +{ + return dwc3_prepare_last_sg(dep, req, req->request.length, 0); } /* * dwc3_prepare_trbs - setup TRBs from requests * @dep: endpoint for which requests are being prepared - * @starting: true if the endpoint is idle and no requests are queued. * * The function goes through the requests list and sets up TRBs for the * transfers. The function returns once there are no more TRBs available or * it runs out of requests. + * + * Returns the number of TRBs prepared or negative errno. */ -static void dwc3_prepare_trbs(struct dwc3_ep *dep) +static int dwc3_prepare_trbs(struct dwc3_ep *dep) { - struct dwc3_request *req, *n; - struct dwc3 *dwc = dep->dwc; - dma_addr_t dma_addr; + struct dwc3_request *req, *n; + int ret = 0; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); + /* + * We can get in a situation where there's a request in the started list + * but there weren't enough TRBs to fully kick it in the first time + * around, so it has been waiting for more TRBs to be freed up. + * + * In that case, we should check if we have a request with pending_sgs + * in the started list and prepare TRBs for that request first, + * otherwise we will prepare TRBs completely out of order and that will + * break things. + */ + list_for_each_entry(req, &dep->started_list, list) { + if (!dwc3_calc_trbs_left(dep)) + return ret; + + /* + * Don't prepare beyond a transfer. In DWC_usb32, its transfer + * burst capability may try to read and use TRBs beyond the + * active transfer instead of stopping. + */ + if (dep->stream_capable && req->request.is_last && + !DWC3_MST_CAPABLE(&dep->dwc->hwparams)) + return ret; + } + list_for_each_entry_safe(req, n, &dep->pending_list, list) { - dma_addr = dma_map_single(dwc->dev, req->request.buf, - req->request.length, - dep->number ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(dwc->dev, dma_addr)) - return; + struct dwc3 *dwc = dep->dwc; - req->request.dma = dma_addr; + ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request, + dep->direction); + if (ret) + return ret; - dwc3_prepare_one_trb_linear(dep, req); + req->sg = req->request.sg; + req->start_sg = req->sg; + req->num_queued_sgs = 0; + req->num_pending_sgs = req->request.num_mapped_sgs; - if (!dwc3_calc_trbs_left(dep)) - return; + ret = dwc3_prepare_trbs_linear(dep, req); + + if (!ret || !dwc3_calc_trbs_left(dep)) + return ret; + + /* + * Don't prepare beyond a transfer. In DWC_usb32, its transfer + * burst capability may try to read and use TRBs beyond the + * active transfer instead of stopping. + */ + if (dep->stream_capable && req->request.is_last && + !DWC3_MST_CAPABLE(&dwc->hwparams)) + return ret; } + + return ret; } +static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep); + static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; - struct dwc3_request *req; - int starting; - int ret; - u32 cmd; + struct dwc3_request *req; + int starting; + int ret; + u32 cmd; - if (!dwc3_calc_trbs_left(dep)) - return 0; + /* + * Note that it's normal to have no new TRBs prepared (i.e. ret == 0). + * This happens when we need to stop and restart a transfer such as in + * the case of reinitiating a stream or retrying an isoc transfer. + */ + ret = dwc3_prepare_trbs(dep); + if (ret < 0) + return ret; starting = !(dep->flags & DWC3_EP_TRANSFER_STARTED); - dwc3_prepare_trbs(dep); + /* + * If there's no new TRB prepared and we don't need to restart a + * transfer, there's no need to update the transfer. + */ + if (!ret && !starting) + return ret; req = next_request(&dep->started_list); if (!req) { @@ -1156,29 +1511,84 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); if (ret < 0) { - /* - * FIXME we need to iterate over the list of requests - * here and stop, unmap, free and del each of the linked - * requests instead of what we do now. - */ - if (req->trb) - memset(req->trb, 0, sizeof(struct dwc3_trb)); - dwc3_gadget_del_and_unmap_request(dep, req, ret); + struct dwc3_request *tmp; + + if (ret == -EAGAIN) + return ret; + + dwc3_stop_active_transfer(dep, true, true); + + list_for_each_entry_safe(req, tmp, &dep->started_list, list) + dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_DEQUEUED); + + /* If ep isn't started, then there's no end transfer pending */ + if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + dwc3_gadget_ep_cleanup_cancelled_requests(dep); + return ret; } + if (dep->stream_capable && req->request.is_last && + !DWC3_MST_CAPABLE(&dep->dwc->hwparams)) + dep->flags |= DWC3_EP_WAIT_TRANSFER_COMPLETE; + return 0; } static int __dwc3_gadget_get_frame(struct dwc3 *dwc) { - u32 reg; + u32 reg; reg = dwc3_readl(dwc->regs, DWC3_DSTS); return DWC3_DSTS_SOFFN(reg); } /** + * __dwc3_stop_active_transfer - stop the current active transfer + * @dep: isoc endpoint + * @force: set forcerm bit in the command + * @interrupt: command complete interrupt after End Transfer command + * + * When setting force, the ForceRM bit will be set. In that case + * the controller won't update the TRB progress on command + * completion. It also won't clear the HWO bit in the TRB. + * The command will also not complete immediately in that case. + */ +static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt) +{ + struct dwc3_gadget_ep_cmd_params params; + u32 cmd; + int ret; + + cmd = DWC3_DEPCMD_ENDTRANSFER; + cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; + cmd |= interrupt ? DWC3_DEPCMD_CMDIOC : 0; + cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); + memset(¶ms, 0, sizeof(params)); + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); + /* + * If the End Transfer command was timed out while the device is + * not in SETUP phase, it's possible that an incoming Setup packet + * may prevent the command's completion. Let's retry when the + * ep0state returns to EP0_SETUP_PHASE. + */ + if (ret == -ETIMEDOUT && dep->dwc->ep0state != EP0_SETUP_PHASE) { + dep->flags |= DWC3_EP_DELAY_STOP; + return 0; + } + WARN_ON_ONCE(ret); + dep->resource_index = 0; + + if (!interrupt) + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; + else if (!ret) + dep->flags |= DWC3_EP_END_TRANSFER_PENDING; + + dep->flags &= ~DWC3_EP_DELAY_STOP; + return ret; +} + +/** * dwc3_gadget_start_isoc_quirk - workaround invalid frame number * @dep: isoc endpoint * @@ -1235,7 +1645,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) * Check if we can start isoc transfer on the next interval or * 4 uframes in the future with BIT[15:14] as dep->combo_num */ - test_frame_number = dep->frame_number & 0x3fff; + test_frame_number = dep->frame_number & DWC3_FRNUMBER_MASK; test_frame_number |= dep->combo_num << 14; test_frame_number += max_t(u32, 4, dep->interval); @@ -1282,7 +1692,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) else if (test0 && test1) dep->combo_num = 0; - dep->frame_number &= 0x3fff; + dep->frame_number &= DWC3_FRNUMBER_MASK; dep->frame_number |= dep->combo_num << 14; dep->frame_number += max_t(u32, 4, dep->interval); @@ -1295,63 +1705,110 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) { + const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; struct dwc3 *dwc = dep->dwc; int ret; int i; - if (list_empty(&dep->pending_list)) { + if (list_empty(&dep->pending_list) && + list_empty(&dep->started_list)) { dep->flags |= DWC3_EP_PENDING_REQUEST; return -EAGAIN; } - if (!dwc->dis_start_transfer_quirk && dwc3_is_usb31(dwc) && - (dwc->revision <= DWC3_USB31_REVISION_160A || - (dwc->revision == DWC3_USB31_REVISION_170A && - dwc->version_type >= DWC31_VERSIONTYPE_EA01 && - dwc->version_type <= DWC31_VERSIONTYPE_EA06))) { - - if (dwc->gadget.speed <= USB_SPEED_HIGH && dep->direction) + if (!dwc->dis_start_transfer_quirk && + (DWC3_VER_IS_PRIOR(DWC31, 170A) || + DWC3_VER_TYPE_IS_WITHIN(DWC31, 170A, EA01, EA06))) { + if (dwc->gadget->speed <= USB_SPEED_HIGH && dep->direction) return dwc3_gadget_start_isoc_quirk(dep); } + if (desc->bInterval <= 14 && + dwc->gadget->speed >= USB_SPEED_HIGH) { + u32 frame = __dwc3_gadget_get_frame(dwc); + bool rollover = frame < + (dep->frame_number & DWC3_FRNUMBER_MASK); + + /* + * frame_number is set from XferNotReady and may be already + * out of date. DSTS only provides the lower 14 bit of the + * current frame number. So add the upper two bits of + * frame_number and handle a possible rollover. + * This will provide the correct frame_number unless more than + * rollover has happened since XferNotReady. + */ + + dep->frame_number = (dep->frame_number & ~DWC3_FRNUMBER_MASK) | + frame; + if (rollover) + dep->frame_number += BIT(14); + } + for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) { - dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1); + int future_interval = i + 1; + + /* Give the controller at least 500us to schedule transfers */ + if (desc->bInterval < 3) + future_interval += 3 - desc->bInterval; + + dep->frame_number = DWC3_ALIGN_FRAME(dep, future_interval); ret = __dwc3_gadget_kick_transfer(dep); if (ret != -EAGAIN) break; } + /* + * After a number of unsuccessful start attempts due to bus-expiry + * status, issue END_TRANSFER command and retry on the next XferNotReady + * event. + */ + if (ret == -EAGAIN) + ret = __dwc3_stop_active_transfer(dep, false, true); + return ret; } static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) { - struct dwc3 *dwc = dep->dwc; + struct dwc3 *dwc = dep->dwc; - if (!dep->endpoint.desc) { - dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", + if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) { + dev_dbg(dwc->dev, "%s: can't queue to disabled endpoint\n", dep->name); return -ESHUTDOWN; } - if (req->dep != dep) { - WARN(true, "request %p belongs to '%s'\n", - &req->request, req->dep->name); + if (WARN(req->dep != dep, "request %pK belongs to '%s'\n", + &req->request, req->dep->name)) return -EINVAL; - } - if (req->status < DWC3_REQUEST_STATUS_COMPLETED) { - WARN(true, "request %p already in flight\n", &req->request); + if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED, + "%s: request %pK already in flight\n", + dep->name, &req->request)) return -EINVAL; - } - req->request.actual = 0; - req->request.status = -EINPROGRESS; + req->request.actual = 0; + req->request.status = -EINPROGRESS; list_add_tail(&req->list, &dep->pending_list); req->status = DWC3_REQUEST_STATUS_QUEUED; + if (dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE) + return 0; + + /* + * Start the transfer only after the END_TRANSFER is completed + * and endpoint STALL is cleared. + */ + if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) || + (dep->flags & DWC3_EP_WEDGE) || + (dep->flags & DWC3_EP_DELAY_STOP) || + (dep->flags & DWC3_EP_STALL)) { + dep->flags |= DWC3_EP_DELAY_START; + return 0; + } + /* * NOTICE: Isochronous endpoints should NEVER be prestarted. We must * wait for a XferNotReady event so we will know what's the current @@ -1361,28 +1818,27 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * errors which will force us issue EndTransfer command. */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if (!(dep->flags & DWC3_EP_PENDING_REQUEST) && - !(dep->flags & DWC3_EP_TRANSFER_STARTED)) - return 0; - - if ((dep->flags & DWC3_EP_PENDING_REQUEST)) { - if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) { + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) { + if ((dep->flags & DWC3_EP_PENDING_REQUEST)) return __dwc3_gadget_start_isoc(dep); - } + + return 0; } } - return __dwc3_gadget_kick_transfer(dep); + __dwc3_gadget_kick_transfer(dep); + + return 0; } 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_request *req = to_dwc3_request(request); + struct dwc3_ep *dep = to_dwc3_ep(ep); - unsigned long flags; + unsigned long flags; - int ret; + int ret; spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_queue(dep, req); @@ -1391,11 +1847,14 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request) return ret; } -static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, - struct dwc3_request *req) +static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *req) { int i; + /* If req->trb is not set, then the request has not started */ + if (!req->trb) + return; + /* * If request was already started, this means we had to * stop the transfer. With that we also need to ignore @@ -1409,7 +1868,7 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, for (i = 0; i < req->num_trbs; i++) { struct dwc3_trb *trb; - trb = req->trb + i; + trb = &dep->trb_pool[dep->trb_dequeue]; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); } @@ -1419,61 +1878,87 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep) { - struct dwc3_request *req; - struct dwc3_request *tmp; + struct dwc3_request *req; + struct dwc3 *dwc = dep->dwc; - list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) { + while (!list_empty(&dep->cancelled_list)) { + req = next_request(&dep->cancelled_list); dwc3_gadget_ep_skip_trbs(dep, req); - dwc3_gadget_giveback(dep, req, -ECONNRESET); + switch (req->status) { + case DWC3_REQUEST_STATUS_DISCONNECTED: + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + break; + case DWC3_REQUEST_STATUS_DEQUEUED: + dwc3_gadget_giveback(dep, req, -ECONNRESET); + break; + case DWC3_REQUEST_STATUS_STALLED: + dwc3_gadget_giveback(dep, req, -EPIPE); + break; + default: + dev_err(dwc->dev, "request cancelled with wrong reason:%d\n", req->status); + dwc3_gadget_giveback(dep, req, -ECONNRESET); + break; + } + /* + * The endpoint is disabled, let the dwc3_remove_requests() + * handle the cleanup. + */ + if (!dep->endpoint.desc) + break; } } static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, - struct usb_request *request) + struct usb_request *request) { - struct dwc3_request *req = to_dwc3_request(request); - struct dwc3_request *r = NULL; - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; - unsigned long flags; - int ret = 0; + struct dwc3_request *req = to_dwc3_request(request); + struct dwc3_request *r = NULL; + + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + + unsigned long flags; + int ret = 0; spin_lock_irqsave(&dwc->lock, flags); - list_for_each_entry(r, &dep->pending_list, list) { + list_for_each_entry(r, &dep->cancelled_list, list) { if (r == req) - break; + goto out; } - if (r != req) { - list_for_each_entry(r, &dep->started_list, list) { - if (r == req) - break; + list_for_each_entry(r, &dep->pending_list, list) { + if (r == req) { + dwc3_gadget_giveback(dep, req, -ECONNRESET); + goto out; } + } + + list_for_each_entry(r, &dep->started_list, list) { if (r == req) { + struct dwc3_request *t; + /* wait until it is processed */ dwc3_stop_active_transfer(dep, true, true); - if (!r->trb) - goto out0; + /* + * Remove any started request if the transfer is + * cancelled. + */ + list_for_each_entry_safe(r, t, &dep->started_list, list) + dwc3_gadget_move_cancelled_request(r, + DWC3_REQUEST_STATUS_DEQUEUED); - dwc3_gadget_move_cancelled_request(req); - if (dep->flags & DWC3_EP_TRANSFER_STARTED) - goto out0; - else - goto out1; + dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE; + + goto out; } - dev_err(dwc->dev, "request %p was not queued to %s\n", - request, ep->name); - ret = -EINVAL; - goto out0; } -out1: - /* giveback the request */ - dwc3_gadget_giveback(dep, req, -ECONNRESET); - -out0: + dev_err(dwc->dev, "request %pK was not queued to %s\n", + request, ep->name); + ret = -EINVAL; +out: spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1481,9 +1966,11 @@ out0: int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) { - struct dwc3_gadget_ep_cmd_params params; - struct dwc3 *dwc = dep->dwc; - int ret; + struct dwc3_gadget_ep_cmd_params params; + struct dwc3 *dwc = dep->dwc; + struct dwc3_request *req; + struct dwc3_request *tmp; + int ret; if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); @@ -1494,8 +1981,9 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) if (value) { struct dwc3_trb *trb; - unsigned transfer_in_flight; - unsigned started; + + unsigned int transfer_in_flight; + unsigned int started; if (dep->number > 1) trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue); @@ -1511,19 +1999,53 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) } ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETSTALL, - ¶ms); + ¶ms); if (ret) dev_err(dwc->dev, "failed to set STALL on %s\n", dep->name); else dep->flags |= DWC3_EP_STALL; } else { + /* + * Don't issue CLEAR_STALL command to control endpoints. The + * controller automatically clears the STALL when it receives + * the SETUP token. + */ + if (dep->number <= 1) { + dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE); + return 0; + } + + dwc3_stop_active_transfer(dep, true, true); + + list_for_each_entry_safe(req, tmp, &dep->started_list, list) + dwc3_gadget_move_cancelled_request(req, DWC3_REQUEST_STATUS_STALLED); + + if (dep->flags & DWC3_EP_END_TRANSFER_PENDING || + (dep->flags & DWC3_EP_DELAY_STOP)) { + dep->flags |= DWC3_EP_PENDING_CLEAR_STALL; + if (protocol) + dwc->clear_stall_protocol = dep->number; + + return 0; + } + + dwc3_gadget_ep_cleanup_cancelled_requests(dep); + ret = dwc3_send_clear_stall_ep_cmd(dep); - if (ret) + if (ret) { dev_err(dwc->dev, "failed to clear STALL on %s\n", dep->name); - else - dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE); + return ret; + } + + dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE); + + if ((dep->flags & DWC3_EP_DELAY_START) && + !usb_endpoint_xfer_isoc(dep->endpoint.desc)) + __dwc3_gadget_kick_transfer(dep); + + dep->flags &= ~DWC3_EP_DELAY_START; } return ret; @@ -1531,10 +2053,11 @@ 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); - unsigned long flags; + struct dwc3_ep *dep = to_dwc3_ep(ep); - int ret; + unsigned long flags; + + int ret; spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_set_halt(dep, value, false); @@ -1545,9 +2068,9 @@ 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); - unsigned long flags; - int ret; + struct dwc3_ep *dep = to_dwc3_ep(ep); + unsigned long flags; + int ret; spin_lock_irqsave(&dwc->lock, flags); dep->flags |= DWC3_EP_WEDGE; @@ -1564,13 +2087,13 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) /* -------------------------------------------------------------------------- */ static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, }; static const struct usb_ep_ops dwc3_gadget_ep0_ops = { - .enable = dwc3_gadget_ep0_enable, + .enable = dwc3_gadget_ep0_enable, .disable = dwc3_gadget_ep0_disable, .alloc_request = dwc3_gadget_ep_alloc_request, .free_request = dwc3_gadget_ep_free_request, @@ -1581,7 +2104,7 @@ static const struct usb_ep_ops dwc3_gadget_ep0_ops = { }; static const struct usb_ep_ops dwc3_gadget_ep_ops = { - .enable = dwc3_gadget_ep_enable, + .enable = dwc3_gadget_ep_enable, .disable = dwc3_gadget_ep_disable, .alloc_request = dwc3_gadget_ep_alloc_request, .free_request = dwc3_gadget_ep_free_request, @@ -1595,20 +2118,19 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = { static int dwc3_gadget_get_frame(struct usb_gadget *g) { - struct dwc3 *dwc = gadget_to_dwc(g); + struct dwc3 *dwc = gadget_to_dwc(g); return __dwc3_gadget_get_frame(dwc); } static int __dwc3_gadget_wakeup(struct dwc3 *dwc) { - int retries; + int retries; - int ret; - u32 reg; + int ret; + u32 reg; - u8 link_state; - u8 speed; + u8 link_state; /* * According to the Databook Remote wakeup request should @@ -1618,16 +2140,15 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) */ reg = dwc3_readl(dwc->regs, DWC3_DSTS); - speed = reg & DWC3_DSTS_CONNECTSPD; - if ((speed == DWC3_DSTS_SUPERSPEED) || - (speed == DWC3_DSTS_SUPERSPEED_PLUS)) - return 0; - link_state = DWC3_DSTS_USBLNKST(reg); switch (link_state) { + case DWC3_LINK_STATE_RESET: case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ + case DWC3_LINK_STATE_U2: /* in HS, means Sleep (L1) */ + case DWC3_LINK_STATE_U1: + case DWC3_LINK_STATE_RESUME: break; default: return -EINVAL; @@ -1640,7 +2161,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) } /* Recent versions do this automatically */ - if (dwc->revision < DWC3_REVISION_194A) { + if (DWC3_VER_IS_PRIOR(DWC3, 194A)) { /* write zeroes to Link Change Request */ reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; @@ -1668,9 +2189,9 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) static int dwc3_gadget_wakeup(struct usb_gadget *g) { - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long flags; - int ret; + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + int ret; spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_wakeup(dwc); @@ -1680,37 +2201,145 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) } static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, - int is_selfpowered) + int is_selfpowered) { - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long flags; + unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); - dwc->is_selfpowered = !!is_selfpowered; + g->is_selfpowered = !!is_selfpowered; spin_unlock_irqrestore(&dwc->lock, flags); return 0; } +static void dwc3_stop_active_transfers(struct dwc3 *dwc) +{ + u32 epnum; + + for (epnum = 2; epnum < dwc->num_eps; epnum++) { + struct dwc3_ep *dep; + + dep = dwc->eps[epnum]; + if (!dep) + continue; + + dwc3_remove_requests(dwc, dep, -ESHUTDOWN); + } +} + +static void __dwc3_gadget_set_ssp_rate(struct dwc3 *dwc) +{ + enum usb_ssp_rate ssp_rate = dwc->gadget_ssp_rate; + u32 reg; + + if (ssp_rate == USB_SSP_GEN_UNKNOWN) + ssp_rate = dwc->max_ssp_rate; + + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg &= ~DWC3_DCFG_SPEED_MASK; + reg &= ~DWC3_DCFG_NUMLANES(~0); + + if (ssp_rate == USB_SSP_GEN_1x2) + reg |= DWC3_DCFG_SUPERSPEED; + else if (dwc->max_ssp_rate != USB_SSP_GEN_1x2) + reg |= DWC3_DCFG_SUPERSPEED_PLUS; + + if (ssp_rate != USB_SSP_GEN_2x1 && + dwc->max_ssp_rate != USB_SSP_GEN_2x1) + reg |= DWC3_DCFG_NUMLANES(1); + + dwc3_writel(dwc->regs, DWC3_DCFG, reg); +} + +static void __dwc3_gadget_set_speed(struct dwc3 *dwc) +{ + enum usb_device_speed speed; + u32 reg; + + speed = dwc->gadget_max_speed; + if (speed == USB_SPEED_UNKNOWN || speed > dwc->maximum_speed) + speed = dwc->maximum_speed; + + if (speed == USB_SPEED_SUPER_PLUS && + DWC3_IP_IS(DWC32)) { + __dwc3_gadget_set_ssp_rate(dwc); + return; + } + + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg &= ~(DWC3_DCFG_SPEED_MASK); + + /* + * WORKAROUND: DWC3 revision < 2.20a have an issue + * which would cause metastability state on Run/Stop + * bit if we try to force the IP to USB2-only mode. + * + * Because of that, we cannot configure the IP to any + * speed other than the SuperSpeed + * + * Refers to: + * + * STAR#9000525659: Clock Domain Crossing on DCTL in + * USB 2.0 Mode + */ + if (DWC3_VER_IS_PRIOR(DWC3, 220A) && + !dwc->dis_metastability_quirk) { + reg |= DWC3_DCFG_SUPERSPEED; + } else { + switch (speed) { + case USB_SPEED_FULL: + reg |= DWC3_DCFG_FULLSPEED; + break; + case USB_SPEED_HIGH: + reg |= DWC3_DCFG_HIGHSPEED; + break; + case USB_SPEED_SUPER: + reg |= DWC3_DCFG_SUPERSPEED; + break; + case USB_SPEED_SUPER_PLUS: + if (DWC3_IP_IS(DWC3)) + reg |= DWC3_DCFG_SUPERSPEED; + else + reg |= DWC3_DCFG_SUPERSPEED_PLUS; + break; + default: + dev_err(dwc->dev, "invalid speed (%d)\n", speed); + + if (DWC3_IP_IS(DWC3)) + reg |= DWC3_DCFG_SUPERSPEED; + else + reg |= DWC3_DCFG_SUPERSPEED_PLUS; + } + } + + if (DWC3_IP_IS(DWC32) && + speed > USB_SPEED_UNKNOWN && + speed < USB_SPEED_SUPER_PLUS) + reg &= ~DWC3_DCFG_NUMLANES(~0); + + dwc3_writel(dwc->regs, DWC3_DCFG, reg); +} + static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { - u32 reg; - u32 timeout = 500; + u32 reg; + u32 timeout = 2000; reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) { - if (dwc->revision <= DWC3_REVISION_187A) { + if (DWC3_VER_IS_WITHIN(DWC3, ANY, 187A)) { reg &= ~DWC3_DCTL_TRGTULST_MASK; reg |= DWC3_DCTL_TRGTULST_RX_DET; } - if (dwc->revision >= DWC3_REVISION_194A) + if (!DWC3_VER_IS_PRIOR(DWC3, 194A)) reg &= ~DWC3_DCTL_KEEP_CONNECT; reg |= DWC3_DCTL_RUN_STOP; if (dwc->has_hibernation) reg |= DWC3_DCTL_KEEP_CONNECT; + __dwc3_gadget_set_speed(dwc); dwc->pullups_connected = true; } else { reg &= ~DWC3_DCTL_RUN_STOP; @@ -1721,9 +2350,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) dwc->pullups_connected = false; } - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); do { + udelay(1000); reg = dwc3_readl(dwc->regs, DWC3_DSTS); reg &= DWC3_DSTS_DEVCTRLHLT; } while (--timeout && !(!is_on ^ !reg)); @@ -1731,54 +2361,104 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (!timeout) return -ETIMEDOUT; - dev_dbg(dwc->dev, "gadget %s data soft-%s\n", - dwc->gadget_driver - ? dwc->gadget_driver->function : "no-function", - is_on ? "connect" : "disconnect"); - return 0; } -static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) +static void dwc3_gadget_disable_irq(struct dwc3 *dwc); +static void __dwc3_gadget_stop(struct dwc3 *dwc); +static int __dwc3_gadget_start(struct dwc3 *dwc); + +static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) { - struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; - int ret; - is_on = !!is_on; + spin_lock_irqsave(&dwc->lock, flags); + dwc->connected = false; /* * Per databook, when we want to stop the gadget, if a control transfer * is still in process, complete it and get the core into setup phase. */ - if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) - dev_warn(dwc->dev, "not in SETUP phase\n"); + if (dwc->ep0state != EP0_SETUP_PHASE) { + /* + * Original Linux code waits for ep0state bein in setup + * phase here using completions. Completions are not properly + * implemented in barebox, hence the code is skipped here. I wasn't + * able to trigger this code in barebox, but if you hit this compare + * it with Linux code and implement it here. + */ + dev_warn(dwc->dev, "%s: unexpected state\n", __func__); + } - spin_lock_irqsave(&dwc->lock, flags); - ret = dwc3_gadget_run_stop(dwc, is_on, false); + /* + * In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a + * Section 4.1.8 Table 4-7, it states that for a device-initiated + * disconnect, the SW needs to ensure that it sends "a DEPENDXFER + * command for any active transfers" before clearing the RunStop + * bit. + */ + dwc3_stop_active_transfers(dwc); + __dwc3_gadget_stop(dwc); spin_unlock_irqrestore(&dwc->lock, flags); + /* + * Note: if the GEVNTCOUNT indicates events in the event buffer, the + * driver needs to acknowledge them before the controller can halt. + * Simply let the interrupt handler acknowledges and handle the + * remaining event generated by the controller while polling for + * DSTS.DEVCTLHLT. + */ + return dwc3_gadget_run_stop(dwc, false, false); +} + +static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + int ret; + + is_on = !!is_on; + + dwc->softconnect = is_on; + + if (!is_on) { + ret = dwc3_gadget_soft_disconnect(dwc); + } else { + /* + * In the Synopsys DWC_usb31 1.90a programming guide section + * 4.1.9, it specifies that for a reconnect after a + * device-initiated disconnect requires a core soft reset + * (DCTL.CSftRst) before enabling the run/stop bit. + */ + dwc3_core_soft_reset(dwc); + + dwc3_event_buffers_setup(dwc); + __dwc3_gadget_start(dwc); + ret = dwc3_gadget_run_stop(dwc, true, false); + } + return ret; } static void dwc3_gadget_enable_irq(struct dwc3 *dwc) { - u32 reg; + u32 reg; /* Enable all but Start and End of Frame IRQs */ - reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | - DWC3_DEVTEN_EVNTOVERFLOWEN | - DWC3_DEVTEN_CMDCMPLTEN | - DWC3_DEVTEN_ERRTICERREN | - DWC3_DEVTEN_WKUPEVTEN | - DWC3_DEVTEN_ULSTCNGEN | - DWC3_DEVTEN_CONNECTDONEEN | - DWC3_DEVTEN_USBRSTEN | - DWC3_DEVTEN_DISCONNEVTEN); - - if (dwc->revision < DWC3_REVISION_250A) + reg = (DWC3_DEVTEN_EVNTOVERFLOWEN | + DWC3_DEVTEN_CMDCMPLTEN | + DWC3_DEVTEN_ERRTICERREN | + DWC3_DEVTEN_WKUPEVTEN | + DWC3_DEVTEN_CONNECTDONEEN | + DWC3_DEVTEN_USBRSTEN | + DWC3_DEVTEN_DISCONNEVTEN); + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) reg |= DWC3_DEVTEN_ULSTCNGEN; + /* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */ + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) + reg |= DWC3_DEVTEN_U3L2L1SUSPEN; + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); } @@ -1817,7 +2497,7 @@ static void dwc3_gadget_setup_nump(struct dwc3 *dwc) u32 reg; ram2_depth = DWC3_GHWPARAMS7_RAM2_DEPTH(dwc->hwparams.hwparams7); - mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0); + mdwidth = dwc3_mdwidth(dwc); nump = ((ram2_depth * mdwidth / 8) - 24 - 16) / 1024; nump = min_t(u32, nump, 16); @@ -1831,9 +2511,20 @@ static void dwc3_gadget_setup_nump(struct dwc3 *dwc) static int __dwc3_gadget_start(struct dwc3 *dwc) { - struct dwc3_ep *dep; - int ret = 0; - u32 reg; + struct dwc3_ep *dep; + int ret = 0; + u32 reg; + + /* + * Use IMOD if enabled via dwc->imod_interval. Otherwise, if + * the core supports IMOD, disable it. + */ + if (dwc->imod_interval) { + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); + } else if (dwc3_has_imod(dwc)) { + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0); + } /* * We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP @@ -1843,19 +2534,38 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) * bursts of data without going through any sort of endpoint throttling. */ reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); - if (dwc3_is_usb31(dwc)) - reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL; - else + if (DWC3_IP_IS(DWC3)) reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL; + else + reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL; dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); dwc3_gadget_setup_nump(dwc); + /* + * Currently the controller handles single stream only. So, Ignore + * Packet Pending bit for stream selection and don't search for another + * stream if the host sends Data Packet with PP=0 (for OUT direction) or + * ACK with NumP=0 and PP=0 (for IN direction). This slightly improves + * the stream performance. + */ + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg |= DWC3_DCFG_IGNSTRMPP; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + + /* Enable MST by default if the device is capable of MST */ + if (DWC3_MST_CAPABLE(&dwc->hwparams)) { + reg = dwc3_readl(dwc->regs, DWC3_DCFG1); + reg &= ~DWC3_DCFG1_DIS_MST_ENH; + dwc3_writel(dwc->regs, DWC3_DCFG1, reg); + } + /* Start with SuperSpeed Default */ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); dep = dwc->eps[0]; + dep->flags = 0; ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); @@ -1863,6 +2573,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) } dep = dwc->eps[1]; + dep->flags = 0; ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); @@ -1871,7 +2582,9 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; + dwc->ep0_bounced = false; dwc->link_state = DWC3_LINK_STATE_SS_DIS; + dwc->delayed_status = false; dwc3_ep0_out_start(dwc); dwc3_gadget_enable_irq(dwc); @@ -1888,109 +2601,163 @@ err0: static int dwc3_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long flags; - int ret = 0; + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; - //dwc3_gadget_wakeup(g); 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); - ret = -EBUSY; - goto err1; - } + dwc->gadget_driver = driver; + spin_unlock_irqrestore(&dwc->lock, flags); - dwc->gadget_driver = driver; + return 0; +} - __dwc3_gadget_start(dwc); +static void __dwc3_gadget_stop(struct dwc3 *dwc) +{ + dwc3_gadget_disable_irq(dwc); + __dwc3_gadget_ep_disable(dwc->eps[0]); + __dwc3_gadget_ep_disable(dwc->eps[1]); +} +static int dwc3_gadget_stop(struct usb_gadget *g) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + dwc->gadget_driver = NULL; + dwc->max_cfg_eps = 0; spin_unlock_irqrestore(&dwc->lock, flags); return 0; +} -err1: - spin_unlock_irqrestore(&dwc->lock, flags); +static void dwc3_gadget_config_params(struct usb_gadget *g, + struct usb_dcd_config_params *params) +{ + struct dwc3 *dwc = gadget_to_dwc(g); - return ret; + params->besl_baseline = USB_DEFAULT_BESL_UNSPECIFIED; + params->besl_deep = USB_DEFAULT_BESL_UNSPECIFIED; + + /* Recommended BESL */ + if (!dwc->dis_enblslpm_quirk) { + /* + * If the recommended BESL baseline is 0 or if the BESL deep is + * less than 2, Microsoft's Windows 10 host usb stack will issue + * a usb reset immediately after it receives the extended BOS + * descriptor and the enumeration will fail. To maintain + * compatibility with the Windows' usb stack, let's set the + * recommended BESL baseline to 1 and clamp the BESL deep to be + * within 2 to 15. + */ + params->besl_baseline = 1; + if (dwc->is_utmi_l1_suspend) + params->besl_deep = + clamp_t(u8, dwc->hird_threshold, 2, 15); + } + + /* U1 Device exit Latency */ + if (dwc->dis_u1_entry_quirk) + params->bU1devExitLat = 0; + else + params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT; + + /* U2 Device exit Latency */ + if (dwc->dis_u2_entry_quirk) + params->bU2DevExitLat = 0; + else + params->bU2DevExitLat = + cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT); } -static int dwc3_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static void dwc3_gadget_set_speed(struct usb_gadget *g, + enum usb_device_speed speed) { - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long flags; + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); + dwc->gadget_max_speed = speed; + spin_unlock_irqrestore(&dwc->lock, flags); +} - dwc3_gadget_disable_irq(dwc); - __dwc3_gadget_ep_disable(dwc->eps[0]); - __dwc3_gadget_ep_disable(dwc->eps[1]); +static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g, + enum usb_ssp_rate rate) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; - dwc->gadget_driver = NULL; + spin_lock_irqsave(&dwc->lock, flags); + dwc->gadget_max_speed = USB_SPEED_SUPER_PLUS; + dwc->gadget_ssp_rate = rate; spin_unlock_irqrestore(&dwc->lock, flags); +} + +static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + + if (dwc->usb2_phy) + return usb_phy_set_power(dwc->usb2_phy, mA); + + if (!dwc->usb_psy) + return -EOPNOTSUPP; return 0; } -static void dwc3_gadget_set_speed(struct dwc3 *dwc, - enum usb_device_speed speed) +/** + * dwc3_gadget_check_config - ensure dwc3 can support the USB configuration + * @g: pointer to the USB gadget + * + * Used to record the maximum number of endpoints being used in a USB composite + * device. (across all configurations) This is to be used in the calculation + * of the TXFIFO sizes when resizing internal memory for individual endpoints. + * It will help ensured that the resizing logic reserves enough space for at + * least one max packet. + */ +static int dwc3_gadget_check_config(struct usb_gadget *g) { - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&dwc->lock, flags); - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg &= ~(DWC3_DCFG_SPEED_MASK); + struct dwc3 *dwc = gadget_to_dwc(g); + struct usb_ep *ep; + int fifo_size = 0; + int ram1_depth; + int ep_num = 0; - /* - * WORKAROUND: DWC3 revision < 2.20a have an issue - * which would cause metastability state on Run/Stop - * bit if we try to force the IP to USB2-only mode. - * - * Because of that, we cannot configure the IP to any - * speed other than the SuperSpeed - * - * Refers to: - * - * STAR#9000525659: Clock Domain Crossing on DCTL in - * USB 2.0 Mode - */ - if (dwc->revision < DWC3_REVISION_220A && - !dwc->dis_metastability_quirk) { - reg |= DWC3_DCFG_SUPERSPEED; - } else { - switch (speed) { - case USB_SPEED_LOW: - reg |= DWC3_DCFG_LOWSPEED; - break; - case USB_SPEED_FULL: - reg |= DWC3_DCFG_FULLSPEED; - break; - case USB_SPEED_HIGH: - reg |= DWC3_DCFG_HIGHSPEED; - break; - case USB_SPEED_SUPER: - reg |= DWC3_DCFG_SUPERSPEED; - break; - case USB_SPEED_SUPER_PLUS: - if (dwc3_is_usb31(dwc)) - reg |= DWC3_DCFG_SUPERSPEED_PLUS; - else - reg |= DWC3_DCFG_SUPERSPEED; - break; - default: - dev_err(dwc->dev, "invalid speed (%d)\n", speed); + if (!dwc->do_fifo_resize) + return 0; - if (dwc->revision & DWC3_REVISION_IS_DWC31) - reg |= DWC3_DCFG_SUPERSPEED_PLUS; - else - reg |= DWC3_DCFG_SUPERSPEED; - } + list_for_each_entry(ep, &g->ep_list, ep_list) { + /* Only interested in the IN endpoints */ + if (ep->claimed && (ep->address & USB_DIR_IN)) + ep_num++; } - dwc3_writel(dwc->regs, DWC3_DCFG, reg); + if (ep_num <= dwc->max_cfg_eps) + return 0; + + /* Update the max number of eps in the composition */ + dwc->max_cfg_eps = ep_num; + + fifo_size = dwc3_gadget_calc_tx_fifo_size(dwc, dwc->max_cfg_eps); + /* Based on the equation, increment by one for every ep */ + fifo_size += dwc->max_cfg_eps; + + /* Check if we can fit a single fifo per endpoint */ + ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); + if (fifo_size > ram1_depth) + return -ENOMEM; + + return 0; +} + +static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + dwc->async_callbacks = enable; spin_unlock_irqrestore(&dwc->lock, flags); } @@ -1998,12 +2765,18 @@ static void dwc3_gadget_poll(struct usb_gadget *g); static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, - .wakeup = dwc3_gadget_wakeup, + .wakeup = dwc3_gadget_wakeup, .set_selfpowered = dwc3_gadget_set_selfpowered, - .pullup = dwc3_gadget_pullup, + .pullup = dwc3_gadget_pullup, .udc_start = dwc3_gadget_start, .udc_stop = dwc3_gadget_stop, .udc_poll = dwc3_gadget_poll, + .udc_set_speed = dwc3_gadget_set_speed, + .udc_set_ssp_rate = dwc3_gadget_set_ssp_rate, + .get_config_params = dwc3_gadget_config_params, + .vbus_draw = dwc3_gadget_vbus_draw, + .check_config = dwc3_gadget_check_config, + .udc_async_callbacks = dwc3_gadget_async_callbacks, }; /* -------------------------------------------------------------------------- */ @@ -2016,7 +2789,9 @@ static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep) dep->endpoint.maxburst = 1; dep->endpoint.ops = &dwc3_gadget_ep0_ops; if (!dep->direction) - dwc->gadget.ep0 = &dep->endpoint; + dwc->gadget->ep0 = &dep->endpoint; + + dep->endpoint.caps.type_control = true; return 0; } @@ -2024,41 +2799,48 @@ static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep) static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; - int mdwidth; - int kbytes; + u32 mdwidth; int size; + int maxpacket; + + mdwidth = dwc3_mdwidth(dwc); - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); /* MDWIDTH is represented in bits, we need it in bytes */ mdwidth /= 8; size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1)); - if (dwc3_is_usb31(dwc)) - size = DWC31_GTXFIFOSIZ_TXFDEF(size); + if (DWC3_IP_IS(DWC3)) + size = DWC3_GTXFIFOSIZ_TXFDEP(size); else - size = DWC3_GTXFIFOSIZ_TXFDEF(size); - - /* FIFO Depth is in MDWDITH bytes. Multiply */ - size *= mdwidth; - - kbytes = size / 1024; - if (kbytes == 0) - kbytes = 1; + size = DWC31_GTXFIFOSIZ_TXFDEP(size); /* - * FIFO sizes account an extra MDWIDTH * (kbytes + 1) bytes for - * internal overhead. We don't really know how these are used, - * but documentation say it exists. + * maxpacket size is determined as part of the following, after assuming + * a mult value of one maxpacket: + * DWC3 revision 280A and prior: + * fifo_size = mult * (max_packet / mdwidth) + 1; + * maxpacket = mdwidth * (fifo_size - 1); + * + * DWC3 revision 290A and onwards: + * fifo_size = mult * ((max_packet + mdwidth)/mdwidth + 1) + 1 + * maxpacket = mdwidth * ((fifo_size - 1) - 1) - mdwidth; */ - size -= mdwidth * (kbytes + 1); - size /= kbytes; + if (DWC3_VER_IS_PRIOR(DWC3, 290A)) + maxpacket = mdwidth * (size - 1); + else + maxpacket = mdwidth * ((size - 1) - 1) - mdwidth; + /* Functionally, space for one max packet is sufficient */ + size = min_t(int, maxpacket, 1024); usb_ep_set_maxpacket_limit(&dep->endpoint, size); - dep->endpoint.max_streams = 15; + dep->endpoint.max_streams = 16; dep->endpoint.ops = &dwc3_gadget_ep_ops; list_add_tail(&dep->endpoint.ep_list, - &dwc->gadget.ep_list); + &dwc->gadget->ep_list); + dep->endpoint.caps.type_iso = true; + dep->endpoint.caps.type_bulk = true; + dep->endpoint.caps.type_int = true; return dwc3_alloc_trb_pool(dep); } @@ -2066,22 +2848,56 @@ static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep) static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; + u32 mdwidth; + int size; + + mdwidth = dwc3_mdwidth(dwc); + + /* MDWIDTH is represented in bits, convert to bytes */ + mdwidth /= 8; + + /* All OUT endpoints share a single RxFIFO space */ + size = dwc3_readl(dwc->regs, DWC3_GRXFIFOSIZ(0)); + if (DWC3_IP_IS(DWC3)) + size = DWC3_GRXFIFOSIZ_RXFDEP(size); + else + size = DWC31_GRXFIFOSIZ_RXFDEP(size); + + /* FIFO depth is in MDWDITH bytes */ + size *= mdwidth; + + /* + * To meet performance requirement, a minimum recommended RxFIFO size + * is defined as follow: + * RxFIFO size >= (3 x MaxPacketSize) + + * (3 x 8 bytes setup packets size) + (16 bytes clock crossing margin) + * + * Then calculate the max packet limit as below. + */ + size -= (3 * 8) + 16; + if (size < 0) + size = 0; + else + size /= 3; - usb_ep_set_maxpacket_limit(&dep->endpoint, 1024); - dep->endpoint.max_streams = 15; + usb_ep_set_maxpacket_limit(&dep->endpoint, size); + dep->endpoint.max_streams = 16; dep->endpoint.ops = &dwc3_gadget_ep_ops; list_add_tail(&dep->endpoint.ep_list, - &dwc->gadget.ep_list); + &dwc->gadget->ep_list); + dep->endpoint.caps.type_iso = true; + dep->endpoint.caps.type_bulk = true; + dep->endpoint.caps.type_int = true; return dwc3_alloc_trb_pool(dep); } static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) { - struct dwc3_ep *dep; - bool direction = epnum & 1; - int ret; - u8 num = epnum >> 1; + struct dwc3_ep *dep; + bool direction = epnum & 1; + int ret; + u8 num = epnum >> 1; dep = kzalloc(sizeof(*dep), GFP_KERNEL); if (!dep) @@ -2096,7 +2912,7 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) dep->start_cmd_status = 0; snprintf(dep->name, sizeof(dep->name), "ep%u%s", num, - direction ? "in" : "out"); + direction ? "in" : "out"); dep->endpoint.name = dep->name; @@ -2105,8 +2921,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) dep->endpoint.comp_desc = NULL; } - spin_lock_init(&dep->lock); - if (num == 0) ret = dwc3_gadget_init_control_endpoint(dep); else if (direction) @@ -2117,21 +2931,26 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) if (ret) return ret; + dep->endpoint.caps.dir_in = direction; + dep->endpoint.caps.dir_out = !direction; + INIT_LIST_HEAD(&dep->pending_list); INIT_LIST_HEAD(&dep->started_list); INIT_LIST_HEAD(&dep->cancelled_list); + dwc3_debugfs_create_endpoint_dir(dep); + return 0; } static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total) { - u8 epnum; + u8 epnum; - INIT_LIST_HEAD(&dwc->gadget.ep_list); + INIT_LIST_HEAD(&dwc->gadget->ep_list); for (epnum = 0; epnum < total; epnum++) { - int ret; + int ret; ret = dwc3_gadget_init_endpoint(dwc, epnum); if (ret) @@ -2143,8 +2962,8 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total) static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) { - struct dwc3_ep *dep; - u8 epnum; + struct dwc3_ep *dep; + u8 epnum; for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) { dep = dwc->eps[epnum]; @@ -2164,6 +2983,7 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) list_del(&dep->endpoint.ep_list); } + dwc3_debugfs_remove_endpoint_dir(dep); kfree(dep); } } @@ -2171,12 +2991,10 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) /* -------------------------------------------------------------------------- */ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, - struct dwc3_request *req, - struct dwc3_trb *trb, - const struct dwc3_event_depevt *event, - int status, int chain) + struct dwc3_request *req, struct dwc3_trb *trb, + const struct dwc3_event_depevt *event, int status, int chain) { - unsigned int count; + unsigned int count; dwc3_ep_inc_deq(dep); @@ -2205,15 +3023,16 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, frame_number = DWC3_TRB_CTRL_GET_SID_SOFN(trb->ctrl); frame_number &= ~(dep->interval - 1); + req->request.frame_number = frame_number; } /* - * If we're dealing with unaligned size OUT transfer, we will be left - * with one TRB pending in the ring. We need to manually clear HWO bit - * from that TRB. + * We use bounce buffer for requests that needs extra TRB or OUT ZLP. If + * this TRB points to the bounce buffer address, it's a MPS alignment + * TRB. Don't add it to req->remaining calculation. */ - - if (req->needs_extra_trb && !(trb->ctrl & DWC3_TRB_CTRL_CHN)) { + if (trb->bpl == lower_32_bits(dep->dwc->bounce_addr) && + trb->bph == upper_32_bits(dep->dwc->bounce_addr)) { trb->ctrl &= ~DWC3_TRB_CTRL_HWO; return 1; } @@ -2227,16 +3046,20 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, if (event->status & DEPEVT_STATUS_SHORT && !chain) return 1; - if (event->status & DEPEVT_STATUS_IOC) + if ((trb->ctrl & DWC3_TRB_CTRL_ISP_IMI) && + DWC3_TRB_SIZE_TRBSTS(trb->size) == DWC3_TRBSTS_MISSED_ISOC) + return 1; + + if ((trb->ctrl & DWC3_TRB_CTRL_IOC) || + (trb->ctrl & DWC3_TRB_CTRL_LST)) return 1; return 0; } static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, - const struct dwc3_event_depevt *event, - int status) + struct dwc3_request *req, const struct dwc3_event_depevt *event, + int status) { struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue]; @@ -2244,15 +3067,24 @@ static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep, event, status, false); } +static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req) +{ + return req->num_pending_sgs == 0 && req->num_queued_sgs == 0; +} + static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event, - struct dwc3_request *req, - int status) + const struct dwc3_event_depevt *event, + struct dwc3_request *req, int status) { + int request_status; int ret; - ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, - status); + ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status); + + req->request.actual = req->request.length - req->remaining; + + if (!dwc3_gadget_ep_request_completed(req)) + goto out; if (req->needs_extra_trb) { ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, @@ -2260,69 +3092,121 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, req->needs_extra_trb = false; } - req->request.actual = req->request.length - req->remaining; + /* + * The event status only reflects the status of the TRB with IOC set. + * For the requests that don't set interrupt on completion, the driver + * needs to check and return the status of the completed TRBs associated + * with the request. Use the status of the last TRB of the request. + */ + if (req->request.no_interrupt) { + struct dwc3_trb *trb; - dwc3_gadget_giveback(dep, req, status); + trb = dwc3_ep_prev_trb(dep, dep->trb_dequeue); + switch (DWC3_TRB_SIZE_TRBSTS(trb->size)) { + case DWC3_TRBSTS_MISSED_ISOC: + /* Isoc endpoint only */ + request_status = -EXDEV; + break; + case DWC3_TRB_STS_XFER_IN_PROG: + /* Applicable when End Transfer with ForceRM=0 */ + case DWC3_TRBSTS_SETUP_PENDING: + /* Control endpoint only */ + case DWC3_TRBSTS_OK: + default: + request_status = 0; + break; + } + } else { + request_status = status; + } + + dwc3_gadget_giveback(dep, req, request_status); +out: return ret; } static void dwc3_gadget_ep_cleanup_completed_requests(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event, - int status) + const struct dwc3_event_depevt *event, int status) { - struct dwc3_request *req; - struct dwc3_request *tmp; + struct dwc3_request *req; - list_for_each_entry_safe(req, tmp, &dep->started_list, list) { + while (!list_empty(&dep->started_list)) { int ret; + req = next_request(&dep->started_list); ret = dwc3_gadget_ep_cleanup_completed_request(dep, event, req, status); if (ret) break; + /* + * The endpoint is disabled, let the dwc3_remove_requests() + * handle the cleanup. + */ + if (!dep->endpoint.desc) + break; } } +static bool dwc3_gadget_ep_should_continue(struct dwc3_ep *dep) +{ + struct dwc3_request *req; + struct dwc3 *dwc = dep->dwc; + + if (!dep->endpoint.desc || !dwc->pullups_connected || + !dwc->connected) + return false; + + if (!list_empty(&dep->pending_list)) + return true; + + /* + * We only need to check the first entry of the started list. We can + * assume the completed requests are removed from the started list. + */ + req = next_request(&dep->started_list); + if (!req) + return false; + + return !dwc3_gadget_ep_request_completed(req); +} + static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { dep->frame_number = event->parameters; } -static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event) +static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep, + const struct dwc3_event_depevt *event, int status) { - struct dwc3 *dwc = dep->dwc; - unsigned status = 0; - bool stop = false; - - dwc3_gadget_endpoint_frame_from_event(dep, event); - - if (event->status & DEPEVT_STATUS_BUSERR) - status = -ECONNRESET; + struct dwc3 *dwc = dep->dwc; + bool no_started_trb = true; - if (event->status & DEPEVT_STATUS_MISSED_ISOC) { - status = -EXDEV; + dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); - if (list_empty(&dep->started_list)) - stop = true; - } + if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) + goto out; - dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); + if (!dep->endpoint.desc) + return no_started_trb; - if (stop) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + list_empty(&dep->started_list) && + (list_empty(&dep->pending_list) || status == -EXDEV)) dwc3_stop_active_transfer(dep, true, true); - dep->flags = DWC3_EP_ENABLED; - } + else if (dwc3_gadget_ep_should_continue(dep)) + if (__dwc3_gadget_kick_transfer(dep) == 0) + no_started_trb = false; +out: /* * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. * See dwc3_gadget_linksts_change_interrupt() for 1st half. */ - if (dwc->revision < DWC3_REVISION_183A) { - u32 reg; - int i; + if (DWC3_VER_IS_PRIOR(DWC3, 183A)) { + u32 reg; + int i; for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { dep = dwc->eps[i]; @@ -2331,7 +3215,7 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, continue; if (!list_empty(&dep->started_list)) - return; + return no_started_trb; } reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -2340,30 +3224,188 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, dwc->u1u2 = 0; } + + return no_started_trb; +} + +static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, + const struct dwc3_event_depevt *event) +{ + int status = 0; + + if (!dep->endpoint.desc) + return; + + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) + dwc3_gadget_endpoint_frame_from_event(dep, event); + + if (event->status & DEPEVT_STATUS_BUSERR) + status = -ECONNRESET; + + if (event->status & DEPEVT_STATUS_MISSED_ISOC) + status = -EXDEV; + + dwc3_gadget_endpoint_trbs_complete(dep, event, status); +} + +static void dwc3_gadget_endpoint_transfer_complete(struct dwc3_ep *dep, + const struct dwc3_event_depevt *event) +{ + int status = 0; + + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; + + if (event->status & DEPEVT_STATUS_BUSERR) + status = -ECONNRESET; + + if (dwc3_gadget_endpoint_trbs_complete(dep, event, status)) + dep->flags &= ~DWC3_EP_WAIT_TRANSFER_COMPLETE; } static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { dwc3_gadget_endpoint_frame_from_event(dep, event); + + /* + * The XferNotReady event is generated only once before the endpoint + * starts. It will be generated again when END_TRANSFER command is + * issued. For some controller versions, the XferNotReady event may be + * generated while the END_TRANSFER command is still in process. Ignore + * it and wait for the next XferNotReady event after the command is + * completed. + */ + if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) + return; + (void) __dwc3_gadget_start_isoc(dep); } +static void dwc3_gadget_endpoint_command_complete(struct dwc3_ep *dep, + const struct dwc3_event_depevt *event) +{ + u8 cmd = DEPEVT_PARAMETER_CMD(event->parameters); + + if (cmd != DWC3_DEPCMD_ENDTRANSFER) + return; + + /* + * The END_TRANSFER command will cause the controller to generate a + * NoStream Event, and it's not due to the host DP NoStream rejection. + * Ignore the next NoStream event. + */ + if (dep->stream_capable) + dep->flags |= DWC3_EP_IGNORE_NEXT_NOSTREAM; + + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; + dwc3_gadget_ep_cleanup_cancelled_requests(dep); + + if (dep->flags & DWC3_EP_PENDING_CLEAR_STALL) { + struct dwc3 *dwc = dep->dwc; + + dep->flags &= ~DWC3_EP_PENDING_CLEAR_STALL; + if (dwc3_send_clear_stall_ep_cmd(dep)) { + struct usb_ep *ep0 = &dwc->eps[0]->endpoint; + + dev_err(dwc->dev, "failed to clear STALL on %s\n", dep->name); + if (dwc->delayed_status) + __dwc3_gadget_ep0_set_halt(ep0, 1); + return; + } + + dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE); + if (dwc->clear_stall_protocol == dep->number) + dwc3_ep0_send_delayed_status(dwc); + } + + if ((dep->flags & DWC3_EP_DELAY_START) && + !usb_endpoint_xfer_isoc(dep->endpoint.desc)) + __dwc3_gadget_kick_transfer(dep); + + dep->flags &= ~DWC3_EP_DELAY_START; +} + +static void dwc3_gadget_endpoint_stream_event(struct dwc3_ep *dep, + const struct dwc3_event_depevt *event) +{ + struct dwc3 *dwc = dep->dwc; + + if (event->status == DEPEVT_STREAMEVT_FOUND) { + dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED; + goto out; + } + + /* Note: NoStream rejection event param value is 0 and not 0xFFFF */ + switch (event->parameters) { + case DEPEVT_STREAM_PRIME: + /* + * If the host can properly transition the endpoint state from + * idle to prime after a NoStream rejection, there's no need to + * force restarting the endpoint to reinitiate the stream. To + * simplify the check, assume the host follows the USB spec if + * it primed the endpoint more than once. + */ + if (dep->flags & DWC3_EP_FORCE_RESTART_STREAM) { + if (dep->flags & DWC3_EP_FIRST_STREAM_PRIMED) + dep->flags &= ~DWC3_EP_FORCE_RESTART_STREAM; + else + dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED; + } + + break; + case DEPEVT_STREAM_NOSTREAM: + if ((dep->flags & DWC3_EP_IGNORE_NEXT_NOSTREAM) || + !(dep->flags & DWC3_EP_FORCE_RESTART_STREAM) || + (!DWC3_MST_CAPABLE(&dwc->hwparams) && + !(dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE))) + break; + + /* + * If the host rejects a stream due to no active stream, by the + * USB and xHCI spec, the endpoint will be put back to idle + * state. When the host is ready (buffer added/updated), it will + * prime the endpoint to inform the usb device controller. This + * triggers the device controller to issue ERDY to restart the + * stream. However, some hosts don't follow this and keep the + * endpoint in the idle state. No prime will come despite host + * streams are updated, and the device controller will not be + * triggered to generate ERDY to move the next stream data. To + * workaround this and maintain compatibility with various + * hosts, force to reinitiate the stream until the host is ready + * instead of waiting for the host to prime the endpoint. + */ + if (DWC3_VER_IS_WITHIN(DWC32, 100A, ANY)) { + unsigned int cmd = DWC3_DGCMD_SET_ENDPOINT_PRIME; + + dwc3_send_gadget_generic_command(dwc, cmd, dep->number); + } else { + dep->flags |= DWC3_EP_DELAY_START; + dwc3_stop_active_transfer(dep, true, true); + return; + } + break; + } + +out: + dep->flags &= ~DWC3_EP_IGNORE_NEXT_NOSTREAM; +} + static void dwc3_endpoint_interrupt(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const struct dwc3_event_depevt *event) { - struct dwc3_ep *dep; - u8 epnum = event->endpoint_number; - u8 cmd; + struct dwc3_ep *dep; + u8 epnum = event->endpoint_number; dep = dwc->eps[epnum]; if (!(dep->flags & DWC3_EP_ENABLED)) { - if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) + if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* Handle only EPCMDCMPLT when EP disabled */ - if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) + if ((event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) && + !(epnum <= 1 && event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE)) return; } @@ -2380,15 +3422,14 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dwc3_gadget_endpoint_transfer_not_ready(dep, event); break; case DWC3_DEPEVT_EPCMDCMPLT: - cmd = DEPEVT_PARAMETER_CMD(event->parameters); - - if (cmd == DWC3_DEPCMD_ENDTRANSFER) { - dep->flags &= ~DWC3_EP_TRANSFER_STARTED; - dwc3_gadget_ep_cleanup_cancelled_requests(dep); - } + dwc3_gadget_endpoint_command_complete(dep, event); break; - case DWC3_DEPEVT_STREAMEVT: case DWC3_DEPEVT_XFERCOMPLETE: + dwc3_gadget_endpoint_transfer_complete(dep, event); + break; + case DWC3_DEPEVT_STREAMEVT: + dwc3_gadget_endpoint_stream_event(dep, event); + break; case DWC3_DEPEVT_RXTXFIFOEVT: break; } @@ -2396,27 +3437,27 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, static void dwc3_disconnect_gadget(struct dwc3 *dwc) { - if (dwc->gadget_driver && dwc->gadget_driver->disconnect) { + if (dwc->async_callbacks && dwc->gadget_driver->disconnect) { spin_unlock(&dwc->lock); - dwc->gadget_driver->disconnect(&dwc->gadget); + dwc->gadget_driver->disconnect(dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_suspend_gadget(struct dwc3 *dwc) { - if (dwc->gadget_driver && dwc->gadget_driver->suspend) { + if (dwc->async_callbacks && dwc->gadget_driver->suspend) { spin_unlock(&dwc->lock); - dwc->gadget_driver->suspend(&dwc->gadget); + dwc->gadget_driver->suspend(dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_resume_gadget(struct dwc3 *dwc) { - if (dwc->gadget_driver && dwc->gadget_driver->resume) { + if (dwc->async_callbacks && dwc->gadget_driver->resume) { spin_unlock(&dwc->lock); - dwc->gadget_driver->resume(&dwc->gadget); + dwc->gadget_driver->resume(dwc->gadget); spin_lock(&dwc->lock); } } @@ -2426,53 +3467,74 @@ static void dwc3_reset_gadget(struct dwc3 *dwc) if (!dwc->gadget_driver) return; - if (dwc->gadget.speed != USB_SPEED_UNKNOWN) { + if (dwc->async_callbacks && dwc->gadget->speed != USB_SPEED_UNKNOWN) { spin_unlock(&dwc->lock); - usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver); + usb_gadget_udc_reset(dwc->gadget, dwc->gadget_driver); spin_lock(&dwc->lock); } } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, - bool interrupt) +void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, + bool interrupt) { struct dwc3 *dwc = dep->dwc; - struct dwc3_gadget_ep_cmd_params params; - u32 cmd; - int ret; - if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) + /* + * Only issue End Transfer command to the control endpoint of a started + * Data Phase. Typically we should only do so in error cases such as + * invalid/unexpected direction as described in the control transfer + * flow of the programming guide. + */ + if (dep->number <= 1 && dwc->ep0state != EP0_DATA_PHASE) + return; + + if (interrupt && (dep->flags & DWC3_EP_DELAY_STOP)) + return; + + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED) || + (dep->flags & DWC3_EP_END_TRANSFER_PENDING)) return; /* + * If a Setup packet is received but yet to DMA out, the controller will + * not process the End Transfer command of any endpoint. Polling of its + * DEPCMD.CmdAct may block setting up TRB for Setup packet, causing a + * timeout. Delay issuing the End Transfer command until the Setup TRB is + * prepared. + */ + if (dwc->ep0state != EP0_SETUP_PHASE && !dwc->delayed_status) { + dep->flags |= DWC3_EP_DELAY_STOP; + return; + } + + /* * NOTICE: We are violating what the Databook says about the * EndTransfer command. Ideally we would _always_ wait for the * EndTransfer Command Completion IRQ, but that's causing too * much trouble synchronizing between us and gadget driver. * * We have discussed this with the IP Provider and it was - * suggested to giveback all requests here, but give HW some - * extra time to synchronize with the interconnect. We're using - * an arbitraty 100us delay for that. + * suggested to giveback all requests here. * * Note also that a similar handling was tested by Synopsys * (thanks a lot Paul) and nothing bad has come out of it. - * In short, what we're doing is: + * In short, what we're doing is issuing EndTransfer with + * CMDIOC bit set and delay kicking transfer until the + * EndTransfer command had completed. + * + * As of IP version 3.10a of the DWC_usb3 IP, the controller + * supports a mode to work around the above limitation. The + * software can poll the CMDACT bit in the DEPCMD register + * after issuing a EndTransfer command. This mode is enabled + * by writing GUCTL2[14]. This polling is already done in the + * dwc3_send_gadget_ep_cmd() function so if the mode is + * enabled, the EndTransfer command will have completed upon + * returning from this function. * - * - Issue EndTransfer WITH CMDIOC bit set - * - Wait 100us + * This mode is NOT available on the DWC_usb31 IP. */ - cmd = DWC3_DEPCMD_ENDTRANSFER; - cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; - cmd |= DWC3_DEPCMD_CMDIOC; - cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); - memset(¶ms, 0, sizeof(params)); - ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); - dep->resource_index = 0; - - if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) - udelay(100); + __dwc3_stop_active_transfer(dep, force, interrupt); } static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) @@ -2481,6 +3543,7 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) { struct dwc3_ep *dep; + int ret; dep = dwc->eps[epnum]; if (!dep) @@ -2491,35 +3554,54 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) dep->flags &= ~DWC3_EP_STALL; - dwc3_send_clear_stall_ep_cmd(dep); + ret = dwc3_send_clear_stall_ep_cmd(dep); + WARN_ON_ONCE(ret); } } static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) { - int reg; + int reg; + + dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET); reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_INITU1ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - reg &= ~DWC3_DCTL_INITU2ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); + + dwc->connected = false; dwc3_disconnect_gadget(dwc); - dwc->gadget.speed = USB_SPEED_UNKNOWN; + dwc->gadget->speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; - usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED); + usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); - dwc->connected = false; + if (dwc->ep0state != EP0_SETUP_PHASE) { + unsigned int dir; + + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + dwc3_ep0_stall_and_restart(dwc); + } } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { - u32 reg; + u32 reg; - dwc->connected = true; + /* + * Ideally, dwc3_reset_gadget() would trigger the function + * drivers to stop any active transfers through ep disable. + * However, for functions which defer ep disable, such as mass + * storage, we will need to rely on the call to stop active + * transfers here, and avoid allowing of request queuing. + */ + dwc->connected = false; /* * WORKAROUND: DWC3 revisions <1.88a have an issue which @@ -2547,16 +3629,45 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) * STAR#9000466709: RTL: Device : Disconnect event not * generated if setup packet pending in FIFO */ - if (dwc->revision < DWC3_REVISION_188A) { + if (DWC3_VER_IS_PRIOR(DWC3, 188A)) { if (dwc->setup_packet_pending) dwc3_gadget_disconnect_interrupt(dwc); } dwc3_reset_gadget(dwc); + /* + * From SNPS databook section 8.1.2, the EP0 should be in setup + * phase. So ensure that EP0 is in setup phase by issuing a stall + * and restart if EP0 is not in setup phase. + */ + if (dwc->ep0state != EP0_SETUP_PHASE) { + unsigned int dir; + + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + + dwc->eps[0]->trb_enqueue = 0; + dwc->eps[1]->trb_enqueue = 0; + + dwc3_ep0_stall_and_restart(dwc); + } + + /* + * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a + * Section 4.1.2 Table 4-2, it states that during a USB reset, the SW + * needs to ensure that it sends "a DEPENDXFER command for any active + * transfers." + */ + dwc3_stop_active_transfers(dwc); + dwc->connected = true; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); dwc->test_mode = false; dwc3_clear_stall_all_ep(dwc); @@ -2568,22 +3679,45 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) { - struct dwc3_ep *dep; - int ret; - u32 reg; - u8 speed; + struct dwc3_ep *dep; + int ret; + u32 reg; + u8 lanes = 1; + u8 speed; + + if (!dwc->softconnect) + return; reg = dwc3_readl(dwc->regs, DWC3_DSTS); speed = reg & DWC3_DSTS_CONNECTSPD; dwc->speed = speed; + if (DWC3_IP_IS(DWC32)) + lanes = DWC3_DSTS_CONNLANES(reg) + 1; + + dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN; + + /* + * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed + * each time on Connect Done. + * + * Currently we always use the reset value. If any platform + * wants to set this to a different value, we need to add a + * setting and update GCTL.RAMCLKSEL here. + */ + switch (speed) { case DWC3_DSTS_SUPERSPEED_PLUS: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); - dwc->gadget.ep0->maxpacket = 512; - dwc->gadget.speed = USB_SPEED_SUPER_PLUS; + dwc->gadget->ep0->maxpacket = 512; + dwc->gadget->speed = USB_SPEED_SUPER_PLUS; + + if (lanes > 1) + dwc->gadget->ssp_rate = USB_SSP_GEN_2x2; + else + dwc->gadget->ssp_rate = USB_SSP_GEN_2x1; break; - case DWC3_DCFG_SUPERSPEED: + case DWC3_DSTS_SUPERSPEED: /* * WORKAROUND: DWC3 revisions <1.90a have an issue which * would cause a missing USB3 Reset event. @@ -2597,36 +3731,36 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) * STAR#9000483510: RTL: SS : USB3 reset event may * not be generated always when the link enters poll */ - if (dwc->revision < DWC3_REVISION_190A) + if (DWC3_VER_IS_PRIOR(DWC3, 190A)) dwc3_gadget_reset_interrupt(dwc); dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); - dwc->gadget.ep0->maxpacket = 512; - dwc->gadget.speed = USB_SPEED_SUPER; + dwc->gadget->ep0->maxpacket = 512; + dwc->gadget->speed = USB_SPEED_SUPER; + + if (lanes > 1) { + dwc->gadget->speed = USB_SPEED_SUPER_PLUS; + dwc->gadget->ssp_rate = USB_SSP_GEN_1x2; + } break; - case DWC3_DCFG_HIGHSPEED: + case DWC3_DSTS_HIGHSPEED: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); - dwc->gadget.ep0->maxpacket = 64; - dwc->gadget.speed = USB_SPEED_HIGH; + dwc->gadget->ep0->maxpacket = 64; + dwc->gadget->speed = USB_SPEED_HIGH; break; - case DWC3_DCFG_FULLSPEED: - case DWC3_DCFG_FULLSPEED1: + case DWC3_DSTS_FULLSPEED: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); - dwc->gadget.ep0->maxpacket = 64; - dwc->gadget.speed = USB_SPEED_FULL; - break; - case DWC3_DCFG_LOWSPEED: - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8); - dwc->gadget.ep0->maxpacket = 8; - dwc->gadget.speed = USB_SPEED_LOW; + dwc->gadget->ep0->maxpacket = 64; + dwc->gadget->speed = USB_SPEED_FULL; break; } - dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket; + dwc->eps[1]->endpoint.maxpacket = dwc->gadget->ep0->maxpacket; /* Enable USB2 LPM Capability */ - if ((dwc->revision > DWC3_REVISION_194A) && + if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A) && + !dwc->usb2_gadget_lpm_disable && (speed != DWC3_DSTS_SUPERSPEED) && (speed != DWC3_DSTS_SUPERSPEED_PLUS)) { reg = dwc3_readl(dwc->regs, DWC3_DCFG); @@ -2636,7 +3770,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); - reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold); + reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold | + (dwc->is_utmi_l1_suspend << 4)); /* * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and @@ -2644,17 +3779,23 @@ 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(DWC3_VER_IS_PRIOR(DWC3, 240A) && dwc->has_lpm_erratum, + "LPM Erratum not available on dwc3 revisions < 2.40a\n"); - if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) - reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold); + if (dwc->has_lpm_erratum && !DWC3_VER_IS_PRIOR(DWC3, 240A)) + reg |= DWC3_DCTL_NYET_THRES(dwc->lpm_nyet_threshold); - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); } else { + if (dwc->usb2_gadget_lpm_disable) { + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg &= ~DWC3_DCFG_LPM_CAP; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + } + reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_HIRD_THRES_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); } dep = dwc->eps[0]; @@ -2687,15 +3828,18 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) * implemented. */ - if (dwc->gadget_driver && dwc->gadget_driver->resume) - dwc->gadget_driver->resume(&dwc->gadget); + if (dwc->async_callbacks && dwc->gadget_driver->resume) { + spin_unlock(&dwc->lock); + dwc->gadget_driver->resume(dwc->gadget); + spin_lock(&dwc->lock); + } } static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, - unsigned int evtinfo) + unsigned int evtinfo) { - enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; - unsigned int pwropt; + enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; + unsigned int pwropt; /* * WORKAROUND: DWC3 < 2.50a have an issue when configured without @@ -2715,11 +3859,10 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, * operational mode */ pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1); - if ((dwc->revision < DWC3_REVISION_250A) && - (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) { + if (DWC3_VER_IS_PRIOR(DWC3, 250A) && + (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) { if ((dwc->link_state == DWC3_LINK_STATE_U3) && - (next == DWC3_LINK_STATE_RESUME)) { - dev_dbg(dwc->dev, "ignoring transition U3 -> Resume\n"); + (next == DWC3_LINK_STATE_RESUME)) { return; } } @@ -2742,10 +3885,10 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us * core send LGO_Ux entering U0 */ - if (dwc->revision < DWC3_REVISION_183A) { + if (DWC3_VER_IS_PRIOR(DWC3, 183A)) { if (next == DWC3_LINK_STATE_U0) { - u32 u1u2; - u32 reg; + u32 u1u2; + u32 reg; switch (dwc->link_state) { case DWC3_LINK_STATE_U1: @@ -2761,7 +3904,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, reg &= ~u1u2; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + dwc3_gadget_dctl_write_safe(dwc, reg); break; default: /* do nothing */ @@ -2777,7 +3920,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, break; case DWC3_LINK_STATE_U2: case DWC3_LINK_STATE_U3: - //dwc3_suspend_gadget(dwc); + dwc3_suspend_gadget(dwc); break; case DWC3_LINK_STATE_RESUME: dwc3_resume_gadget(dwc); @@ -2802,12 +3945,12 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, } static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, - unsigned int evtinfo) + 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 + /* + * WORKAROUND: DWC3 revision 2.20a with hibernation support * have a known issue which can cause USB CV TD.9.23 to fail * randomly. * @@ -2826,9 +3969,8 @@ static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, } static void dwc3_gadget_interrupt(struct dwc3 *dwc, - const struct dwc3_event_devt *event) + const struct dwc3_event_devt *event) { - switch (event->type) { case DWC3_DEVICE_EVENT_DISCONNECT: dwc3_gadget_disconnect_interrupt(dwc); @@ -2843,96 +3985,154 @@ 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: dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); break; - case DWC3_DEVICE_EVENT_EOPF: - dev_dbg(dwc->dev, "End of Periodic Frame\n"); + case DWC3_DEVICE_EVENT_SUSPEND: /* It changed to be suspend event for version 2.30a and above */ - if (dwc->revision >= DWC3_REVISION_230A) { + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) { /* * Ignore suspend event until the gadget enters into * USB_STATE_CONFIGURED state. */ - if (dwc->gadget.state >= USB_STATE_CONFIGURED) + if (dwc->gadget->state >= USB_STATE_CONFIGURED) dwc3_gadget_suspend_interrupt(dwc, event->event_info); } break; case DWC3_DEVICE_EVENT_SOF: - dev_dbg(dwc->dev, "Start of Periodic Frame\n"); - break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - dev_dbg(dwc->dev, "Erratic Error\n"); - break; case DWC3_DEVICE_EVENT_CMD_CMPL: - dev_dbg(dwc->dev, "Command Complete\n"); - break; case DWC3_DEVICE_EVENT_OVERFLOW: - dev_dbg(dwc->dev, "Overflow\n"); break; default: - dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type); + dev_warn(dwc->dev, "UNKNOWN IRQ %d\n", event->type); } } static void dwc3_process_event_entry(struct dwc3 *dwc, - const union dwc3_event *event) + const union dwc3_event *event) { if (!event->type.is_devspec) dwc3_endpoint_interrupt(dwc, &event->depevt); else if (event->type.type == DWC3_EVENT_TYPE_DEV) dwc3_gadget_interrupt(dwc, &event->devt); + else + dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw); } -static void dwc3_gadget_poll(struct usb_gadget * g) +static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) { - struct dwc3 *dwc = gadget_to_dwc(g); - struct dwc3_event_buffer *evt = dwc->ev_buf; + struct dwc3 *dwc = evt->dwc; + irqreturn_t ret = IRQ_NONE; + int left; + + left = evt->count; + + if (!(evt->flags & DWC3_EVENT_PENDING)) + return IRQ_NONE; + + while (left > 0) { + union dwc3_event event; + + event.raw = *(u32 *) (evt->cache + evt->lpos); + + dwc3_process_event_entry(dwc, &event); + + /* + * FIXME we wrap around correctly to the next entry as + * almost all entries are 4 bytes in size. There is one + * entry which has 12 bytes which is a regular entry + * followed by 8 bytes data. ATM I don't know how + * things are organized if we get next to the a + * boundary so I worry about that once we try to handle + * that. + */ + evt->lpos = (evt->lpos + 4) % evt->length; + left -= 4; + } + + evt->count = 0; + ret = IRQ_HANDLED; + + /* Unmask interrupt */ + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_SIZE(evt->length)); + + if (dwc->imod_interval) { + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); + } + + /* Keep the clearing of DWC3_EVENT_PENDING at the end */ + evt->flags &= ~DWC3_EVENT_PENDING; + + return ret; +} + +static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) +{ + struct dwc3 *dwc = evt->dwc; u32 amount; u32 count; - void *buf; - int pos = 0; + + /* + * With PCIe legacy interrupt, test shows that top-half irq handler can + * be called again after HW interrupt deassertion. Check if bottom-half + * irq event handler completes before caching new event to prevent + * losing events. + */ + if (evt->flags & DWC3_EVENT_PENDING) + return IRQ_HANDLED; count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); count &= DWC3_GEVNTCOUNT_MASK; if (!count) - return; + return IRQ_NONE; - buf = xzalloc(count); + evt->count = count; + evt->flags |= DWC3_EVENT_PENDING; + + /* Mask interrupt */ + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(evt->length)); amount = min(count, evt->length - evt->lpos); - memcpy_fromio(buf, evt->buf + evt->lpos, amount); + memcpy_fromio(evt->cache + evt->lpos, evt->buf + evt->lpos, amount); if (amount < count) - memcpy_fromio(buf + amount, evt->buf, count - amount); - - evt->lpos = (evt->lpos + count) % evt->length; + memcpy_fromio(evt->cache, evt->buf, count - amount); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); - while (count > 0) { - union dwc3_event event; + dwc3_process_event_buf(evt); - event.raw = *(u32 *)(buf + pos); + return IRQ_HANDLED; +} - dwc3_process_event_entry(dwc, &event); +static void dwc3_gadget_poll(struct usb_gadget *g) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + struct dwc3_event_buffer *evt = dwc->ev_buf; - count -= 4; - pos += 4; - } + dwc3_check_event_buf(evt); +} + +static void dwc_gadget_release(struct device *dev) +{ + struct usb_gadget *gadget = container_of(dev, struct usb_gadget, dev); - free(buf); + kfree(gadget); } /** - * dwc3_gadget_init - Initializes gadget related registers + * dwc3_gadget_init - initializes gadget related registers * @dwc: pointer to our controller context structure * * Returns 0 on success otherwise negative errno. @@ -2940,46 +4140,69 @@ static void dwc3_gadget_poll(struct usb_gadget * g) int dwc3_gadget_init(struct dwc3 *dwc) { int ret; + struct device *dev; dwc->ep0_trb = dma_alloc_coherent(sizeof(*dwc->ep0_trb) * 2, - &dwc->ep0_trb_addr); + &dwc->ep0_trb_addr); if (!dwc->ep0_trb) { dev_err(dwc->dev, "failed to allocate ep0 trb\n"); ret = -ENOMEM; - goto err1; + goto err0; } - dwc->setup_buf = xzalloc(DWC3_EP0_SETUP_SIZE); + dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL); if (!dwc->setup_buf) { ret = -ENOMEM; - goto err2; + goto err1; } - dwc->bounce = dma_alloc_coherent(DWC3_BOUNCE_SIZE, - &dwc->bounce_addr); + dwc->bounce = dma_alloc_coherent(DWC3_BOUNCE_SIZE, &dwc->bounce_addr); if (!dwc->bounce) { - dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n"); + ret = -ENOMEM; + goto err2; + } + + init_completion(&dwc->ep0_in_setup); + dwc->gadget = kzalloc(sizeof(struct usb_gadget), GFP_KERNEL); + if (!dwc->gadget) { ret = -ENOMEM; goto err3; } - dwc->gadget.ops = &dwc3_gadget_ops; - dwc->gadget.max_speed = USB_SPEED_SUPER; - dwc->gadget.speed = USB_SPEED_UNKNOWN; - dwc->gadget.name = "dwc3-gadget"; + + usb_initialize_gadget(dwc->dev, dwc->gadget, dwc_gadget_release); + dev = &dwc->gadget->dev; + dev->platform_data = dwc; + dwc->gadget->ops = &dwc3_gadget_ops; + dwc->gadget->speed = USB_SPEED_UNKNOWN; + dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN; + dwc->gadget->sg_supported = true; + dwc->gadget->name = "dwc3-gadget"; + dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable; /* - * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize - * on ep out. + * FIXME We might be setting max_speed to <SUPER, however versions + * <2.20a of dwc3 have an issue with metastability (documented + * elsewhere in this driver) which tells us we can't set max speed to + * anything lower than SUPER. + * + * Because gadget.max_speed is only used by composite.c and function + * drivers (i.e. it won't go into dwc3's registers) we are allowing this + * to happen so we avoid sending SuperSpeed Capability descriptor + * together with our BOS descriptor as that could confuse host into + * thinking we can handle super speed. + * + * Note that, in fact, we won't even support GetBOS requests when speed + * is less than super speed because we don't have means, yet, to tell + * composite.c that we are USB 2.0 + LPM ECN. */ - dwc->gadget.quirk_ep_out_aligned_size = true; - - if (dwc->revision < DWC3_REVISION_220A && + if (DWC3_VER_IS_PRIOR(DWC3, 220A) && !dwc->dis_metastability_quirk) dev_info(dwc->dev, "changing max_speed on rev %08x\n", dwc->revision); - dwc->gadget.max_speed = dwc->maximum_speed; + dwc->gadget->max_speed = dwc->maximum_speed; + dwc->gadget->max_ssp_rate = dwc->max_ssp_rate; /* * REVISIT: Here we should clear all pending IRQs to be @@ -2990,26 +4213,47 @@ 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(dwc->gadget); if (ret) { - dev_err(dwc->dev, "failed to register udc\n"); - goto err4; + dev_err(dwc->dev, "failed to add gadget\n"); + goto err5; } - dwc3_gadget_set_speed(dwc, dwc->maximum_speed); + if (DWC3_IP_IS(DWC32) && dwc->maximum_speed == USB_SPEED_SUPER_PLUS) + dwc3_gadget_set_ssp_rate(dwc->gadget, dwc->max_ssp_rate); + else + dwc3_gadget_set_speed(dwc->gadget, dwc->maximum_speed); return 0; -err4: +err5: dwc3_gadget_free_endpoints(dwc); +err4: + usb_put_gadget(dwc->gadget); + dwc->gadget = NULL; err3: - dma_free_coherent(dwc->bounce, 0, DWC3_BOUNCE_SIZE); + dma_free_coherent(dwc->bounce, dwc->bounce_addr, DWC3_BOUNCE_SIZE); err2: kfree(dwc->setup_buf); err1: - dma_free_coherent(dwc->ep0_trb, 0, sizeof(*dwc->ep0_trb) * 2); + dma_free_coherent(dwc->ep0_trb, dwc->ep0_trb_addr, sizeof(*dwc->ep0_trb) * 2); +err0: return ret; } + +/* -------------------------------------------------------------------------- */ + +void dwc3_gadget_exit(struct dwc3 *dwc) +{ + if (!dwc->gadget) + return; + + usb_del_gadget_udc(dwc->gadget); + dwc3_gadget_free_endpoints(dwc); + dma_free_coherent(dwc->bounce, dwc->bounce_addr, DWC3_BOUNCE_SIZE); + kfree(dwc->setup_buf); + dma_free_coherent(dwc->ep0_trb, dwc->ep0_trb_addr, sizeof(*dwc->ep0_trb) * 2); +} diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 47c2d5b955..0afa10b318 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -1,70 +1,75 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* SPDX-License-Identifier: GPL-2.0 */ +/* * gadget.h - DesignWare USB3 DRD Gadget Header * - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://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 - * */ #ifndef __DRIVERS_USB_DWC3_GADGET_H #define __DRIVERS_USB_DWC3_GADGET_H -#include <usb/gadget.h> +#include <linux/usb/gadget.h> #include <linux/list.h> #include "io.h" struct dwc3; #define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint)) -#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget)) +#define gadget_to_dwc(g) (g->dev.platform_data) /* DEPCFG parameter 1 */ -#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0) -#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8) -#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9) -#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10) -#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11) -#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13) -#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16) -#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24) -#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25) -#define DWC3_DEPCFG_BULK_BASED (1 << 30) -#define DWC3_DEPCFG_FIFO_BASED (1 << 31) +#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0) +#define DWC3_DEPCFG_XFER_COMPLETE_EN BIT(8) +#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9) +#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10) +#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11) +#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(13) +#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16) +#define DWC3_DEPCFG_STREAM_CAPABLE BIT(24) +#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25) +#define DWC3_DEPCFG_BULK_BASED BIT(30) +#define DWC3_DEPCFG_FIFO_BASED BIT(31) /* DEPCFG parameter 0 */ -#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1) -#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3) -#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17) -#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22) +#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1) +#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) (((n) & 0x7ff) << 3) +#define DWC3_DEPCFG_FIFO_NUMBER(n) (((n) & 0x1f) << 17) +#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22) #define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26) /* This applies for core versions earlier than 1.94a */ -#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31) +#define DWC3_DEPCFG_IGN_SEQ_NUM BIT(31) /* These apply for core versions 1.94a and later */ -#define DWC3_DEPCFG_ACTION_INIT (0 << 30) -#define DWC3_DEPCFG_ACTION_RESTORE (1 << 30) +#define DWC3_DEPCFG_ACTION_INIT (0 << 30) +#define DWC3_DEPCFG_ACTION_RESTORE BIT(30) #define DWC3_DEPCFG_ACTION_MODIFY (2 << 30) /* DEPXFERCFG parameter 0 */ #define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff) +/* U1 Device exit Latency */ +#define DWC3_DEFAULT_U1_DEV_EXIT_LAT 0x0A /* Less then 10 microsec */ + +/* U2 Device exit Latency */ +#define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */ + +/* Frame/Microframe Number Mask */ +#define DWC3_FRNUMBER_MASK 0x3fff /* -------------------------------------------------------------------------- */ #define to_dwc3_request(r) (container_of(r, struct dwc3_request, request)) +/** + * next_request - gets the next request on the given list + * @list: the request list to operate on + * + * Caller should take care of locking. This function return %NULL or the first + * request available on @list. + */ static inline struct dwc3_request *next_request(struct list_head *list) { - if (list_empty(list)) - return NULL; - - return list_first_entry(list, struct dwc3_request, list); + return list_first_entry_or_null(list, struct dwc3_request, list); } /** @@ -76,7 +81,7 @@ static inline struct dwc3_request *next_request(struct list_head *list) */ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) { - struct dwc3_ep *dep = req->dep; + struct dwc3_ep *dep = req->dep; req->status = DWC3_REQUEST_STATUS_STARTED; list_move_tail(&req->list, &dep->started_list); @@ -85,15 +90,17 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) /** * dwc3_gadget_move_cancelled_request - move @req to the cancelled_list * @req: the request to be moved + * @reason: cancelled reason for the dwc3 request * * Caller should take care of locking. This function will move @req from its * current list to the endpoint's cancelled_list. */ -static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req) +static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req, + unsigned int reason) { - struct dwc3_ep *dep = req->dep; + struct dwc3_ep *dep = req->dep; - req->status = DWC3_REQUEST_STATUS_CANCELLED; + req->status = reason; list_move_tail(&req->list, &dep->cancelled_list); } @@ -103,11 +110,14 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); void dwc3_ep0_out_start(struct dwc3 *dwc); +void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep); +void dwc3_ep0_stall_and_restart(struct dwc3 *dwc); int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); 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); int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); -void dwc3_gadget_handle_interrupt(struct dwc3 *dwc); +void dwc3_ep0_send_delayed_status(struct dwc3 *dwc); +void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt); /** * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW @@ -118,10 +128,24 @@ void dwc3_gadget_handle_interrupt(struct dwc3 *dwc); */ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep) { - u32 res_id; + u32 res_id; res_id = dwc3_readl(dep->regs, DWC3_DEPCMD); dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id); } +/** + * dwc3_gadget_dctl_write_safe - write to DCTL safe from link state change + * @dwc: pointer to our context structure + * @value: value to write to DCTL + * + * Use this function when doing read-modify-write to DCTL. It will not + * send link state change request. + */ +static inline void dwc3_gadget_dctl_write_safe(struct dwc3 *dwc, u32 value) +{ + value &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; + dwc3_writel(dwc->regs, DWC3_DCTL, value); +} + #endif /* __DRIVERS_USB_DWC3_GADGET_H */ diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 09ed01fc56..281d016a86 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -34,3 +34,7 @@ int dwc3_host_init(struct dwc3 *dwc) return 0; } + +void dwc3_host_exit(struct dwc3 *dwc) +{ +} diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 96c51768f6..ffaf355936 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -2,6 +2,7 @@ menuconfig USB_GADGET select USB select POLLER + select NLS bool "USB gadget support" config USB_GADGET_DRIVER_ARC_PBL diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 36d71f9b8e..f45b23f22d 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -1,11 +1,5 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_USB_GADGET) += composite.o config.o usbstring.o epautoconf.o udc-core.o functions.o config.o multi.o -obj-$(CONFIG_USB_GADGET_SERIAL) += u_serial.o serial.o f_serial.o f_acm.o -obj-$(CONFIG_USB_GADGET_DFU) += dfu.o -obj-$(CONFIG_USB_GADGET_FASTBOOT) += f_fastboot.o -obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o storage_common.o -obj-$(CONFIG_USB_GADGET_DRIVER_ARC) += fsl_udc.o -pbl-$(CONFIG_USB_GADGET_DRIVER_ARC_PBL) += fsl_udc_pbl.o -obj-$(CONFIG_USB_GADGET_DRIVER_AT91) += at91_udc.o -obj-$(CONFIG_USB_GADGET_DRIVER_PXA27X) += pxa27x_udc.o +obj-$(CONFIG_USB_GADGET) += composite.o config.o usbstring.o epautoconf.o functions.o config.o + +obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 396e7387a8..58c10f1191 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0+ /* * composite.c - infrastructure for Composite USB Gadgets * @@ -12,11 +12,31 @@ #include <dma.h> #include <linux/err.h> #include <linux/bitmap.h> -#include <usb/composite.h> +#include <linux/usb/composite.h> +#include <linux/bitfield.h> +#include <linux/uuid.h> #include <asm/unaligned.h> #include <asm/byteorder.h> -static unsigned int usb_gadget_vbus_draw_ma = 2; +#include "u_os_desc.h" + +#define CONFIG_USB_GADGET_VBUS_DRAW 2 /* FIXME */ + +/** + * struct usb_os_string - represents OS String to be reported by a gadget + * @bLength: total length of the entire descritor, always 0x12 + * @bDescriptorType: USB_DT_STRING + * @qwSignature: the OS String proper + * @bMS_VendorCode: code used by the host for subsequent requests + * @bPad: not used, must be zero + */ +struct usb_os_string { + __u8 bLength; + __u8 bDescriptorType; + __u8 qwSignature[OS_STRING_QW_SIGN_LEN]; + __u8 bMS_VendorCode; + __u8 bPad; +} __packed; /* * The code in this file is utility code, used to build a gadget driver @@ -32,40 +52,89 @@ static struct usb_gadget_strings **get_containers_gs( } /** - * next_ep_desc() - advance to the next EP descriptor + * function_descriptors() - get function descriptors for speed + * @f: the function + * @speed: the speed + * + * Returns the descriptors or NULL if not set. + */ +static struct usb_descriptor_header ** +function_descriptors(struct usb_function *f, + enum usb_device_speed speed) +{ + struct usb_descriptor_header **descriptors; + + /* + * NOTE: we try to help gadget drivers which might not be setting + * max_speed appropriately. + */ + + switch (speed) { + case USB_SPEED_SUPER_PLUS: + descriptors = f->ssp_descriptors; + if (descriptors) + break; + fallthrough; + case USB_SPEED_SUPER: + descriptors = f->ss_descriptors; + if (descriptors) + break; + fallthrough; + case USB_SPEED_HIGH: + descriptors = f->hs_descriptors; + if (descriptors) + break; + fallthrough; + default: + descriptors = f->fs_descriptors; + } + + /* + * if we can't find any descriptors at all, then this gadget deserves to + * Oops with a NULL pointer dereference + */ + + return descriptors; +} + +/** + * next_desc() - advance to the next desc_type descriptor * @t: currect pointer within descriptor array + * @desc_type: descriptor type * - * Return: next EP descriptor or NULL + * Return: next desc_type descriptor or NULL * - * Iterate over @t until either EP descriptor found or + * Iterate over @t until either desc_type descriptor found or * NULL (that indicates end of list) encountered */ static struct usb_descriptor_header** -next_ep_desc(struct usb_descriptor_header **t) +next_desc(struct usb_descriptor_header **t, u8 desc_type) { for (; *t; t++) { - if ((*t)->bDescriptorType == USB_DT_ENDPOINT) + if ((*t)->bDescriptorType == desc_type) return t; } return NULL; } /* - * for_each_ep_desc()- iterate over endpoint descriptors in the - * descriptors list - * @start: pointer within descriptor array. - * @ep_desc: endpoint descriptor to use as the loop cursor + * for_each_desc() - iterate over desc_type descriptors in the + * descriptors list + * @start: pointer within descriptor array. + * @iter_desc: desc_type descriptor to use as the loop cursor + * @desc_type: wanted descriptr type */ -#define for_each_ep_desc(start, ep_desc) \ - for (ep_desc = next_ep_desc(start); \ - ep_desc; ep_desc = next_ep_desc(ep_desc+1)) +#define for_each_desc(start, iter_desc, desc_type) \ + for (iter_desc = next_desc(start, desc_type); \ + iter_desc; iter_desc = next_desc(iter_desc + 1, desc_type)) /** - * config_ep_by_speed() - configures the given endpoint + * config_ep_by_speed_and_alt() - configures the given endpoint * according to gadget speed. * @g: pointer to the gadget * @f: usb function * @_ep: the endpoint to configure + * @alt: alternate setting number * * Return: error code, 0 on success * @@ -78,44 +147,80 @@ next_ep_desc(struct usb_descriptor_header **t) * Note: the supplied function should hold all the descriptors * for supported speeds */ -int config_ep_by_speed(struct usb_gadget *g, - struct usb_function *f, - struct usb_ep *_ep) +int config_ep_by_speed_and_alt(struct usb_gadget *g, + struct usb_function *f, + struct usb_ep *_ep, + u8 alt) { - struct usb_composite_dev *cdev; struct usb_endpoint_descriptor *chosen_desc = NULL; + struct usb_interface_descriptor *int_desc = NULL; struct usb_descriptor_header **speed_desc = NULL; struct usb_ss_ep_comp_descriptor *comp_desc = NULL; int want_comp_desc = 0; struct usb_descriptor_header **d_spd; /* cursor for speed desc */ + struct usb_composite_dev *cdev; + bool incomplete_desc = false; if (!g || !f || !_ep) return -EIO; - cdev = get_gadget_data(g); - /* select desired speed */ switch (g->speed) { + case USB_SPEED_SUPER_PLUS: + if (gadget_is_superspeed_plus(g)) { + if (f->ssp_descriptors) { + speed_desc = f->ssp_descriptors; + want_comp_desc = 1; + break; + } + incomplete_desc = true; + } + fallthrough; case USB_SPEED_SUPER: if (gadget_is_superspeed(g)) { - speed_desc = f->ss_descriptors; - want_comp_desc = 1; - break; + if (f->ss_descriptors) { + speed_desc = f->ss_descriptors; + want_comp_desc = 1; + break; + } + incomplete_desc = true; } - /* else: Fall trough */ + fallthrough; case USB_SPEED_HIGH: if (gadget_is_dualspeed(g)) { - speed_desc = f->hs_descriptors; - break; + if (f->hs_descriptors) { + speed_desc = f->hs_descriptors; + break; + } + incomplete_desc = true; } - /* else: fall through */ + fallthrough; default: speed_desc = f->fs_descriptors; } + + cdev = get_gadget_data(g); + if (incomplete_desc) + WARNING(cdev, + "%s doesn't hold the descriptors for current speed\n", + f->name); + + /* find correct alternate setting descriptor */ + for_each_desc(speed_desc, d_spd, USB_DT_INTERFACE) { + int_desc = (struct usb_interface_descriptor *)*d_spd; + + if (int_desc->bAlternateSetting == alt) { + speed_desc = d_spd; + goto intf_found; + } + } + return -EIO; + +intf_found: /* find descriptors */ - for_each_ep_desc(speed_desc, d_spd) { + for_each_desc(speed_desc, d_spd, USB_DT_ENDPOINT) { chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; if (chosen_desc->bEndpointAddress == _ep->address) goto ep_found; @@ -128,7 +233,12 @@ ep_found: _ep->desc = chosen_desc; _ep->comp_desc = NULL; _ep->maxburst = 0; - _ep->mult = 0; + _ep->mult = 1; + + if (g->speed == USB_SPEED_HIGH && (usb_endpoint_xfer_isoc(_ep->desc) || + usb_endpoint_xfer_int(_ep->desc))) + _ep->mult = usb_endpoint_maxp_mult(_ep->desc); + if (!want_comp_desc) return 0; @@ -141,11 +251,12 @@ ep_found: (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP)) return -EIO; _ep->comp_desc = comp_desc; - if (g->speed == USB_SPEED_SUPER) { + if (g->speed >= USB_SPEED_SUPER) { switch (usb_endpoint_type(_ep->desc)) { case USB_ENDPOINT_XFER_ISOC: /* mult: bits 1:0 of bmAttributes */ - _ep->mult = comp_desc->bmAttributes & 0x3; + _ep->mult = (comp_desc->bmAttributes & 0x3) + 1; + fallthrough; case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_INT: _ep->maxburst = comp_desc->bMaxBurst + 1; @@ -159,6 +270,32 @@ ep_found: } return 0; } +EXPORT_SYMBOL_GPL(config_ep_by_speed_and_alt); + +/** + * config_ep_by_speed() - configures the given endpoint + * according to gadget speed. + * @g: pointer to the gadget + * @f: usb function + * @_ep: the endpoint to configure + * + * Return: error code, 0 on success + * + * This function chooses the right descriptors for a given + * endpoint according to gadget speed and saves it in the + * endpoint desc field. If the endpoint already has a descriptor + * assigned to it - overwrites it with currently corresponding + * descriptor. The endpoint maxpacket field is updated according + * to the chosen descriptor. + * Note: the supplied function should hold all the descriptors + * for supported speeds + */ +int config_ep_by_speed(struct usb_gadget *g, + struct usb_function *f, + struct usb_ep *_ep) +{ + return config_ep_by_speed_and_alt(g, f, _ep, 0); +} EXPORT_SYMBOL_GPL(config_ep_by_speed); /** @@ -190,6 +327,12 @@ int usb_add_function(struct usb_configuration *config, function->config = config; list_add_tail(&function->list, &config->functions); + if (function->bind_deactivated) { + value = usb_function_deactivate(function); + if (value) + goto done; + } + /* REVISIT *require* function->bind? */ if (function->bind) { value = function->bind(config, function); @@ -211,6 +354,8 @@ int usb_add_function(struct usb_configuration *config, config->highspeed = true; if (!config->superspeed && function->ss_descriptors) config->superspeed = true; + if (!config->superspeed_plus && function->ssp_descriptors) + config->superspeed_plus = true; done: if (value) @@ -229,6 +374,9 @@ void usb_remove_function(struct usb_configuration *c, struct usb_function *f) list_del(&f->list); if (f->unbind) f->unbind(c, f); + + if (f->bind_deactivated) + usb_function_activate(f); } EXPORT_SYMBOL_GPL(usb_remove_function); @@ -254,13 +402,20 @@ EXPORT_SYMBOL_GPL(usb_remove_function); int usb_function_deactivate(struct usb_function *function) { struct usb_composite_dev *cdev = function->config->cdev; + unsigned long flags; int status = 0; - if (cdev->deactivations == 0) - status = usb_gadget_disconnect(cdev->gadget); + spin_lock_irqsave(&cdev->lock, flags); + + if (cdev->deactivations == 0) { + spin_unlock_irqrestore(&cdev->lock, flags); + status = usb_gadget_deactivate(cdev->gadget); + spin_lock_irqsave(&cdev->lock, flags); + } if (status == 0) cdev->deactivations++; + spin_unlock_irqrestore(&cdev->lock, flags); return status; } EXPORT_SYMBOL_GPL(usb_function_deactivate); @@ -278,16 +433,23 @@ EXPORT_SYMBOL_GPL(usb_function_deactivate); int usb_function_activate(struct usb_function *function) { struct usb_composite_dev *cdev = function->config->cdev; + unsigned long flags; int status = 0; + spin_lock_irqsave(&cdev->lock, flags); + if (WARN_ON(cdev->deactivations == 0)) status = -EINVAL; else { cdev->deactivations--; - if (cdev->deactivations == 0) - status = usb_gadget_connect(cdev->gadget); + if (cdev->deactivations == 0) { + spin_unlock_irqrestore(&cdev->lock, flags); + status = usb_gadget_activate(cdev->gadget); + spin_lock_irqsave(&cdev->lock, flags); + } } + spin_unlock_irqrestore(&cdev->lock, flags); return status; } EXPORT_SYMBOL_GPL(usb_function_activate); @@ -334,18 +496,20 @@ static u8 encode_bMaxPower(enum usb_device_speed speed, { unsigned val; - if (c->MaxPower) + if (c->MaxPower || (c->bmAttributes & USB_CONFIG_ATT_SELFPOWER)) val = c->MaxPower; else - val = usb_gadget_vbus_draw_ma; + val = CONFIG_USB_GADGET_VBUS_DRAW; if (!val) return 0; - switch (speed) { - case USB_SPEED_SUPER: - return DIV_ROUND_UP(val, 8); - default: - return DIV_ROUND_UP(val, 2); - } + if (speed < USB_SPEED_SUPER) + return min(val, 500U) / 2; + else + /* + * USB 3.x supports up to 900mA, but since 900 isn't divisible + * by 8 the integral division will effectively cap to 896mA. + */ + return min(val, 900U) / 8; } static int config_buf(struct usb_configuration *config, @@ -383,17 +547,7 @@ static int config_buf(struct usb_configuration *config, list_for_each_entry(f, &config->functions, list) { struct usb_descriptor_header **descriptors; - switch (speed) { - case USB_SPEED_SUPER: - descriptors = f->ss_descriptors; - break; - case USB_SPEED_HIGH: - descriptors = f->hs_descriptors; - break; - default: - descriptors = f->fs_descriptors; - } - + descriptors = function_descriptors(f, speed); if (!descriptors) continue; status = usb_descriptor_fillbuf(next, len, @@ -413,10 +567,11 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) { struct usb_gadget *gadget = cdev->gadget; struct usb_configuration *c; + struct list_head *pos; u8 type = w_value >> 8; enum usb_device_speed speed = USB_SPEED_UNKNOWN; - if (gadget->speed == USB_SPEED_SUPER) + if (gadget->speed >= USB_SPEED_SUPER) speed = gadget->speed; else if (gadget_is_dualspeed(gadget)) { int hs = 0; @@ -431,9 +586,26 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) /* This is a lookup by config *INDEX* */ w_value &= 0xff; - list_for_each_entry(c, &cdev->configs, list) { + + pos = &cdev->configs; + c = cdev->os_desc_config; + if (c) + goto check_config; + + while ((pos = pos->next) != &cdev->configs) { + c = list_entry(pos, typeof(*c), list); + + /* skip OS Descriptors config which is handled separately */ + if (c == cdev->os_desc_config) + continue; + +check_config: /* ignore configs that won't work at this speed */ switch (speed) { + case USB_SPEED_SUPER_PLUS: + if (!c->superspeed_plus) + continue; + break; case USB_SPEED_SUPER: if (!c->superspeed) continue; @@ -461,18 +633,24 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) unsigned count = 0; int hs = 0; int ss = 0; + int ssp = 0; if (gadget_is_dualspeed(gadget)) { if (gadget->speed == USB_SPEED_HIGH) hs = 1; if (gadget->speed == USB_SPEED_SUPER) ss = 1; + if (gadget->speed == USB_SPEED_SUPER_PLUS) + ssp = 1; if (type == USB_DT_DEVICE_QUALIFIER) hs = !hs; } list_for_each_entry(c, &cdev->configs, list) { /* ignore configs that won't work at this speed */ - if (ss) { + if (ssp) { + if (!c->superspeed_plus) + continue; + } else if (ss) { if (!c->superspeed) continue; } else if (hs) { @@ -499,9 +677,9 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type) static int bos_desc(struct usb_composite_dev *cdev) { struct usb_ext_cap_descriptor *usb_ext; - struct usb_ss_cap_descriptor *ss_cap; struct usb_dcd_config_params dcd_config_params; struct usb_bos_descriptor *bos = cdev->req->buf; + unsigned int besl = 0; bos->bLength = USB_DT_BOS_SIZE; bos->bDescriptorType = USB_DT_BOS; @@ -509,45 +687,173 @@ static int bos_desc(struct usb_composite_dev *cdev) bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); bos->bNumDeviceCaps = 0; + /* Get Controller configuration */ + if (cdev->gadget->ops->get_config_params) { + cdev->gadget->ops->get_config_params(cdev->gadget, + &dcd_config_params); + } else { + dcd_config_params.besl_baseline = + USB_DEFAULT_BESL_UNSPECIFIED; + dcd_config_params.besl_deep = + USB_DEFAULT_BESL_UNSPECIFIED; + dcd_config_params.bU1devExitLat = + USB_DEFAULT_U1_DEV_EXIT_LAT; + dcd_config_params.bU2DevExitLat = + cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); + } + + if (dcd_config_params.besl_baseline != USB_DEFAULT_BESL_UNSPECIFIED) + besl = USB_BESL_BASELINE_VALID | + USB_SET_BESL_BASELINE(dcd_config_params.besl_baseline); + + if (dcd_config_params.besl_deep != USB_DEFAULT_BESL_UNSPECIFIED) + besl |= USB_BESL_DEEP_VALID | + USB_SET_BESL_DEEP(dcd_config_params.besl_deep); + /* * A SuperSpeed device shall include the USB2.0 extension descriptor * and shall support LPM when operating in USB2.0 HS mode. */ - usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); - bos->bNumDeviceCaps++; - le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); - usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; - usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; - usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; - usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); + if (cdev->gadget->lpm_capable) { + usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + bos->bNumDeviceCaps++; + le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); + usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; + usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; + usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | + USB_BESL_SUPPORT | besl); + } /* * The Superspeed USB Capability descriptor shall be implemented by all * SuperSpeed devices. */ - ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); - bos->bNumDeviceCaps++; - le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); - ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; - ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; - ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; - ss_cap->bmAttributes = 0; /* LTM is not supported yet */ - ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | - USB_FULL_SPEED_OPERATION | - USB_HIGH_SPEED_OPERATION | - USB_5GBPS_OPERATION); - ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; + if (gadget_is_superspeed(cdev->gadget)) { + struct usb_ss_cap_descriptor *ss_cap; + + ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + bos->bNumDeviceCaps++; + le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); + ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; + ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; + ss_cap->bmAttributes = 0; /* LTM is not supported yet */ + ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | + USB_FULL_SPEED_OPERATION | + USB_HIGH_SPEED_OPERATION | + USB_5GBPS_OPERATION); + ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; + ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; + ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; + } - /* Get Controller configuration */ - if (cdev->gadget->ops->get_config_params) - cdev->gadget->ops->get_config_params(&dcd_config_params); - else { - dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; - dcd_config_params.bU2DevExitLat = - cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); + /* The SuperSpeedPlus USB Device Capability descriptor */ + if (gadget_is_superspeed_plus(cdev->gadget)) { + struct usb_ssp_cap_descriptor *ssp_cap; + u8 ssac = 1; + u8 ssic; + int i; + + if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x2) + ssac = 3; + + /* + * Paired RX and TX sublink speed attributes share + * the same SSID. + */ + ssic = (ssac + 1) / 2 - 1; + + ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + bos->bNumDeviceCaps++; + + le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(ssac)); + ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(ssac); + ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE; + ssp_cap->bReserved = 0; + ssp_cap->wReserved = 0; + + ssp_cap->bmAttributes = + cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, ssac) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, ssic)); + + ssp_cap->wFunctionalitySupport = + cpu_to_le16(FIELD_PREP(USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, 0) | + FIELD_PREP(USB_SSP_MIN_RX_LANE_COUNT, 1) | + FIELD_PREP(USB_SSP_MIN_TX_LANE_COUNT, 1)); + + /* + * Use 1 SSID if the gadget supports up to gen2x1 or not + * specified: + * - SSID 0 for symmetric RX/TX sublink speed of 10 Gbps. + * + * Use 1 SSID if the gadget supports up to gen1x2: + * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps. + * + * Use 2 SSIDs if the gadget supports up to gen2x2: + * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps. + * - SSID 1 for symmetric RX/TX sublink speed of 10 Gbps. + */ + for (i = 0; i < ssac + 1; i++) { + u8 ssid; + u8 mantissa; + u8 type; + + ssid = i >> 1; + + if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x1 || + cdev->gadget->max_ssp_rate == USB_SSP_GEN_UNKNOWN) + mantissa = 10; + else + mantissa = 5 << ssid; + + if (i % 2) + type = USB_SSP_SUBLINK_SPEED_ST_SYM_TX; + else + type = USB_SSP_SUBLINK_SPEED_ST_SYM_RX; + + ssp_cap->bmSublinkSpeedAttr[i] = + cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, ssid) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE, + USB_SSP_SUBLINK_SPEED_LSE_GBPS) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, type) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP, + USB_SSP_SUBLINK_SPEED_LP_SSP) | + FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, mantissa)); + } + } + + /* The WebUSB Platform Capability descriptor */ + if (cdev->use_webusb) { + struct usb_plat_dev_cap_descriptor *webusb_cap; + struct usb_webusb_cap_data *webusb_cap_data; + guid_t webusb_uuid = WEBUSB_UUID; + + webusb_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); + webusb_cap_data = (struct usb_webusb_cap_data *) webusb_cap->CapabilityData; + bos->bNumDeviceCaps++; + le16_add_cpu(&bos->wTotalLength, + USB_DT_USB_PLAT_DEV_CAP_SIZE(USB_WEBUSB_CAP_DATA_SIZE)); + + webusb_cap->bLength = USB_DT_USB_PLAT_DEV_CAP_SIZE(USB_WEBUSB_CAP_DATA_SIZE); + webusb_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + webusb_cap->bDevCapabilityType = USB_PLAT_DEV_CAP_TYPE; + webusb_cap->bReserved = 0; + export_guid(webusb_cap->UUID, &webusb_uuid); + + if (cdev->bcd_webusb_version != 0) + webusb_cap_data->bcdVersion = cpu_to_le16(cdev->bcd_webusb_version); + else + webusb_cap_data->bcdVersion = WEBUSB_VERSION_1_00; + + webusb_cap_data->bVendorCode = cdev->b_webusb_vendor_code; + + if (strnlen(cdev->landing_page, sizeof(cdev->landing_page)) > 0) + webusb_cap_data->iLandingPage = WEBUSB_LANDING_PAGE_PRESENT; + else + webusb_cap_data->iLandingPage = WEBUSB_LANDING_PAGE_NOT_PRESENT; } - ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; - ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; return le16_to_cpu(bos->wTotalLength); } @@ -575,45 +881,41 @@ static void reset_config(struct usb_composite_dev *cdev) { struct usb_function *f; - if (cdev->in_reset_config) - return; - - cdev->in_reset_config = 1; - DBG(cdev, "reset config\n"); list_for_each_entry(f, &cdev->config->functions, list) { if (f->disable) f->disable(f); + bitmap_zero(f->endpoints, 32); } cdev->config = NULL; cdev->delayed_status = 0; - cdev->in_reset_config = 0; } static int set_config(struct usb_composite_dev *cdev, const struct usb_ctrlrequest *ctrl, unsigned number) { struct usb_gadget *gadget = cdev->gadget; - struct usb_configuration *c = NULL; + struct usb_configuration *c = NULL, *iter; int result = -EINVAL; unsigned power = gadget_is_otg(gadget) ? 8 : 100; int tmp; if (number) { - list_for_each_entry(c, &cdev->configs, list) { - if (c->bConfigurationValue == number) { - /* - * We disable the FDs of the previous - * configuration only if the new configuration - * is a valid one - */ - if (cdev->config) - reset_config(cdev); - result = 0; - break; - } + list_for_each_entry(iter, &cdev->configs, list) { + if (iter->bConfigurationValue != number) + continue; + /* + * We disable the FDs of the previous + * configuration only if the new configuration + * is a valid one + */ + if (cdev->config) + reset_config(cdev); + c = iter; + result = 0; + break; } if (result < 0) goto done; @@ -624,12 +926,13 @@ static int set_config(struct usb_composite_dev *cdev, } INFO(cdev, "%s config #%d: %s\n", - usb_speed_string(gadget->speed), - number, c ? c->label : "unconfigured"); + usb_speed_string(gadget->speed), + number, c ? c->label : "unconfigured"); if (!c) goto done; + usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); cdev->config = c; /* Initialize all interfaces by setting them to altsetting zero. */ @@ -646,16 +949,7 @@ static int set_config(struct usb_composite_dev *cdev, * function's setup callback instead of the current * configuration's setup callback. */ - switch (gadget->speed) { - case USB_SPEED_SUPER: - descriptors = f->ss_descriptors; - break; - case USB_SPEED_HIGH: - descriptors = f->hs_descriptors; - break; - default: - descriptors = f->fs_descriptors; - } + descriptors = function_descriptors(f, gadget->speed); for (; *descriptors; ++descriptors) { struct usb_endpoint_descriptor *ep; @@ -690,8 +984,21 @@ static int set_config(struct usb_composite_dev *cdev, } /* when we return, be sure our power usage is valid */ - power = c->MaxPower ? c->MaxPower : usb_gadget_vbus_draw_ma; + if (c->MaxPower || (c->bmAttributes & USB_CONFIG_ATT_SELFPOWER)) + power = c->MaxPower; + else + power = CONFIG_USB_GADGET_VBUS_DRAW; + + if (gadget->speed < USB_SPEED_SUPER) + power = min(power, 500U); + else + power = min(power, 900U); done: + if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) + usb_gadget_set_selfpowered(gadget); + else + usb_gadget_clear_selfpowered(gadget); + usb_gadget_vbus_draw(gadget, power); if (result >= 0 && cdev->delayed_status) result = USB_GADGET_DELAYED_STATUS; @@ -775,8 +1082,9 @@ int usb_add_config(struct usb_composite_dev *cdev, } else { unsigned i; - DBG(cdev, "cfg %d/%p speeds:%s%s%s\n", + DBG(cdev, "cfg %d/%p speeds:%s%s%s%s\n", config->bConfigurationValue, config, + config->superspeed_plus ? " superplus" : "", config->superspeed ? " super" : "", config->highspeed ? " high" : "", config->fullspeed @@ -795,9 +1103,7 @@ int usb_add_config(struct usb_composite_dev *cdev, } } - /* set_alt(), or next bind(), sets up - * ep->driver_data as needed. - */ + /* set_alt(), or next bind(), sets up ep->claimed as needed */ usb_ep_autoconfig_reset(cdev->gadget); done: @@ -816,12 +1122,8 @@ static void remove_config(struct usb_composite_dev *cdev, f = list_first_entry(&config->functions, struct usb_function, list); - list_del(&f->list); - if (f->unbind) { - DBG(cdev, "unbind function '%s'/%p\n", f->name, f); - f->unbind(config, f); - /* may free memory for "f" */ - } + + usb_remove_function(config, f); } list_del(&config->list); if (config->unbind) { @@ -843,9 +1145,15 @@ static void remove_config(struct usb_composite_dev *cdev, void usb_remove_config(struct usb_composite_dev *cdev, struct usb_configuration *config) { + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->config == config) reset_config(cdev); + spin_unlock_irqrestore(&cdev->lock, flags); + remove_config(cdev, config); } @@ -853,7 +1161,7 @@ void usb_remove_config(struct usb_composite_dev *cdev, /* We support strings in multiple languages ... string descriptor zero * says which languages are supported. The typical case will be that - * only one language (probably English) is used, with I18N handled on + * only one language (probably English) is used, with i18n handled on * the host side. */ @@ -866,7 +1174,7 @@ static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) while (*sp) { s = *sp; language = cpu_to_le16(s->language); - for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { + for (tmp = buf; *tmp && tmp < &buf[USB_MAX_STRING_LEN]; tmp++) { if (*tmp == language) goto repeat; } @@ -906,7 +1214,7 @@ static int get_string(struct usb_composite_dev *cdev, struct usb_function *f; int len; - /* Yes, not only is USB's I18N support probably more than most + /* Yes, not only is USB's i18n support probably more than most * folk will ever care about ... also, it's all supported here. * (Except for UTF8 support for Unicode's "Astral Planes".) */ @@ -941,7 +1249,7 @@ static int get_string(struct usb_composite_dev *cdev, collect_langs(sp, s->wData); } - for (len = 0; len <= 126 && s->wData[len]; len++) + for (len = 0; len <= USB_MAX_STRING_LEN && s->wData[len]; len++) continue; if (!len) return -EINVAL; @@ -950,6 +1258,19 @@ static int get_string(struct usb_composite_dev *cdev, return s->bLength; } + if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) { + struct usb_os_string *b = buf; + b->bLength = sizeof(*b); + b->bDescriptorType = USB_DT_STRING; + compiletime_assert( + sizeof(b->qwSignature) == sizeof(cdev->qw_sign), + "qwSignature size must be equal to qw_sign"); + memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature)); + b->bMS_VendorCode = cdev->b_vendor_code; + b->bPad = 0; + return sizeof(*b); + } + list_for_each_entry(uc, &cdev->gstrings, list) { struct usb_gadget_strings **sp; @@ -1013,7 +1334,7 @@ int usb_string_id(struct usb_composite_dev *cdev) EXPORT_SYMBOL_GPL(usb_string_id); /** - * usb_string_ids() - allocate unused string IDs in batch + * usb_string_ids_tab() - allocate unused string IDs in batch * @cdev: the device whose string descriptor IDs are being allocated * @str: an array of usb_string objects to assign numbers to * Context: single threaded during gadget setup @@ -1105,11 +1426,11 @@ static struct usb_gadget_string_container *copy_gadget_strings( * This function will create a deep copy of usb_gadget_strings and usb_string * and attach it to the cdev. The actual string (usb_string.s) will not be * copied but only a referenced will be made. The struct usb_gadget_strings - * array may contain multiple languges and should be NULL terminated. + * array may contain multiple languages and should be NULL terminated. * The ->language pointer of each struct usb_gadget_strings has to contain the * same amount of entries. * For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first - * usb_string entry of es-ES containts the translation of the first usb_string + * usb_string entry of es-ES contains the translation of the first usb_string * entry of en-US. Therefore both entries become the same id assign. */ struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev, @@ -1211,6 +1532,8 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) if (cdev->req == req) cdev->setup_pending = false; + else if (cdev->os_desc_req == req) + cdev->os_desc_pending = false; else WARN(1, "unknown request %p\n", req); } @@ -1224,6 +1547,8 @@ static int composite_ep0_queue(struct usb_composite_dev *cdev, if (ret == 0) { if (cdev->req == req) cdev->setup_pending = true; + else if (cdev->os_desc_req == req) + cdev->os_desc_pending = true; else WARN(1, "unknown request %p\n", req); } @@ -1231,6 +1556,156 @@ static int composite_ep0_queue(struct usb_composite_dev *cdev, return ret; } +static int count_ext_compat(struct usb_configuration *c) +{ + int i, res; + + res = 0; + for (i = 0; i < c->next_interface_id; ++i) { + struct usb_function *f; + int j; + + f = c->interface[i]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (i != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) + ++res; + } + } + BUG_ON(res > 255); + return res; +} + +static int fill_ext_compat(struct usb_configuration *c, u8 *buf) +{ + int i, count; + + count = 16; + buf += 16; + for (i = 0; i < c->next_interface_id; ++i) { + struct usb_function *f; + int j; + + f = c->interface[i]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (i != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) { + *buf++ = i; + *buf++ = 0x01; + memcpy(buf, d->ext_compat_id, 16); + buf += 22; + } else { + ++buf; + *buf = 0x01; + buf += 23; + } + count += 24; + if (count + 24 >= USB_COMP_EP0_OS_DESC_BUFSIZ) + return count; + } + } + + return count; +} + +static int count_ext_prop(struct usb_configuration *c, int interface) +{ + struct usb_function *f; + int j; + + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) + return d->ext_prop_count; + } + return 0; +} + +static int len_ext_prop(struct usb_configuration *c, int interface) +{ + struct usb_function *f; + struct usb_os_desc *d; + int j, res; + + res = 10; /* header length */ + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d) + return min(res + d->ext_prop_len, 4096); + } + return res; +} + +static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) +{ + struct usb_function *f; + struct usb_os_desc *d; + struct usb_os_desc_ext_prop *ext_prop; + int j, count, n, ret; + + f = c->interface[interface]; + count = 10; /* header length */ + buf += 10; + for (j = 0; j < f->os_desc_n; ++j) { + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d) + list_for_each_entry(ext_prop, &d->ext_prop, entry) { + n = ext_prop->data_len + + ext_prop->name_len + 14; + if (count + n >= USB_COMP_EP0_OS_DESC_BUFSIZ) + return count; + usb_ext_prop_put_size(buf, n); + usb_ext_prop_put_type(buf, ext_prop->type); + ret = usb_ext_prop_put_name(buf, ext_prop->name, + ext_prop->name_len); + if (ret < 0) + return ret; + switch (ext_prop->type) { + case USB_EXT_PROP_UNICODE: + case USB_EXT_PROP_UNICODE_ENV: + case USB_EXT_PROP_UNICODE_LINK: + usb_ext_prop_put_unicode(buf, ret, + ext_prop->data, + ext_prop->data_len); + break; + case USB_EXT_PROP_BINARY: + usb_ext_prop_put_binary(buf, ret, + ext_prop->data, + ext_prop->data_len); + break; + case USB_EXT_PROP_LE32: + /* not implemented */ + case USB_EXT_PROP_BE32: + /* not implemented */ + default: + return -EINVAL; + } + buf += n; + count += n; + } + } + + return count; +} + /* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver(like @@ -1250,8 +1725,21 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); struct usb_function *f = NULL; + struct usb_function *iter; u8 endp; + if (w_length > USB_COMP_EP0_BUFSIZ) { + if (ctrl->bRequestType & USB_DIR_IN) { + /* Cast away the const, we are going to overwrite on purpose. */ + __le16 *temp = (__le16 *)&ctrl->wLength; + + *temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ); + w_length = USB_COMP_EP0_BUFSIZ; + } else { + goto done; + } + } + /* partial re-init of the response message; the function or the * gadget might need to intercept e.g. a control-OUT completion * when we delegate to it. @@ -1262,6 +1750,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) req->length = 0; gadget->ep0->driver_data = cdev; + /* + * Don't let non-standard requests match any of the cases below + * by accident. + */ + if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) + goto unknown; + switch (ctrl->bRequest) { /* we handle all standard USB descriptors */ @@ -1277,11 +1772,16 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) cdev->gadget->ep0->maxpacket; if (gadget_is_superspeed(gadget)) { if (gadget->speed >= USB_SPEED_SUPER) { - cdev->desc.bcdUSB = cpu_to_le16(0x0300); + cdev->desc.bcdUSB = cpu_to_le16(0x0320); cdev->desc.bMaxPacketSize0 = 9; } else { cdev->desc.bcdUSB = cpu_to_le16(0x0210); } + } else { + if (gadget->lpm_capable || cdev->use_webusb) + cdev->desc.bcdUSB = cpu_to_le16(0x0201); + else + cdev->desc.bcdUSB = cpu_to_le16(0x0200); } value = min(w_length, (u16) sizeof cdev->desc); @@ -1299,7 +1799,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!gadget_is_dualspeed(gadget) || gadget->speed >= USB_SPEED_SUPER) break; - /* FALLTHROUGH */ + fallthrough; case USB_DT_CONFIG: value = config_desc(cdev, w_value); if (value >= 0) @@ -1312,11 +1812,32 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min(w_length, (u16) value); break; case USB_DT_BOS: - if (gadget_is_superspeed(gadget)) { + if (gadget_is_superspeed(gadget) || + gadget->lpm_capable || cdev->use_webusb) { value = bos_desc(cdev); value = min(w_length, (u16) value); } break; + case USB_DT_OTG: + if (gadget_is_otg(gadget)) { + struct usb_configuration *config; + int otg_desc_len = 0; + + if (cdev->config) + config = cdev->config; + else + config = list_first_entry( + &cdev->configs, + struct usb_configuration, list); + if (!config) + goto done; + + otg_desc_len += sizeof(struct usb_otg_descriptor); + + value = min_t(int, w_length, otg_desc_len); + memcpy(req->buf, config->descriptors[0], value); + } + break; } break; @@ -1332,7 +1853,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) else VDBG(cdev, "HNP inactive\n"); } + spin_lock(&cdev->lock); value = set_config(cdev, ctrl, w_value); + spin_unlock(&cdev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) @@ -1344,9 +1867,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min(w_length, (u16) 1); break; - /* function drivers must handle get/set altsetting; if there's - * no get() method, we know only altsetting zero works. - */ + /* function drivers must handle get/set altsetting */ case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; @@ -1355,8 +1876,16 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) f = cdev->config->interface[intf]; if (!f) break; - if (w_value && !f->set_alt) + + /* + * If there's no get_alt() method, we know only altsetting zero + * works. There is no need to check if set_alt() is not NULL + * as we check this in usb_add_function(). + */ + if (w_value && !f->get_alt) break; + + spin_lock(&cdev->lock); value = f->set_alt(f, w_index, w_value); if (value == USB_GADGET_DELAYED_STATUS) { DBG(cdev, @@ -1366,6 +1895,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) DBG(cdev, "delayed_status count %d\n", cdev->delayed_status); } + spin_unlock(&cdev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) @@ -1382,15 +1912,24 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) *((u8 *)req->buf) = value; value = min(w_length, (u16) 1); break; - - /* - * USB 3.0 additions: - * Function driver should handle get_status request. If such cb - * wasn't supplied we respond with default value = 0 - * Note: function driver should supply such cb only for the first - * interface of the function - */ case USB_REQ_GET_STATUS: + if (gadget_is_otg(gadget) && gadget->hnp_polling_support && + (w_index == OTG_STS_SELECTOR)) { + if (ctrl->bRequestType != (USB_DIR_IN | + USB_RECIP_DEVICE)) + goto unknown; + *((u8 *)req->buf) = gadget->host_request_flag; + value = 1; + break; + } + + /* + * USB 3.0 additions: + * Function driver should handle get_status request. If such cb + * wasn't supplied we respond with default value = 0 + * Note: function driver should supply such cb only for the + * first interface of the function + */ if (!gadget_is_superspeed(gadget)) goto unknown; if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)) @@ -1439,6 +1978,116 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; default: unknown: + /* + * OS descriptors handling + */ + if (cdev->use_os_string && cdev->os_desc_config && + (ctrl->bRequestType & USB_TYPE_VENDOR) && + ctrl->bRequest == cdev->b_vendor_code) { + struct usb_configuration *os_desc_cfg; + u8 *buf; + int interface; + int count = 0; + + req = cdev->os_desc_req; + req->context = cdev; + req->complete = composite_setup_complete; + buf = req->buf; + os_desc_cfg = cdev->os_desc_config; + w_length = min_t(u16, w_length, USB_COMP_EP0_OS_DESC_BUFSIZ); + memset(buf, 0, w_length); + buf[5] = 0x01; + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + if (w_index != 0x4 || (w_value >> 8)) + break; + buf[6] = w_index; + /* Number of ext compat interfaces */ + count = count_ext_compat(os_desc_cfg); + buf[8] = count; + count *= 24; /* 24 B/ext compat desc */ + count += 16; /* header */ + put_unaligned_le32(count, buf); + value = w_length; + if (w_length > 0x10) { + value = fill_ext_compat(os_desc_cfg, buf); + value = min_t(u16, w_length, value); + } + break; + case USB_RECIP_INTERFACE: + if (w_index != 0x5 || (w_value >> 8)) + break; + interface = w_value & 0xFF; + if (interface >= MAX_CONFIG_INTERFACES || + !os_desc_cfg->interface[interface]) + break; + buf[6] = w_index; + count = count_ext_prop(os_desc_cfg, + interface); + put_unaligned_le16(count, buf + 8); + count = len_ext_prop(os_desc_cfg, + interface); + put_unaligned_le32(count, buf); + value = w_length; + if (w_length > 0x0A) { + value = fill_ext_prop(os_desc_cfg, + interface, buf); + if (value >= 0) + value = min_t(u16, w_length, value); + } + break; + } + + goto check_value; + } + + /* + * WebUSB URL descriptor handling, following: + * https://wicg.github.io/webusb/#device-requests + */ + if (cdev->use_webusb && + ctrl->bRequestType == (USB_DIR_IN | USB_TYPE_VENDOR) && + w_index == WEBUSB_GET_URL && + w_value == WEBUSB_LANDING_PAGE_PRESENT && + ctrl->bRequest == cdev->b_webusb_vendor_code) { + unsigned int landing_page_length; + unsigned int landing_page_offset; + struct webusb_url_descriptor *url_descriptor = + (struct webusb_url_descriptor *)cdev->req->buf; + + url_descriptor->bDescriptorType = WEBUSB_URL_DESCRIPTOR_TYPE; + + if (strncasecmp(cdev->landing_page, "https://", 8) == 0) { + landing_page_offset = 8; + url_descriptor->bScheme = WEBUSB_URL_SCHEME_HTTPS; + } else if (strncasecmp(cdev->landing_page, "http://", 7) == 0) { + landing_page_offset = 7; + url_descriptor->bScheme = WEBUSB_URL_SCHEME_HTTP; + } else { + landing_page_offset = 0; + url_descriptor->bScheme = WEBUSB_URL_SCHEME_NONE; + } + + landing_page_length = strnlen(cdev->landing_page, + sizeof(url_descriptor->URL) + - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset); + + if (ctrl->wLength < WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + + landing_page_length) + landing_page_length = ctrl->wLength + - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset; + + memcpy(url_descriptor->URL, + cdev->landing_page + landing_page_offset, + landing_page_length - landing_page_offset); + url_descriptor->bLength = landing_page_length + - landing_page_offset + WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH; + + value = url_descriptor->bLength; + + goto check_value; + } + VDBG(cdev, "non-core control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, @@ -1447,11 +2096,22 @@ unknown: /* functions always handle their interfaces and endpoints... * punt other recipients (other, WUSB, ...) to the current * configuration code. - * - * REVISIT it could make sense to let the composite device - * take such requests too, if that's ever needed: to work - * in config 0, etc. */ + if (cdev->config) { + list_for_each_entry(f, &cdev->config->functions, list) + if (f->req_match && + f->req_match(f, ctrl, false)) + goto try_fun_setup; + } else { + struct usb_configuration *c; + list_for_each_entry(c, &cdev->configs, list) + list_for_each_entry(f, &c->functions, list) + if (f->req_match && + f->req_match(f, ctrl, true)) + goto try_fun_setup; + } + f = NULL; + switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) @@ -1460,16 +2120,18 @@ unknown: break; case USB_RECIP_ENDPOINT: + if (!cdev->config) + break; endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); - list_for_each_entry(f, &cdev->config->functions, list) { - if (test_bit(endp, f->endpoints)) + list_for_each_entry(iter, &cdev->config->functions, list) { + if (test_bit(endp, iter->endpoints)) { + f = iter; break; + } } - if (&f->list == &cdev->config->functions) - f = NULL; break; } - +try_fun_setup: if (f && f->setup) value = f->setup(f, ctrl); else { @@ -1497,9 +2159,11 @@ unknown: goto done; } +check_value: /* respond with data transfer before status phase? */ if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) { req->length = value; + req->context = cdev; req->zero = value < w_length; value = composite_ep0_queue(cdev, req); if (value < 0) { @@ -1518,17 +2182,38 @@ done: return value; } -void composite_disconnect(struct usb_gadget *gadget) +static void __composite_disconnect(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); + unsigned long flags; /* REVISIT: should we have config and device level * disconnect callbacks? */ + spin_lock_irqsave(&cdev->lock, flags); + cdev->suspended = 0; if (cdev->config) reset_config(cdev); if (cdev->driver->disconnect) cdev->driver->disconnect(cdev); + spin_unlock_irqrestore(&cdev->lock, flags); +} + +void composite_disconnect(struct usb_gadget *gadget) +{ + usb_gadget_vbus_draw(gadget, 0); + __composite_disconnect(gadget); +} + +void composite_reset(struct usb_gadget *gadget) +{ + /* + * Section 1.4.13 Standard Downstream Port of the USB battery charging + * specification v1.2 states that a device connected on a SDP shall only + * draw at max 100mA while in a connected, but unconfigured state. + */ + usb_gadget_vbus_draw(gadget, 100); + __composite_disconnect(gadget); } /*-------------------------------------------------------------------------*/ @@ -1536,6 +2221,8 @@ void composite_disconnect(struct usb_gadget *gadget) static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver) { struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_gadget_strings *gstr = cdev->driver->strings[0]; + struct usb_string *dev_str = gstr->strings; /* composite_disconnect() must already have been called * by the underlying peripheral controller driver! @@ -1555,6 +2242,9 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver) composite_dev_cleanup(cdev); + if (dev_str[USB_GADGET_MANUFACTURER_IDX].s == cdev->def_manufacturer) + dev_str[USB_GADGET_MANUFACTURER_IDX].s = ""; + kfree(cdev->def_manufacturer); kfree(cdev); set_gadget_data(gadget, NULL); @@ -1619,6 +2309,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite, goto fail; cdev->req->complete = composite_setup_complete; + cdev->req->context = cdev; gadget->ep0->driver_data = cdev; cdev->driver = composite; @@ -1628,7 +2319,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite, * more than 100mA from USB must report itself as bus-powered in * the GetStatus(DEVICE) call. */ - if (usb_gadget_vbus_draw_ma <= USB_SELF_POWER_VBUS_MAX_DRAW) + if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) usb_gadget_set_selfpowered(gadget); /* interface and string IDs start at zero via kzalloc. @@ -1644,21 +2335,73 @@ fail: return ret; } +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, + struct usb_ep *ep0) +{ + int ret = 0; + + cdev->os_desc_req = usb_ep_alloc_request(ep0); + if (!cdev->os_desc_req) { + ret = -ENOMEM; + goto end; + } + + cdev->os_desc_req->buf = kmalloc(USB_COMP_EP0_OS_DESC_BUFSIZ, + GFP_KERNEL); + if (!cdev->os_desc_req->buf) { + ret = -ENOMEM; + usb_ep_free_request(ep0, cdev->os_desc_req); + goto end; + } + cdev->os_desc_req->context = cdev; + cdev->os_desc_req->complete = composite_setup_complete; +end: + return ret; +} + void composite_dev_cleanup(struct usb_composite_dev *cdev) { struct usb_gadget_string_container *uc, *tmp; + struct usb_ep *ep, *tmp_ep; list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) { list_del(&uc->list); kfree(uc); } + if (cdev->os_desc_req) { + if (cdev->os_desc_pending) + usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req); + + kfree(cdev->os_desc_req->buf); + cdev->os_desc_req->buf = NULL; + usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); + cdev->os_desc_req = NULL; + } if (cdev->req) { if (cdev->setup_pending) usb_ep_dequeue(cdev->gadget->ep0, cdev->req); + kfree(cdev->req->buf); + cdev->req->buf = NULL; usb_ep_free_request(cdev->gadget->ep0, cdev->req); + cdev->req = NULL; } cdev->next_string_id = 0; + + /* + * Some UDC backends have a dynamic EP allocation scheme. + * + * In that case, the dispose() callback is used to notify the + * backend that the EPs are no longer in use. + * + * Note: The UDC backend can remove the EP from the ep_list as + * a result, so we need to use the _safe list iterator. + */ + list_for_each_entry_safe(ep, tmp_ep, + &cdev->gadget->ep_list, ep_list) { + if (ep->ops->dispose) + ep->ops->dispose(ep); + } } static int composite_bind(struct usb_gadget *gadget, @@ -1672,6 +2415,7 @@ static int composite_bind(struct usb_gadget *gadget, if (!cdev) return status; + spin_lock_init(&cdev->lock); cdev->gadget = gadget; set_gadget_data(gadget, cdev); INIT_LIST_HEAD(&cdev->configs); @@ -1689,6 +2433,12 @@ static int composite_bind(struct usb_gadget *gadget, if (status < 0) goto fail; + if (cdev->use_os_string) { + status = composite_os_desc_req_prepare(cdev, gadget->ep0); + if (status) + goto fail; + } + update_unchanged_dev_desc(&cdev->desc, composite->dev); /* has userspace failed to provide a serial number? */ @@ -1710,6 +2460,7 @@ static const struct usb_gadget_driver composite_driver_template = { .unbind = composite_unbind, .setup = composite_setup, + .reset = composite_reset, .disconnect = composite_disconnect, }; @@ -1746,7 +2497,7 @@ int usb_composite_probe(struct usb_composite_driver *driver) gadget_driver->driver.name = driver->name; gadget_driver->max_speed = driver->max_speed; - return usb_gadget_probe_driver(gadget_driver); + return usb_gadget_register_driver(gadget_driver); } EXPORT_SYMBOL_GPL(usb_composite_probe); @@ -1777,8 +2528,10 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) { int value; struct usb_request *req = cdev->req; + unsigned long flags; DBG(cdev, "%s\n", __func__); + spin_lock_irqsave(&cdev->lock, flags); if (cdev->delayed_status == 0) { WARN(cdev, "%s: Unexpected call\n", __func__); @@ -1786,6 +2539,7 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) } else if (--cdev->delayed_status == 0) { DBG(cdev, "%s: Completing delayed status\n", __func__); req->length = 0; + req->context = cdev; value = composite_ep0_queue(cdev, req); if (value < 0) { DBG(cdev, "ep_queue --> %d\n", value); @@ -1793,12 +2547,14 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev) composite_setup_complete(cdev->gadget->ep0, req); } } + + spin_unlock_irqrestore(&cdev->lock, flags); } EXPORT_SYMBOL_GPL(usb_composite_setup_continue); static char *composite_default_mfr(struct usb_gadget *gadget) { - return basprintf("barebox %s", gadget->name); + return basprintf("barebox with %s", gadget->name); } void usb_composite_overwrite_options(struct usb_composite_dev *cdev, diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 369eb2ba5e..27e4dda52f 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -7,9 +7,9 @@ #include <common.h> -#include <usb/ch9.h> -#include <usb/gadget.h> -#include <usb/composite.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> /** * usb_descriptor_fillbuf - fill buffer with descriptors @@ -152,7 +152,8 @@ EXPORT_SYMBOL_GPL(usb_copy_descriptors); int usb_assign_descriptors(struct usb_function *f, struct usb_descriptor_header **fs, struct usb_descriptor_header **hs, - struct usb_descriptor_header **ss) + struct usb_descriptor_header **ss, + struct usb_descriptor_header **ssp) { struct usb_gadget *g = f->config->cdev->gadget; @@ -171,6 +172,11 @@ int usb_assign_descriptors(struct usb_function *f, if (!f->ss_descriptors) goto err; } + if (ssp && gadget_is_superspeed_plus(g)) { + f->ssp_descriptors = usb_copy_descriptors(ssp); + if (!f->ssp_descriptors) + goto err; + } return 0; err: usb_free_all_descriptors(f); diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index e9f13f4262..ff16abaf12 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -11,10 +11,10 @@ #include <linux/ctype.h> #include <asm/byteorder.h> -#include <usb/ch9.h> -#include <usb/gadget.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> -#include "gadget_chips.h" +#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) /* * This should work with endpoints from controller drivers sharing the @@ -182,18 +182,6 @@ ep_matches ( return 1; } -static struct usb_ep * -find_ep (struct usb_gadget *gadget, const char *name) -{ - struct usb_ep *ep; - - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (0 == strcmp (ep->name, name)) - return ep; - } - return NULL; -} - /** * usb_ep_autoconfig_ss() - choose an endpoint matching the ep * descriptor and ep companion descriptor @@ -249,34 +237,6 @@ struct usb_ep *usb_ep_autoconfig_ss( type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - /* First, apply chip-specific "best usage" knowledge. - * This might make a good usb_gadget_ops hook ... - */ - if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { - /* ep-e, ep-f are PIO with only 64 byte fifos */ - ep = find_ep (gadget, "ep-e"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; - ep = find_ep (gadget, "ep-f"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; - - } else if (gadget_is_goku (gadget)) { - if (USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough */ - ep = find_ep(gadget, "ep3-bulk"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; - } else if (USB_ENDPOINT_XFER_BULK == type - && (USB_DIR_IN & desc->bEndpointAddress)) { - /* DMA may be available */ - ep = find_ep(gadget, "ep2-bulk"); - if (ep && ep_matches(gadget, ep, desc, - ep_comp)) - goto found_ep; - } - } - /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { if (ep_matches(gadget, ep, desc, ep_comp)) diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile new file mode 100644 index 0000000000..de306b929f --- /dev/null +++ b/drivers/usb/gadget/function/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_USB_GADGET_SERIAL) += u_serial.o f_serial.o f_acm.o +obj-$(CONFIG_USB_GADGET_DFU) += dfu.o +obj-$(CONFIG_USB_GADGET_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o storage_common.o diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/function/dfu.c index 0b7ca82c4a..431480094b 100644 --- a/drivers/usb/gadget/dfu.c +++ b/drivers/usb/gadget/function/dfu.c @@ -26,15 +26,15 @@ #include <dma.h> #include <asm/byteorder.h> -#include <usb/composite.h> +#include <linux/usb/composite.h> #include <linux/types.h> #include <linux/list.h> -#include <usb/gadget.h> +#include <linux/usb/gadget.h> #include <linux/stat.h> #include <libfile.h> #include <linux/err.h> -#include <usb/ch9.h> -#include <usb/dfu.h> +#include <linux/usb/ch9.h> +#include <linux/usb/dfu.h> #include <config.h> #include <common.h> #include <malloc.h> @@ -427,7 +427,7 @@ dfu_bind(struct usb_configuration *c, struct usb_function *f) header[i] = (struct usb_descriptor_header *) &usb_dfu_func; header[i + 1] = NULL; - status = usb_assign_descriptors(f, header, header, NULL); + status = usb_assign_descriptors(f, header, header, header, header); free(desc); free(header); diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 42438947c1..3532fd5892 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -12,14 +12,13 @@ /* #define VERBOSE_DEBUG */ #include <common.h> -#include <usb/cdc.h> +#include <linux/usb/cdc.h> #include <linux/err.h> #include <linux/spinlock.h> #include <asm/byteorder.h> -#include <usb/composite.h> +#include <linux/usb/composite.h> #include "u_serial.h" -#include "gadget_chips.h" /* @@ -679,7 +678,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function, - acm_ss_function); + acm_ss_function, acm_ss_function); if (status) goto fail; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/function/f_fastboot.c index 96924c4cb9..41450268fc 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/function/f_fastboot.c @@ -25,7 +25,7 @@ #include <unistd.h> #include <progress.h> #include <fastboot.h> -#include <usb/fastboot.h> +#include <linux/usb/fastboot.h> #define FASTBOOT_INTERFACE_CLASS 0xff #define FASTBOOT_INTERFACE_SUB_CLASS 0x42 @@ -39,7 +39,7 @@ struct f_fastboot { /* IN/OUT EP's and corresponding requests */ struct usb_ep *in_ep, *out_ep; - struct usb_request *in_req, *out_req; + struct usb_request *out_req; struct work_queue wq; }; @@ -109,6 +109,36 @@ static struct usb_descriptor_header *fb_hs_descs[] = { NULL, }; +static struct usb_endpoint_descriptor ss_ep_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_ep_out = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor fb_ss_bulk_comp_desc = { + .bLength = sizeof(fb_ss_bulk_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *fb_ss_descs[] = { + (struct usb_descriptor_header *)&interface_desc, + (struct usb_descriptor_header *)&ss_ep_in, + (struct usb_descriptor_header *)&fb_ss_bulk_comp_desc, + (struct usb_descriptor_header *)&ss_ep_out, + (struct usb_descriptor_header *)&fb_ss_bulk_comp_desc, + NULL, +}; + /* * static strings, in UTF-8 */ @@ -134,10 +164,6 @@ static int fastboot_write_usb(struct fastboot *fb, const char *buffer, unsigned int buffer_size); static void fastboot_start_download_usb(struct fastboot *fb); -static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) -{ -} - struct fastboot_work { struct work_struct work; struct f_fastboot *f_fb; @@ -183,6 +209,17 @@ static struct usb_request *fastboot_alloc_request(struct usb_ep *ep) return req; } +static void fastboot_free_request(struct usb_ep *ep, struct usb_request *req) +{ + free(req->buf); + usb_ep_free_request(ep, req); +} + +static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) +{ + fastboot_free_request(ep, req); +} + static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; @@ -248,6 +285,8 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress; hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress; + ss_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress; + ss_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress; f_fb->out_req = fastboot_alloc_request(f_fb->out_ep); if (!f_fb->out_req) { @@ -259,24 +298,13 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) f_fb->out_req->complete = rx_handler_command; f_fb->out_req->context = f_fb; - f_fb->in_req = fastboot_alloc_request(f_fb->in_ep); - if (!f_fb->in_req) { - puts("failed alloc req in\n"); - ret = -EINVAL; - goto err_free_out_req; - } - f_fb->in_req->complete = fastboot_complete; - - ret = usb_assign_descriptors(f, fb_fs_descs, fb_hs_descs, NULL); + ret = usb_assign_descriptors(f, fb_fs_descs, fb_hs_descs, fb_ss_descs, fb_ss_descs); if (ret) goto err_free_in_req; return 0; err_free_in_req: - free(f_fb->in_req->buf); - usb_ep_free_request(f_fb->in_ep, f_fb->in_req); -err_free_out_req: free(f_fb->out_req->buf); usb_ep_free_request(f_fb->out_ep, f_fb->out_req); fb_generic_free: @@ -291,12 +319,6 @@ static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_fastboot *f_fb = func_to_fastboot(f); - usb_ep_dequeue(f_fb->in_ep, f_fb->in_req); - free(f_fb->in_req->buf); - usb_ep_free_request(f_fb->in_ep, f_fb->in_req); - f_fb->in_req = NULL; - - usb_ep_dequeue(f_fb->out_ep, f_fb->out_req); free(f_fb->out_req->buf); usb_ep_free_request(f_fb->out_ep, f_fb->out_req); f_fb->out_req = NULL; @@ -404,28 +426,23 @@ DECLARE_USB_FUNCTION_INIT(fastboot, fastboot_alloc_instance, fastboot_alloc_func static int fastboot_write_usb(struct fastboot *fb, const char *buffer, unsigned int buffer_size) { struct f_fastboot *f_fb = container_of(fb, struct f_fastboot, fastboot); - struct usb_request *in_req = f_fb->in_req; - uint64_t start; + struct usb_request *in_req; int ret; + in_req = fastboot_alloc_request(f_fb->in_ep); + if (!in_req) + return -ENOMEM; + memcpy(in_req->buf, buffer, buffer_size); in_req->length = buffer_size; + in_req->complete = fastboot_complete; ret = usb_ep_queue(f_fb->in_ep, in_req); - if (ret) + if (ret) { + fastboot_free_request(f_fb->in_ep, in_req); pr_err("Error %d on queue\n", ret); - - start = get_time_ns(); - - while (in_req->status == -EINPROGRESS) { - if (is_timeout(start, 2 * SECOND)) - return -ETIMEDOUT; - usb_gadget_poll(); } - if (in_req->status) - pr_err("Failed to send answer: %d\n", in_req->status); - return 0; } diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 1c26c4d996..2c934c621a 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -225,12 +225,12 @@ #include <scsi.h> #include <linux/err.h> -#include <usb/mass_storage.h> +#include <linux/usb/mass_storage.h> #include <asm/unaligned.h> #include <linux/bitops.h> -#include <usb/gadget.h> -#include <usb/composite.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> #include <linux/bitmap.h> #include <linux/completion.h> #include <bthread.h> @@ -2194,15 +2194,18 @@ reset: fsg = common->fsg; /* Enable the endpoints */ - fsg->bulk_in->desc = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); + rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in); + if (rc) + goto reset; rc = enable_endpoint(common, fsg->bulk_in); if (rc) goto reset; fsg->bulk_in_enabled = 1; - fsg->bulk_out->desc = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); + rc = config_ep_by_speed(common->gadget, &(fsg->function), + fsg->bulk_out); + if (rc) + goto reset; rc = enable_endpoint(common, fsg->bulk_out); if (rc) goto reset; @@ -2615,7 +2618,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) struct usb_gadget *gadget = c->cdev->gadget; int ret; struct usb_ep *ep; - struct usb_descriptor_header **hs_function = NULL; + unsigned max_burst; struct fsg_common *common = fsg->common; if (!ums_files) { @@ -2656,17 +2659,26 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ep->driver_data = common; /* claim the endpoint */ fsg->bulk_out = ep; - if (gadget_is_dualspeed(gadget)) { - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - hs_function = fsg_hs_function; - } + /* Assume endpoint addresses are the same for both speeds */ + fsg_hs_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_hs_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; + + /* Calculate bMaxBurst, we know packet size is 1024 */ + max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); + + fsg_ss_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; + + fsg_ss_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; /* Copy descriptors */ - return usb_assign_descriptors(f, fsg_fs_function, hs_function, NULL); + return usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function, + fsg_ss_function, fsg_ss_function); autoconf_fail: ERROR(fsg, "unable to autoconfigure all endpoints\n"); diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/function/f_serial.c index 33cf54dc1c..a768c580ea 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -12,7 +12,6 @@ #include <linux/err.h> #include "u_serial.h" -#include "gadget_chips.h" /* @@ -232,7 +231,7 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f) gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function, - gser_ss_function); + gser_ss_function, gser_ss_function); if (status) goto fail; DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/function/storage_common.c index 69fcd06565..60e0994235 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -104,6 +104,48 @@ struct usb_descriptor_header *fsg_hs_function[] = { NULL, }; +struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { + .bLength = sizeof(fsg_ss_bulk_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /*.bMaxBurst = DYNAMIC, */ +}; + +struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { + .bLength = sizeof(fsg_ss_bulk_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /*.bMaxBurst = DYNAMIC, */ +}; + +struct usb_descriptor_header *fsg_ss_function[] = { + (struct usb_descriptor_header *) &fsg_intf_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc, + (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, + NULL, +}; +EXPORT_SYMBOL_GPL(fsg_ss_function); + /* Maxpacket and other transfer characteristics vary by speed. */ struct usb_endpoint_descriptor * fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/function/storage_common.h index bd499c9e03..29afe77685 100644 --- a/drivers/usb/gadget/storage_common.h +++ b/drivers/usb/gadget/function/storage_common.h @@ -4,9 +4,9 @@ #define USB_STORAGE_COMMON_H #include <driver.h> -#include <usb/storage.h> +#include <linux/usb/storage.h> #include <asm/unaligned.h> -#include <usb/mass_storage.h> +#include <linux/usb/mass_storage.h> #ifndef DEBUG #undef VERBOSE_DEBUG @@ -232,6 +232,12 @@ extern struct usb_endpoint_descriptor fsg_hs_bulk_in_desc; extern struct usb_endpoint_descriptor fsg_hs_bulk_out_desc; extern struct usb_descriptor_header *fsg_hs_function[]; +extern struct usb_endpoint_descriptor fsg_ss_bulk_in_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc; +extern struct usb_endpoint_descriptor fsg_ss_bulk_out_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc; +extern struct usb_descriptor_header *fsg_ss_function[]; + int fsg_lun_open(struct fsg_lun *curlun, unsigned int num_sectors, const char *filename); void fsg_lun_close(struct fsg_lun *curlun); diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 2ce3f1c791..ca4e77c5ff 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -16,7 +16,7 @@ #include <common.h> #include <complete.h> -#include <usb/cdc.h> +#include <linux/usb/cdc.h> #include <kfifo.h> #include <clock.h> #include <linux/err.h> @@ -155,12 +155,13 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) { struct gs_port *port = ep->driver_data; + list_add_tail(&req->list, &port->read_pool); + port->read_nb_queued--; + if (req->status == -ESHUTDOWN) return; kfifo_put(port->recv_fifo, req->buf, req->actual); - list_add_tail(&req->list, &port->read_pool); - port->read_nb_queued--; gs_start_rx(port); } diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/function/u_serial.h index 80450ccc86..44fcace030 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/function/u_serial.h @@ -9,8 +9,8 @@ #ifndef __U_SERIAL_H #define __U_SERIAL_H -#include <usb/composite.h> -#include <usb/cdc.h> +#include <linux/usb/composite.h> +#include <linux/usb/cdc.h> #define MAX_U_SERIAL_PORTS 4 diff --git a/drivers/usb/gadget/functions.c b/drivers/usb/gadget/functions.c index 9b08938a33..7a57915007 100644 --- a/drivers/usb/gadget/functions.c +++ b/drivers/usb/gadget/functions.c @@ -2,7 +2,7 @@ #include <common.h> #include <linux/err.h> -#include <usb/composite.h> +#include <linux/usb/composite.h> static LIST_HEAD(func_list); diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h deleted file mode 100644 index 78e0601027..0000000000 --- a/drivers/usb/gadget/gadget_chips.h +++ /dev/null @@ -1,56 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * USB device controllers have lots of quirks. Use these macros in - * gadget drivers or other code that needs to deal with them, and which - * autoconfigures instead of using early binding to the hardware. - * - * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by - * some config file that gets updated as new hardware is supported. - * (And avoiding all runtime comparisons in typical one-choice configs!) - * - * NOTE: some of these controller drivers may not be available yet. - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. - */ - -#ifndef __GADGET_CHIPS_H -#define __GADGET_CHIPS_H - -#include <usb/gadget.h> - -/* - * NOTICE: the entries below are alphabetical and should be kept - * that way. - * - * Always be sure to add new entries to the correct position or - * accept the bashing later. - * - * If you have forgotten the alphabetical order let VIM/EMACS - * do that for you. - */ -#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) -#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) -#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) -#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) -#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) -#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) - -/** - * gadget_supports_altsettings - return true if altsettings work - * @gadget: the gadget in question - */ -static inline bool gadget_supports_altsettings(struct usb_gadget *gadget) -{ - /* PXA 21x/25x/26x has no altsettings at all */ - if (gadget_is_pxa(gadget)) - return false; - - /* PXA 27x and 3xx have *broken* altsetting support */ - if (gadget_is_pxa27x(gadget)) - return false; - - /* Everything else is *presumably* fine ... */ - return true; -} - -#endif /* __GADGET_CHIPS_H */ diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile new file mode 100644 index 0000000000..5d5382a673 --- /dev/null +++ b/drivers/usb/gadget/legacy/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +ccflags-y := -I$(srctree)/drivers/usb/gadget/ +ccflags-y += -I$(srctree)/drivers/usb/gadget/udc/ +ccflags-y += -I$(srctree)/drivers/usb/gadget/function/ + +obj-$(CONFIG_USB_GADGET_SERIAL) += serial.o +obj-$(CONFIG_USB_GADGET) += multi.o diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/legacy/multi.c index 6225e9a313..7046a529b1 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -9,7 +9,7 @@ */ #include <common.h> -#include <usb/gadget-multi.h> +#include <linux/usb/gadget-multi.h> #include <linux/err.h> #include "u_serial.h" @@ -275,7 +275,7 @@ static struct usb_composite_driver multi_driver = { .name = "g_multi", .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .bind = multi_bind, .unbind = multi_unbind, .needs_serial = 1, diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/legacy/serial.c index 0ef2665b69..46c41f6dea 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/legacy/serial.c @@ -11,14 +11,13 @@ #include <errno.h> #include <init.h> #include <linux/err.h> -#include <usb/ch9.h> -#include <usb/gadget.h> -#include <usb/composite.h> -#include <usb/usbserial.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> +#include <linux/usb/usbserial.h> #include <asm/byteorder.h> #include "u_serial.h" -#include "gadget_chips.h" /* Defines */ diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h new file mode 100644 index 0000000000..5d7d35c8cc --- /dev/null +++ b/drivers/usb/gadget/u_os_desc.h @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * u_os_desc.h + * + * Utility definitions for "OS Descriptors" support + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> + */ + +#ifndef __U_OS_DESC_H__ +#define __U_OS_DESC_H__ + +#include <asm/unaligned.h> +#include <linux/nls.h> + +#define USB_EXT_PROP_DW_SIZE 0 +#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE 4 +#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH 8 +#define USB_EXT_PROP_B_PROPERTY_NAME 10 +#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH 10 +#define USB_EXT_PROP_B_PROPERTY_DATA 14 + +#define USB_EXT_PROP_RESERVED 0 +#define USB_EXT_PROP_UNICODE 1 +#define USB_EXT_PROP_UNICODE_ENV 2 +#define USB_EXT_PROP_BINARY 3 +#define USB_EXT_PROP_LE32 4 +#define USB_EXT_PROP_BE32 5 +#define USB_EXT_PROP_UNICODE_LINK 6 +#define USB_EXT_PROP_UNICODE_MULTI 7 + +static inline u8 *__usb_ext_prop_ptr(u8 *buf, size_t offset) +{ + return buf + offset; +} + +static inline u8 *usb_ext_prop_size_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_SIZE); +} + +static inline u8 *usb_ext_prop_type_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_PROPERTY_DATA_TYPE); +} + +static inline u8 *usb_ext_prop_name_len_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_W_PROPERTY_NAME_LENGTH); +} + +static inline u8 *usb_ext_prop_name_ptr(u8 *buf) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_NAME); +} + +static inline u8 *usb_ext_prop_data_len_ptr(u8 *buf, size_t off) +{ + return __usb_ext_prop_ptr(buf, + USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + off); +} + +static inline u8 *usb_ext_prop_data_ptr(u8 *buf, size_t off) +{ + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_DATA + off); +} + +static inline void usb_ext_prop_put_size(u8 *buf, int dw_size) +{ + put_unaligned_le32(dw_size, usb_ext_prop_size_ptr(buf)); +} + +static inline void usb_ext_prop_put_type(u8 *buf, int type) +{ + put_unaligned_le32(type, usb_ext_prop_type_ptr(buf)); +} + +static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl) +{ + int result; + + put_unaligned_le16(pnl, usb_ext_prop_name_len_ptr(buf)); + result = utf8s_to_utf16s(name, strlen(name), UTF16_LITTLE_ENDIAN, + (wchar_t *) usb_ext_prop_name_ptr(buf), pnl - 2); + if (result < 0) + return result; + + put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl - 2]); + + return pnl; +} + +static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const u8 *data, + int data_len) +{ + put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl)); + memcpy(usb_ext_prop_data_ptr(buf, pnl), data, data_len); +} + +static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string, + int data_len) +{ + int result; + put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl)); + result = utf8s_to_utf16s(string, data_len >> 1, UTF16_LITTLE_ENDIAN, + (wchar_t *) usb_ext_prop_data_ptr(buf, pnl), + data_len - 2); + if (result < 0) + return result; + + put_unaligned_le16(0, + &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len - 2]); + + return data_len; +} + +#endif /* __U_OS_DESC_H__ */ diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c deleted file mode 100644 index 30b17dbc5a..0000000000 --- a/drivers/usb/gadget/udc-core.c +++ /dev/null @@ -1,355 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/** - * udc.c - Core UDC Framework - * - * Copyright (C) 2010 Texas Instruments - * Author: Felipe Balbi <balbi@ti.com> - */ -#define VERBOSE_DEBUG -#include <common.h> -#include <driver.h> -#include <init.h> -#include <poller.h> -#include <usb/ch9.h> -#include <usb/gadget.h> - -/** - * struct usb_udc - describes one usb device controller - * @driver - the gadget driver pointer. For use by the class code - * @dev - the child device to the actual controller - * @gadget - the gadget. For use by the class code - * @list - for use by the udc class driver - * - * This represents the internal data structure which is used by the UDC-class - * to hold information about udc driver and gadget together. - */ -struct usb_udc { - struct usb_gadget_driver *driver; - struct usb_gadget *gadget; - struct device dev; - struct list_head list; - struct poller_struct poller; -}; - -static LIST_HEAD(udc_list); - -/* ------------------------------------------------------------------------- */ - -void usb_gadget_set_state(struct usb_gadget *gadget, - enum usb_device_state state) -{ - gadget->state = state; -} -EXPORT_SYMBOL_GPL(usb_gadget_set_state); - -/** - * usb_gadget_udc_reset - notifies the udc core that bus reset occurs - * @gadget: The gadget which bus reset occurs - * @driver: The gadget driver we want to notify - * - * If the udc driver has bus reset handler, it needs to call this when the bus - * reset occurs, it notifies the gadget driver that the bus reset occurs as - * well as updates gadget state. - */ -void usb_gadget_udc_reset(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - usb_gadget_set_state(gadget, USB_STATE_DEFAULT); -} -EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); -/* ------------------------------------------------------------------------- */ - -/** - * usb_gadget_udc_start - tells usb device controller to start up - * @gadget: The gadget we want to get started - * @driver: The driver we want to bind to @gadget - * - * This call is issued by the UDC Class driver when it's about - * to register a gadget driver to the device controller, before - * calling gadget driver's bind() method. - * - * It allows the controller to be powered off until strictly - * necessary to have it powered on. - * - * Returns zero on success, else negative errno. - */ -static inline int usb_gadget_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - return gadget->ops->udc_start(gadget, driver); -} - -/** - * usb_gadget_udc_stop - tells usb device controller we don't need it anymore - * @gadget: The device we want to stop activity - * @driver: The driver to unbind from @gadget - * - * This call is issued by the UDC Class driver after calling - * gadget driver's unbind() method. - * - * The details are implementation specific, but it can go as - * far as powering off UDC completely and disable its data - * line pullups. - */ -static inline void usb_gadget_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - gadget->ops->udc_stop(gadget, driver); -} - -int usb_gadget_poll(void) -{ - struct usb_udc *udc; - - list_for_each_entry(udc, &udc_list, list) { - if (udc->gadget->ops->udc_poll) - udc->gadget->ops->udc_poll(udc->gadget); - } - - return 0; -} - -/** - * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller driver's - * device. - * @gadget: the gadget to be added to the list. - * @release: a gadget release function. - * - * Returns zero on success, negative errno otherwise. - */ -int usb_add_gadget_udc_release(struct device *parent, - struct usb_gadget *gadget, - void (*release)(struct device *dev)) -{ - struct usb_udc *udc; - int ret = -ENOMEM; - - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (!udc) - goto err1; - - dev_set_name(&gadget->dev, "usbgadget"); - gadget->dev.id = DEVICE_ID_SINGLE; - gadget->dev.parent = parent; - - ret = register_device(&gadget->dev); - if (ret) - goto err2; - - dev_add_param_uint32(&gadget->dev, "product", NULL, NULL, - &gadget->product_id, "0x%04x", NULL); - dev_add_param_uint32(&gadget->dev, "vendor", NULL, NULL, - &gadget->vendor_id, "0x%04x", NULL); - gadget->manufacturer = xstrdup("barebox"); - dev_add_param_string(&gadget->dev, "manufacturer", NULL, NULL, - &gadget->manufacturer, NULL); - gadget->productname = xstrdup(barebox_get_model()); - dev_add_param_string(&gadget->dev, "productname", NULL, NULL, - &gadget->productname, NULL); - gadget->serialnumber = xstrdup(""); - dev_add_param_string(&gadget->dev, "serialnumber", NULL, NULL, - &gadget->serialnumber, NULL); - - dev_set_name(&udc->dev, "udc"); - udc->dev.id = DEVICE_ID_DYNAMIC; - - udc->gadget = gadget; - - list_add_tail(&udc->list, &udc_list); - - register_device(&udc->dev); - - usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); - - return 0; -err2: - kfree(udc); - -err1: - return ret; -} -EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); - -/** - * usb_add_gadget_udc - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller - * driver's device. - * @gadget: the gadget to be added to the list - * - * Returns zero on success, negative errno otherwise. - */ -int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) -{ - return usb_add_gadget_udc_release(parent, gadget, NULL); -} -EXPORT_SYMBOL_GPL(usb_add_gadget_udc); - -static void usb_gadget_remove_driver(struct usb_udc *udc) -{ - dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", - udc->gadget->name); - - if (udc->gadget->ops->udc_poll) - poller_unregister(&udc->poller); - - usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); - udc->driver->unbind(udc->gadget); - usb_gadget_udc_stop(udc->gadget, NULL); - - udc->driver = NULL; - udc->dev.driver = NULL; - udc->gadget->dev.driver = NULL; -} - -/** - * usb_del_gadget_udc - deletes @udc from udc_list - * @gadget: the gadget to be removed. - * - * This, will call usb_gadget_unregister_driver() if - * the @udc is still busy. - */ -void usb_del_gadget_udc(struct usb_gadget *gadget) -{ - struct usb_udc *udc = NULL; - - list_for_each_entry(udc, &udc_list, list) - if (udc->gadget == gadget) - goto found; - - dev_err(gadget->dev.parent, "gadget not registered.\n"); - - return; - -found: - dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); - - list_del(&udc->list); - - if (udc->driver) - usb_gadget_remove_driver(udc); - - unregister_device(&udc->dev); - unregister_device(&gadget->dev); -} -EXPORT_SYMBOL_GPL(usb_del_gadget_udc); - -/* ------------------------------------------------------------------------- */ - -static void udc_poll_driver(struct poller_struct *poller) -{ - struct usb_udc *udc = container_of(poller, struct usb_udc, poller); - - udc->gadget->ops->udc_poll(udc->gadget); -} - -static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) -{ - int ret; - - dev_dbg(&udc->dev, "registering UDC driver [%s]\n", - driver->function); - - udc->driver = driver; - udc->dev.driver = &driver->driver; - udc->gadget->dev.driver = &driver->driver; - - if (udc->gadget->ops->udc_poll) { - udc->poller.func = udc_poll_driver; - ret = poller_register(&udc->poller, dev_name(&udc->dev)); - if (ret) - return ret; - } - - ret = driver->bind(udc->gadget, driver); - if (ret) - goto err1; - - ret = usb_gadget_udc_start(udc->gadget, driver); - if (ret) { - driver->unbind(udc->gadget); - goto err1; - } - usb_gadget_connect(udc->gadget); - - return 0; -err1: - if (udc->gadget->ops->udc_poll) - poller_unregister(&udc->poller); - - if (ret != -EISNAM) - dev_err(&udc->dev, "failed to start %s: %d\n", - udc->driver->function, ret); - udc->driver = NULL; - udc->dev.driver = NULL; - udc->gadget->dev.driver = NULL; - return ret; -} - -int udc_attach_driver(const char *name, struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - list_for_each_entry(udc, &udc_list, list) { - ret = strcmp(name, dev_name(&udc->dev)); - if (!ret) - break; - } - if (ret) { - ret = -ENODEV; - goto out; - } - if (udc->driver) { - ret = -EBUSY; - goto out; - } - ret = udc_bind_to_driver(udc, driver); -out: - return ret; -} -EXPORT_SYMBOL_GPL(udc_attach_driver); - -int usb_gadget_probe_driver(struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret; - - if (!driver || !driver->bind || !driver->setup) - return -EINVAL; - - list_for_each_entry(udc, &udc_list, list) { - /* For now we take the first one */ - if (!udc->driver) - goto found; - } - - pr_debug("couldn't find an available UDC\n"); - - return -ENODEV; -found: - ret = udc_bind_to_driver(udc, driver); - - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - if (!driver || !driver->unbind) - return -EINVAL; - - list_for_each_entry(udc, &udc_list, list) - if (udc->driver == driver) { - usb_gadget_remove_driver(udc); - ret = 0; - break; - } - - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile new file mode 100644 index 0000000000..f52660fcf5 --- /dev/null +++ b/drivers/usb/gadget/udc/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_USB_GADGET) += core.o + +obj-$(CONFIG_USB_GADGET_DRIVER_ARC) += fsl_udc.o +pbl-$(CONFIG_USB_GADGET_DRIVER_ARC_PBL) += fsl_udc_pbl.o +obj-$(CONFIG_USB_GADGET_DRIVER_AT91) += at91_udc.o +obj-$(CONFIG_USB_GADGET_DRIVER_PXA27X) += pxa27x_udc.o diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index fc5f24021d..654362d69e 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -16,8 +16,8 @@ #include <gpio.h> #include <io.h> #include <clock.h> -#include <usb/ch9.h> -#include <usb/gadget.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> #include <of_gpio.h> #include <linux/list.h> @@ -1240,7 +1240,7 @@ static int at91_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *d return 0; } -static int at91_udc_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver) +static int at91_udc_stop(struct usb_gadget *gadget) { struct at91_udc *udc = container_of(gadget, struct at91_udc, gadget); @@ -1248,7 +1248,8 @@ static int at91_udc_stop(struct usb_gadget *gadget, struct usb_gadget_driver *dr at91_udp_write(udc, AT91_UDP_IDR, ~0); udc->driver = NULL; - DBG(udc, "unbound from %s\n", driver->function); + DBG(udc, "unbound\n"); + return 0; } diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h index cecaa5b52e..cecaa5b52e 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/udc/at91_udc.h diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c new file mode 100644 index 0000000000..b58498680a --- /dev/null +++ b/drivers/usb/gadget/udc/core.c @@ -0,0 +1,1517 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * udc.c - Core UDC Framework + * + * Copyright (C) 2010 Texas Instruments + * Author: Felipe Balbi <balbi@ti.com> + */ + +#define pr_fmt(fmt) "UDC core: " fmt + +#include <common.h> +#include <dma.h> +#include <linux/usb/gadget.h> +#include <linux/usb/ch9.h> + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/idr.h> +#include <linux/err.h> + +static int gadget_id_numbers; + +static struct bus_type gadget_bus_type; + +/** + * struct usb_udc - describes one usb device controller + * @driver: the gadget driver pointer. For use by the class code + * @dev: the child device to the actual controller + * @gadget: the gadget. For use by the class code + * @list: for use by the udc class driver + * @vbus: for udcs who care about vbus status, this value is real vbus status; + * for udcs who do not care about vbus status, this value is always true + * @started: the UDC's started state. True if the UDC had started. + * + * This represents the internal data structure which is used by the UDC-class + * to hold information about udc driver and gadget together. + */ +struct usb_udc { + struct usb_gadget_driver *driver; + struct usb_gadget *gadget; + struct device dev; + struct list_head list; + bool vbus; + bool started; + struct poller_struct poller; +}; + +static LIST_HEAD(udc_list); + +/* Protects udc_list, udc->driver, driver->is_bound, and related calls */ +static DEFINE_MUTEX(udc_lock); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint + * @ep:the endpoint being configured + * @maxpacket_limit:value of maximum packet size limit + * + * This function should be used only in UDC drivers to initialize endpoint + * (usually in probe function). + */ +void usb_ep_set_maxpacket_limit(struct usb_ep *ep, + unsigned maxpacket_limit) +{ + ep->maxpacket_limit = maxpacket_limit; + ep->maxpacket = maxpacket_limit; +} +EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * + * When configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB host".) + * + * This routine may be called in an atomic (interrupt) context. + * + * returns zero, or a negative error code. + */ +int usb_ep_enable(struct usb_ep *ep) +{ + int ret = 0; + + if (ep->enabled) + goto out; + + /* UDC drivers can't handle endpoints with maxpacket size 0 */ + if (usb_endpoint_maxp(ep->desc) == 0) { + /* + * We should log an error message here, but we can't call + * dev_err() because there's no way to find the gadget + * given only ep. + */ + ret = -EINVAL; + goto out; + } + + ret = ep->ops->enable(ep, ep->desc); + if (ret) + goto out; + + ep->enabled = true; + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_enable); + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * This routine may be called in an atomic (interrupt) context. + * + * returns zero, or a negative error code. + */ +int usb_ep_disable(struct usb_ep *ep) +{ + int ret = 0; + + if (!ep->enabled) + goto out; + + ret = ep->ops->disable(ep); + if (ret) + goto out; + + ep->enabled = false; + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_disable); + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +struct usb_request *usb_ep_alloc_request(struct usb_ep *ep) +{ + struct usb_request *req = NULL; + + req = ep->ops->alloc_request(ep); + + return req; +} +EXPORT_SYMBOL_GPL(usb_ep_alloc_request); + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +void usb_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + ep->ops->free_request(ep, req); +} +EXPORT_SYMBOL_GPL(usb_ep_free_request); + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transferring data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. Depending on the controller, + * it may not be possible to trigger a status-stage protocol stall when the + * data stage is over, that is, from within the response's completion + * routine. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Note that @req's ->complete() callback must never be called from + * within usb_ep_queue() as that can create deadlock situations. + * + * This routine may be called in interrupt context. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + * + * If and only if @req is successfully queued (the return value is zero), + * @req->complete() will be called exactly once, when the Gadget core and + * UDC are finished with the request. When the completion function is called, + * control of the request is returned to the device driver which submitted it. + * The completion handler may then immediately free or reuse @req. + */ +int usb_ep_queue(struct usb_ep *ep, + struct usb_request *req) +{ + int ret = 0; + + if (WARN_ON_ONCE(!ep->enabled && ep->address)) { + ret = -ESHUTDOWN; + goto out; + } + + ret = ep->ops->queue(ep, req); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_queue); + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * If the request is still active on the endpoint, it is dequeued and + * eventually its completion routine is called (with status -ECONNRESET); + * else a negative error code is returned. This routine is asynchronous, + * that is, it may return before the completion routine runs. + * + * Note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. Such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + * + * This routine may be called in interrupt context. + */ +int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + int ret; + + ret = ep->ops->dequeue(ep, req); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_dequeue); + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * This routine may be called in interrupt context. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +int usb_ep_set_halt(struct usb_ep *ep) +{ + int ret; + + ret = ep->ops->set_halt(ep, 1); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_set_halt); + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * This routine may be called in interrupt context. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +int usb_ep_clear_halt(struct usb_ep *ep) +{ + int ret; + + ret = ep->ops->set_halt(ep, 0); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_clear_halt); + +/** + * usb_ep_set_wedge - sets the halt feature and ignores clear requests + * @ep: the endpoint being wedged + * + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) + * requests. If the gadget driver clears the halt status, it will + * automatically unwedge the endpoint. + * + * This routine may be called in interrupt context. + * + * Returns zero on success, else negative errno. + */ +int usb_ep_set_wedge(struct usb_ep *ep) +{ + int ret; + + if (ep->ops->set_wedge) + ret = ep->ops->set_wedge(ep); + else + ret = ep->ops->set_halt(ep, 1); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_set_wedge); + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This routine may be called in interrupt context. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +int usb_ep_fifo_status(struct usb_ep *ep) +{ + int ret; + + if (ep->ops->fifo_status) + ret = ep->ops->fifo_status(ep); + else + ret = -EOPNOTSUPP; + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_status); + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + * + * This routine may be called in interrupt context. + */ +void usb_ep_fifo_flush(struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush(ep); +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_flush); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +int usb_gadget_frame_number(struct usb_gadget *gadget) +{ + int ret; + + ret = gadget->ops->get_frame(gadget); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_frame_number); + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +int usb_gadget_wakeup(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->wakeup(gadget); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_wakeup); + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_selfpowered(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->set_selfpowered) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_selfpowered(gadget, 1); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered); + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->set_selfpowered) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_selfpowered(gadget, 0); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered); + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->vbus_session) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_session(gadget, 1); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect); + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + int ret = 0; + + if (!gadget->ops->vbus_draw) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_draw(gadget, mA); + if (!ret) + gadget->mA = mA; + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw); + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->vbus_session) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_session(gadget, 0); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_connect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->pullup) { + ret = -EOPNOTSUPP; + goto out; + } + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will be connected automatically after activation. + */ + gadget->connected = true; + goto out; + } + + ret = gadget->ops->pullup(gadget, 1); + if (!ret) + gadget->connected = 1; + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_connect); + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * Following a successful disconnect, invoke the ->disconnect() callback + * for the current gadget driver so that UDC drivers don't need to. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_disconnect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->pullup) { + ret = -EOPNOTSUPP; + goto out; + } + + if (!gadget->connected) + goto out; + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will stay disconnected after activation. + */ + gadget->connected = false; + goto out; + } + + ret = gadget->ops->pullup(gadget, 0); + if (!ret) + gadget->connected = 0; + + mutex_lock(&udc_lock); + if (gadget->udc->driver) + gadget->udc->driver->disconnect(gadget); + mutex_unlock(&udc_lock); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_disconnect); + +/** + * usb_gadget_deactivate - deactivate function which is not ready to work + * @gadget: the peripheral being deactivated + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_activate() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_deactivate(struct usb_gadget *gadget) +{ + int ret = 0; + + if (gadget->deactivated) + goto out; + + if (gadget->connected) { + ret = usb_gadget_disconnect(gadget); + if (ret) + goto out; + + /* + * If gadget was being connected before deactivation, we want + * to reconnect it in usb_gadget_activate(). + */ + gadget->connected = true; + } + gadget->deactivated = true; + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_deactivate); + +/** + * usb_gadget_activate - activate function which is not ready to work + * @gadget: the peripheral being activated + * + * This routine activates gadget which was previously deactivated with + * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_activate(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->deactivated) + goto out; + + gadget->deactivated = false; + + /* + * If gadget has been connected before deactivation, or became connected + * while it was being deactivated, we call usb_gadget_connect(). + */ + if (gadget->connected) + ret = usb_gadget_connect(gadget); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_activate); + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_HAS_DMA + +int usb_gadget_map_request_by_dev(struct device *dev, + struct usb_request *req, int is_in) +{ + if (req->length == 0) + return 0; + + req->dma = dma_map_single(dev, req->buf, req->length, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + if (dma_mapping_error(dev, req->dma)) { + dev_err(dev, "failed to map buffer\n"); + return -EFAULT; + } + + req->dma_mapped = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); + +int usb_gadget_map_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); +} +EXPORT_SYMBOL_GPL(usb_gadget_map_request); + +void usb_gadget_unmap_request_by_dev(struct device *dev, + struct usb_request *req, int is_in) +{ + if (req->length == 0) + return; + + if (req->dma_mapped) { + dma_unmap_single(dev, req->dma, req->length, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->dma_mapped = 0; + } +} +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); + +void usb_gadget_unmap_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); +} +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); + +#endif /* CONFIG_HAS_DMA */ + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_giveback_request - give the request back to the gadget layer + * @ep: the endpoint to be used with with the request + * @req: the request being given back + * + * This is called by device controller drivers in order to return the + * completed request back to the gadget layer. + */ +void usb_gadget_giveback_request(struct usb_ep *ep, + struct usb_request *req) +{ + req->complete(ep, req); +} +EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); + +/* ------------------------------------------------------------------------- */ + +/** + * gadget_find_ep_by_name - returns ep whose name is the same as sting passed + * in second parameter or NULL if searched endpoint not found + * @g: controller to check for quirk + * @name: name of searched endpoint + */ +struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name) +{ + struct usb_ep *ep; + + gadget_for_each_ep(ep, g) { + if (!strcmp(ep->name, name)) + return ep; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(gadget_find_ep_by_name); + +/* ------------------------------------------------------------------------- */ + +int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + struct usb_ep *ep, struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + u8 type; + u16 max; + int num_req_streams = 0; + + /* endpoint already claimed? */ + if (ep->claimed) + return 0; + + type = usb_endpoint_type(desc); + max = usb_endpoint_maxp(desc); + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return 0; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return 0; + + if (max > ep->maxpacket_limit) + return 0; + + /* "high bandwidth" works only at high speed */ + if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp_mult(desc) > 1) + return 0; + + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + /* only support ep0 for portable CONTROL traffic */ + return 0; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return 0; + /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return 0; + if (ep_comp && gadget_is_superspeed(gadget)) { + /* Get the number of required streams from the + * EP companion descriptor and see if the EP + * matches it + */ + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } + break; + case USB_ENDPOINT_XFER_INT: + /* Bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if (!ep->caps.type_int && !ep->caps.type_bulk) + return 0; + /* INT: limit 64 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 64) + return 0; + break; + } + + return 1; +} +EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); + +/** + * usb_gadget_check_config - checks if the UDC can support the binded + * configuration + * @gadget: controller to check the USB configuration + * + * Ensure that a UDC is able to support the requested resources by a + * configuration, and that there are no resource limitations, such as + * internal memory allocated to all requested endpoints. + * + * Returns zero on success, else a negative errno. + */ +int usb_gadget_check_config(struct usb_gadget *gadget) +{ + if (gadget->ops->check_config) + return gadget->ops->check_config(gadget); + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_check_config); + +/* ------------------------------------------------------------------------- */ + +void usb_gadget_set_state(struct usb_gadget *gadget, + enum usb_device_state state) +{ + gadget->state = state; +} +EXPORT_SYMBOL_GPL(usb_gadget_set_state); + +/* ------------------------------------------------------------------------- */ + +static void usb_udc_connect_control(struct usb_udc *udc) +{ + if (udc->vbus) + usb_gadget_connect(udc->gadget); + else + usb_gadget_disconnect(udc->gadget); +} + +/** + * usb_udc_vbus_handler - updates the udc core vbus status, and try to + * connect or disconnect gadget + * @gadget: The gadget which vbus change occurs + * @status: The vbus status + * + * The udc driver calls it when it wants to connect or disconnect gadget + * according to vbus status. + */ +void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) +{ + struct usb_udc *udc = gadget->udc; + + if (udc) { + udc->vbus = status; + usb_udc_connect_control(udc); + } +} +EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); + +/** + * usb_gadget_udc_reset - notifies the udc core that bus reset occurs + * @gadget: The gadget which bus reset occurs + * @driver: The gadget driver we want to notify + * + * If the udc driver has bus reset handler, it needs to call this when the bus + * reset occurs, it notifies the gadget driver that the bus reset occurs as + * well as updates gadget state. + */ +void usb_gadget_udc_reset(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + driver->reset(gadget); + usb_gadget_set_state(gadget, USB_STATE_DEFAULT); +} +EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); + +/** + * usb_gadget_udc_start - tells usb device controller to start up + * @udc: The UDC to be started + * + * This call is issued by the UDC Class driver when it's about + * to register a gadget driver to the device controller, before + * calling gadget driver's bind() method. + * + * It allows the controller to be powered off until strictly + * necessary to have it powered on. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_udc_start(struct usb_udc *udc) +{ + int ret; + + if (udc->started) { + dev_err(&udc->dev, "UDC had already started\n"); + return -EBUSY; + } + + ret = udc->gadget->ops->udc_start(udc->gadget, udc->driver); + if (!ret) + udc->started = true; + + return ret; +} + +/** + * usb_gadget_udc_stop - tells usb device controller we don't need it anymore + * @udc: The UDC to be stopped + * + * This call is issued by the UDC Class driver after calling + * gadget driver's unbind() method. + * + * The details are implementation specific, but it can go as + * far as powering off UDC completely and disable its data + * line pullups. + */ +static inline void usb_gadget_udc_stop(struct usb_udc *udc) +{ + if (!udc->started) { + dev_err(&udc->dev, "UDC had already stopped\n"); + return; + } + + udc->gadget->ops->udc_stop(udc->gadget); + udc->started = false; +} + +/** + * usb_gadget_udc_set_speed - tells usb device controller speed supported by + * current driver + * @udc: The device we want to set maximum speed + * @speed: The maximum speed to allowed to run + * + * This call is issued by the UDC Class driver before calling + * usb_gadget_udc_start() in order to make sure that we don't try to + * connect on speeds the gadget driver doesn't support. + */ +static inline void usb_gadget_udc_set_speed(struct usb_udc *udc, + enum usb_device_speed speed) +{ + struct usb_gadget *gadget = udc->gadget; + enum usb_device_speed s; + + if (speed == USB_SPEED_UNKNOWN) + s = gadget->max_speed; + else + s = min(speed, gadget->max_speed); + + if (s == USB_SPEED_SUPER_PLUS && gadget->ops->udc_set_ssp_rate) + gadget->ops->udc_set_ssp_rate(gadget, gadget->max_ssp_rate); + else if (gadget->ops->udc_set_speed) + gadget->ops->udc_set_speed(gadget, s); +} + +/** + * usb_gadget_enable_async_callbacks - tell usb device controller to enable asynchronous callbacks + * @udc: The UDC which should enable async callbacks + * + * This routine is used when binding gadget drivers. It undoes the effect + * of usb_gadget_disable_async_callbacks(); the UDC driver should enable IRQs + * (if necessary) and resume issuing callbacks. + * + * This routine will always be called in process context. + */ +static inline void usb_gadget_enable_async_callbacks(struct usb_udc *udc) +{ + struct usb_gadget *gadget = udc->gadget; + + if (gadget->ops->udc_async_callbacks) + gadget->ops->udc_async_callbacks(gadget, true); +} + +/** + * usb_gadget_disable_async_callbacks - tell usb device controller to disable asynchronous callbacks + * @udc: The UDC which should disable async callbacks + * + * This routine is used when unbinding gadget drivers. It prevents a race: + * The UDC driver doesn't know when the gadget driver's ->unbind callback + * runs, so unless it is told to disable asynchronous callbacks, it might + * issue a callback (such as ->disconnect) after the unbind has completed. + * + * After this function runs, the UDC driver must suppress all ->suspend, + * ->resume, ->disconnect, ->reset, and ->setup callbacks to the gadget driver + * until async callbacks are again enabled. A simple-minded but effective + * way to accomplish this is to tell the UDC hardware not to generate any + * more IRQs. + * + * Request completion callbacks must still be issued. However, it's okay + * to defer them until the request is cancelled, since the pull-up will be + * turned off during the time period when async callbacks are disabled. + * + * This routine will always be called in process context. + */ +static inline void usb_gadget_disable_async_callbacks(struct usb_udc *udc) +{ + struct usb_gadget *gadget = udc->gadget; + + if (gadget->ops->udc_async_callbacks) + gadget->ops->udc_async_callbacks(gadget, false); +} + +/** + * usb_initialize_gadget - initialize a gadget and its embedded struct device + * @parent: the parent device to this udc. Usually the controller driver's + * device. + * @gadget: the gadget to be initialized. + * @release: a gadget release function. + */ +void usb_initialize_gadget(struct device *parent, struct usb_gadget *gadget, + void (*release)(struct device *dev)) +{ + gadget->dev.parent = parent; + gadget->dev.bus = &gadget_bus_type; +} +EXPORT_SYMBOL_GPL(usb_initialize_gadget); + +/** + * usb_add_gadget - adds a new gadget to the udc class driver list + * @gadget: the gadget to be added to the list. + * + * Returns zero on success, negative errno otherwise. + * Does not do a final usb_put_gadget() if an error occurs. + */ +int usb_add_gadget(struct usb_gadget *gadget) +{ + struct usb_udc *udc; + int ret = -ENOMEM; + + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + goto error; + + udc->dev.parent = gadget->dev.parent; + ret = dev_set_name(&udc->dev, "usbgadget"); + if (ret) + goto err_put_udc; + + udc->gadget = gadget; + gadget->udc = udc; + + udc->started = false; + + mutex_lock(&udc_lock); + list_add_tail(&udc->list, &udc_list); + mutex_unlock(&udc_lock); + + ret = register_device(&udc->dev); + if (ret) + goto err_unlist_udc; + + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + udc->vbus = true; + + ret = gadget_id_numbers++; + if (ret < 0) + goto err_del_udc; + gadget->id_number = ret; + dev_set_name(&gadget->dev, "gadget"); + gadget->dev.id = ret; + + ret = register_device(&gadget->dev); + if (ret) + goto err_free_id; + + dev_add_param_uint32(&gadget->dev, "product", NULL, NULL, + &gadget->product_id, "0x%04x", NULL); + dev_add_param_uint32(&gadget->dev, "vendor", NULL, NULL, + &gadget->vendor_id, "0x%04x", NULL); + gadget->manufacturer = xstrdup("barebox"); + dev_add_param_string(&gadget->dev, "manufacturer", NULL, NULL, + &gadget->manufacturer, NULL); + gadget->productname = xstrdup(barebox_get_model()); + dev_add_param_string(&gadget->dev, "productname", NULL, NULL, + &gadget->productname, NULL); + gadget->serialnumber = xstrdup(""); + dev_add_param_string(&gadget->dev, "serialnumber", NULL, NULL, + &gadget->serialnumber, NULL); + + return 0; + + err_free_id: + err_del_udc: + unregister_device(&udc->dev); + + err_unlist_udc: + mutex_lock(&udc_lock); + list_del(&udc->list); + mutex_unlock(&udc_lock); + + err_put_udc: + error: + return ret; +} +EXPORT_SYMBOL_GPL(usb_add_gadget); + +int usb_gadget_poll(void) +{ + struct usb_udc *udc; + + list_for_each_entry(udc, &udc_list, list) { + if (udc->gadget->ops->udc_poll) + udc->gadget->ops->udc_poll(udc->gadget); + } + + return 0; +} + +/** + * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller driver's + * device. + * @gadget: the gadget to be added to the list. + * @release: a gadget release function. + * + * Returns zero on success, negative errno otherwise. + * Calls the gadget release function in the latter case. + */ +int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, + void (*release)(struct device *dev)) +{ + int ret; + + usb_initialize_gadget(parent, gadget, release); + ret = usb_add_gadget(gadget); + if (ret) + usb_put_gadget(gadget); + return ret; +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); + +/** + * usb_get_gadget_udc_name - get the name of the first UDC controller + * This functions returns the name of the first UDC controller in the system. + * Please note that this interface is usefull only for legacy drivers which + * assume that there is only one UDC controller in the system and they need to + * get its name before initialization. There is no guarantee that the UDC + * of the returned name will be still available, when gadget driver registers + * itself. + * + * Returns pointer to string with UDC controller name on success, NULL + * otherwise. Caller should kfree() returned string. + */ +char *usb_get_gadget_udc_name(void) +{ + struct usb_udc *udc; + char *name = NULL; + + /* For now we take the first available UDC */ + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) { + if (!udc->driver) { + name = kstrdup(udc->gadget->name, GFP_KERNEL); + break; + } + } + mutex_unlock(&udc_lock); + return name; +} +EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name); + +/** + * usb_add_gadget_udc - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller + * driver's device. + * @gadget: the gadget to be added to the list + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) +{ + return usb_add_gadget_udc_release(parent, gadget, NULL); +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc); + +/** + * usb_del_gadget - deletes a gadget and unregisters its udc + * @gadget: the gadget to be deleted. + * + * This will unbind @gadget, if it is bound. + * It will not do a final usb_put_gadget(). + */ +void usb_del_gadget(struct usb_gadget *gadget) +{ + struct usb_udc *udc = gadget->udc; + + if (!udc) + return; + + dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); + + mutex_lock(&udc_lock); + list_del(&udc->list); + mutex_unlock(&udc_lock); + + unregister_device(&gadget->dev); + unregister_device(&udc->dev); +} +EXPORT_SYMBOL_GPL(usb_del_gadget); + +/** + * usb_del_gadget_udc - unregisters a gadget + * @gadget: the gadget to be unregistered. + * + * Calls usb_del_gadget() and does a final usb_put_gadget(). + */ +void usb_del_gadget_udc(struct usb_gadget *gadget) +{ + usb_del_gadget(gadget); + usb_put_gadget(gadget); +} +EXPORT_SYMBOL_GPL(usb_del_gadget_udc); + +/* ------------------------------------------------------------------------- */ + +static int gadget_match_driver(struct device *dev, struct driver *drv) +{ + struct usb_gadget *gadget = dev_to_usb_gadget(dev); + struct usb_udc *udc = gadget->udc; + struct usb_gadget_driver *driver = container_of(drv, + struct usb_gadget_driver, driver); + + /* If the driver specifies a udc_name, it must match the UDC's name */ + if (driver->udc_name && + strcmp(driver->udc_name, dev_name(&udc->dev)) != 0) + return -1; + + /* If the driver is already bound to a gadget, it doesn't match */ + if (driver->is_bound) + return -1; + + /* Otherwise any gadget driver matches any UDC */ + return 0; +} + +static void udc_poll_driver(struct poller_struct *poller) +{ + struct usb_udc *udc = container_of(poller, struct usb_udc, poller); + + udc->gadget->ops->udc_poll(udc->gadget); +} + +static int gadget_bind_driver(struct device *dev) +{ + struct usb_gadget *gadget = dev_to_usb_gadget(dev); + struct usb_udc *udc = gadget->udc; + struct usb_gadget_driver *driver = container_of(dev->driver, + struct usb_gadget_driver, driver); + int ret = 0; + + mutex_lock(&udc_lock); + if (driver->is_bound) { + mutex_unlock(&udc_lock); + return -ENXIO; /* Driver binds to only one gadget */ + } + driver->is_bound = true; + udc->driver = driver; + mutex_unlock(&udc_lock); + + dev_dbg(&udc->dev, "binding gadget driver [%s]\n", driver->function); + + usb_gadget_udc_set_speed(udc, driver->max_speed); + + if (udc->gadget->ops->udc_poll) { + udc->poller.func = udc_poll_driver; + ret = poller_register(&udc->poller, dev_name(&udc->dev)); + if (ret) + return ret; + } + + ret = driver->bind(udc->gadget, driver); + if (ret) + goto err_bind; + + ret = usb_gadget_udc_start(udc); + if (ret) + goto err_start; + usb_gadget_enable_async_callbacks(udc); + usb_udc_connect_control(udc); + + return 0; + + err_start: + driver->unbind(udc->gadget); + + err_bind: + if (ret != -EISNAM) + dev_err(&udc->dev, "failed to start %s: %d\n", + driver->function, ret); + + if (udc->gadget->ops->udc_poll) + poller_unregister(&udc->poller); + + mutex_lock(&udc_lock); + udc->driver = NULL; + driver->is_bound = false; + mutex_unlock(&udc_lock); + + return ret; +} + +static void gadget_unbind_driver(struct device *dev) +{ + struct usb_gadget *gadget = dev_to_usb_gadget(dev); + struct usb_udc *udc = gadget->udc; + struct usb_gadget_driver *driver = udc->driver; + + dev_dbg(&udc->dev, "unbinding gadget driver [%s]\n", driver->function); + + if (udc->gadget->ops->udc_poll) + poller_unregister(&udc->poller); + + usb_gadget_disconnect(gadget); + usb_gadget_disable_async_callbacks(udc); + udc->driver->unbind(gadget); + usb_gadget_udc_stop(udc); + + mutex_lock(&udc_lock); + driver->is_bound = false; + udc->driver = NULL; + mutex_unlock(&udc_lock); +} + +/* ------------------------------------------------------------------------- */ + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + int ret; + + if (!driver || !driver->bind || !driver->setup) + return -EINVAL; + + driver->driver.bus = &gadget_bus_type; + ret = register_driver(&driver->driver); + if (ret) { + pr_warn("%s: driver registration failed: %d\n", + driver->function, ret); + return ret; + } + + mutex_lock(&udc_lock); + if (!driver->is_bound) { + if (driver->match_existing_only) { + pr_warn("%s: couldn't find an available UDC or it's busy\n", + driver->function); + ret = -EBUSY; + } else { + pr_info("%s: couldn't find an available UDC\n", + driver->function); + ret = 0; + } + } + mutex_unlock(&udc_lock); + + if (ret) + unregister_driver(&driver->driver); + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + if (!driver || !driver->unbind) + return -EINVAL; + + unregister_driver(&driver->driver); + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); + +/* ------------------------------------------------------------------------- */ + +static struct bus_type gadget_bus_type = { + .name = "gadget", + .probe = gadget_bind_driver, + .remove = gadget_unbind_driver, + .match = gadget_match_driver, +}; + +static int usb_udc_init(void) +{ + bus_register(&gadget_bus_type); + + return 0; +} +coredevice_initcall(usb_udc_init); diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/udc/fsl_udc.c index 2f2f4caebb..6a1d4304df 100644 --- a/drivers/usb/gadget/fsl_udc.c +++ b/drivers/usb/gadget/udc/fsl_udc.c @@ -4,9 +4,9 @@ #include <dma.h> #include <init.h> #include <clock.h> -#include <usb/ch9.h> -#include <usb/gadget.h> -#include <usb/fsl_usb2.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/fsl_usb2.h> #include <io.h> #include <asm/byteorder.h> #include <linux/err.h> @@ -1646,7 +1646,7 @@ static int fsl_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *dr } /* Disconnect from gadget driver */ -static int fsl_udc_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver) +static int fsl_udc_stop(struct usb_gadget *gadget) { struct fsl_udc *udc = to_fsl_udc(gadget); struct fsl_ep *loop_ep; diff --git a/drivers/usb/gadget/fsl_udc_pbl.c b/drivers/usb/gadget/udc/fsl_udc_pbl.c index 218d61db3c..6a4e0557fc 100644 --- a/drivers/usb/gadget/fsl_udc_pbl.c +++ b/drivers/usb/gadget/udc/fsl_udc_pbl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include <common.h> -#include <usb/ch9.h> +#include <linux/usb/ch9.h> #include <soc/fsl/fsl_udc.h> #include <mach/imx/imx8mm-regs.h> #include <mach/imx/imx6-regs.h> diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index e5e2ca2b7c..67b7e28de9 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -14,8 +14,8 @@ #include <gpio.h> #include <init.h> -#include <usb/ch9.h> -#include <usb/gadget.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> #include "pxa27x_udc.h" #include <mach/pxa/udc_pxa2xx.h> @@ -869,7 +869,7 @@ static int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active) } static int pxa_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); -static int pxa_udc_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver); +static int pxa_udc_stop(struct usb_gadget *gadget); static void pxa_udc_gadget_poll(struct usb_gadget *gadget); static const struct usb_gadget_ops pxa_udc_ops = { @@ -987,36 +987,26 @@ static int pxa_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *dr return 0; } -static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) +static void stop_activity(struct pxa_udc *udc) { int i; - /* don't disconnect drivers more than once */ - if (udc->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; udc->gadget.speed = USB_SPEED_UNKNOWN; for (i = 0; i < NR_USB_ENDPOINTS; i++) pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep); - - if (driver) - driver->disconnect(&udc->gadget); } -static int pxa_udc_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver) +static int pxa_udc_stop(struct usb_gadget *gadget) { struct pxa_udc *udc = the_controller; if (!udc) return -ENODEV; - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - stop_activity(udc, driver); + stop_activity(udc); udc_disable(udc); - driver->disconnect(&udc->gadget); - driver->unbind(&udc->gadget); udc->driver = NULL; /* @@ -1348,7 +1338,7 @@ static void irq_udc_reset(struct pxa_udc *udc) if ((udccr & UDCCR_UDA) == 0) { dev_dbg(udc->dev, "USB reset start\n"); - stop_activity(udc, udc->driver); + stop_activity(udc); } udc->gadget.speed = USB_SPEED_FULL; @@ -1369,7 +1359,7 @@ static void pxa_udc_gadget_poll(struct usb_gadget *gadget) if (should_enable_udc(udc)) udc_enable(udc); if (should_disable_udc(udc)) { - stop_activity(udc, udc->driver); + stop_activity(udc); udc_disable(udc); } diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h index 80a93cdcf9..80a93cdcf9 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/udc/pxa27x_udc.h diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 474c666e53..58eb28ad1a 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -6,8 +6,8 @@ #include <common.h> #include <errno.h> -#include <usb/ch9.h> -#include <usb/gadget.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> static inline void put_unaligned_le16(u16 val, u8 *p) { @@ -97,7 +97,7 @@ fail: * characters (which are also widely used in C strings). */ int -usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) +usb_gadget_get_string (const struct usb_gadget_strings *table, int id, u8 *buf) { struct usb_string *s; int len; diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 17bc896a8b..67ba7cbcc1 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -8,9 +8,9 @@ #include <linux/err.h> #include <driver.h> #include <init.h> -#include <usb/usb.h> -#include <usb/usb_defs.h> -#include <usb/ehci.h> +#include <linux/usb/usb.h> +#include <linux/usb/usb_defs.h> +#include <linux/usb/ehci.h> #include <errno.h> #include <io.h> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 53d06a46fa..a0b8b807b6 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -10,7 +10,7 @@ #include <common.h> #include <dma.h> #include <asm/byteorder.h> -#include <usb/usb.h> +#include <linux/usb/usb.h> #include <io.h> #include <malloc.h> #include <driver.h> @@ -19,7 +19,7 @@ #include <clock.h> #include <errno.h> #include <of.h> -#include <usb/ehci.h> +#include <linux/usb/ehci.h> #include <linux/err.h> #include <linux/sizes.h> #include <linux/clk.h> @@ -510,7 +510,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, } #if defined(CONFIG_MACH_EFIKA_MX_SMARTBOOK) && defined(CONFIG_USB_ULPI) -#include <usb/ulpi.h> +#include <linux/usb/ulpi.h> /* * Add support for setting CHRGVBUS to workaround a hardware bug on efika mx/sb * boards. diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index dd18c4af39..e364796a1a 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -10,7 +10,7 @@ /*-------------------------------------------------------------------------*/ #include <mfd/twl4030.h> -#include <usb/twl4030.h> +#include <linux/usb/twl4030.h> #include <mach/omap/ehci.h> #include <common.h> #include <io.h> diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index b1416a20d3..a7caf7ea04 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -7,8 +7,8 @@ #include <linux/clk.h> #include <driver.h> #include <init.h> -#include <usb/usb.h> -#include <usb/usb_defs.h> +#include <linux/usb/usb.h> +#include <linux/usb/usb_defs.h> #include <errno.h> #include <gpio.h> #include <of_gpio.h> diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index fcec5eee5e..e4b69dcf62 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -30,8 +30,8 @@ #include <clock.h> #include <dma.h> #include <malloc.h> -#include <usb/usb.h> -#include <usb/usb_defs.h> +#include <linux/usb/usb.h> +#include <linux/usb/usb_defs.h> #include <init.h> #include <errno.h> #include <linux/err.h> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index ae20560eb5..f975b1c0a9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -20,8 +20,8 @@ #include <io.h> #include <linux/err.h> #include <linux/sizes.h> -#include <usb/usb.h> -#include <usb/xhci.h> +#include <linux/usb/usb.h> +#include <linux/usb/xhci.h> #include <asm/unaligned.h> #include "xhci.h" diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0abe8a67a3..995772f927 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -19,8 +19,8 @@ #include <io.h> #include <linux/err.h> #include <linux/sizes.h> -#include <usb/usb.h> -#include <usb/xhci.h> +#include <linux/usb/usb.h> +#include <linux/usb/xhci.h> #include <asm/unaligned.h> #include "xhci.h" diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 27fca63f96..f149e78452 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -24,8 +24,8 @@ #include <init.h> #include <io.h> #include <linux/err.h> -#include <usb/usb.h> -#include <usb/xhci.h> +#include <linux/usb/usb.h> +#include <linux/usb/xhci.h> #include <asm/unaligned.h> #include "xhci.h" diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a6a0483245..5c72f62402 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -30,8 +30,8 @@ /* Section 5.3.3 - MaxPorts */ #define MAX_HC_PORTS 255 -/* Up to 16 ms to halt an HC */ -#define XHCI_MAX_HALT_USEC (16*1000) +/* Up to 32 ms to halt an HC */ +#define XHCI_MAX_HALT_USEC (32*1000) #define XHCI_MAX_RESET_USEC (250*1000) @@ -1134,8 +1134,6 @@ void xhci_hcd_stop(int index); /************************************************************* EXTENDED CAPABILITY DEFINITIONS *************************************************************/ -/* Up to 16 ms to halt an HC */ -#define XHCI_MAX_HALT_USEC (16*1000) /* HC not running - set to 1 when run/stop bit is cleared. */ #define XHCI_STS_HALT (1 << 0) diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c index 2493e6d202..053a985a70 100644 --- a/drivers/usb/imx/chipidea-imx.c +++ b/drivers/usb/imx/chipidea-imx.c @@ -9,13 +9,13 @@ #include <of.h> #include <errno.h> #include <driver.h> -#include <usb/usb.h> -#include <usb/ehci.h> +#include <linux/usb/usb.h> +#include <linux/usb/ehci.h> #include <regulator.h> -#include <usb/chipidea-imx.h> -#include <usb/phy.h> -#include <usb/ulpi.h> -#include <usb/fsl_usb2.h> +#include <linux/usb/chipidea-imx.h> +#include <linux/usb/phy.h> +#include <linux/usb/ulpi.h> +#include <linux/usb/fsl_usb2.h> #include <linux/err.h> #include <linux/phy/phy.h> #include <linux/clk.h> diff --git a/drivers/usb/imx/imx-usb-misc.c b/drivers/usb/imx/imx-usb-misc.c index bd91ac2e57..b4d7011d5c 100644 --- a/drivers/usb/imx/imx-usb-misc.c +++ b/drivers/usb/imx/imx-usb-misc.c @@ -9,7 +9,7 @@ #include <io.h> #include <of.h> #include <errno.h> -#include <usb/chipidea-imx.h> +#include <linux/usb/chipidea-imx.h> #include <mach/imx/imx6-regs.h> #include <mach/imx/iomux-mx6.h> diff --git a/drivers/usb/imx/imx-usb-phy.c b/drivers/usb/imx/imx-usb-phy.c index 628e569820..1e9698b98a 100644 --- a/drivers/usb/imx/imx-usb-phy.c +++ b/drivers/usb/imx/imx-usb-phy.c @@ -10,7 +10,7 @@ #include <errno.h> #include <driver.h> #include <malloc.h> -#include <usb/phy.h> +#include <linux/usb/phy.h> #include <linux/phy/phy.h> #include <linux/clk.h> #include <linux/err.h> diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index 0b847f06ad..b5c68098fd 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -12,7 +12,7 @@ #include <linux/printk.h> #include <of_device.h> #include <regulator.h> -#include <usb/usb.h> +#include <linux/usb/usb.h> #include "onboard_usb_hub.h" diff --git a/drivers/usb/musb/musb_barebox.c b/drivers/usb/musb/musb_barebox.c index 357a8f4281..81fdd6338f 100644 --- a/drivers/usb/musb/musb_barebox.c +++ b/drivers/usb/musb/musb_barebox.c @@ -2,8 +2,8 @@ #include <common.h> #include <init.h> #include <clock.h> -#include <usb/musb.h> -#include <usb/usb.h> +#include <linux/usb/musb.h> +#include <linux/usb/usb.h> #include <linux/types.h> #include <linux/err.h> #include <linux/barebox-wrapper.h> diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ab825553b5..76622b4d55 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -67,8 +67,8 @@ #include <common.h> #include <init.h> #include <clock.h> -#include <usb/musb.h> -#include <usb/usb.h> +#include <linux/usb/musb.h> +#include <linux/usb/usb.h> #include <linux/types.h> #include <linux/err.h> #include <linux/barebox-wrapper.h> diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index a4e97c989b..d954719161 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -12,8 +12,8 @@ #include <poller.h> #include <notifier.h> -#include <usb/usb.h> -#include <usb/phy.h> +#include <linux/usb/usb.h> +#include <linux/usb/phy.h> #include <linux/spinlock.h> struct musb; diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 910ab347aa..b677760796 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -17,8 +17,8 @@ #include <common.h> #include <init.h> #include <clock.h> -#include <usb/usb.h> -#include <usb/musb.h> +#include <linux/usb/usb.h> +#include <linux/usb/musb.h> #include <malloc.h> #include <linux/err.h> #include <linux/barebox-wrapper.h> diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index c28049c062..87d6602f74 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -991,8 +991,7 @@ static void musb_gadget_poll(struct usb_gadget *gadget) static int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver); -static int musb_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); +static int musb_gadget_stop(struct usb_gadget *g); static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, @@ -1167,16 +1166,9 @@ err: return retval; } -static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) +static void stop_activity(struct musb *musb) { - int i; - struct musb_hw_ep *hw_ep; - - /* don't disconnect if it's not connected */ - if (musb->g.speed == USB_SPEED_UNKNOWN) - driver = NULL; - else - musb->g.speed = USB_SPEED_UNKNOWN; + musb->g.speed = USB_SPEED_UNKNOWN; /* deactivate the hardware */ if (musb->softconnect) { @@ -1184,25 +1176,6 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) musb_pullup(musb, 0); } musb_stop(musb); - - /* killing any outstanding requests will quiesce the driver; - * then report disconnect - */ - if (driver) { - for (i = 0, hw_ep = musb->endpoints; - i < musb->nr_endpoints; - i++, hw_ep++) { - musb_ep_select(musb->mregs, i); - if (hw_ep->is_shared_fifo /* || !epnum */) { - nuke(&hw_ep->ep_in, -ESHUTDOWN); - } else { - if (hw_ep->max_packet_sz_tx) - nuke(&hw_ep->ep_in, -ESHUTDOWN); - if (hw_ep->max_packet_sz_rx) - nuke(&hw_ep->ep_out, -ESHUTDOWN); - } - } - } } /* @@ -1211,8 +1184,7 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) * * @param driver the gadget driver to unregister */ -static int musb_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int musb_gadget_stop(struct usb_gadget *g) { struct musb *musb = gadget_to_musb(g); unsigned long flags; @@ -1226,10 +1198,7 @@ static int musb_gadget_stop(struct usb_gadget *g, (void) musb_gadget_vbus_draw(&musb->g, 0); - stop_activity(musb, driver); - - dev_dbg(musb->controller, "unregistering driver %s\n", - driver ? driver->function : "(removed)"); + stop_activity(musb); musb->is_active = 0; musb->gadget_driver = NULL; diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index af81f062e6..bbd1a35880 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h @@ -11,7 +11,7 @@ #define __MUSB_GADGET_H #include <linux/list.h> -#include <usb/gadget.h> +#include <linux/usb/gadget.h> #if IS_ENABLED(CONFIG_USB_MUSB_GADGET) extern int musb_g_ep0_irq(struct musb *); diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 7a7c366521..5585f2e3b5 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -12,7 +12,7 @@ //#include <linux/scatterlist.h> #include <linux/list.h> -#include <usb/usb.h> +#include <linux/usb/usb.h> #include <asm/unaligned.h> /* diff --git a/drivers/usb/otg/otgdev.c b/drivers/usb/otg/otgdev.c index 1ac1b642ac..d0a1cecc85 100644 --- a/drivers/usb/otg/otgdev.c +++ b/drivers/usb/otg/otgdev.c @@ -2,7 +2,7 @@ #include <common.h> #include <driver.h> -#include <usb/usb.h> +#include <linux/usb/usb.h> struct otg_mode { struct device dev; diff --git a/drivers/usb/otg/twl4030.c b/drivers/usb/otg/twl4030.c index cd82148b2e..5cbf734ded 100644 --- a/drivers/usb/otg/twl4030.c +++ b/drivers/usb/otg/twl4030.c @@ -24,7 +24,7 @@ */ #include <mfd/twl4030.h> -#include <usb/twl4030.h> +#include <linux/usb/twl4030.h> #include <clock.h> static int twl4030_usb_write(u8 address, u8 data) diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c index aa9470b7ae..d231b49b08 100644 --- a/drivers/usb/otg/ulpi.c +++ b/drivers/usb/otg/ulpi.c @@ -6,7 +6,7 @@ #include <common.h> #include <io.h> #include <errno.h> -#include <usb/ulpi.h> +#include <linux/usb/ulpi.h> /* ULPIVIEW register bits */ #define ULPIVW_WU (1 << 31) /* Wakeup */ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 5699fc14b0..103ae293a3 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -12,8 +12,8 @@ #include <malloc.h> #include <errno.h> #include <scsi.h> -#include <usb/usb.h> -#include <usb/usb_defs.h> +#include <linux/usb/usb.h> +#include <linux/usb/usb_defs.h> #include <asm/unaligned.h> diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index b9626b303e..ae16d7b60b 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -10,7 +10,7 @@ #ifndef _STORAGE_USB_H_ #define _STORAGE_USB_H_ -#include <usb/usb.h> +#include <linux/usb/usb.h> #include <block.h> #include <disks.h> #include <scsi.h> |