From 94cce13948c01cd4bb9c307cfb9788eaa518ee51 Mon Sep 17 00:00:00 2001 From: Dmitry Ilyin <6576495+widgetii@users.noreply.github.com> Date: Fri, 31 Jul 2026 18:21:02 +0300 Subject: [PATCH] gk7205v200: flip dwc3 to host before unbinding xhci (otg) (#114) Booting the otg profile with /etc/usbmode = device made S72usbmode's `usb-mode device` log, on every single boot: xhci-hcd xhci-hcd.0.auto: Host not halted after 16000 microseconds. xhci-hcd xhci-hcd.0.auto: Host controller not halted, aborting reset. dwc3_core_init() leaves GCTL.PRTCAPDIR = OTG(3) and this 4.9 dwc3 never moves off OTG on its own. xhci-hcd binds and registers both buses on top of that anyway, but it is not actually driving the port -- so unbinding straight from OTG asks xhci_halt() to halt a host that was never really running, and it times out. The gadget composed regardless, so this was cosmetic in practice, but it left the host controller un-halted: exactly the live-DMA-engine state the unbind is there to avoid. Flip the controller to host before unbinding, so the already-bound xHCI is genuinely running and the unbind halts cleanly. A switch from host is already in that state, so only boot pays for the extra flip. Measured on gk7205v200 (Xiongmai IPC_GK7205V200_50H20AI_S38): 5/5 cold boots warned before, 0/5 after. Runtime host<->device round trips stay clean and still take ~0.35s, with no reboot and no majestic restart. Co-Authored-By: Claude Opus 4.8 --- .../general/overlay/usr/bin/usb-mode | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/devices/gk7205v200_otg_generic/general/overlay/usr/bin/usb-mode b/devices/gk7205v200_otg_generic/general/overlay/usr/bin/usb-mode index 5354043..586f58a 100755 --- a/devices/gk7205v200_otg_generic/general/overlay/usr/bin/usb-mode +++ b/devices/gk7205v200_otg_generic/general/overlay/usr/bin/usb-mode @@ -99,6 +99,20 @@ to_device() { need_debugfs if X=$(xhci_device) && [ -e "/sys/bus/platform/drivers/xhci-hcd/$X" ]; then + # Coming straight from boot the controller is still in its power-on + # GCTL.PRTCAPDIR = OTG(3) (see the header note: nothing moves it off + # OTG on its own). xhci-hcd binds and registers both buses on top of + # that anyway, but it is not actually driving the port -- so unbinding + # directly from OTG asks xhci_halt() to halt a host that was never + # really running, and it times out: + # xhci-hcd.0.auto: Host not halted after 16000 microseconds. + # xhci-hcd.0.auto: Host controller not halted, aborting reset. + # Leaving the controller un-halted is precisely the live-DMA-engine + # state this unbind exists to avoid. Flip to host first so the already + # bound xHCI is genuinely running, and the unbind then halts cleanly. + # A switch from host is already in that state, so only boot pays for it. + [ "$(cat "$MODE_FILE")" = host ] || echo host > "$MODE_FILE" + echo "usb-mode: unbinding host controller $X" echo "$X" > /sys/bus/platform/drivers/xhci-hcd/unbind fi