From: Junhui Liu <junhui.liu@pigmoral.tech>
To: Tom Rini <trini@konsulko.com>, Marek Vasut <marex@denx.de>,
Lukasz Majewski <lukma@denx.de>,
Mattijs Korpershoek <mkorpershoek@baylibre.com>
Cc: u-boot@lists.denx.de, seashell11234455@gmail.com,
pbrobinson@gmail.com, junhui.liu@pigmoral.tech
Subject: [PATCH v3 7/8] usb: dwc2: Unify flush and reset logic with v4.20a support
Date: Sat, 04 Jan 2025 11:37:21 +0800 [thread overview]
Message-ID: <20250104-dwc2-dev-v3-7-d4b2bc1996e4@pigmoral.tech> (raw)
In-Reply-To: <20250104-dwc2-dev-v3-0-d4b2bc1996e4@pigmoral.tech>
From: Kongyang Liu <seashell11234455@gmail.com>
This patch merges flush and reset logic for both host and gadget code
into a common set of functions, reducing duplication. It also adds support
for the updated reset logic to compatible with core version since v4.20a.
This patch mainly refers to the patch in the kernel.
link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65dc2e725286106f99c6f6b78e3d9c52c15f3a9c
Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
---
This commit does not add the handling of ret returned from the
dwc2_core_reset, dwc2_flush_tx_fifo and dwc2_flush_rx_fifo, because this
may involve changes to the code logic, I think this should be a separate
patch to handle with it.
---
drivers/usb/common/Makefile | 2 +
drivers/usb/common/dwc2_core.c | 115 +++++++++++++++++++++++++++++
drivers/usb/common/dwc2_core.h | 4 +
drivers/usb/gadget/dwc2_udc_otg.c | 12 +--
drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 6 +-
drivers/usb/host/dwc2.c | 80 +-------------------
6 files changed, 129 insertions(+), 90 deletions(-)
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index 11cc4657a0f403b84b1b8336781e1893d9c7a8f1..73e5bc6d7fdca692276e119911b47db4bf03586a 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -4,6 +4,8 @@
#
obj-$(CONFIG_$(XPL_)DM_USB) += common.o
+obj-$(CONFIG_USB_DWC2) += dwc2_core.o
+obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_core.o
obj-$(CONFIG_USB_ISP1760) += usb_urb.o
obj-$(CONFIG_USB_MUSB_HOST) += usb_urb.o
obj-$(CONFIG_USB_MUSB_GADGET) += usb_urb.o
diff --git a/drivers/usb/common/dwc2_core.c b/drivers/usb/common/dwc2_core.c
new file mode 100644
index 0000000000000000000000000000000000000000..7c7fa3b34550c79706dfbe8b4ca06b3c25ab3e15
--- /dev/null
+++ b/drivers/usb/common/dwc2_core.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <wait_bit.h>
+
+#include "dwc2_core.h"
+
+int dwc2_core_reset(struct dwc2_core_regs *regs)
+{
+ u32 snpsid;
+ int ret;
+ bool host_mode = false;
+
+ if (!(readl(®s->global_regs.gotgctl) & GOTGCTL_CONID_B) ||
+ (readl(®s->global_regs.gusbcfg) & GUSBCFG_FORCEDEVMODE))
+ host_mode = true;
+
+ /* Core Soft Reset */
+ snpsid = readl(®s->global_regs.gsnpsid);
+ writel(GRSTCTL_CSFTRST, ®s->global_regs.grstctl);
+ if (FIELD_GET(GSNPSID_VER_MASK, snpsid) < 0x420a) {
+ ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_CSFTRST,
+ false, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GRSTCTL_CSFTRST timeout\n", __func__);
+ return ret;
+ }
+ } else {
+ ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_CSFTRST_DONE,
+ true, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GRSTCTL_CSFTRST_DONE timeout\n", __func__);
+ return ret;
+ }
+ clrsetbits_le32(®s->global_regs.grstctl, GRSTCTL_CSFTRST, GRSTCTL_CSFTRST_DONE);
+ }
+
+ /* Wait for AHB master IDLE state. */
+ ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_AHBIDLE,
+ true, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__);
+ return ret;
+ }
+
+ if (host_mode) {
+ ret = wait_for_bit_le32(®s->global_regs.gintsts, GINTSTS_CURMODE_HOST,
+ host_mode, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GINTSTS_CURMODE_HOST timeout\n", __func__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int dwc2_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
+{
+ int ret;
+
+ log_debug("Flush Tx FIFO %d\n", num);
+
+ /* Wait for AHB master IDLE state */
+ ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_AHBIDLE, true, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__);
+ return ret;
+ }
+
+ writel(GRSTCTL_TXFFLSH | FIELD_PREP(GRSTCTL_TXFNUM_MASK, num), ®s->global_regs.grstctl);
+
+ ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_TXFFLSH, false, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GRSTCTL_TXFFLSH timeout\n", __func__);
+ return ret;
+ }
+
+ /* Wait for at least 3 PHY Clocks */
+ udelay(1);
+
+ return 0;
+}
+
+int dwc2_flush_rx_fifo(struct dwc2_core_regs *regs)
+{
+ int ret;
+
+ log_debug("Flush Rx FIFO\n");
+
+ /* Wait for AHB master IDLE state */
+ ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_AHBIDLE, true, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__);
+ return ret;
+ }
+
+ writel(GRSTCTL_RXFFLSH, ®s->global_regs.grstctl);
+
+ ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_RXFFLSH, false, 1000, false);
+ if (ret) {
+ log_warning("%s: Waiting for GRSTCTL_RXFFLSH timeout\n", __func__);
+ return ret;
+ }
+
+ /* Wait for at least 3 PHY Clocks */
+ udelay(1);
+
+ return 0;
+}
diff --git a/drivers/usb/common/dwc2_core.h b/drivers/usb/common/dwc2_core.h
index 862d3b3691c9caf84590d34960df21117848df0a..1897ad7cb540ed7a24fd8cd21650a40da20363fb 100644
--- a/drivers/usb/common/dwc2_core.h
+++ b/drivers/usb/common/dwc2_core.h
@@ -125,6 +125,10 @@ struct dwc2_core_regs {
u8 ep_fifo[16][0x1000]; /* 0x1000 */
};
+int dwc2_core_reset(struct dwc2_core_regs *regs);
+int dwc2_flush_tx_fifo(struct dwc2_core_regs *regs, const int num);
+int dwc2_flush_rx_fifo(struct dwc2_core_regs *regs);
+
/* Core Global Register */
#define GOTGCTL_CHIRPEN BIT(27)
#define GOTGCTL_MULT_VALID_BC_MASK GENMASK(26, 22)
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index 0fc9ee1b90fa71135083a1a6dae2e74992e51181..83d63d7f2162d49c387e0042bd33cc7a5856d407 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -471,7 +471,7 @@ static void reconfig_usbd(struct dwc2_udc *dev)
u32 max_hw_ep;
int pdata_hw_ep;
- writel(GRSTCTL_CSFTRST, ®->global_regs.grstctl);
+ dwc2_core_reset(reg);
debug("Resetting OTG controller\n");
@@ -575,16 +575,10 @@ static void reconfig_usbd(struct dwc2_udc *dev)
®->global_regs.dptxfsizn[i]);
}
/* Flush the RX FIFO */
- writel(GRSTCTL_RXFFLSH, ®->global_regs.grstctl);
- while (readl(®->global_regs.grstctl) & GRSTCTL_RXFFLSH)
- debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__);
+ dwc2_flush_rx_fifo(reg);
/* Flush all the Tx FIFO's */
- writel(FIELD_PREP(GRSTCTL_TXFNUM_MASK, GRSTCTL_TXFNUM_ALL), ®->global_regs.grstctl);
- writel(FIELD_PREP(GRSTCTL_TXFNUM_MASK, GRSTCTL_TXFNUM_ALL) | GRSTCTL_TXFFLSH,
- ®->global_regs.grstctl);
- while (readl(®->global_regs.grstctl) & GRSTCTL_TXFFLSH)
- debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__);
+ dwc2_flush_tx_fifo(reg, GRSTCTL_TXFNUM_ALL);
/* 13. Clear NAK bit of EP0, EP1, EP2*/
/* For Slave mode*/
diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
index 64d2fe7bbde4494b4cbcdf57032b720901fdd4eb..2be93592c423df7a9acea473b0e84e1f948999be 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
+++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
@@ -164,11 +164,7 @@ static int setdma_tx(struct dwc2_ep *ep, struct dwc2_request *req)
pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
/* Flush the endpoint's Tx FIFO */
- writel(FIELD_PREP(GRSTCTL_TXFNUM_MASK, ep->fifo_num), ®->global_regs.grstctl);
- writel(FIELD_PREP(GRSTCTL_TXFNUM_MASK, ep->fifo_num) | GRSTCTL_TXFFLSH,
- ®->global_regs.grstctl);
- while (readl(®->global_regs.grstctl) & GRSTCTL_TXFFLSH)
- ;
+ dwc2_flush_tx_fifo(reg, ep->fifo_num);
writel(phys_to_bus((unsigned long)ep->dma_buf), ®->device_regs.in_endp[ep_num].diepdma);
writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, pktcnt) |
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
index ff7885f8195c0bc08669dd99ef6c94992c991945..b27429235798ce223bb8a11999e3d520c26ef377 100644
--- a/drivers/usb/host/dwc2.c
+++ b/drivers/usb/host/dwc2.c
@@ -108,78 +108,6 @@ static void init_fslspclksel(struct dwc2_core_regs *regs)
FIELD_PREP(HCFG_FSLSPCLKSEL_MASK, phyclk));
}
-/*
- * Flush a Tx FIFO.
- *
- * @param regs Programming view of DWC_otg controller.
- * @param num Tx FIFO to flush.
- */
-static void dwc_otg_flush_tx_fifo(struct udevice *dev,
- struct dwc2_core_regs *regs, const int num)
-{
- int ret;
-
- writel(GRSTCTL_TXFFLSH | FIELD_PREP(GRSTCTL_TXFNUM_MASK, num),
- ®s->global_regs.grstctl);
- ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_TXFFLSH,
- false, 1000, false);
- if (ret)
- dev_info(dev, "%s: Timeout!\n", __func__);
-
- /* Wait for 3 PHY Clocks */
- udelay(1);
-}
-
-/*
- * Flush Rx FIFO.
- *
- * @param regs Programming view of DWC_otg controller.
- */
-static void dwc_otg_flush_rx_fifo(struct udevice *dev,
- struct dwc2_core_regs *regs)
-{
- int ret;
-
- writel(GRSTCTL_RXFFLSH, ®s->global_regs.grstctl);
- ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_RXFFLSH,
- false, 1000, false);
- if (ret)
- dev_info(dev, "%s: Timeout!\n", __func__);
-
- /* Wait for 3 PHY Clocks */
- udelay(1);
-}
-
-/*
- * Do core a soft reset of the core. Be careful with this because it
- * resets all the internal state machines of the core.
- */
-static void dwc_otg_core_reset(struct udevice *dev,
- struct dwc2_core_regs *regs)
-{
- int ret;
-
- /* Wait for AHB master IDLE state. */
- ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_AHBIDLE,
- true, 1000, false);
- if (ret)
- dev_info(dev, "%s: Timeout!\n", __func__);
-
- /* Core Soft Reset */
- writel(GRSTCTL_CSFTRST, ®s->global_regs.grstctl);
- ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_CSFTRST,
- false, 1000, false);
- if (ret)
- dev_info(dev, "%s: Timeout!\n", __func__);
-
- /*
- * Wait for core to come out of reset.
- * NOTE: This long sleep is _very_ important, otherwise the core will
- * not stay in host mode after a connector ID change!
- */
- mdelay(100);
-}
-
#if CONFIG_IS_ENABLED(DM_USB) && defined(CONFIG_DM_REGULATOR)
static int dwc_vbus_supply_init(struct udevice *dev)
{
@@ -281,8 +209,8 @@ static void dwc_otg_core_host_init(struct udevice *dev,
clrbits_le32(®s->global_regs.gotgctl, GOTGCTL_HSTSETHNPEN);
/* Make sure the FIFOs are flushed. */
- dwc_otg_flush_tx_fifo(dev, regs, GRSTCTL_TXFNUM_ALL); /* All Tx FIFOs */
- dwc_otg_flush_rx_fifo(dev, regs);
+ dwc2_flush_tx_fifo(regs, GRSTCTL_TXFNUM_ALL); /* All Tx FIFOs */
+ dwc2_flush_rx_fifo(regs);
/* Flush out any leftover queued requests. */
num_channels = FIELD_GET(GHWCFG2_NUM_HOST_CHAN_MASK, readl(®s->global_regs.ghwcfg2)) + 1;
@@ -352,7 +280,7 @@ static void dwc_otg_core_init(struct udevice *dev)
writel(usbcfg, ®s->global_regs.gusbcfg);
/* Reset the Controller */
- dwc_otg_core_reset(dev, regs);
+ dwc2_core_reset(regs);
/*
* This programming sequence needs to happen in FS mode before
@@ -413,7 +341,7 @@ static void dwc_otg_core_init(struct udevice *dev)
writel(usbcfg, ®s->global_regs.gusbcfg);
/* Reset after setting the PHY parameters */
- dwc_otg_core_reset(dev, regs);
+ dwc2_core_reset(regs);
#endif
usbcfg = readl(®s->global_regs.gusbcfg);
--
2.47.1
next prev parent reply other threads:[~2025-01-04 13:19 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-04 3:37 [PATCH v3 0/8] usb: dwc2: Refactor and update USB DWC2 driver Junhui Liu
2025-01-04 3:37 ` [PATCH v3 1/8] usb: dwc2: Extract register definitions to common header file Junhui Liu
2025-01-07 9:03 ` Mattijs Korpershoek
2025-01-04 3:37 ` [PATCH v3 2/8] usb: dwc2: Fix incorrect ULPI_UTMI_SEL bit setting Junhui Liu
2025-01-07 9:11 ` Mattijs Korpershoek
2025-01-04 3:37 ` [PATCH v3 3/8] USB: dwc2: Fix HBstLen setting for external DMA mode Junhui Liu
2025-01-07 9:16 ` Mattijs Korpershoek
2025-01-04 3:37 ` [PATCH v3 4/8] usb: dwc2: Clean up with bitfield macros Junhui Liu
2025-01-05 19:14 ` Marek Vasut
2025-01-07 9:22 ` Mattijs Korpershoek
2025-01-04 3:37 ` [PATCH v3 5/8] usb: dwc2: Align macros with Linux kernel definitions Junhui Liu
2025-01-07 9:26 ` Mattijs Korpershoek
2025-01-04 3:37 ` [PATCH v3 6/8] usb: dwc2: Extract macro definitions to common header Junhui Liu
2025-01-07 9:55 ` Mattijs Korpershoek
2025-01-07 12:52 ` Junhui Liu
2025-01-04 3:37 ` Junhui Liu [this message]
2025-01-05 19:19 ` [PATCH v3 7/8] usb: dwc2: Unify flush and reset logic with v4.20a support Marek Vasut
2025-01-06 9:14 ` Junhui Liu
2025-01-06 15:37 ` Marek Vasut
2025-01-07 12:39 ` Junhui Liu
2025-01-07 12:57 ` Marek Vasut
2025-01-04 3:37 ` [PATCH v3 8/8] usb: dwc2: Replace uint<x>_t types with u<x> Junhui Liu
2025-01-07 9:47 ` [PATCH v3 0/8] usb: dwc2: Refactor and update USB DWC2 driver Mattijs Korpershoek
2025-01-07 12:44 ` Junhui Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250104-dwc2-dev-v3-7-d4b2bc1996e4@pigmoral.tech \
--to=junhui.liu@pigmoral.tech \
--cc=lukma@denx.de \
--cc=marex@denx.de \
--cc=mkorpershoek@baylibre.com \
--cc=pbrobinson@gmail.com \
--cc=seashell11234455@gmail.com \
--cc=trini@konsulko.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox