Skip to contentSkip to conversation

dwc2 fixes for HiKey

RFC PATCH Superseded John Stultz 4 participants 12 messages Oct 13, 2016 – Oct 22, 2016

Subsystems (4)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover dwc2 fixes for HiKey

I wanted to send out two patches we're using on the dwc2 driver in order to make HiKey function.

The first is seemingly just a bug fix we ran into when changing modes while the bus was auto-suspended.

The second is a little more interesting as it works around a limitation of the the device to negotiate the usb speed automatically.

I wanted to send these out for initial review and consideration.

Feedback would be greatly appreciated!

thanks
-john

Cc Wei Xu <[email protected]>
Cc Guodong Xu <[email protected]>
Cc Amit Pundir <[email protected]>
Cc Rob Herring <[email protected]>
Cc Mark Rutland <[email protected]>
Cc John Youn <[email protected]>
Cc Douglas Anderson <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Chen Yu <[email protected]>

Chen Yu (2):
usb: dwc2: Force port resume on switching to device mode
usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

 arch/arm64/boot/dts/hisilicon/hi6220.dtsi |  1 +
 drivers/usb/dwc2/core.h                   |  7 +++
 drivers/usb/dwc2/hcd.c                    | 83 +++++++++++++++++++++++++++++++
 drivers/usb/dwc2/platform.c               |  3 ++
 4 files changed, 94 insertions(+)
Signature · 1 line
2.7.4
#1 lore raw

RFC PATCH 1/2 usb: dwc2: Force port resume on switching to device mode

From: Chen Yu <[email protected]>

We've seen failures when switching between host and gadget mode, which was diagnosed as being caused due to the bus being auto-suspended when we switched.

So this patch forces a port resume when switching to device mode if the bus is suspended.

Cc Wei Xu <[email protected]>
Cc Guodong Xu <[email protected]>
Cc Amit Pundir <[email protected]>
Cc Rob Herring <[email protected]>
Cc Mark Rutland <[email protected]>
Cc John Youn <[email protected]>
Cc Douglas Anderson <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
---
 drivers/usb/dwc2/hcd.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/usb/dwc2/hcd.c +8 -0
index df5a065..b374e60 100644
@@ -54,6 +54,9 @@
 #include "core.h"
 #include "hcd.h"
 
+
+static void dwc2_port_resume(struct dwc2_hsotg *hsotg);
+
 /*
  * =========================================================================
  *  Host Core Layer Functions
@@ -3204,6 +3207,11 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
 	if (gotgctl & GOTGCTL_CONID_B) {
 		/* Wait for switch to device mode */
 		dev_dbg(hsotg->dev, "connId B\n");
+		if (hsotg->bus_suspended) {
+			dev_info(hsotg->dev,
+				"Do port resume before switching to device mode\n");
+			dwc2_port_resume(hsotg);
+		}
 		while (!dwc2_is_device_mode(hsotg)) {
 			dev_info(hsotg->dev,
 				 "Waiting for Peripheral Mode, Mode=%s\n",
Signature · 1 line
2.7.4
#2 lore raw

RFC PATCH 2/2 usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

In reply to John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Cc Wei Xu <[email protected]>
Cc Guodong Xu <[email protected]>
Cc Amit Pundir <[email protected]>
Cc Rob Herring <[email protected]>
Cc Mark Rutland <[email protected]>
Cc John Youn <[email protected]>
Cc Douglas Anderson <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
---
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi |  1 +
 drivers/usb/dwc2/core.h                   |  7 +++
 drivers/usb/dwc2/hcd.c                    | 75 +++++++++++++++++++++++++++++++
 drivers/usb/dwc2/platform.c               |  3 ++
 4 files changed, 86 insertions(+)
arch/arm64/boot/dts/hisilicon/hi6220.dtsi +1 -0
index 17839db..2c8f435 100644
@@ -752,6 +752,7 @@
 			g-np-tx-fifo-size = <128>;
 			g-tx-fifo-size = <128 128 128 128 128 128>;
 			interrupts = <0 77 0x4>;
+			hi6220,change_speed_quirk;
 		};
 
 		mailbox: mailbox@f7510000 {
drivers/usb/dwc2/core.h +7 -0
index 2a21a04..24fea73 100644
@@ -823,6 +823,10 @@ struct dwc2_hregs_backup {
  * @frame_list_sz:      Frame list size
  * @desc_gen_cache:     Kmem cache for generic descriptors
  * @desc_hsisoc_cache:  Kmem cache for hs isochronous descriptors
+ * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL
+ *                      while full&low speed device connect. And change speed
+ *                      back to DWC2_SPEED_PARAM_HIGH while device is gone.
+ * @device_count:       Number of devices connect to root hub
  *
  * These are for peripheral mode:
  *
@@ -951,6 +955,9 @@ struct dwc2_hsotg {
 	struct kmem_cache *desc_gen_cache;
 	struct kmem_cache *desc_hsisoc_cache;
 
+	int change_speed_quirk;
+	unsigned int device_count;
+
 #ifdef DEBUG
 	u32 frrem_samples;
 	u64 frrem_accum;
drivers/usb/dwc2/hcd.c +75 -0

87 lines not on this page · raw message

drivers/usb/dwc2/platform.c +3 -0
index 8e1728b..21c328b 100644
@@ -585,6 +585,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
 	dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
 		(unsigned long)res->start, hsotg->regs);
 
+	hsotg->change_speed_quirk = device_property_read_bool(&dev->dev,
+				"hi6220,change_speed_quirk");
+
 	retval = dwc2_lowlevel_hw_init(hsotg);
 	if (retval)
 		return retval;
Signature · 1 line
2.7.4
#3 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

Quoted 30 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Cc Wei Xu <[email protected]>
Cc Guodong Xu <[email protected]>
Cc Amit Pundir <[email protected]>
Cc Rob Herring <[email protected]>
Cc Mark Rutland <[email protected]>
Cc John Youn <[email protected]>
Cc Douglas Anderson <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
---
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi |  1 +
 drivers/usb/dwc2/core.h                   |  7 +++
 drivers/usb/dwc2/hcd.c                    | 75 +++++++++++++++++++++++++++++++
 drivers/usb/dwc2/platform.c               |  3 ++
 4 files changed, 86 insertions(+)
arch/arm64/boot/dts/hisilicon/hi6220.dtsi +0 -0
index 17839db..2c8f435 100644

arch/arm64/boot/dts/hisilicon/hi6220.dtsi line 755

Quoted 4 lines
arch/arm64/boot/dts/hisilicon/hi6220.dtsi +1 -0
@@ -752,6 +752,7 @@
                        g-np-tx-fifo-size = <128>;
                        g-tx-fifo-size = <128 128 128 128 128 128>;
                        interrupts = <0 77 0x4>;
+                       hi6220,change_speed_quirk;

I also realize I'm missing the DT binding documentation for this, but I wanted to get a rough idea if this approach was ok first. On the next submission (if there aren't major objections to the approach) I can split the binding documentation and dts change into different patches.

thanks
-john

#4 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

In reply to John Stultz
Quoted 160 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Cc Wei Xu <[email protected]>
Cc Guodong Xu <[email protected]>
Cc Amit Pundir <[email protected]>
Cc Rob Herring <[email protected]>
Cc Mark Rutland <[email protected]>
Cc John Youn <[email protected]>
Cc Douglas Anderson <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
---
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi |  1 +
 drivers/usb/dwc2/core.h                   |  7 +++
 drivers/usb/dwc2/hcd.c                    | 75 +++++++++++++++++++++++++++++++
 drivers/usb/dwc2/platform.c               |  3 ++
 4 files changed, 86 insertions(+)
arch/arm64/boot/dts/hisilicon/hi6220.dtsi +1 -0
index 17839db..2c8f435 100644
@@ -752,6 +752,7 @@
                        g-np-tx-fifo-size = <128>;
                        g-tx-fifo-size = <128 128 128 128 128 128>;
                        interrupts = <0 77 0x4>;
+                       hi6220,change_speed_quirk;
                };
 
                mailbox: mailbox@f7510000 {
drivers/usb/dwc2/core.h +7 -0
index 2a21a04..24fea73 100644
@@ -823,6 +823,10 @@ struct dwc2_hregs_backup {
  * @frame_list_sz:      Frame list size
  * @desc_gen_cache:     Kmem cache for generic descriptors
  * @desc_hsisoc_cache:  Kmem cache for hs isochronous descriptors
+ * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL
+ *                      while full&low speed device connect. And change speed
+ *                      back to DWC2_SPEED_PARAM_HIGH while device is gone.
+ * @device_count:       Number of devices connect to root hub
  *
  * These are for peripheral mode:
  *
@@ -951,6 +955,9 @@ struct dwc2_hsotg {
        struct kmem_cache *desc_gen_cache;
        struct kmem_cache *desc_hsisoc_cache;
 
+       int change_speed_quirk;
+       unsigned int device_count;
+
 #ifdef DEBUG
        u32 frrem_samples;
        u64 frrem_accum;
drivers/usb/dwc2/hcd.c +75 -0
index b374e60..663033e 100644
@@ -4868,6 +4868,75 @@ static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd,
        spin_unlock_irqrestore(&hsotg->lock, flags);
 }
 
+/*
+ * HPRT0_SPD_HIGH_SPEED: high speed
+ * HPRT0_SPD_FULL_SPEED: full speed
+ */
+static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       if (hsotg->core_params->speed == speed)
+               return;
+
+       hsotg->core_params->speed = speed;
+       queue_work(hsotg->wq_otg, &hsotg->wf_otg);
+}
+
+static int dwc2_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       if (!hsotg->change_speed_quirk)
+               return 1;
+
+       hsotg->device_count++;
+       dev_info(hsotg->dev, "Device count is %u after alloc dev\n",
+                       hsotg->device_count);
+
+       return 1;
+}
+
+static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       if (!hsotg->change_speed_quirk)
+               return;
+
+       if (hsotg->device_count)
+               hsotg->device_count--;
+
+       dev_info(hsotg->dev, "Device count is %u after free dev\n",
+                       hsotg->device_count);
+
+       if (hsotg->device_count == 1 && udev->parent &&
+                       udev->parent->speed > USB_SPEED_UNKNOWN &&
+                       udev->parent->speed < USB_SPEED_HIGH) {
+               dev_info(hsotg->dev, "Set speed to default high-speed\n");
+               dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+       }
+}
+
+static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       if (!hsotg->change_speed_quirk)
+               return 0;
+
+       if (udev->speed == USB_SPEED_HIGH) {
+               dev_info(hsotg->dev, "Set speed to high-speed\n");
+               dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+       } else if (udev->speed == USB_SPEED_FULL
+                       || udev->speed == USB_SPEED_LOW) {
+               dev_info(hsotg->dev, "Set speed to full-speed\n");
+               dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
+       }
+
+       return 0;
+}
+
 static struct hc_driver dwc2_hc_driver = {
        .description = "dwc2_hsotg",
        .product_desc = "DWC OTG Controller",
@@ -5023,6 +5092,12 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
                        dev_warn(hsotg->dev, "can't set coherent DMA mask\n");
        }
 
+       if (hsotg->change_speed_quirk) {
+               dwc2_hc_driver.alloc_dev = dwc2_alloc_dev;
+               dwc2_hc_driver.free_dev = dwc2_free_dev;
+               dwc2_hc_driver.reset_device = dwc2_reset_device;
+       }
+
        hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));
        if (!hcd)
                goto error1;
drivers/usb/dwc2/platform.c +0 -0
index 8e1728b..21c328b 100644

drivers/usb/dwc2/platform.c static int dwc2_driver_probe(struct platform_device *dev) · line 589

Quoted 5 lines
drivers/usb/dwc2/platform.c +2 -0
@@ -585,6 +585,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
        dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
                (unsigned long)res->start, hsotg->regs);
 
+       hsotg->change_speed_quirk = device_property_read_bool(&dev->dev,
+                               "hi6220,change_speed_quirk");

Can't this be determined from the hi6220's compatible string?

In any case, "hi6220" is not a vendor. This should be hisilicon,change... and don't use '_'. And to bikeshed things, "no-speed-change-quirk".

Rob

#5 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

Quoted 26 lines · Rob Herring
Quoted 25 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Cc Wei Xu <[email protected]>
Cc Guodong Xu <[email protected]>
Cc Amit Pundir <[email protected]>
Cc Rob Herring <[email protected]>
Cc Mark Rutland <[email protected]>
Cc John Youn <[email protected]>
Cc Douglas Anderson <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
---
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi |  1 +
 drivers/usb/dwc2/core.h                   |  7 +++
 drivers/usb/dwc2/hcd.c                    | 75 +++++++++++++++++++++++++++++++
 drivers/usb/dwc2/platform.c               |  3 ++
 4 files changed, 86 insertions(+)

[snip]

Quoted 8 lines
Quoted 8 lines
drivers/usb/dwc2/platform.c +0 -0
index 8e1728b..21c328b 100644
@@ -585,6 +585,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
        dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
                (unsigned long)res->start, hsotg->regs);
 
Quoted 4 lines

drivers/usb/dwc2/platform.c static int dwc2_driver_probe(struct platform_device *dev) · line 589

Quoted 2 lines
drivers/usb/dwc2/platform.c +2 -0
+       hsotg->change_speed_quirk = device_property_read_bool(&dev->dev,
+                               "hi6220,change_speed_quirk");

Can't this be determined from the hi6220's compatible string?

Ah. Good suggestion! I'm moving the quirk field to the core_params. Should avoid any dts or binding changes.

thanks
-john

#6 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

In reply to John Stultz
Quoted 6 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Hi,

Could you expand more on this by explaining what exactly is the limitation and the workaround?

[snip]

Quoted 13 lines
drivers/usb/dwc2/hcd.c +13 -0
+/*
+ * HPRT0_SPD_HIGH_SPEED: high speed
+ * HPRT0_SPD_FULL_SPEED: full speed
+ */
+static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (hsotg->core_params->speed == speed)
+		return;
+
+	hsotg->core_params->speed = speed;
+	queue_work(hsotg->wq_otg, &hsotg->wf_otg);

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4893

Quoted 10 lines
drivers/usb/dwc2/hcd.c +10 -0
+}
+
+static int dwc2_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 1;
+
+	hsotg->device_count++;

Why do you need to track the device count?

Quoted 32 lines
drivers/usb/dwc2/hcd.c +32 -0
+	dev_info(hsotg->dev, "Device count is %u after alloc dev\n",
+			hsotg->device_count);
+
+	return 1;
+}
+
+static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return;
+
+	if (hsotg->device_count)
+		hsotg->device_count--;
+
+	dev_info(hsotg->dev, "Device count is %u after free dev\n",
+			hsotg->device_count);
+
+	if (hsotg->device_count == 1 && udev->parent &&
+			udev->parent->speed > USB_SPEED_UNKNOWN &&
+			udev->parent->speed < USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to default high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	}
+}
+
+static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4935

Quoted 10 lines
drivers/usb/dwc2/hcd.c +10 -0
+		return 0;
+
+	if (udev->speed == USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	} else if (udev->speed == USB_SPEED_FULL
+			|| udev->speed == USB_SPEED_LOW) {
+		dev_info(hsotg->dev, "Set speed to full-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
+	}

It seems you are reinitializing the core every time a device is reset and the udev->speed does not match the core_param speed. But how is the udev->speed being set correctly if the hw cannot negotiate the speed in the first place?

Also should it be for every device? What about if a device gets plugged in behind a hub? I don't think you want to execute this code in that case.

This should only affect devices plugged into the root hub, correct? And the hsotg controller only has one root hub port. It seems things could be simplified a bit.

Regards,
John

#7 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

Quoted 8 lines · John Youn
Quoted 6 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Quoted 5 lines

Hi,

Could you expand more on this by explaining what exactly is the limitation and the workaround?

The USB host limitation of Hisilicon Hi6220 is full-speed and low-speed devices can not be enumerated when gets plugged behind a hub.

Quoted 67 lines

[snip]

Quoted 13 lines
drivers/usb/dwc2/hcd.c +13 -0
+/*
+ * HPRT0_SPD_HIGH_SPEED: high speed
+ * HPRT0_SPD_FULL_SPEED: full speed
+ */
+static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (hsotg->core_params->speed == speed)
+		return;
+
+	hsotg->core_params->speed = speed;
+	queue_work(hsotg->wq_otg, &hsotg->wf_otg);

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4893

Quoted 10 lines
drivers/usb/dwc2/hcd.c +10 -0
+}
+
+static int dwc2_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 1;
+
+	hsotg->device_count++;

Why do you need to track the device count?

