diff options
| author | Tom Rini <[email protected]> | 2026-08-06 14:06:12 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-08-06 19:36:40 -0600 |
| commit | 8aafc34c49360159130dd97b632843360635e3e1 (patch) | |
| tree | ae4248498d8122cc143248f40094544cd3b2d463 | |
| parent | baa64b2f892890f00a377eac4a3e685472bb56b5 (diff) | |
| parent | 9879c40f6d010f7d019dcbf8b76d5642e40567c4 (diff) | |
Merge branch 'main' of https://git.u-boot-project.org/u-boot/custodians/u-boot-usb
- Cadence controller bugfix.
| -rw-r--r-- | drivers/usb/mtu3/mtu3.h | 2 | ||||
| -rw-r--r-- | drivers/usb/mtu3/mtu3_core.c | 42 | ||||
| -rw-r--r-- | drivers/usb/mtu3/mtu3_gadget.c | 5 |
3 files changed, 45 insertions, 4 deletions
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 8a7ae83ee99..c812cd6fdcf 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -408,7 +408,7 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set); void mtu3_ep0_setup(struct mtu3 *mtu); void mtu3_start(struct mtu3 *mtu); void mtu3_stop(struct mtu3 *mtu); -void mtu3_dev_on_off(struct mtu3 *mtu, int is_on); +int mtu3_dev_on_off(struct mtu3 *mtu, int is_on); void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed); int mtu3_gadget_setup(struct mtu3 *mtu); diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index 2f5cc9b1480..d9df55ac5fe 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -10,10 +10,13 @@ #include <linux/log2.h> #include <linux/bitmap.h> +#include <linux/iopoll.h> #include "mtu3.h" #include "mtu3_dr.h" +#define MTU3_TX_FIFO_DRAIN_TIMEOUT_US 1000 + static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size) { struct mtu3_fifo_info *fifo = mep->fifo; @@ -226,6 +229,34 @@ static void mtu3_ep_reset(struct mtu3_ep *mep) mtu3_clrbits(mtu->mac_base, U3D_EP_RST, rst_bit); } +static int mtu3_wait_for_tx_fifo_empty(struct mtu3 *mtu) +{ + struct mtu3_ep *mep; + u32 value; + int err; + int ret = 0; + int i; + + for (i = 1; i < mtu->num_eps; i++) { + mep = mtu->in_eps + i; + if (!(mep->flags & MTU3_EP_ENABLED) || + !list_empty(&mep->req_list)) + continue; + + err = readl_poll_timeout(mtu->mac_base + MU3D_EP_TXCR0(i), + value, value & TX_FIFOEMPTY, + MTU3_TX_FIFO_DRAIN_TIMEOUT_US); + if (err) { + dev_warn(mtu->dev, "%s TX FIFO did not drain\n", + mep->name); + mtu3_ep_reset(mep); + ret = err; + } + } + + return ret; +} + /* set/clear the stall and toggle bits for non-ep0 */ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set) { @@ -261,8 +292,15 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set) set ? "SEND STALL" : "CLEAR STALL, with EP RESET"); } -void mtu3_dev_on_off(struct mtu3 *mtu, int is_on) +int mtu3_dev_on_off(struct mtu3 *mtu, int is_on) { + int ret = 0; + + /* QMU completion may precede transmission from the TX FIFO. */ + if (!is_on) + ret = mtu3_wait_for_tx_fifo_empty(mtu); + + /* Force the disconnect after a timeout; the failed endpoint was reset. */ if (mtu->is_u3_ip && mtu->speed >= USB_SPEED_SUPER) mtu3_ss_func_set(mtu, is_on); else @@ -270,6 +308,8 @@ void mtu3_dev_on_off(struct mtu3 *mtu, int is_on) dev_info(mtu->dev, "gadget (%s) pullup D%s\n", usb_speed_string(mtu->speed), is_on ? "+" : "-"); + + return ret; } void mtu3_start(struct mtu3 *mtu) diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 027b7e61113..da633faae7b 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -451,6 +451,7 @@ static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on) { struct mtu3 *mtu = gadget_to_mtu3(gadget); unsigned long flags; + int ret = 0; dev_dbg(mtu->dev, "%s (%s) for %sactive device\n", __func__, is_on ? "on" : "off", mtu->is_active ? "" : "in"); @@ -464,12 +465,12 @@ static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on) mtu->softconnect = is_on; } else if (is_on != mtu->softconnect) { mtu->softconnect = is_on; - mtu3_dev_on_off(mtu, is_on); + ret = mtu3_dev_on_off(mtu, is_on); } spin_unlock_irqrestore(&mtu->lock, flags); - return 0; + return ret; } static int mtu3_gadget_start(struct usb_gadget *gadget, |
