This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 8205f941d6bd4fc5aa0354cef885c7ee06a0d197
Author: Ricard Rosson <[email protected]>
AuthorDate: Wed Jul 8 22:05:03 2026 +0100

    arch/rp2040: set buffer AVAILABLE bit after the rest of buffer control
    
    Per the RP2040 datasheet section 4.1.2.5.1, when handing a buffer to the
    USB controller the AVAILABLE bit must be written after the rest of the
    buffer-control register (length and data PID) and after a short delay,
    because buffer control crosses from the system clock domain into the USB
    clock domain.  Writing everything in a single store risks the controller
    acting on a stale length or PID.  rp2040_update_buffer_control() wrote
    the whole word, AVAILABLE included, in one access.
    
    Follow the sequence the datasheet (and the Pico SDK) use: write the
    control word with AVAILABLE cleared, wait ~12 CPU cycles, then set
    AVAILABLE.  The delay covers system clocks up to 12x the 48 MHz USB
    clock.
    
    Validated on raspberrypi-pico (RP2040) as part of bringing up cdcncm;
    no regression on cdcacm/usbmsc.
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01AHJRvWeBMTHwzpwjaUg4HW
    Signed-off-by: Ricard Rosson <[email protected]>
---
 arch/arm/src/rp2040/rp2040_usbdev.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm/src/rp2040/rp2040_usbdev.c 
b/arch/arm/src/rp2040/rp2040_usbdev.c
index 0bdc06deb29..ceb7a9e965c 100644
--- a/arch/arm/src/rp2040/rp2040_usbdev.c
+++ b/arch/arm/src/rp2040/rp2040_usbdev.c
@@ -473,6 +473,7 @@ static void rp2040_update_buffer_control(struct rp2040_ep_s 
*privep,
                                          uint32_t or_mask)
 {
   uint32_t value = 0;
+  int i;
 
   if (and_mask)
     {
@@ -482,6 +483,24 @@ static void rp2040_update_buffer_control(struct 
rp2040_ep_s *privep,
   if (or_mask)
     {
       value |= or_mask;
+
+      if (or_mask & RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL)
+        {
+          /* RP2040 datasheet 4.1.2.5.1: the AVAILABLE bit must be set
+           * after the rest of the buffer control register has been
+           * written and had time to settle across the clock domain
+           * crossing, or the controller may act on a stale length/PID.
+           * 12 CPU cycles covers system clocks up to 12x clk_usb.
+           */
+
+          putreg32(value & ~RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL,
+                   privep->buf_ctrl);
+
+          for (i = 0; i < 12; i++)
+            {
+              __asm__ volatile("nop");
+            }
+        }
     }
 
   putreg32(value, privep->buf_ctrl);

Reply via email to