Quoted 39 lines
drivers/usb/dwc2/hcd.c +39 -0
+	dev_info(hsotg->dev, "Device count is %u after alloc dev\n",
+			hsotg->device_count);
+
+	return 1;
+}
+
+static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return;
+
+	if (hsotg->device_count)
+		hsotg->device_count--;
+
+	dev_info(hsotg->dev, "Device count is %u after free dev\n",
+			hsotg->device_count);
+
+	if (hsotg->device_count == 1 && udev->parent &&
+			udev->parent->speed > USB_SPEED_UNKNOWN &&
+			udev->parent->speed < USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to default high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	}
+}
+
+static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 0;
+
+	if (udev->speed == USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	} else if (udev->speed == USB_SPEED_FULL
+			|| udev->speed == USB_SPEED_LOW) {
Quoted 9 lines

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4935

Quoted 3 lines
drivers/usb/dwc2/hcd.c +3 -0
+		dev_info(hsotg->dev, "Set speed to full-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
+	}

It seems you are reinitializing the core every time a device is reset and the udev->speed does not match the core_param speed. But how is the udev->speed being set correctly if the hw cannot negotiate the speed in the first place?

The hardware can negotiate the speed, but communication with a full-speed or low-speed device behind a hub is the problem.

Quoted 8 lines

Also should it be for every device? What about if a device gets plugged in behind a hub? I don't think you want to execute this code in that case.

This should only affect devices plugged into the root hub, correct? And the hsotg controller only has one root hub port. It seems things could be simplified a bit.

The patch is initially written for Hikey Hi6220 board, and there is a hub always connected to root hub, so the patch sets the configuration to HPRT0_SPD_HIGH_SPEED when there is only one device(the hub).

Thanks for your suggestions, the patch needs modified in these aspect:
1. Change the speed setting only when the device is behind a hub in dwc2_reset_device.
2. Change the speed to HPRT0_SPD_HIGH_SPEED only when the last device is a hub.

What do you think about the fix? Any suggestions will be appreciate!

thanks
- Chen Yu

#8 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

Quoted 104 lines · Chen Yu
Quoted 8 lines · John Youn
Quoted 6 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Quoted 5 lines

Hi,

Could you expand more on this by explaining what exactly is the limitation and the workaround?

The USB host limitation of Hisilicon Hi6220 is full-speed and low-speed devices can not be enumerated when gets plugged behind a hub.

Quoted 67 lines

[snip]

Quoted 13 lines
drivers/usb/dwc2/hcd.c +13 -0
+/*
+ * HPRT0_SPD_HIGH_SPEED: high speed
+ * HPRT0_SPD_FULL_SPEED: full speed
+ */
+static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (hsotg->core_params->speed == speed)
+		return;
+
+	hsotg->core_params->speed = speed;
+	queue_work(hsotg->wq_otg, &hsotg->wf_otg);

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4893

Quoted 10 lines
drivers/usb/dwc2/hcd.c +10 -0
+}
+
+static int dwc2_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 1;
+
+	hsotg->device_count++;

Why do you need to track the device count?

Quoted 39 lines
drivers/usb/dwc2/hcd.c +39 -0
+	dev_info(hsotg->dev, "Device count is %u after alloc dev\n",
+			hsotg->device_count);
+
+	return 1;
+}
+
+static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return;
+
+	if (hsotg->device_count)
+		hsotg->device_count--;
+
+	dev_info(hsotg->dev, "Device count is %u after free dev\n",
+			hsotg->device_count);
+
+	if (hsotg->device_count == 1 && udev->parent &&
+			udev->parent->speed > USB_SPEED_UNKNOWN &&
+			udev->parent->speed < USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to default high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	}
+}
+
+static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 0;
+
+	if (udev->speed == USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	} else if (udev->speed == USB_SPEED_FULL
+			|| udev->speed == USB_SPEED_LOW) {
Quoted 9 lines

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4935

Quoted 3 lines
drivers/usb/dwc2/hcd.c +3 -0
+		dev_info(hsotg->dev, "Set speed to full-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
+	}

It seems you are reinitializing the core every time a device is reset and the udev->speed does not match the core_param speed. But how is the udev->speed being set correctly if the hw cannot negotiate the speed in the first place?

The hardware can negotiate the speed, but communication with a full-speed or low-speed device behind a hub is the problem.

Quoted 4 lines

Also should it be for every device? What about if a device gets plugged in behind a hub? I don't think you want to execute this code in that case.

Quoted 8 lines
Quoted 4 lines

This should only affect devices plugged into the root hub, correct? And the hsotg controller only has one root hub port. It seems things could be simplified a bit.

The patch is initially written for Hikey Hi6220 board, and there is a hub always connected to root hub, so the patch sets the configuration to HPRT0_SPD_HIGH_SPEED when there is only one device(the hub).

Ok, I see.

Quoted 3 lines

Thanks for your suggestions, the patch needs modified in these aspect:
1. Change the speed setting only when the device is behind a hub in dwc2_reset_device.

I still think you will have issues with multiple devices. Since you have a built-in hub after root hub, it will always be behind the hub. So whenver you need to change speeds, it will always reset every device in the tree. Have you tested with multiple devices and also multiple levels of hubs?

Quoted 3 lines

2. Change the speed to HPRT0_SPD_HIGH_SPEED only when the last device is a hub.

What do you think about the fix? Any suggestions will be appreciate!

I'm not sure if any fix can work for all cases. Has this problem always been there?

Regards,
John

#9 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

Quoted 117 lines · John Youn
Quoted 104 lines · Chen Yu
Quoted 8 lines · John Youn
Quoted 6 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Quoted 5 lines

Hi,

Could you expand more on this by explaining what exactly is the limitation and the workaround?

The USB host limitation of Hisilicon Hi6220 is full-speed and low-speed devices can not be enumerated when gets plugged behind a hub.

Quoted 67 lines

[snip]

Quoted 13 lines
drivers/usb/dwc2/hcd.c +13 -0
+/*
+ * HPRT0_SPD_HIGH_SPEED: high speed
+ * HPRT0_SPD_FULL_SPEED: full speed
+ */
+static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (hsotg->core_params->speed == speed)
+		return;
+
+	hsotg->core_params->speed = speed;
+	queue_work(hsotg->wq_otg, &hsotg->wf_otg);

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4893

Quoted 10 lines
drivers/usb/dwc2/hcd.c +10 -0
+}
+
+static int dwc2_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 1;
+
+	hsotg->device_count++;

Why do you need to track the device count?

Quoted 39 lines
drivers/usb/dwc2/hcd.c +39 -0
+	dev_info(hsotg->dev, "Device count is %u after alloc dev\n",
+			hsotg->device_count);
+
+	return 1;
+}
+
+static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return;
+
+	if (hsotg->device_count)
+		hsotg->device_count--;
+
+	dev_info(hsotg->dev, "Device count is %u after free dev\n",
+			hsotg->device_count);
+
+	if (hsotg->device_count == 1 && udev->parent &&
+			udev->parent->speed > USB_SPEED_UNKNOWN &&
+			udev->parent->speed < USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to default high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	}
+}
+
+static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 0;
+
+	if (udev->speed == USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	} else if (udev->speed == USB_SPEED_FULL
+			|| udev->speed == USB_SPEED_LOW) {
Quoted 9 lines

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4935

Quoted 3 lines
drivers/usb/dwc2/hcd.c +3 -0
+		dev_info(hsotg->dev, "Set speed to full-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
+	}

It seems you are reinitializing the core every time a device is reset and the udev->speed does not match the core_param speed. But how is the udev->speed being set correctly if the hw cannot negotiate the speed in the first place?

The hardware can negotiate the speed, but communication with a full-speed or low-speed device behind a hub is the problem.

Quoted 4 lines

Also should it be for every device? What about if a device gets plugged in behind a hub? I don't think you want to execute this code in that case.

Quoted 8 lines
Quoted 4 lines

This should only affect devices plugged into the root hub, correct? And the hsotg controller only has one root hub port. It seems things could be simplified a bit.

The patch is initially written for Hikey Hi6220 board, and there is a hub always connected to root hub, so the patch sets the configuration to HPRT0_SPD_HIGH_SPEED when there is only one device(the hub).

Ok, I see.

Quoted 1 line
Quoted 9 lines
Quoted 2 lines

Thanks for your suggestions, the patch needs modified in these aspect:
1. Change the speed setting only when the device is behind a hub in dwc2_reset_device.

I still think you will have issues with multiple devices. Since you have a built-in hub after root hub, it will always be behind the hub. So whenver you need to change speeds, it will always reset every device in the tree. Have you tested with multiple devices and also multiple levels of hubs?

Yes, a full-speed device or low-speed device being plugged in will reset other devices if current speed setting is not full-speed.
I have tested with multiple devices and also two levels of high-speed hubs, the patch was working well for enumerating full-speed device and low-speed device. Also it changed the speed to high when there was only one hub connected to root hub.

Quoted 6 lines
Quoted 3 lines

2. Change the speed to HPRT0_SPD_HIGH_SPEED only when the last device is a hub.

What do you think about the fix? Any suggestions will be appreciate!

I'm not sure if any fix can work for all cases. Has this problem always been there?

Yes, the problem is always there because Hi6220 can not support "Split Transaction".

#10 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

Quoted 135 lines · Chen Yu
Quoted 117 lines · John Youn
Quoted 104 lines · Chen Yu
Quoted 8 lines · John Youn
Quoted 6 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Quoted 5 lines

Hi,

Could you expand more on this by explaining what exactly is the limitation and the workaround?

The USB host limitation of Hisilicon Hi6220 is full-speed and low-speed devices can not be enumerated when gets plugged behind a hub.

Quoted 67 lines

[snip]

Quoted 13 lines
drivers/usb/dwc2/hcd.c +13 -0
+/*
+ * HPRT0_SPD_HIGH_SPEED: high speed
+ * HPRT0_SPD_FULL_SPEED: full speed
+ */
+static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (hsotg->core_params->speed == speed)
+		return;
+
+	hsotg->core_params->speed = speed;
+	queue_work(hsotg->wq_otg, &hsotg->wf_otg);

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4893

Quoted 10 lines
drivers/usb/dwc2/hcd.c +10 -0
+}
+
+static int dwc2_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 1;
+
+	hsotg->device_count++;

