Skip to content

Migrate NXP Kinetis khci to chipidea ci_fs (device + host) + fixes#3763

Open
hathach wants to merge 5 commits into
masterfrom
claude/migrate-khci-to-ci_fs
Open

Migrate NXP Kinetis khci to chipidea ci_fs (device + host) + fixes#3763
hathach wants to merge 5 commits into
masterfrom
claude/migrate-khci-to-ci_fs

Conversation

@hathach

@hathach hathach commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

Completes the NXP Kinetis khci → chipidea ci_fs driver migration that was started for device only (commit d70403f1f"host is not yet"), and fixes two pre-existing driver bugs surfaced by HIL testing.

  • device: switch kinetis_k/kl/k32l (Makefiles + k32l CMake) to dcd_ci_fs.c
  • host: add hcd_ci_fs.c (port of hcd_khci.c onto the shared ci_fs_regs_t) and switch all Kinetis families to it; remove src/portable/nxp/khci/ entirely
  • enable host examples (device_info, cdc_msc_hid) for mcu:KINETIS_K
  • README: merge the KL and K32L2 rows into a single KL, K32L ci_fs row

Bug fixes (pre-existing — present in the old khci driver too)

  1. dcd_ci_fs — device OUT even/odd BDT desync. A multi-packet OUT arms both even/odd BDTs; on a short packet the sibling was left armed, desyncing the ping-pong so the next OUT landed in the wrong buffer half → stack read stale data. Fixes device/mtp hanging on Kinetis (MSC only arms single-packet command receives, so it never hit this path).
  2. hcd_ci_fs — host data toggle flipped on NAK. A NAK transfers no data, so the toggle must be preserved; the retried bulk packet was going out with the wrong DATA0/1 and being silently discarded (MSC CBW/CSW hang). Also: prepare_packets asserted and dropped a transfer when the single shared BDT was busy under concurrent activity — now it defers and retries on the next SOF.

BSP / CI

  • kinetis_k: implement non-blocking board_uart_read via an RDRF-interrupt RX FIFO (matching stm32; board_uart_write already non-blocking), and board_get_unique_id() from the SIM 128-bit UID.
  • add frdm_k64f host test (CDC + MSC behind a hub) to test/hil/tinyusb.json.

HIL verification (real hardware)

  • Device: frdm_kl25z and frdm_k64f13/13 (cdc, msc, dfu, throughput, audio/iso, hid, midi, printer, mtp, …).
  • Host (frdm_k64f): host/cdc_msc_hid passes — CDC mount + line coding + 1024-byte echo, and MSC mount + disk-size check, through a USB hub.

Known limitation

host/device_info enumerates only the first of two devices behind a hub: its continuous synchronous descriptor dump starves the 2nd device's enumeration at the usbh control-transfer layer. This is a device_info/usbh interaction (not ci_fs — cdc_msc_hid enumerates both fine) and is left as-is.

Net: +~90 / −1200 lines (khci retired).

🤖 Generated with Claude Code

https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi

hathach and others added 4 commits July 10, 2026 00:17
Complete the khci -> chipidea ci_fs migration that was started for device
(commit d70403f "host is not yet"):

- device: switch kinetis_k/kl/k32l (Makefiles + k32l CMake) to dcd_ci_fs.c
- host: add hcd_ci_fs.c (port of hcd_khci.c onto ci_fs_regs_t) and switch all
  Kinetis families to it; remove src/portable/nxp/khci entirely
- enable host examples (device_info, cdc_msc_hid) for mcu:KINETIS_K
- README: merge the KL and K32L2 rows into a single "KL, K32L" ci_fs row

hcd_ci_fs.c also fixes two pre-existing host bugs found via HIL on frdm_k64f
(present in the old hcd_khci.c too):
- data toggle was flipped on a NAK in suspend_transfer; a NAK transfers no
  data so the toggle must be preserved, else the retried bulk packet is
  silently discarded by the device (MSC CBW/CSW hang). See comment in file.
- prepare_packets asserted and dropped a transfer when the single shared BDT
  was still owned by an in-flight transfer under concurrent activity; now it
  returns busy and resume_transfer defers/retries on the next SOF.

HIL verified on frdm_k64f: device 13/13, host cdc_msc_hid (CDC mount + echo +
MSC mount, through a hub).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
A multi-packet OUT transfer speculatively arms both even/odd BDTs to avoid
NAK. When the host ends the transfer early with a short packet, the sibling
BDT was left armed (own=1), desyncing the even/odd ping-pong so the next OUT
packet landed at buffer+max_packet_size instead of buffer and the stack read
stale data. Disarm the sibling on completion.

Fixes device/mtp on Kinetis (GetDeviceInfo command was received into the wrong
buffer half -> hang). Pre-existing (MSC only arms single-packet command
receives so it never hit the double-buffer path). HIL: frdm_kl25z & frdm_k64f
device 13/13.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
- board_uart_read was a stub returning 0, so host examples that bridge the
  UART console to a CDC device (echo test) received nothing. Implement it via
  an RDRF-interrupt-fed tu_fifo, matching the stm32 family (non-blocking, no
  RX overrun). board_uart_write is already non-blocking.
- implement board_get_unique_id() from the SIM 128-bit UID registers so
  frdm_k64f/teensy_35 report a real USB serial instead of the fixed default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
frdm_k64f as a USB host with a CH9102 CDC (TX-RX loopback) and a Lexar MSC
drive behind a hub; flasher = onboard OpenSDA J-Link. host/cdc_msc_hid passes
(CDC mount+echo, MSC mount + disk-size check). device_info remains a known
device_info/usbh limitation (its synchronous descriptor dump starves a 2nd
device's enumeration) and is not ci_fs-specific.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
Copilot AI review requested due to automatic review settings July 9, 2026 17:19
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copilot AI 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.

Pull request overview

Completes the NXP Kinetis USB driver migration from the legacy khci implementation to the shared ChipIdea-FS (ci_fs) register model across device + host, while also addressing two driver correctness issues found via HIL testing.

Changes:

  • Switch Kinetis BSP build recipes (Make + CMake) from src/portable/nxp/khci/* to src/portable/chipidea/ci_fs/* and retire the old KHCI DCD implementation.
  • Add/enable Kinetis host support via hcd_ci_fs.c, enable additional host examples for mcu:KINETIS_K, and extend HIL config with a new FRDM-K64F host test setup.
  • Fix dcd_ci_fs OUT ping-pong (even/odd BDT) desync by disarming the sibling BDT on early-terminated OUT transfers.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.

Show a summary per file
File Description
test/hil/tinyusb.json Adds frdm_k64f host test configuration and attached-device expectations.
src/portable/nxp/khci/dcd_khci.c Removes legacy KHCI device controller driver implementation.
src/portable/chipidea/ci_fs/hcd_ci_fs.c Updates/ports host controller driver to ci_fs_regs_t usage and adds scheduling fixes for busy BDT / toggle handling.
src/portable/chipidea/ci_fs/dcd_ci_fs.c Fixes OUT transfer ping-pong desync by disarming the sibling BDT on completion.
README.rst Updates Kinetis row(s) to reflect ci_fs usage.
hw/bsp/kinetis_kl/family.mk Switches KL build to dcd_ci_fs.c + hcd_ci_fs.c.
hw/bsp/kinetis_kl/family.cmake Switches KL CMake build to hcd_ci_fs.c.
hw/bsp/kinetis_k32l/family.mk Switches K32L build to dcd_ci_fs.c + hcd_ci_fs.c.
hw/bsp/kinetis_k32l/family.cmake Switches K32L CMake build to dcd_ci_fs.c + hcd_ci_fs.c.
hw/bsp/kinetis_k/family.mk Switches K build to dcd_ci_fs.c + hcd_ci_fs.c.
hw/bsp/kinetis_k/family.cmake Switches K CMake build to hcd_ci_fs.c.
hw/bsp/kinetis_k/family.c Improves UART RX handling using an IRQ-fed FIFO and adds SIM-based unique ID support.
examples/host/device_info/only.txt Enables device_info host example for mcu:KINETIS_K.
examples/host/cdc_msc_hid/only.txt Enables cdc_msc_hid host example for mcu:KINETIS_K.
Comments suppressed due to low confidence (1)

src/portable/chipidea/ci_fs/hcd_ci_fs.c:642

  • SOF (SOFTOK) handler clears _hcd.pending wholesale (_hcd.pending = 0;). Since _hcd.pending is a bitmap and this driver now sets bits from multiple paths (NAK retry + shared-BDT busy deferral), clearing all bits will silently drop other pending pipes/transfers. This can stall enumeration or concurrent bulk/interrupt transfers behind a hub.

Clear only the bit you're servicing, and only disable SOFTOK when no pending bits remain.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Size Difference Report

Because TinyUSB code size varies by port and configuration, the metrics below represent the averaged totals across all example builds.

Note: If there is no change, only one value is shown.

Changes >1% in size

file .text .bss size % diff
dcd_khci.c 1952 ➙ 0 (-1952) 1290 ➙ 0 (-1290) 3242 ➙ 0 (-3242) -100.0%
hcd_ci_fs.c 0 ➙ 2402 (+2402) 0 ➙ 469 (+469) 0 ➙ 2872 (+2872) n/a
hcd_khci.c 2443 ➙ 0 (-2443) 454 ➙ 0 (-454) 2897 ➙ 0 (-2897) -100.0%
TOTAL 4395 ➙ 2402 (-1993) 1744 ➙ 469 (-1275) 6139 ➙ 2872 (-3267) -53.2%
Changes <1% in size
file .text .rodata .data .bss size % diff
cdc_host.c 6399 ➙ 6405 (+6) 487 15 971 ➙ 946 (-25) 7594 ➙ 7565 (-29) -0.4%
dcd_ci_fs.c 1924 ➙ 1953 (+29) 0 0 1290 3214 ➙ 3243 (+29) +0.9%
hid_host.c 1246 ➙ 1247 (+1) 0 0 1270 ➙ 1288 (+18) 2516 ➙ 2534 (+18) +0.7%
msc_host.c 1633 ➙ 1625 (-8) 0 0 395 2028 ➙ 2020 (-8) -0.4%
tusb_fifo.c 855 ➙ 856 (+1) 0 486 0 850 ➙ 851 (+1) +0.1%
usbh.c 4979 57 82 ➙ 81 (-1) 1165 ➙ 1173 (+8) 6250 ➙ 6256 (+6) +0.1%
TOTAL 17036 ➙ 17065 (+29) 544 583 ➙ 582 (-1) 5091 ➙ 5092 (+1) 22452 ➙ 22469 (+17) +0.1%
No changes
file .text .rodata .data .bss size % diff
audio_device.c 2890 0 1259 1623 4508 +0.0%
cdc_device.c 1236 16 1092 728 1963 +0.0%
dcd_ch32_usbfs.c 1659 0 0 2444 4103 +0.0%
dcd_ch32_usbhs.c 1892 0 0 481 2373 +0.0%
dcd_ci_hs.c 1756 0 0 1344 2534 +0.0%
dcd_da146xx.c 3067 0 0 144 3211 +0.0%
dcd_dwc2.c 4223 19 0 265 4506 +0.0%
dcd_eptri.c 2273 0 0 259 2532 +0.0%
dcd_ft9xx.c 3284 0 0 172 3456 +0.0%
dcd_lpc17_40.c 1481 0 0 648 1805 +0.0%
dcd_lpc_ip3511.c 1463 0 0 264 1683 +0.0%
dcd_mm32f327x_otg.c 1477 0 0 1290 2767 +0.0%
dcd_msp430x5xx.c 1801 0 0 176 1977 +0.0%
dcd_musb.c 2595 0 0 179 2773 +0.0%
dcd_nrf5x.c 2939 0 0 292 3231 +0.0%
dcd_nuc120.c 1096 0 0 78 1174 +0.0%
dcd_nuc121.c 1170 0 0 101 1270 +0.0%
dcd_nuc505.c 0 0 1533 157 1690 +0.0%
dcd_rp2040.c 840 0 764 653 2257 +0.0%
dcd_rusb2.c 2918 0 0 156 3074 +0.0%
dcd_samd.c 1036 0 0 266 1302 +0.0%
dcd_samg.c 1322 0 0 72 1394 +0.0%
dcd_stm32_fsdev.c 2543 0 0 291 2834 +0.0%
dfu_device.c 776 28 712 136 912 +0.0%
dfu_rt_device.c 157 0 134 0 157 +0.0%
dwc2_common.c 603 22 0 0 615 +0.0%
ecm_rndis_device.c 1067 0 1 2759 3826 +0.0%
ehci.c 2763 0 0 6274 7783 +0.0%
fsdev_common.c 180 0 0 0 180 +0.0%
hcd_ch32_usbfs.c 2491 0 0 502 2993 +0.0%
hcd_ci_hs.c 181 0 0 0 181 +0.0%
hcd_dwc2.c 5071 25 1 545 5642 +0.0%
hcd_musb.c 3071 0 0 157 3228 +0.0%
hcd_pio_usb.c 262 0 240 0 502 +0.0%
hcd_rp2040.c 1996 17 4 321 2338 +0.0%
hcd_rusb2.c 2923 0 0 245 3168 +0.0%
hcd_samd.c 2220 0 0 324 2544 +0.0%
hcd_stm32_fsdev.c 3248 0 1 420 3670 +0.0%
hid_device.c 1124 44 997 119 1242 +0.0%
hub.c 1384 ➙ 1385 (+1) 8 8 30 1419 +0.0%
midi2_device.c 3006 34 1342 561 3579 +0.0%
midi2_host.c 1802 0 0 5921 7723 +0.0%
midi_device.c 1149 0 1007 619 1765 +0.0%
midi_host.c 1339 7 7 3538 4880 +0.0%
msc_device.c 2527 108 2293 804 3331 +0.0%
mtp_device.c 1713 22 743 589 2309 +0.0%
ncm_device.c 1766 28 821 4393 6172 +0.0%
ohci.c 1925 0 0 2503 4428 +0.0%
printer_device.c 828 0 706 560 1387 +0.0%
rp2040_usb.c 386 35 619 11 1051 +0.0%
rusb2_common.c 160 0 16 0 176 +0.0%
tusb.c 457 0 389 3 459 +0.0%
typec_stm32.c 1230 8 2 19 1255 +0.0%
usbc.c 500 2 20 166 688 +0.0%
usbd.c 3536 57 90 355 3955 +0.0%
usbtmc_device.c 2261 24 69 313 2606 +0.0%
vendor_device.c 639 0 534 559 1197 +0.0%
video_device.c 4433 5 1235 480 4905 +0.0%
TOTAL 104135 ➙ 104136 (+1) 509 16639 45309 150683 +0.0%

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

Top 10 targets by memory change (%) (out of 2406 targets) View Project Dashboard →

target .text .rodata .data .bss total % diff
frdm_k64f/board_test 860 → 1,004 (+144) 32 → 44 (+12) 892 → 1,048 (+156) +17.5%
frdm_k64f/dfu 13,476 → 13,724 (+248) 2,176 → 2,688 (+512) 15,940 → 16,700 (+760) +4.8%
frdm_k64f/dfu_runtime 9,964 → 10,200 (+236) 10,012 → 10,248 (+236) +2.4%
frdm_k64f/hid_generic_inout 10,804 → 11,040 (+236) 10,852 → 11,088 (+236) +2.2%
frdm_k64f/hid_multiple_interface 11,624 → 11,860 (+236) 11,672 → 11,908 (+236) +2.0%
frdm_k64f/hid_boot_interface 11,636 → 11,872 (+236) 11,684 → 11,920 (+236) +2.0%
frdm_k64f/hid_composite 11,800 → 12,036 (+236) 11,848 → 12,084 (+236) +2.0%
frdm_k64f/midi_test 11,780 → 11,984 (+204) 11,828 → 12,032 (+204) +1.7%
frdm_k64f/hid_composite_freertos 19,328 → 19,660 (+332) 19,448 → 19,780 (+332) +1.7%
frdm_k64f/usbtmc 13,684 → 13,920 (+236) 13,852 → 14,088 (+236) +1.7%

@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

hcd_ci_fs shares a single BDT set across all pipes. prepare_packets()
speculatively arms the sibling (odd^1) BDT of a multi-packet transfer so it
can ping-pong without NAKs. When such a transfer ends early (a short IN
packet) or fails, the still-owned sibling was never released, permanently
blocking the shared BDT for every other pipe.

This deadlocked a 2nd device enumerating behind a hub while another device
issued descriptor reads (host/device_info with CDC+MSC): the MSC's control
transfers could never acquire the BDT, so it never got Set Address.

Release the sibling in process_tokdne()'s completion path, but ONLY for a
multi-packet transfer (length > max_packet_size): a single-packet transfer
never arms a sibling, so that BDT slot may legitimately belong to another
pipe's in-flight transfer and must not be disturbed (doing so unconditionally
corrupts concurrent transfers, e.g. the CDC bulk-IN vs MSC enum in
host/cdc_msc_hid).

Mirrors the equivalent device-side fix in dcd_ci_fs.c; the host needs the
multi-packet guard because its BDT set is shared across pipes.

Verified on frdm_k64f (HIL): host/device_info now enumerates both CDC+MSC
behind a hub, host/cdc_msc_hid still mounts the MSC (no regression).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown

Hardware-in-the-loop (HIL) Test Report

hfp-iar

✅ 52 passed · ❌ 0 failed · ⚪ 0 skipped · blank not run

Board cdc_dual_ports cdc_msc dfu cdc_msc_throughput audio_test_freertos dfu_runtime cdc_msc_freertos hid_boot_interface msc_dual_lun hid_generic_inout printer_to_cdc midi_test mtp
stm32l412nucleo ✅ CDC 632k/390k MSC 783k/732k
stm32f746disco ✅ CDC 12.3M/12.2M MSC 12M/30.6M
stm32f746disco-DMA ✅ CDC 12.6M/8.8M MSC 13.3M/30.6M
lpcxpresso43s67 ✅ CDC 11.2M/10.8M MSC 29.3M/32.5M

hfp.json

✅ 52 passed · ❌ 0 failed · ⚪ 0 skipped · blank not run

Board cdc_dual_ports cdc_msc dfu cdc_msc_throughput audio_test_freertos dfu_runtime cdc_msc_freertos hid_boot_interface msc_dual_lun hid_generic_inout printer_to_cdc midi_test mtp
stm32l412nucleo ✅ CDC 629k/393k MSC 815k/785k
stm32f746disco ✅ CDC 13.6M/9.5M MSC 15.4M/28M
stm32f746disco-DMA ✅ CDC 13M/9.4M MSC 15.1M/31.1M
lpcxpresso43s67 ✅ CDC 12.5M/11.6M MSC 30M/32.7M

tinyusb.json

✅ 314 passed · ❌ 105 failed · ⚪ 28 skipped · blank not run

Board cdc_dual_ports cdc_msc dfu cdc_msc_throughput audio_test_freertos dfu_runtime cdc_msc_freertos hid_boot_interface msc_dual_lun hid_generic_inout printer_to_cdc midi_test mtp host_info_to_device_cdc cdc_msc_hid msc_file_explorer msc_file_explorer_freertos device_info hid_composite_freertos usbtest
ek_tm4c123gxl ✅ CDC 683k/774k MSC 767k/755k ✅ 28/28 +2skip
espressif_p4_function_ev
espressif_p4_function_ev-DMA
espressif_s3_devkitm rd 409KB/s
espressif_s3_devkitm-DMA
feather_nrf52840_express ✅ CDC 508k/515k MSC 606k/529k ✅ 28/28 +2skip
max32666fthr ✅ CDC 6.8M/12.2M MSC 12.4M/14.7M
metro_m4_express ✅ CDC 488k/483k MSC 531k/510k ✅ 28/28 +2skip
mimxrt1015_evk ✅ CDC 7.8M/12.3M MSC 11.8M/10.7M
mimxrt1064_evk ✅ CDC 7.8M/13.2M MSC 11.7M/10.8M rd 1365KB/s rd 1361KB/s
lpcxpresso11u37
ra6m5_ek
ra4m1_ek
raspberry_pi_pico ✅ CDC 501k/555k MSC 533k/484k rd 62KB/s rd 62KB/s ✅ 28/28 +2skip
raspberry_pi_pico_w rd 1103KB/s
raspberry_pi_pico2 rd 1108KB/s rd 1022KB/s
adafruit_fruit_jam ✅ CDC 575k/537k MSC 558k/487k rd 62KB/s ✅ 28/28 +2skip
stm32f072disco ✅ CDC 509k/414k MSC 619k/458k ✅ 28/28 +2skip
stm32f407disco ✅ CDC 877k/859k MSC 865k/793k ✅ 28/28 +2skip
stm32f723disco ✅ CDC 868k/682k MSC 930k/881k rd 13443KB/s rd 3942KB/s ✅ 28/28 +2skip
stm32f723disco-DMA ✅ CDC 893k/875k MSC 943k/881k rd 15420KB/s rd 4032KB/s ✅ 28/28 +2skip
stm32h743nucleo ✅ CDC 576k/710k MSC 653k/693k ✅ 28/28 +2skip
stm32h743nucleo-DMA ✅ CDC 834k/835k MSC 899k/864k ✅ 28/28 +2skip
stm32g0b1nucleo ✅ CDC 578k/495k MSC 696k/638k ✅ 28/28 +2skip
stm32l476disco ✅ CDC 595k/569k MSC 826k/729k ✅ 28/28 +2skip
stm32u083nucleo ✅ CDC 656k/419k MSC 822k/770k ✅ 28/28 +2skip
nanoch32v203-fsdev
nanoch32v203-usbfs
ch32v103r_r1_1v0 ✅ CDC 508k/508k MSC 511k/511k
ch32v307v_r1_1v0-usbhs
ch32v307v_r1_1v0-usbfs
ch582m_evt ✅ CDC 232k/200k MSC 479k/481k
nrf5340dk ✅ CDC 399k/412k MSC 538k/443k ✅ 28/28 +2skip
nrf54lm20dk ✅ CDC 1.9M/4.1M MSC 6.4M/7.8M ✅ 28/28 +2skip
frdm_k64f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants