From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4144AC44511 for ; Thu, 16 Jul 2026 16:11:04 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 78A1884D99; Thu, 16 Jul 2026 18:09:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="WGfUJjtS"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id B13C984D02; Thu, 16 Jul 2026 15:43:30 +0200 (CEST) Received: from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com [IPv6:2a00:1450:4864:20::62f]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id F3C7184CEB for ; Thu, 16 Jul 2026 15:43:27 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=anders.roxell@linaro.org Received: by mail-ej1-x62f.google.com with SMTP id a640c23a62f3a-c15b51ba80dso63223866b.2 for ; Thu, 16 Jul 2026 06:43:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1784209407; x=1784814207; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=+RI1SuR3kXH7pUEGbk/MyR0gYbws/gohCthpP9J72aA=; b=WGfUJjtSQfOp2fhSqKPdTz87gDT0UoDVj7fHxwlc3z5CWNZ9govujYLCk3tRR7CJq+ jLr8PBy3SIHJXBkRiiq2fm1/BPfRlGunWh/nRsOkuaO9onwjJXSt5azrM5do/EN+1tHc 1jSa+F1K/+kqEh247nVJOoxP8myJAHl6fkxtEVxUe35mTGfAeGYRG551nWgm72jahrXi fUAUmSOl/p/ULsRgTtV/tthBJ6DSmpe1TSdAk675voSe1HZIC7KmXPhnC8bMCUme091l Ihqdtd0BbnN4G4xzpc+e0AQKjb2Y9TX1Gtn0KPmK0wSScmoTgWyym8qBGtxnoGTIjhiQ 6/qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784209407; x=1784814207; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=+RI1SuR3kXH7pUEGbk/MyR0gYbws/gohCthpP9J72aA=; b=OoNezAkxSnW5AuVjGjELgnPQ5HEMjxUBaQL9d0IWaUJ9sQfvwEiVw1fRpFz4RKHdXt 1/1rxjOInmJ0Ik4hWdwVCMlqEjvWRpRJ5yPpAQQdPlMPU0d2NXi813CV8tXgoB4fgk5Q zGwaGh5VO6wor0PirgELMPKwR5XPRLnSj55lWMR2rYBhYYSUSlMOLlJsNrwl/v2iFftG soldxrJ5zLKWC60CCHzompcQ8f+sNja/GC5GTNUUrWUApjxIKte2kKtXtUzC/WdEeUSR LMmKrN6VSCsKj4ZSVVdyul7jbI5DhU+z/V3Tx83rAfnl4vIOytSNHXfMqGSpCr3EiFDG SmYw== X-Gm-Message-State: AOJu0YwkRtR04gfSfI6mcFtw14IruMHibdiM6sL3gSrd4QsmGDKytIYZ FcUO/Zlb0WhXIpZwlaWD2L0RDi1zOx9WEfNIE77Ib01rCMjmatuS0ckWs4VJs54N4y862zEDKhu HLD2C X-Gm-Gg: AfdE7ckhacBoP/r32qTLR1Ec3ipkcTuf3ohJpFds6CIlnnDeAoSZMtgfKF19qELko3o 9mBaL/iPZbXeskxia+wk2RuZcS7jJRE1L8l4zLx1zOQna+TtFoqZIYrhShSyzsmYNGhAfTansn2 OH3RNuPEAZ3uibm5xv9GF1sav57QfV52T9I2VUjn5sl/xNRQ1hU8u9g8vRNSeBtWs2TUrPdI3o4 95BklPVXodYkVJ0KXT3yX1cVtZ/VEI+djUfZ0KphQFd6ax4XXKglxxZA3DX26pabamlKAhkTW0I ORQf2zus7iH0wHfAG7xauvqEMER/YtXoKrNaGSkI9UxWspJHLxQKuGWLrpKFUokPMKKwhHHwscB dKiPxCp3ZywMz0/R+GzQK4mE+C3btfMqjX/jo4wgROalcesIjNI8vYIj6mKxMXcK5UVzl8HBzyS yH9Ud/8gQIjfDkBxBhfHHSsEQCCxT4kAzUj/fRNg== X-Received: by 2002:a17:907:3cc3:b0:c12:2aef:af2b with SMTP id a640c23a62f3a-c161e98a19cmr734859966b.4.1784209407207; Thu, 16 Jul 2026 06:43:27 -0700 (PDT) Received: from localhost (c-85-229-7-191.bbcust.telenor.se. [85.229.7.191]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c16874a3f91sm221454966b.61.2026.07.16.06.43.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 06:43:26 -0700 (PDT) From: Anders Roxell To: u-boot@lists.denx.de, marex@denx.de Cc: mkorpershoek@kernel.org, ilias.apalodimas@linaro.org, trini@konsulko.com, michal.simek@amd.com, alchark@flipper.net, jerome.forissier@arm.com, Jens Wiklander , Simon Glass , Anders Roxell , Lukasz Majewski Subject: [PATCH v5 12/75] usb: dwc3: import from kernel v4.9 Date: Thu, 16 Jul 2026 15:41:42 +0200 Message-ID: <20260716134305.614278-13-anders.roxell@linaro.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260716134305.614278-1-anders.roxell@linaro.org> References: <20260716134305.614278-1-anders.roxell@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailman-Approved-At: Thu, 16 Jul 2026 18:09:05 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean From: Jens Wiklander Sync Linux kernel dwc3 changes from v4.8 to v4.9. The following files are preserved accross the import: Makefile Kconfig dwc3-meson-g12a.c dwc3-meson-gxl.c dwc3-omap.c dwc3-uniphier.c dwc3-generic.h dwc3-generic.c dwc3-generic-sti.c dwc3-layerscape.c ti_usb_phy.c Skipping unused files: debugfs.c drd.c dwc3-exynos.c dwc3-haps.c dwc3-imx8mp.c dwc3-keystone.c dwc3-octeon.c dwc3-of-simple.c dwc3-pci.c dwc3-qcom.c dwc3-qcom-legacy.c dwc3-rtk.c dwc3-st.c dwc3-xilinx.c host.c trace.c trace.h ulpi.c Note that this is a raw import and doesn't build. A fixup commit at the end of the series fixes that. List of commits: git log --oneline v4.8..v4.9 Commits imported: 4accb8a1ee7d usb: dwc3: st: add missing include 9b9d7cdd0a20 usb: dwc3: Fix error handling for core init 51fbc7c06c89 usb: dwc3: Fix size used in dma_free_coherent() d889c23ce4e3 usb: dwc3: gadget: never pre-start Isochronous endpoints a9c3ca5fae6b usb: dwc3: gadget: properly account queued requests b281dc630b41 usb: dwc3: of-simple: add compatible for Cavium 26c9cac402c4 usb: dwc3: of-simple: allow glues without clocks 8d53e6267594 usb: dwc3: of-simple: Fix warning during unbind 5e6c88d28ccb usb: dwc3: fix Clear Stall EP command failure d6e10bf2ba47 usb: dwc3: avoid -Wmaybe-uninitialized warning 9d6173e125d9 usb: dwc3: Fix dr_mode validation 073c47aca7b7 usb: dwc3: ulpi: make dwc3_ulpi_ops constant e6f74849784c usb: ulpi: rename operations {read|write}_dev to simply {read|write} b7cf1dc3414d usb: dwc3: ulpi: use new api 594e121f2568 usb: dwc3: gadget: stop kicking if we run out of space 7ae7df4982af usb: dwc3: gadget: abolish trbs_left 06281d460fc5 usb: dwc3: Add ENDXFER command polling 512e47572f7d usb: dwc3: Add revision numbers for the USB 3.0 IP 00af62330c39 usb: dwc3: core: Move the mode setting to the right place f652191be3f6 usb: dwc3: of-simple: add compatible for rockchip rk3399 00fe081dc3a3 usb: dwc3: add dis_del_phy_power_chg_quirk 32f2ed864dd5 usb: dwc3: make usb2 phy utmi interface configurable 16199f338939 usb: dwc3: add dis_u2_freeclk_exists_quirk dc55c67e9c95 usb: dwc3: gadget: improve increment request->actual f99f53f24d87 usb: dwc3: gadget: remove condition that never happens 1f512119a08c usb: dwc3: gadget: add remaining sg entries to ring 2c78c0295fd8 usb: dwc3: gadget: interrupt on ring full too 0b3e4af3c740 usb: dwc3: gadget: add sg and num_pending_sgs to dwc3_request 31162af447d7 usb: dwc3: gadget: avoid while (1) loop on completion 08a36b543803 usb: dwc3: gadget: simplify __dwc3_gadget_ep_queue() 45438a0cd9c2 usb: dwc3: gadget: simplify dwc3_ep_prev_trb() 737f1ae2556a usb: dwc3: gadget: increment dequeue pointer on completion 4bc48c974708 usb: dwc3: gadget: retire LST bit completely a26a142275c6 usb: remove redundant dependency on USB_SUPPORT Signed-off-by: Jens Wiklander Reviewed-by: Simon Glass Signed-off-by: Anders Roxell --- drivers/usb/dwc3/core.c | 127 ++++++++++++++--- drivers/usb/dwc3/core.h | 35 ++++- drivers/usb/dwc3/gadget.c | 292 +++++++++++++++----------------------- 3 files changed, 258 insertions(+), 196 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 35d092456bec..fea446900cad 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -49,6 +49,57 @@ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ +/** + * dwc3_get_dr_mode - Validates and sets dr_mode + * @dwc: pointer to our context structure + */ +static int dwc3_get_dr_mode(struct dwc3 *dwc) +{ + enum usb_dr_mode mode; + struct device *dev = dwc->dev; + unsigned int hw_mode; + + if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) + dwc->dr_mode = USB_DR_MODE_OTG; + + mode = dwc->dr_mode; + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + switch (hw_mode) { + case DWC3_GHWPARAMS0_MODE_GADGET: + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) { + dev_err(dev, + "Controller does not support host mode.\n"); + return -EINVAL; + } + mode = USB_DR_MODE_PERIPHERAL; + break; + case DWC3_GHWPARAMS0_MODE_HOST: + if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { + dev_err(dev, + "Controller does not support device mode.\n"); + return -EINVAL; + } + mode = USB_DR_MODE_HOST; + break; + default: + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) + mode = USB_DR_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) + mode = USB_DR_MODE_PERIPHERAL; + } + + if (mode != dwc->dr_mode) { + dev_warn(dev, + "Configuration mismatch. dr_mode forced to %s\n", + mode == USB_DR_MODE_HOST ? "host" : "gadget"); + + dwc->dr_mode = mode; + } + + return 0; +} + void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -448,6 +499,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_u3_susphy_quirk) reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + if (dwc->dis_del_phy_power_chg_quirk) + reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); @@ -485,6 +539,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc) break; } + switch (dwc->hsphy_mode) { + case USBPHY_INTERFACE_MODE_UTMI: + reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | + DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); + reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) | + DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT); + break; + case USBPHY_INTERFACE_MODE_UTMIW: + reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | + DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); + reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) | + DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); + break; + default: + break; + } + /* * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to * '0' during coreConsultant configuration. So default value will @@ -500,6 +571,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_enblslpm_quirk) reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + if (dwc->dis_u2_freeclk_exists_quirk) + reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); return 0; @@ -666,18 +740,43 @@ static int dwc3_core_init(struct dwc3 *dwc) goto err4; } + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + break; + case USB_DR_MODE_HOST: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + break; + case USB_DR_MODE_OTG: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + break; + default: + dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode); + break; + } + + /* + * ENDXFER polling is available on version 3.10a and later of + * the DWC_usb3 controller. It is NOT available in the + * DWC_usb31 controller. + */ + if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg |= DWC3_GUCTL2_RST_ACTBITLATER; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + return 0; err4: - phy_power_off(dwc->usb2_generic_phy); + phy_power_off(dwc->usb3_generic_phy); err3: - phy_power_off(dwc->usb3_generic_phy); + phy_power_off(dwc->usb2_generic_phy); err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); - dwc3_core_exit(dwc); err1: usb_phy_shutdown(dwc->usb2_phy); @@ -763,7 +862,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -772,7 +870,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -781,7 +878,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_OTG: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -888,6 +984,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->dr_mode = usb_get_dr_mode(dev); + dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); dwc->has_lpm_erratum = device_property_read_bool(dev, "snps,has-lpm-erratum"); @@ -924,6 +1021,10 @@ static int dwc3_probe(struct platform_device *pdev) "snps,dis_enblslpm_quirk"); dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev, "snps,dis_rxdet_inp3_quirk"); + dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev, + "snps,dis-u2-freeclk-exists-quirk"); + dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev, + "snps,dis-del-phy-power-chg-quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); @@ -972,17 +1073,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } - if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && - (dwc->dr_mode == USB_DR_MODE_OTG || - dwc->dr_mode == USB_DR_MODE_UNKNOWN)) - dwc->dr_mode = USB_DR_MODE_HOST; - else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) && - (dwc->dr_mode == USB_DR_MODE_OTG || - dwc->dr_mode == USB_DR_MODE_UNKNOWN)) - dwc->dr_mode = USB_DR_MODE_PERIPHERAL; - - if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) - dwc->dr_mode = USB_DR_MODE_OTG; + ret = dwc3_get_dr_mode(dwc); + if (ret) + goto err3; ret = dwc3_alloc_scratch_buffers(dwc); if (ret) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 45d6de5107c7..6b60e42626a2 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -109,6 +109,7 @@ #define DWC3_GPRTBIMAP_HS1 0xc184 #define DWC3_GPRTBIMAP_FS0 0xc188 #define DWC3_GPRTBIMAP_FS1 0xc18c +#define DWC3_GUCTL2 0xc19c #define DWC3_VER_NUMBER 0xc1a0 #define DWC3_VER_TYPE 0xc1a4 @@ -199,9 +200,18 @@ /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) +#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS (1 << 30) #define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) +#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3) +#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1) +#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10) +#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK DWC3_GUSB2PHYCFG_USBTRDTIM(0xf) +#define USBTRDTIM_UTMI_8_BIT 9 +#define USBTRDTIM_UTMI_16_BIT 5 +#define UTMI_PHYIF_16_BIT 1 +#define UTMI_PHYIF_8_BIT 0 /* Global USB2 PHY Vendor Control Register */ #define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25) @@ -235,7 +245,10 @@ #define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff) /* Global HWPARAMS0 Register */ -#define DWC3_GHWPARAMS0_USB3_MODE(n) ((n) & 0x3) +#define DWC3_GHWPARAMS0_MODE(n) ((n) & 0x3) +#define DWC3_GHWPARAMS0_MODE_GADGET 0 +#define DWC3_GHWPARAMS0_MODE_HOST 1 +#define DWC3_GHWPARAMS0_MODE_DRD 2 #define DWC3_GHWPARAMS0_MBUS_TYPE(n) (((n) >> 3) & 0x7) #define DWC3_GHWPARAMS0_SBUS_TYPE(n) (((n) >> 6) & 0x3) #define DWC3_GHWPARAMS0_MDWIDTH(n) (((n) >> 8) & 0xff) @@ -279,6 +292,9 @@ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f +/* Global User Control Register 2 */ +#define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14) + /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -685,6 +701,8 @@ struct dwc3_hwparams { * @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 + * @num_pending_sgs: counter to pending sgs * @first_trb_index: index to first trb used by this request * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb @@ -697,7 +715,9 @@ struct dwc3_request { struct usb_request request; struct list_head list; struct dwc3_ep *dep; + struct scatterlist *sg; + unsigned num_pending_sgs; u8 first_trb_index; u8 epnum; struct dwc3_trb *trb; @@ -743,6 +763,9 @@ struct dwc3_scratchpad_array { * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents * @dr_mode: requested mode of operation + * @hsphy_mode: UTMI phy mode, one of following: + * - USBPHY_INTERFACE_MODE_UTMI + * - USBPHY_INTERFACE_MODE_UTMIW * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY @@ -799,6 +822,11 @@ struct dwc3_scratchpad_array { * @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_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. + * @dis_del_phy_power_chg_quirk: set if we disable delay phy power + * change quirk. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -845,6 +873,7 @@ struct dwc3 { size_t regs_size; enum usb_dr_mode dr_mode; + enum usb_phy_interface hsphy_mode; u32 fladj; u32 irq_gadget; @@ -880,6 +909,8 @@ struct dwc3 { #define DWC3_REVISION_260A 0x5533260a #define DWC3_REVISION_270A 0x5533270a #define DWC3_REVISION_280A 0x5533280a +#define DWC3_REVISION_300A 0x5533300a +#define DWC3_REVISION_310A 0x5533310a /* * NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really @@ -942,6 +973,8 @@ struct dwc3 { unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; unsigned dis_rxdet_inp3_quirk:1; + unsigned dis_u2_freeclk_exists_quirk:1; + unsigned dis_del_phy_power_chg_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 122e64df2f4d..1dfa56a5f1c5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -174,15 +174,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status) { struct dwc3 *dwc = dep->dwc; - int i; - if (req->started) { - i = 0; - do { - dwc3_ep_inc_deq(dep); - } while(++i < req->request.num_mapped_sgs); - req->started = false; - } + req->started = false; list_del(&req->list); req->trb = NULL; @@ -348,7 +341,8 @@ 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)) + if (dep->direction && (dwc->revision >= DWC3_REVISION_260A) && + (dwc->gadget.speed >= USB_SPEED_SUPER)) cmd |= DWC3_DEPCMD_CLEARPENDIN; memset(¶ms, 0, sizeof(params)); @@ -490,7 +484,8 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, params.param0 |= DWC3_DEPCFG_ACTION_INIT; } - params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; + if (usb_endpoint_xfer_control(desc)) + params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc)) params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -764,6 +759,8 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, kfree(req); } +static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep); + /** * dwc3_prepare_one_trb - setup one TRB from one request * @dep: endpoint for which this request is prepared @@ -771,15 +768,13 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, */ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_request *req, dma_addr_t dma, - unsigned length, unsigned last, unsigned chain, unsigned node) + unsigned length, unsigned chain, unsigned node) { struct dwc3_trb *trb; - dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s", + dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s", dep->name, req, (unsigned long long) dma, - length, last ? " last" : "", - chain ? " chain" : ""); - + length, chain ? " chain" : ""); trb = &dep->trb_pool[dep->trb_enqueue]; @@ -788,6 +783,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); req->first_trb_index = dep->trb_enqueue; + dep->queued_requests++; } dwc3_ep_inc_enq(dep); @@ -826,12 +822,10 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, /* always enable Continue on Short Packet */ trb->ctrl |= DWC3_TRB_CTRL_CSP; - if (!req->request.no_interrupt && !chain) + if ((!req->request.no_interrupt && !chain) || + (dwc3_calc_trbs_left(dep) == 0)) trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; - if (last && !usb_endpoint_xfer_isoc(dep->endpoint.desc)) - trb->ctrl |= DWC3_TRB_CTRL_LST; - if (chain) trb->ctrl |= DWC3_TRB_CTRL_CHN; @@ -840,8 +834,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_HWO; - dep->queued_requests++; - trace_dwc3_prepare_trb(dep, trb); } @@ -856,12 +848,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, */ static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index) { - if (!index) - index = DWC3_TRB_NUM - 2; - else - index = dep->trb_enqueue - 1; + u8 tmp = index; + + if (!tmp) + tmp = DWC3_TRB_NUM - 1; - return &dep->trb_pool[index]; + return &dep->trb_pool[tmp - 1]; } static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) @@ -894,65 +886,42 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) } static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left, - unsigned int more_coming) + struct dwc3_request *req) { - struct usb_request *request = &req->request; - struct scatterlist *sg = request->sg; + struct scatterlist *sg = req->sg; struct scatterlist *s; - unsigned int last = false; unsigned int length; dma_addr_t dma; int i; - for_each_sg(sg, s, request->num_mapped_sgs, i) { + for_each_sg(sg, s, req->num_pending_sgs, i) { unsigned chain = true; length = sg_dma_len(s); dma = sg_dma_address(s); - if (sg_is_last(s)) { - if (usb_endpoint_xfer_int(dep->endpoint.desc) || - !more_coming) - last = true; - - chain = false; - } - - if (!trbs_left--) - last = true; - - if (last) + if (sg_is_last(s)) chain = false; dwc3_prepare_one_trb(dep, req, dma, length, - last, chain, i); + chain, i); - if (last) + if (!dwc3_calc_trbs_left(dep)) break; } } static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left, - unsigned int more_coming) + struct dwc3_request *req) { - unsigned int last = false; unsigned int length; dma_addr_t dma; dma = req->request.dma; length = req->request.length; - if (!trbs_left) - last = true; - - /* Is this the last request? */ - if (usb_endpoint_xfer_int(dep->endpoint.desc) || !more_coming) - last = true; - dwc3_prepare_one_trb(dep, req, dma, length, - last, false, 0); + false, 0); } /* @@ -966,26 +935,19 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; - unsigned int more_coming; - u32 trbs_left; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); - trbs_left = dwc3_calc_trbs_left(dep); - if (!trbs_left) + if (!dwc3_calc_trbs_left(dep)) return; - more_coming = dep->allocated_requests - dep->queued_requests; - list_for_each_entry_safe(req, n, &dep->pending_list, list) { - if (req->request.num_mapped_sgs > 0) - dwc3_prepare_one_trb_sg(dep, req, trbs_left--, - more_coming); + if (req->num_pending_sgs > 0) + dwc3_prepare_one_trb_sg(dep, req); else - dwc3_prepare_one_trb_linear(dep, req, trbs_left--, - more_coming); + dwc3_prepare_one_trb_linear(dep, req); - if (!trbs_left) + if (!dwc3_calc_trbs_left(dep)) return; } } @@ -1101,93 +1063,37 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) trace_dwc3_ep_queue(req); - /* - * We only add to our list of requests now and - * start consuming the list once we get XferNotReady - * IRQ. - * - * That way, we avoid doing anything that we don't need - * to do now and defer it until the point we receive a - * particular token from the Host side. - * - * This will also avoid Host cancelling URBs due to too - * many NAKs. - */ ret = usb_gadget_map_request(&dwc->gadget, &req->request, dep->direction); if (ret) return ret; - list_add_tail(&req->list, &dep->pending_list); + req->sg = req->request.sg; + req->num_pending_sgs = req->request.num_mapped_sgs; - /* - * If there are no pending requests and the endpoint isn't already - * busy, we will just start the request straight away. - * - * This will save one IRQ (XFER_NOT_READY) and possibly make it a - * little bit faster. - */ - if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && - !usb_endpoint_xfer_int(dep->endpoint.desc)) { - ret = __dwc3_gadget_kick_transfer(dep, 0); - goto out; - } + list_add_tail(&req->list, &dep->pending_list); /* - * There are a few special cases: - * - * 1. XferNotReady with empty list of requests. We need to kick the - * transfer here in that situation, otherwise we will be NAKing - * forever. If we get XferNotReady before gadget driver has a - * chance to queue a request, we will ACK the IRQ but won't be - * able to receive the data until the next request is queued. - * The following code is handling exactly that. + * NOTICE: Isochronous endpoints should NEVER be prestarted. We must + * wait for a XferNotReady event so we will know what's the current + * (micro-)frame number. * + * Without this trick, we are very, very likely gonna get Bus Expiry + * errors which will force us issue EndTransfer command. */ - if (dep->flags & DWC3_EP_PENDING_REQUEST) { - /* - * If xfernotready is already elapsed and it is a case - * of isoc transfer, then issue END TRANSFER, so that - * you can receive xfernotready again and can have - * notion of current microframe. - */ - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if (list_empty(&dep->started_list)) { - dwc3_stop_active_transfer(dwc, dep->number, true); - dep->flags = DWC3_EP_ENABLED; - } - return 0; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { + if ((dep->flags & DWC3_EP_PENDING_REQUEST) && + list_empty(&dep->started_list)) { + dwc3_stop_active_transfer(dwc, dep->number, true); + dep->flags = DWC3_EP_ENABLED; } - - ret = __dwc3_gadget_kick_transfer(dep, 0); - if (!ret) - dep->flags &= ~DWC3_EP_PENDING_REQUEST; - - goto out; - } - - /* - * 2. XferInProgress on Isoc EP with an active transfer. We need to - * kick the transfer here after queuing a request, otherwise the - * core may not see the modified TRB(s). - */ - if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - (dep->flags & DWC3_EP_BUSY) && - !(dep->flags & DWC3_EP_MISSED_ISOC)) { - WARN_ON_ONCE(!dep->resource_index); - ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index); - goto out; + return 0; } - /* - * 4. Stream Capable Bulk Endpoints. We need to start the transfer - * right away, otherwise host will not know we have streams to be - * handled. - */ - if (dep->stream_capable) - ret = __dwc3_gadget_kick_transfer(dep, 0); + if (!dwc3_calc_trbs_left(dep)) + return 0; -out: + ret = __dwc3_gadget_kick_transfer(dep, 0); if (ret && ret != -EBUSY) dwc3_trace(trace_dwc3_gadget, "%s: failed to kick transfers", @@ -1962,7 +1868,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, unsigned int s_pkt = 0; unsigned int trb_status; - dep->queued_requests--; + dwc3_ep_inc_deq(dep); + + if (req->trb == trb) + dep->queued_requests--; + trace_dwc3_complete_trb(dep, trb); /* @@ -1982,6 +1892,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; count = trb->size & DWC3_TRB_SIZE_MASK; + req->request.actual += count; if (dep->direction) { if (count) { @@ -2021,48 +1932,51 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, if (s_pkt && !chain) return 1; - if ((event->status & DEPEVT_STATUS_LST) && - (trb->ctrl & (DWC3_TRB_CTRL_LST | - DWC3_TRB_CTRL_HWO))) - return 1; + if ((event->status & DEPEVT_STATUS_IOC) && (trb->ctrl & DWC3_TRB_CTRL_IOC)) return 1; + return 0; } static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, const struct dwc3_event_depevt *event, int status) { - struct dwc3_request *req; + struct dwc3_request *req, *n; struct dwc3_trb *trb; - unsigned int slot; - unsigned int i; - int count = 0; + bool ioc = false; int ret; - do { + list_for_each_entry_safe(req, n, &dep->started_list, list) { + unsigned length; + unsigned actual; int chain; - req = next_request(&dep->started_list); - if (WARN_ON_ONCE(!req)) - return 1; - - chain = req->request.num_mapped_sgs > 0; - i = 0; - do { - slot = req->first_trb_index + i; - if (slot == DWC3_TRB_NUM - 1) - slot++; - slot %= DWC3_TRB_NUM; - trb = &dep->trb_pool[slot]; - count += trb->size & DWC3_TRB_SIZE_MASK; + length = req->request.length; + chain = req->num_pending_sgs > 0; + if (chain) { + struct scatterlist *sg = req->sg; + struct scatterlist *s; + unsigned int pending = req->num_pending_sgs; + unsigned int i; + for_each_sg(sg, s, pending, i) { + trb = &dep->trb_pool[dep->trb_dequeue]; + + req->sg = sg_next(s); + req->num_pending_sgs--; + + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, + event, status, chain); + if (ret) + break; + } + } else { + trb = &dep->trb_pool[dep->trb_dequeue]; ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); - if (ret) - break; - } while (++i < req->request.num_mapped_sgs); + } /* * We assume here we will always receive the entire data block @@ -2071,12 +1985,21 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, * should receive and we simply bounce the request back to the * gadget driver for further processing. */ - req->request.actual += req->request.length - count; + actual = length - req->request.actual; + req->request.actual = actual; + + if (ret && chain && (actual < length) && req->num_pending_sgs) + return __dwc3_gadget_kick_transfer(dep, 0); + dwc3_gadget_giveback(dep, req, status); - if (ret) + if (ret) { + if ((event->status & DEPEVT_STATUS_IOC) && + (trb->ctrl & DWC3_TRB_CTRL_IOC)) + ioc = true; break; - } while (1); + } + } /* * Our endpoint might get disabled by another thread during @@ -2103,10 +2026,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; } - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) - if ((event->status & DEPEVT_STATUS_IOC) && - (trb->ctrl & DWC3_TRB_CTRL_IOC)) - return 0; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && ioc) + return 0; + return 1; } @@ -2322,6 +2244,18 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) * * - Issue EndTransfer WITH CMDIOC bit set * - Wait 100us + * + * 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 and we don't need to delay for + * 100us. + * + * This mode is NOT available on the DWC_usb31 IP. */ cmd = DWC3_DEPCMD_ENDTRANSFER; @@ -2333,7 +2267,9 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) WARN_ON_ONCE(ret); dep->resource_index = 0; dep->flags &= ~DWC3_EP_BUSY; - udelay(100); + + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) + udelay(100); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) @@ -3054,7 +2990,7 @@ err3: kfree(dwc->setup_buf); err2: - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); err1: @@ -3079,7 +3015,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) kfree(dwc->setup_buf); kfree(dwc->zlp_buf); - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), -- 2.53.0