Why do you need to track the device count?

Quoted 39 lines
drivers/usb/dwc2/hcd.c +39 -0
+	dev_info(hsotg->dev, "Device count is %u after alloc dev\n",
+			hsotg->device_count);
+
+	return 1;
+}
+
+static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return;
+
+	if (hsotg->device_count)
+		hsotg->device_count--;
+
+	dev_info(hsotg->dev, "Device count is %u after free dev\n",
+			hsotg->device_count);
+
+	if (hsotg->device_count == 1 && udev->parent &&
+			udev->parent->speed > USB_SPEED_UNKNOWN &&
+			udev->parent->speed < USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to default high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	}
+}
+
+static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 0;
+
+	if (udev->speed == USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	} else if (udev->speed == USB_SPEED_FULL
+			|| udev->speed == USB_SPEED_LOW) {
Quoted 9 lines

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4935

Quoted 3 lines
drivers/usb/dwc2/hcd.c +3 -0
+		dev_info(hsotg->dev, "Set speed to full-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
+	}

It seems you are reinitializing the core every time a device is reset and the udev->speed does not match the core_param speed. But how is the udev->speed being set correctly if the hw cannot negotiate the speed in the first place?

The hardware can negotiate the speed, but communication with a full-speed or low-speed device behind a hub is the problem.

Quoted 4 lines

Also should it be for every device? What about if a device gets plugged in behind a hub? I don't think you want to execute this code in that case.

Quoted 8 lines
Quoted 4 lines

This should only affect devices plugged into the root hub, correct? And the hsotg controller only has one root hub port. It seems things could be simplified a bit.

The patch is initially written for Hikey Hi6220 board, and there is a hub always connected to root hub, so the patch sets the configuration to HPRT0_SPD_HIGH_SPEED when there is only one device(the hub).

Ok, I see.

Quoted 1 line
Quoted 9 lines
Quoted 2 lines

Thanks for your suggestions, the patch needs modified in these aspect:
1. Change the speed setting only when the device is behind a hub in dwc2_reset_device.

I still think you will have issues with multiple devices. Since you have a built-in hub after root hub, it will always be behind the hub. So whenver you need to change speeds, it will always reset every device in the tree. Have you tested with multiple devices and also multiple levels of hubs?

Yes, a full-speed device or low-speed device being plugged in will reset other devices if current speed setting is not full-speed.
I have tested with multiple devices and also two levels of high-speed hubs, the patch was working well for enumerating full-speed device and low-speed device. Also it changed the speed to high when there was only one hub connected to root hub.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

2. Change the speed to HPRT0_SPD_HIGH_SPEED only when the last device is a hub.

What do you think about the fix? Any suggestions will be appreciate!

I'm not sure if any fix can work for all cases. Has this problem always been there?

Yes, the problem is always there because Hi6220 can not support "Split Transaction".

So the problem is actually that the on board hub doesn't support splits? That's much different than your initial description and the workaround makes more sense in this context.

But why can't it support splits?

And how can an FS device pass enumeration if the hub doesn't support splits? I feel like there is still something missing.

Also, if you plug in a HS hub, and then an FS device behind that. That should work fine, no? So you wouldn't want to reset anything in that case.

Regards,
John

#11 lore raw

Re: [RFC][PATCH 2/2] usb: dwc2: Add a quirk to allow speed negotiation for Hisilicon Hi6220

Quoted 149 lines · John Youn
Quoted 135 lines · Chen Yu
Quoted 117 lines · John Youn
Quoted 104 lines · Chen Yu
Quoted 8 lines · John Youn
Quoted 6 lines · John Stultz

From: Chen Yu <[email protected]>

The Hi6220's usb controller is limited in that it does not automatically autonegotiate the usb speed. Thus it requires a quirk so that we can manually negotiate the best usb speed for the attached device.

Quoted 5 lines

Hi,

Could you expand more on this by explaining what exactly is the limitation and the workaround?

The USB host limitation of Hisilicon Hi6220 is full-speed and low-speed devices can not be enumerated when gets plugged behind a hub.

Quoted 67 lines

[snip]

Quoted 13 lines
drivers/usb/dwc2/hcd.c +13 -0
+/*
+ * HPRT0_SPD_HIGH_SPEED: high speed
+ * HPRT0_SPD_FULL_SPEED: full speed
+ */
+static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (hsotg->core_params->speed == speed)
+		return;
+
+	hsotg->core_params->speed = speed;
+	queue_work(hsotg->wq_otg, &hsotg->wf_otg);

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4893

Quoted 10 lines
drivers/usb/dwc2/hcd.c +10 -0
+}
+
+static int dwc2_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 1;
+
+	hsotg->device_count++;

