[PATCH 0/3] phy: sophgo: Add USB role switch for CV18XX/SG200X
Chen-Yu Yeh
chenyou910331 at gmail.com
Tue Nov 3 00:58:44 PST 2026
This makes one DTB work as both USB host and USB device on the Milk-V
Duo 256M, following the discussion in the thread "Milk-V Duo 256M: USB
peripheral mode works on mainline, how should dr_mode be handled?" on
the sophgo list. There, Inochi pointed out that a dual-role switch is the
right way and that the default should match the vendor image.
The usb-role-switch support in dwc2 hangs on this SoC. It clears B-valid
through the GOTGCTL session overrides while VBUS is present, and
GOTGINT.SesEndDet then fires back to back. The vendor kernel writes only
the ID override in the top syscon and lets dwc2 follow the Connector ID
change, and this works on mainline too, without any change to dwc2. So
the role switch lives in the PHY driver, which already owns those bits.
Test setup
==========
Milk-V Duo 256M, vendor buildroot rootfs, loaded by hand from U-Boot.
Tree: v7.3-rc5 with these changes, CONFIG_USB_DWC2_DUAL_ROLE=y,
CONFIG_USB_ETH=y. The series itself is based on current master; the files
touched by patches 1 and 2 are the same in both trees.
Tests 1 to 3 ran with CONFIG_USB_DWC2_DEBUG=y and the DT properties
applied through an overlay. Test 4 ran with debug disabled and the
board DTS from patch 3.
In the logs below,
R=/sys/class/usb_role/3000000.syscon:phy at 48-role-switch
1. Default peripheral, bare board on a PC, nothing done after boot
------------------------------------------------------------------
# ls /sys/class/usb_role/
3000000.syscon:phy at 48-role-switch
# cat $R/role
device
# devmem 0x03000048 32
0x000003C0
# cat /sys/class/udc/*/state
configured
PC$ lsusb | grep 0525
Bus 003 Device 009: ID 0525:a4a2 Netchip Technology, Inc. Linux-USB Ethernet/RNDIS Gadget
2. Switching at runtime, same setup
-----------------------------------
# echo host > $R/role
# cat $R/role
host
# devmem 0x03000048 32
0x00000142
# echo device > $R/role
# cat $R/role
device
# devmem 0x03000048 32
0x000003C0
# cat /sys/class/udc/*/state
configured
The switch was repeated without an interrupt storm, then:
# echo none > $R/role
# cat $R/role
device
# devmem 0x03000048 32
0x000003C0
3. Default host, on the USB & Ethernet IO board, nothing done after boot
------------------------------------------------------------------------
Only role-switch-default-mode differs from patch 3 here.
[ 3.409672] usb 1-1: new high-speed USB device number 2 using dwc2
[ 3.666655] hub 1-1:1.0: 4 ports detected
[ 72.484979] usb 1-1.1: new high-speed USB device number 3 using dwc2
[ 74.804484] sda: sda1 sda2 sda3 sda4
The USB stick was plugged in by hand at about 72 s.
# cat $R/role
host
# devmem 0x03000048 32
0x00000142
# devmem 0x04340018 32
0xF300081E
# devmem 0x04340440 32
0x00001005
# echo none > $R/role
# cat $R/role
host
# ls /dev/sd*
/dev/sda /dev/sda1 /dev/sda2 /dev/sda3 /dev/sda4
4. Patch 3 as committed, debug disabled
---------------------------------------
Bare board on a PC, nothing done after boot:
# cat $R/role
device
PC: usb 3-9: New USB device found, idVendor=0525, idProduct=a4a2
PC: usb 3-9: Product: RNDIS/Ethernet Gadget
On the IO board, with a USB stick already plugged in at boot:
# cat $R/role
device
# echo host > $R/role
# cat $R/role
host
# dmesg | grep -E 'usb 1-1'
[ 415.464739] usb 1-1: new high-speed USB device number 2 using dwc2
[ 415.940738] usb 1-1.1: new high-speed USB device number 3 using dwc2
Before this series
==================
With usb-role-switch on the dwc2 node, "echo host" hangs the board in the
SesEndDet storm, and so does boot without role-switch-default-mode.
With dr_mode = "otg" and no role switch, writing the ID override by hand
worked:
devmem 0x03000048 32 0x3C0 -> high-speed RNDIS gadget on the PC
devmem 0x03000048 32 0x142 -> disconnects from the PC, host side starts
Three round trips were all correct, and ping over usb0 afterwards was
5/5. On the IO board, the hub and USB stick appeared after one toggle,
but not at boot, because usb_add_hcd() moved the PHY to host after dwc2
had already set up for device:
at boot after one toggle
GINTSTS 0x05000023 0x04200021
GINTMSK 0xd0bc3cd4 0xf300081e (PrtInt masked -> unmasked)
HPRT0 0x00021403 0x00001005 (ConnDet pending -> port enabled)
Test 3 above reaches the right-hand values at boot without a toggle.
Not tested
==========
- A USB stick already plugged in at boot in the default host case.
- Running on a master based tree: all tests used the v7.3-rc5 tree.
- Boards other than the Duo 256M. Nothing changes on them, since the
role switch is only registered when the PHY node has usb-role-switch.
Question
========
With patch 3, the hub on the IO board needs "echo host" after each boot.
Should the IO board overlay (sg2002-milkv-duo256m-eth.dtso) set
role-switch-default-mode = "host", or should it stay the same as the
vendor image?
Chen-Yu Yeh (3):
dt-bindings: phy: sophgo,cv1800b-usb2-phy: Add USB role switch
properties
phy: sophgo: Add USB role switch support for CV18XX/SG200X
riscv: dts: sophgo: sg2002-milkv-duo256m: Enable USB role switch
.../bindings/phy/sophgo,cv1800b-usb2-phy.yaml | 11 ++
.../boot/dts/sophgo/sg2002-milkv-duo256m.dts | 7 +-
drivers/phy/sophgo/Kconfig | 2 +
drivers/phy/sophgo/phy-cv1800-usb2.c | 107 ++++++++++++++++--
4 files changed, 119 insertions(+), 8 deletions(-)
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
--
2.43.0
More information about the linux-phy
mailing list