Skip to content

boards/rp2040: add USB fastboot support for waveshare boards - #20083

Merged
acassis merged 3 commits into
apache:masterfrom
JianyuWang0623:rp2040/fastboot-usb
Sep 8, 2026
Merged

boards/rp2040: add USB fastboot support for waveshare boards#20083
acassis merged 3 commits into
apache:masterfrom
JianyuWang0623:rp2040/fastboot-usb

Conversation

@JianyuWang0623

@JianyuWang0623 JianyuWang0623 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds USB fastboot support for the waveshare RP2040 boards and fixes a
real RP2040 usbdev driver bug found in the process (Stage 2 of the
"RP2040 waveshare series optimization" work, following the already
merged reboot-bootloader change in #20059).

  • boards/arm/rp2040/common/src/rp2040_composite.c: add a third
    composite slot for CONFIG_USBADB (the generic ADB driver, which
    with CONFIG_USBFASTBOOT becomes the "fastboot" personality)
    alongside the existing MSC/CDC-ACM slots.
  • New fastboot_usb defconfig for waveshare-rp2040-zero and
    waveshare-rp2040-lcd-1.28: boots directly into fastbootd
    (CONFIG_INIT_ENTRYPOINT="fastbootd_main", no nsh) and brings up a
    CDC/ACM (console) + USB fastboot composite device via
    CONFIG_SYSTEM_FASTBOOTD_USB_BOARDCTL, so the CDC/ACM sub-interface
    still provides console/log visibility without a wired UART, while
    the fastboot vendor interface is what fastboot devices/getvar
    talk to.
  • arch/arm/src/rp2040/rp2040_usbdev.c: fix a bug in
    rp2040_allocep() that this new fastboot config exposed. It indexes
    the endpoint's DPSRAM buffer/control registers via
    RP2040_DPINDEX(eplog)/RP2040_EPINDEX(eplog), both of which take
    the transfer direction from the direction bit of eplog itself
    instead of trusting the explicit in argument also passed to this
    function. This is harmless for callers that always encode the
    direction bit into eplog (e.g. CDC/ACM's
    CDCACM_MKEPBULKIN()/MKEPINTIN(), which OR in USB_DIR_IN), but
    drivers/usbdev/usbdev_fs.c (the generic ADB/fastboot class driver)
    calls DEV_ALLOCEP() with a bare endpoint number in eplog (no
    direction bit) and passes direction only via in - matching this
    function's own "direction bit ignored" contract for eplog. For
    such a bare-number IN endpoint, USB_ISEPOUT(eplog) always
    evaluates true, so RP2040_DPINDEX(eplog) silently pointed the
    endpoint's buffer/control registers at its OUT slot instead of its
    IN slot, leaving the real IN slot unconfigured; the SIE then
    responds to every IN token on that endpoint with a STALL. The fix
    normalizes eplog to agree with in once, up front, so both
    macros keep their original single-argument form.

Impact

  • RP2040 only.
  • The rp2040_allocep() fix affects every RP2040 board, but only
    changes behavior for callers that pass a bare (no direction bit)
    eplog, which today is exactly the generic ADB/fastboot driver;
    existing CDC/ACM/MSC/composite configs already encode the direction
    bit and are unaffected (verified: no behavior change observed on
    the existing usbnsh/composite configs used in prior testing).

Testing

Host: Ubuntu (x86_64), arm-none-eabi-gcc, built with
make PICO_SDK_PATH=<pico-sdk> (required for the boot2 stage to be
included in the generated .uf2).

Board: waveshare-rp2040-lcd-1.28 (physically connected over USB via
picotool/BOOTSEL for flashing). waveshare-rp2040-zero's
fastboot_usb defconfig was build-tested only (no second physical
board available in this environment).

Before the rp2040_usbdev.c fix, the fastboot USB interface enumerated
correctly but every response from device to host hard-STALLed.
Captured with usbmon on a getvar:product request:

S Bo:1:050:7 -115 14 = 67657476 61723a70 726f6475 6374   (OUT "getvar:product", host->device, succeeds)
C Bo:1:050:7 0 14 >
S Bi:1:050:6 -115 64 <                                    (IN, device->host, host requests the reply)
C Bi:1:050:6 -32 0                                        (completes with errno -32 = EPIPE, i.e. a real STALL)

After the fix, on the same board/defconfig:

$ lsusb -v -d 03eb:2023 | grep -E "bInterfaceNumber|bInterfaceClass"
      bInterfaceNumber        0
      bInterfaceClass         2 Communications
      bInterfaceNumber        1
      bInterfaceClass        10 CDC Data
      bInterfaceNumber        2
      bInterfaceClass       255 Vendor Specific Class

$ fastboot devices
0101	fastboot

$ fastboot getvar product
product: NuttX
Finished. Total time: 0.001s

$ fastboot reboot bootloader
Rebooting into bootloader                          OKAY [  0.000s]

dmesg shows clean enumeration with no can't set config errors and
all three interfaces bound:

usb 1-5.4: New USB device found, idVendor=03eb, idProduct=2023, bcdDevice=10.10
usb 1-5.4: Product: NuttX Fastboot Composite
usb 1-5.4: Manufacturer: NuttX
cdc_acm 1-5.4:1.0: ttyACM5: USB ACM device

tools/nxstyle and tools/checkpatch.sh are clean for both commits'
actual changed lines (spot-checked directly; checkpatch.sh -g HEAD
reports All checks pass; some pre-existing, unrelated nxstyle
violations in rp2040_usbdev.c predate this series - confirmed via
git blame to point at the original 2021 driver commit b860e3c4ad35

  • and are not touched by either commit here).

@github-actions github-actions Bot added Arch: arm Issues related to ARM (32-bit) architecture Size: M The size of the change in this PR is medium Board: arm labels Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

Comment thread arch/arm/src/rp2040/rp2040_usbdev.c

@acassis acassis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JianyuWang0623 please add fastboot_usb to the board Documentation to list it and explain how to use

Add a CDC/ACM (console) + USB fastboot (ADB "fastboot" personality)
composite device to the shared rp2040_composite.c board glue, and a
new "fastboot_usb" defconfig for waveshare-rp2040-zero and
waveshare-rp2040-lcd-1.28.

- boards/arm/rp2040/common/src/rp2040_composite.c: add a third
  composite slot for CONFIG_USBADB (covers both plain ADB and, with
  CONFIG_USBFASTBOOT, the "fastboot" personality of the same driver)
  alongside the existing MSC/CDC-ACM slots.  While adding this,
  fixed a latent bug: the CDC/ACM block never advanced ifnobase/
  strbase after filling in its own slot, because CDC/ACM used to
  always be the *last* device in the composite (nothing downstream
  ever needed the incremented values).  Now that a device can follow
  CDC/ACM, the missing increment caused the fastboot interface to be
  assigned the same USB interface number as CDC/ACM's control
  interface (both 0), which the Linux kernel rejects with "Duplicate
  descriptor for config 1 interface 0 altsetting 0, skipping" and
  drops the fastboot interface entirely (confirmed via lsusb -v and
  disassembly of the generated board_composite_connect() code).

- boards/arm/rp2040/waveshare-rp2040-zero/configs/fastboot_usb and
  boards/arm/rp2040/waveshare-rp2040-lcd-1.28/configs/fastboot_usb:
  new defconfig booting directly into fastbootd
  (CONFIG_INIT_ENTRYPOINT="fastbootd_main", no nsh) which brings up
  the CDC/ACM + fastboot composite via
  CONFIG_SYSTEM_FASTBOOTD_USB_BOARDCTL as soon as fastbootd starts,
  so the CDC/ACM sub-interface still provides a console for boot/
  fastbootd log visibility without requiring a wired UART, while the
  fastboot vendor interface is what `fastboot devices`/`getvar` talk
  to.

Assisted-by: OpenCode:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
rp2040_allocep() indexes the endpoint's DPSRAM buffer/control
registers via RP2040_DPINDEX(eplog) and RP2040_EPINDEX(eplog), both
of which take the transfer direction from the direction bit of
'eplog' itself instead of trusting the explicit 'in' argument that
is also passed to this function.

This is harmless for callers that always encode the direction bit
into 'eplog' (e.g. CDC/ACM's CDCACM_MKEPBULKIN()/MKEPINTIN(), which
OR in USB_DIR_IN), since 'in' then always agrees with that bit.  But
drivers/usbdev/usbdev_fs.c (the generic ADB/fastboot class driver)
calls DEV_ALLOCEP() with a bare endpoint number in 'eplog' (no
direction bit) and passes the direction only via the separate 'in'
parameter - matching this function's own "direction bit ignored"
contract for 'eplog' (see its Input Parameters doc, and the
pre-existing "Ignore any direction bits in the logical address"
comment, both dating back to the original driver in b860e3c).
For such a bare-number IN endpoint, USB_ISEPOUT(eplog) always
evaluates true (the IN bit is never set on a plain number), so
RP2040_DPINDEX(eplog) silently pointed the endpoint's buffer/control
registers at its OUT slot instead of its IN slot.  The real IN slot
was left unconfigured, so the SIE responded to every IN token on
that endpoint with a STALL - confirmed on real hardware via usbmon:
'C Bi:1:050:6 -32 0' (EPIPE) on every attempt, while the paired OUT
endpoint (which "accidentally" resolved to the correct slot for the
same reason) worked fine.

Fix: normalize 'eplog' to agree with the explicit 'in' argument
before it is used by RP2040_EPINDEX()/RP2040_DPINDEX(), so both
macros keep their original, single-argument form and every use of
eplog's direction bit below this point is consistent with 'in'.
Existing 0x80-encoded callers (EP0, CDC/ACM) already agree with 'in'
and are unaffected by the normalization.

Also fix two pre-existing nxstyle violations in this same file
(a misaligned comment block under USB_REQ_SYNCHFRAME, and a bare
';' body instead of empty braces on a while loop), both dating back
to the original driver in b860e3c as well; CI runs nxstyle on
the whole file whenever it is touched.

Assisted-by: OpenCode:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Add a "fastboot_usb" section to the waveshare-rp2040-zero and
waveshare-rp2040-lcd-1.28 board doc pages, describing the USB fastboot
composite configuration added by the previous commits: fastbootd runs
on boot instead of NSH, composed together with CDC/ACM for the
console, and reachable on the host via fastboot devices/getvar/reboot.

Assisted-by: OpenCode:claude-sonnet-5
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
@github-actions github-actions Bot added the Area: Documentation Improvements or additions to documentation label Sep 8, 2026
@JianyuWang0623

Copy link
Copy Markdown
Contributor Author

@JianyuWang0623 please add fastboot_usb to the board Documentation to list it and explain how to use

@acassis done, "Documentation/rp2040: document fastboot_usb config for waveshare boards"

@JianyuWang0623
JianyuWang0623 marked this pull request as ready for review September 8, 2026 05:58
@acassis
acassis merged commit f17c655 into apache:master Sep 8, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Area: Documentation Improvements or additions to documentation Board: arm Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants