error_count and hcint_cplt_pending track one transfer but live in the
channel, so the next transfer to claim it could start one error away
from failing or with a stale completion bit. Reset both on claim.
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Claude:opus-5.5
nRF7120 shares the same host quirks as nRF54LM20. Extend the series
check to include nRF71 series so the driver builds correctly on
nRF7120-DK.
Signed-off-by: Tomasz Moń <tomasz.mon@nordicsemi.no>
R_USBH_PortOpen() takes hub_addr/hub_port to program the controller's
split-transaction (UPPHUB/HUBPORT) fields for FS/LS devices behind a
high-speed hub, but both call sites hardcoded 0, 0 (root port),
leaving any device behind a hub addressed incorrectly except by
accident when the hub sits directly on the root port.
struct usb_device already carries the hub topology (hub, hub_port,
level, tt) populated by the generic USB host hub class driver, so add
get_hs_hub_addr_port() to walk a device's hub chain up to the nearest
high-speed ancestor and use its address and port, matching the
pattern used by uhc_mcux_common.c. This is not necessarily the
device's immediate parent, since one or more full-speed hubs can sit
between it and the high-speed hub performing the split.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: The.Thanh Nguyen <the.nguyen.yf@renesas.com>
We don't need to explicit lock the uhc_dwc2 mutex on
enqueue and dequeue, as it was already done via higher
calls uhc_ep_enqueue() and uhc_ep_dequeue().
Signed-off-by: Roman Leonov <jam_roma@yahoo.com>
The core disables the port on a disconnect, but when the line read
connected again by the end of the debounce, the driver only logged an
error and left the port disabled, so nothing was enumerated again. Tear
down in both cases; a device still attached is detected again after the
reset.
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Claude:opus-5.5
Channels held by transfers still running when a device disconnected were
never released. ch_claim() then dereferences their dangling transfer
pointers, and the free channel count never recovers. Release them when
the port reports the device gone.
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Claude:opus-5
An attach was reported at the speed the line state suggests, which is
full speed for a high-speed device until the port reset switches it over.
The host stack then read the device descriptor over a full-speed control
pipe, which fails on the high-speed bus, and enumerated the device again
only after the speed poll reported it removed and reconnected.
Reset the port first and report the device once, at the speed the reset
settled on.
Tested on an EK-RA8P1 with a Pixel 9 Pro XL: every attach enumerates on
the first descriptor read.
Assisted-by: Claude:opus-5.5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Nothing queued for a device that detached ever completes. The controller
withdraws a pending setup stage on a detach, so a control transfer caught
there was only handed back by the host stack's 5 s timeout, and transfers
left on a released pipe stayed at the head of its list, where the next
device's transfers queued behind them and a stale one was restarted.
On a detach, hand back every queued transfer with -ECONNRESET, as the
other UHC drivers do, so that its owner can release it. Do the same
before resetting a newly attached device, for what was queued after the
detach was handled.
Tested on an EK-RA8P1 with a Pixel 9 Pro XL and an Android Open
Accessory host application: after a reset with the phone attached, the
control transfer caught by the detach comes back at once rather than
after the 5 s timeout, and the session starts 2 to 3 s after the reset
instead of 7 s.
Assisted-by: Claude:opus-5.5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
A device that repeats a packet whose ACK it missed makes the core
acknowledge and drop it, then halt the channel with DTGERR. An interrupt
IN channel left that unhandled and stopped polling, which stalled the
status endpoint of a hub. Take the toggle the core now expects and poll
again at the next interval. Seen with a GL850G hub on an ESP32-P4.
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Claude:opus-5.5
Shutting down the high-speed controller cleared the ICU event link of
the full-speed interrupt, which that controller does not have. Its
vector is FSP_INVALID_VECTOR, which is negative, so the write landed 33
words before the IELSR table, and the high-speed event stayed linked.
Clear the link of the interrupt that was set up.
Tested on an EK-RA8P1 with an application that initializes, enables,
disables and shuts down the host stack: after the shutdown, IELSR for
the USBHS interrupt reads 0 instead of the USBHS event.
Assisted-by: Claude:opus-5.5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
The STM32 UDC endpoint dequeue path currently flushes the endpoint and
cancels queued requests without explicitly aborting an active transfer.
Use the STM32 HAL endpoint abort operation before flushing and cancelling
the endpoint queue so that an in-progress transfer is stopped before the
queued requests are released.
Signed-off-by: Ahmed Ashraf NourEldeen <a.programmer55559@gmail.com>
The driver thread logs every new transfer at info level. With the
console on CDC-ACM, each log line queues an IN transfer, which logs
again, so the console floods endlessly and the CPU is kept busy. This
is per-transfer tracing: log it at debug level, as the other UDC
drivers do.
Assisted-by: Claude:opus-5.5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
The endpoint state was only cleared at controller init, so a device
attached after another was removed inherited its data toggles and its
first transfers were dropped as duplicates. Clear it on a bus reset,
which returns every endpoint to DATA0.
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Claude:opus-5
The STM32 OTG (dwc2) UDC allocated each IN endpoint's TxFIFO with
HAL_PCDEx_SetTxFiFo() on ep_enable and released it on ep_disable.
HAL_PCDEx_SetTxFiFo() does not take an offset: it derives the FIFO's start
address from the sum of the RxFIFO, the EP0 TxFIFO and every lower-indexed
TxFIFO read from the live core registers, i.e. it always packs FIFOs
contiguously in ascending index order. That is only correct when IN
endpoints are enabled once, in ascending index order, and never disabled
and re-enabled -- which the USB stack does not guarantee.
A UAC2 full-duplex device is a concrete counter-example. It has two audio
streaming interfaces the host enables independently via SET_INTERFACE as
the playback and capture streams start, stop and recover (an ALSA underrun
re-selects the alternate setting): a playback OUT interface carrying an
explicit-feedback IN endpoint and a capture IN interface. When the capture
IN endpoint (higher index) is enabled while the feedback IN endpoint (lower
index) is still disabled, HAL_PCDEx_SetTxFiFo() computes the capture FIFO's
offset with the feedback FIFO depth still zero and places capture at the
offset the feedback FIFO will later occupy. Enabling the feedback endpoint
then places its FIFO on top of the capture FIFO. The overlapping TxFIFOs
corrupt the OTG core: every IN endpoint (including an unrelated CDC-ACM
management interface) wedges with no recovery short of a power cycle. The
FIFO RAM is not exhausted (~928/1280 B used); the failure is purely a
layout overlap.
Track the FIFO RAM with a per-instance bitmap (one bit per 32-bit word,
sys_bitarray) and program each IN endpoint's DIEPTXF start address and
depth
explicitly. A TxFIFO is allocated from the bitmap on enable and released on
disable, and its explicit offset means it never moves or overlaps another
endpoint's FIFO regardless of the order in which endpoints are enabled and
disabled. Unlike a scheme that freezes reservations to avoid the overlap,
releasing on disable lets the RAM be reused, so reconfiguring endpoints
with
different sizes cannot spuriously fail to fit.
The bitmap is sized from the device's ram-size and reserves the RxFIFO and
EP0 TxFIFO region up front; there is no new Kconfig and no dynamic
allocation. Only the OTG path is changed; the st,stm32-usb (PMA) path is
untouched.
Verified on an STM32U575 (OTG-FS) UAC2 full-duplex composite device
(playback iso-OUT + explicit-feedback iso-IN + capture iso-IN, plus
CDC-ACM): no core wedge over a stress run with the capture and playback
streams starting, stopping and recovering out of order, CDC-ACM stays
alive throughout, and a UAC2 loopback round-trips with correlation 1.0 and
0 dropouts (SNR 65 dB). Before the change the same setup wedged all IN
endpoints within seconds of the first ALSA underrun.
Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Peter Buchegger <peter.buchegger7@gmail.com>
Since commit 3cb68a9fc4 ("drivers: usb: common: stm32_pwr: add
support for STM32H5E/F line"), stm32_usb_pwr_enable() and
stm32_usb_pwr_disable() call LL_PWR_EnableVddUSB() and
LL_PWR_DisableVddUSB() on every STM32H5. STM32H503 has no PWR_USBSCR
register, as its USB transceiver is supplied from VDD (RM0492 Rev 3
section 9.4.5), and the HAL does not define these functions for it, so
any build that enables the USB device controller on it fails.
Call them only when PWR_USBSCR_USB33SV is defined, which is how this
file selected them on STM32H5 before that commit.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: YunHung Hua <oliverhua.us@gmail.com>
Use sys_ref to track the lifetime of the transfer when it is passed
between the layers. The semantics is similar to net_buf's
net_buf_ref()/net_buf_unref(). This also removes the need to call
uhc_xfer_free() and simplifies the reuse of the transfer by the class
drivers.
uhc_xfer_free() should be removed once all the users are ported to use
uhc_xfer_unref().
Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
When operating in Buffer DMA mode, DWC2 driver would stop responding to
control transfer under following scenario:
1. USB host issues control transfer, device ACKs it
2. USB device stack starts processing control transfer
3. USB host suspends the bus
4. DWC2 driver enters hibernation
5. USB stack finishes processing control transfer, enqueues buffers
6. USB host issues bus reset or resumes the bus
7. DWC2 driver exits hibernation
8. USB host issues new control transfer, device ACKs it
9. USB device stack never gets the setup buffer because the controller
did not issue any interrupt. DWC2 driver is completely unaware that
the host started control transfer.
Fix the issue by detecting the problematic condition on hibernation exit
and cancelling obsolete requests and/or enqueueing SETUP buffer.
Signed-off-by: Tomasz Moń <tomasz.mon@nordicsemi.no>
Nothing keeps the PM policy from putting the SoC into Stop while the
controller is enabled. On STM32F4, Stop disables the PLLs (RM0090
Rev 22 sections 5.3.4 and 5.3.5), including the one whose Q output
clocks the OTG controllers, so on an STM32F429I-DISC1 with CONFIG_PM=y
the device never enumerates.
Lock PM_STATE_SUSPEND_TO_IDLE, and PM_STATE_SUSPEND_TO_RAM with
CONFIG_PM_S2RAM, from udc_stm32_enable() until udc_stm32_disable(), as
uart_stm32, spi_stm32 and the other STM32 drivers do while they are
busy. udc_disable() marks the controller disabled even when
udc_stm32_disable() fails, so the states are released on every path
out of it.
Tested on the STM32F429I-DISC1: samples/subsys/usb/cdc_acm enumerates
with CONFIG_PM=y, and the SoC no longer enters Stop while the
controller is enabled.
Fixes#120448
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: YunHung Hua <oliverhua.us@gmail.com>
First commit to support UHC driver for Renesas RA family
Signed-off-by: Minh Hoang <minh.hoang.wm@bp.renesas.com>
Signed-off-by: The Nguyen <the.nguyen.yf@renesas.com>
Since hclk is not fixed in sama7d65, added hclk control feature.
Add clock control when suspending and resuming for better power efficiency.
Signed-off-by: CHEN Xing <xing.chen@microchip.com>
max3421e_xfer_data() limited each OUT packet to MAX3421E_MAX_EP_SIZE
instead of the endpoint's maximum packet size, overrunning an endpoint
whose mps is smaller. The IN path has already been fixed; this is the
same defect on the OUT side.
Pass the transfer rather than the endpoint address so both ep and mps
are available.
Not exercised on hardware: enumeration uses no OUT data stage, so the
bug is latent there and only reached by a bulk OUT or a class request to
such a device.
Assisted-by: Claude:claude-opus-5
Signed-off-by: John Goble <john.goble@nimbusdigital.com>
To support external USB hubs, we need to distinguish
data not only by endpoint number, but also by device
address. For this purpose additional members were
added to the channel data structure, that now holds
the information and do not interfere, when several
devices has the same endpoint number.
Signed-off-by: Roman Leonov <jam_roma@yahoo.com>
Interrupt transfer is a periodic transfer which USB host
needs periodically to poll at a fixed interval.
ch_handle_in_interrupt() handles the IN interrupt during the
channel IRQ handling.
ch_schedule_interrupt and ch_start_interrupt() to schedule the
frame for periodic transfer and start it, using the enqueued
xfer.
validate_interrupt_xfer() to verify the correctness of the
enqueued xfer to provide the better debug options.
Signed-off-by: Roman Leonov <jam_roma@yahoo.com>
The MAXUSB HAL kills every pending request on a bus reset without
running its completion callback, and udc_setup_received() clears the
busy flag for the control pair only. A bulk endpoint that was
mid-transfer therefore stays busy for good, and udc_event_xfer_out()
returns before arming it without a word: the endpoint never delivers
again until the part is reset.
Clear it where the transfer is abandoned - in ep_dequeue, as every other
UDC driver does, and in ep_disable, whose MXC_USB_ResetEp() drops the
transfer too.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Maureen Helm <maureen.helm@analog.com>
CONFIG_UDC_DRIVER_LOG_LEVEL only exists when CONFIG_LOG is enabled, so
using it in a plain C condition breaks any build that compiles this
driver without logging.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Tom Burdick <thomas.burdick@infineon.com>
This change enhances USB_HostHelperGetPeripheralInformation()
so the MCUX USB host driver can correctly report hub-related
topology data, including the parent hub address, port number,
nearest high speed hub, HS hub port, hub think time and level.
The goal is to ensure proper device identification and routing,
especially when full speed or low speed devices are connected
behind multi level or high speed hubs.
Signed-off-by: Aiden Hu <weiwei.hu@nxp.com>
Dynamically allocating fifo sizes leads to very complex code that yields
subpar results. DWC2 controller has very specific requirements related
to configured FIFO sizes that significantly increase the complexity:
* each fifo has specific upper bound on both size and starting
location (fixed for each silicon)
* assigned locations must be contiguous
* assigned locations cannot be changed on-the-fly
Zephyr tried to dynamically assign fifos using simple but essentially
broken algorithm that:
* assumed 1-to-1 endpoint number to TxFIFO mapping
DWC2 controller can be configured with non-contiguous IN endpoint
numbers, but TxFIFOs are always contiguous.
* allocated minimum required space for each endpoint
There is no benefit in using less SPRAM than hardware has available,
but using only 128 locations per bulk endpoint significantly limits
maximum transfer rate when using DMA. At least 256 locations allows
DMA to load next packet data before previous packet is transmitted
on the bus. Actual performance degradation depends on clock rates
and latencies. MSC on nRF54H20 using bulk endpoints with only 128
locations can achieve no more than 15.6 MB/s throughput, while with
256 locations speeds up to 36.9 MB/s are possible (running otherwise
identical software).
* used one-size-fits-all defaults for RxFIFO
Remedied with some upper limits calculated at runtime, but the limit
was not taking into account complete configuration.
* was unable to effectively handle multiple alternate settings
This did lead to set interface failures where e.g. HID interface
with wMaxPacketSize > 64 was not using the highest numbered IN
endpoint within active configuration.
Instead of trying to come up with bandaid for each issue that would
significantly complicate the code, just shift the responsibility towards
firmware developer. While for many typical applications board defaults
are perfectly fine, the application developer may want to come up with
specific devicetree overrides best suited for their use case.
Signed-off-by: Tomasz Moń <tomasz.mon@nordicsemi.no>
Cache maintenance was being done on the DMA address after
uhc_dwc2_quirk_dma_addr_xlate() translated it, which is not
CPU-visible on some platforms and causes a data abort. Move
cache maintenance before the translation in ch_process_control(),
ch_start_control(), and ch_start_bulk().
Signed-off-by: Muhammad Waleed Badar <walid.badar@gmail.com>
dma_addr is an integer type, not a pointer, so comparing it
against NULL and passing it directly to sys_cache_data_invd_range()
/sys_cache_data_flush_range() was incorrect.
Signed-off-by: Muhammad Waleed Badar <walid.badar@gmail.com>
Each channel gets an event bit at UHC_DWC2_EVENT_PORT_PEND_CHANNEL plus
its index, so the enumerator has to be last. It sat in the middle, and on
a controller with several channels those bits collided with the suspend,
resume and dequeue events. Found on an STM32N6570-DK, which has 16.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Typically Zephyr device tree macros that take a node_id as argument
start with DT_ and those that take an inst start with DT_INST_.
For the STM32 clock driver we currently have two macros named
STM32_DT_INST_CLOCK_INFO_BY_NAME and STM32_CLOCK_INFO_BY_NAME.
For consistency, the latter is renamed STM32_DT_CLOCK_INFO_BY_NAME.
Signed-off-by: Guillaume Gautier <guillaume.gautier-ext@st.com>
Update the STM32 HAL module to new revision with updated STM32Cube
package for various series and update the RTC driver accordingly:
some function that was named differently in STM32CubeU3 vs. all other
series has been realigned to the usual name so an #if SERIES check in
that driver can - in fact, must - be dropped.
Signed-off-by: Mathieu Choplain <mathieu.choplain-ext@st.com>
The HAL2 glue currently works on STM32C5 series but is incomplete.
It will also break upon updating to STM32CubeC5 v2.1.0 because the API
changed a bit (bringing it closer to what existed in HAL1, really).
Plug the holes by implementing missing glue pieces, and removing any use
of the raw HAL1/HAL2 macros, except in udc_stm32_device_speed() for the
sake of simplicity. This ensures the glue works with STM32CubeC5 v2.1.0
and should ensure a series with OTG_HS Just Works, although this latter
claim has not been verified due to no such hardware being available.
Signed-off-by: Mathieu Choplain <mathieu.choplain-ext@st.com>
Add a BCM2835-specific vendor quirk that acquires the VideoCore
power domain through the runtime PM API in pre_enable, disable
and shutdown, and translate physical addresses to the DMA bus
address space using dma_addr_xlate hook.
Signed-off-by: Muhammad Waleed Badar <walid.badar@gmail.com>
Add uhc_dwc2_quirk_dma_addr_translation() call before each HCDMA write
(control setup/data, bulk) to allow platform-specific translation
of CPU-side buffer addresses into bus/DMA addresses (e.g. BCM2711
VC AXI +0xC0000000 offset) prior to being written into HCDMA.
Signed-off-by: Muhammad Waleed Badar <walid.badar@gmail.com>
Use mem_addr_t for DMA buffer addresses in control and bulk
transfers instead of uint8_t *.
Cast the buffer pointers to mem_addr_t when assigning the DMA
address.
Signed-off-by: Muhammad Waleed Badar <walid.badar@gmail.com>
The FIFO sizes were derived from full speed packet sizes regardless of
the speed the port came up at. On a high speed port a 512 byte bulk
OUT did not fit the non-periodic TX FIFO, so the channel halted with
only CHHLTD set and no status bit, which the OUT handler did not act
on: the transfer never completed and the caller timed out. The shared
RX FIFO was sized from a 256 byte packet and cannot absorb
back-to-back 512 byte IN packets, which overruns under a sustained
stream and reports transaction errors the driver does not recover
from.
Derive both the TX and the RX sizes from the speed the port reports,
and fail a transfer whose channel halts without a reason instead of
leaving the caller waiting.
Assisted-by: Claude:opus-5
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
Bulk transfers programmed HCDMA without any cache maintenance, so on
SoCs with a data cache the controller sent stale OUT payloads and the
CPU read stale IN data. A mass storage command block wrapper written
by the CPU never reached the device, which answered with a STALL.
Flush OUT payloads before starting the transfer and invalidate the IN
buffer both before the transfer and before the received data is
consumed.
Assisted-by: Claude:opus-5
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
The host driver programs HCDMA with buffers that live in cached
memory and never synchronised them, so on SoCs with a data cache the
controller read stale setup packets and the CPU read stale IN data.
On ESP32-P4 this surfaced as a spurious STALL on the first
GET_DESCRIPTOR, because the descriptor bytes fetched by DMA were
never visible to the CPU.
Flush the setup packet and OUT payloads before starting a transfer
and invalidate IN buffers before the data is consumed.
Assisted-by: Claude:opus-5
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
Add the UHC vendor quirk for the ESP32-P4 USB-OTG 2.0 controller so
the DWC2 host driver can drive the high speed port. The quirk enables
the peripheral clock, brings up the UTMI PHY and connects the D+/D-
pulldown resistors required in host mode.
The PHY is initialised from pre_init because the HAL init resets the
PHY, which must not happen once the host port is powered.
Assisted-by: Claude:opus-5
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
While processing ISR messages in the worker thread, acquire and hold the
UDC device lock to prevent races with the UDC API entrypoints which also
mutate the device state, leading to corruption.
Signed-off-by: Mathieu Choplain <mathieu.choplain-ext@st.com>
Do not schedule transfers while a bus reset or resume operation is in
progress. Starting a transfer during these operations can produce a
J-state error with some full-speed devices.
Keep scheduling disabled until the controller reports that the active
bus operation has completed.
Signed-off-by: Benjamin Jurewicz <bjurewicz@internships.antmicro.com>
The driver's endpoint configuration must be per instance.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
udc_mcux_ep_dequeue() must both cancel the transfer already submitted to
the HAL controller and drop the requests still queued in the endpoint
FIFO. The HAL controller reports its cancelled transfer (with
-ECONNABORTED) from the driver thread through the complete_bufs path, so
cancelling the FIFO-queued requests from the dequeue caller's context
would deliver their callbacks out of order with respect to the
HAL-cancelled one.
Request the HAL cancellation via deviceCancel() inline, but defer the
FIFO cancellation to the driver thread so that all -ECONNABORTED
callbacks are delivered from the same context and in order. A new
UDC_MCUX_EVT_DEQUEUE event carries a per-endpoint bitmask (ep_dequeue)
of the endpoints awaiting FIFO cancellation; the thread walks the mask,
calls udc_ep_cancel_queued() for each endpoint under the UDC lock, and
signals completion through a condition variable (dequeue_cond). The
caller waits on that condvar so the operation still appears synchronous.
add k_sched_lock to avoid the meaningless context switch.
The busy-state clearing is removed, as the HAL driver's transfer
cancellation callback already handles it.
Signed-off-by: Mark Wang <yichang.wang@nxp.com>
The NXP MCUX EHCI and IP3511 UDC drivers previously processed controller
events through a k_mem_slab event pool, a k_fifo, and the shared system
workqueue. Each notification allocated an event block, copied the HAL
message, and queued work; the slab could be exhausted under load and the
transfer buffer was only touched later in workqueue context.
Rework both drivers to use a dedicated per-instance driver thread woken
by a single k_event. Completed transfer buffers are now updated in place
in the HAL notification (ISR) context, detached from the endpoint queue,
and appended to a per-instance complete_bufs slist; the thread drains
the list and reports each buffer to the stack, then feeds the next
queued request. Multiple completions coalesce into a single
UDC_MCUX_EVT_XFER wake-up and bus reset is handled under
UDC_MCUX_EVT_RESET.
The now-unused event slab, k_fifo, and workqueue dependency are removed,
and Kconfig gains per-driver thread stack-size and priority options.
Signed-off-by: Mark Wang <yichang.wang@nxp.com>