Why do you need to track the device count?

Quoted 39 lines
drivers/usb/dwc2/hcd.c +39 -0
+	dev_info(hsotg->dev, "Device count is %u after alloc dev\n",
+			hsotg->device_count);
+
+	return 1;
+}
+
+static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return;
+
+	if (hsotg->device_count)
+		hsotg->device_count--;
+
+	dev_info(hsotg->dev, "Device count is %u after free dev\n",
+			hsotg->device_count);
+
+	if (hsotg->device_count == 1 && udev->parent &&
+			udev->parent->speed > USB_SPEED_UNKNOWN &&
+			udev->parent->speed < USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to default high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	}
+}
+
+static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+	if (!hsotg->change_speed_quirk)
+		return 0;
+
+	if (udev->speed == USB_SPEED_HIGH) {
+		dev_info(hsotg->dev, "Set speed to high-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED);
+	} else if (udev->speed == USB_SPEED_FULL
+			|| udev->speed == USB_SPEED_LOW) {
Quoted 9 lines

drivers/usb/dwc2/hcd.c static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, · line 4935

Quoted 3 lines
drivers/usb/dwc2/hcd.c +3 -0
+		dev_info(hsotg->dev, "Set speed to full-speed\n");
+		dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED);
+	}

It seems you are reinitializing the core every time a device is reset and the udev->speed does not match the core_param speed. But how is the udev->speed being set correctly if the hw cannot negotiate the speed in the first place?

The hardware can negotiate the speed, but communication with a full-speed or low-speed device behind a hub is the problem.

Quoted 4 lines

Also should it be for every device? What about if a device gets plugged in behind a hub? I don't think you want to execute this code in that case.

Quoted 8 lines
Quoted 4 lines

This should only affect devices plugged into the root hub, correct? And the hsotg controller only has one root hub port. It seems things could be simplified a bit.

The patch is initially written for Hikey Hi6220 board, and there is a hub always connected to root hub, so the patch sets the configuration to HPRT0_SPD_HIGH_SPEED when there is only one device(the hub).

Ok, I see.

Quoted 1 line
Quoted 9 lines
Quoted 2 lines

Thanks for your suggestions, the patch needs modified in these aspect:
1. Change the speed setting only when the device is behind a hub in dwc2_reset_device.

I still think you will have issues with multiple devices. Since you have a built-in hub after root hub, it will always be behind the hub. So whenver you need to change speeds, it will always reset every device in the tree. Have you tested with multiple devices and also multiple levels of hubs?

Yes, a full-speed device or low-speed device being plugged in will reset other devices if current speed setting is not full-speed.
I have tested with multiple devices and also two levels of high-speed hubs, the patch was working well for enumerating full-speed device and low-speed device. Also it changed the speed to high when there was only one hub connected to root hub.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

2. Change the speed to HPRT0_SPD_HIGH_SPEED only when the last device is a hub.

What do you think about the fix? Any suggestions will be appreciate!

I'm not sure if any fix can work for all cases. Has this problem always been there?

Yes, the problem is always there because Hi6220 can not support "Split Transaction".

So the problem is actually that the on board hub doesn't support splits? That's much different than your initial description and the workaround makes more sense in this context.

Quoted 9 lines

But why can't it support splits?

And how can an FS device pass enumeration if the hub doesn't support splits? I feel like there is still something missing.

Also, if you plug in a HS hub, and then an FS device behind that. That should work fine, no? So you wouldn't want to reset anything in that case.

Hi6220 is a SOC of Hisilicon, not the board. The hub on board is a HS hub and support splits. The limitation is from the Hi6220 chip.