Disable USB3, keep USB2

Which system do you use? Android, Ubuntu, OOWOW or others?

Android 11, self-built

Please describe your issue below:

On the VIM4 there are two USB ports, one USB2.0 and one USB3.0.
We are currently evaluating a device that has issues with USB3.0 (SuperSpeed) and would like to turn the USB3.0 port into a regular USB2.0.

We have tried to edit the device-tree but without success.
How would we go about turning off the USB3.0 SuperSpeed functionality for that specific port?

1 Like

@xavier
We need some time to analyze the problem and provide feedback.

We found a solution to disable USB3 while keeping USB2 function:

  1. Disable the USB3 phy (crg_phy_20) in the Device Tree
  2. Add the following patch to the AMLogic USB drivers
  3. Verify that the USB3 device is enumerated as an USB2 device (check bus index and Spd value, e.g. 480 vs 5000)
    cat /sys/kernel/debug/usb/devices
diff --git a/drivers/amlogic/usb/crg/crg_drd.c b/drivers/amlogic/usb/crg/crg_drd.c
index 62da05be4a3d..132c6d387cf2 100644
--- a/drivers/amlogic/usb/crg/crg_drd.c
+++ b/drivers/amlogic/usb/crg/crg_drd.c
@@ -123,8 +123,10 @@ static int crg_core_resume(struct crg_drd *crg)
        if (ret)
                return ret;
 
-       usb_phy_set_suspend(crg->usb2_phy, 0);
-       usb_phy_set_suspend(crg->usb3_phy, 0);
+       if (crg->usb2_phy)
+               usb_phy_set_suspend(crg->usb2_phy, 0);
+       if (crg->usb3_phy)
+               usb_phy_set_suspend(crg->usb3_phy, 0);
 
        switch (crg->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
@@ -151,8 +153,12 @@ static int crg_core_get_phy(struct crg_drd *crg)
        crg->super_speed_support = 0;
 
        crg->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
+       if (IS_ERR(crg->usb2_phy))
+               crg->usb2_phy = NULL;
 
        crg->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+       if (IS_ERR(crg->usb3_phy))
+               crg->usb3_phy = NULL;
 
        if (crg->usb3_phy)
                if (crg->usb3_phy->flags == AML_USB3_PHY_ENABLE)

Explanation:

  1. The USB3 phy (crg_phy_20) is disabled in the Device Tree

  2. This results in Linux kernel panic due to null pointer dereference at
    pc : crg_probe+0x160/0x7cc
    x0 = 0xffffffffffffffed
    This is -19 in signed decimal, which corresponds to -ENODEV (No such device) in Linux error codes.

  3. drivers/amlogic/usb/crg/crg_drd.c:crg_probe() calls crg_core_get_phy(), which executes
    crg->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);

  4. devm_usb_get_phy_by_phandle returns ERR_PTR(-ENODEV) when no matching Device Tree node is found, but the code in drivers/amlogic/usb/crg/crg_drd.c assumes NULL is returned when no device is found. So the code will incorrectly dereference the error pointer.

1 Like

@xavier
Thank you very much for sharing.