This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x SDK 8 Device on External USB Hub not working

Using the SDK 8.0.0.0 (Kernel 3.14) we are attaching an external usb hub to the BeagleBone black.  Devices on the external USB hub only enumerate on a reboot, not when the device is plugged in after power up.

I've tried several external usb hubs, powered and unpowered.  The hub always shows up, but nothing that is plugged into the hub does unless the board is rebooted.  

Also, if a working device on the hub is unpowered, it rarely de-enumerates fro lsusb.

This is a problem for our application because we are power controlling the external devices.

Any help is appreciated.

  • Robert,

    This is a known issue in SDK8.0. Please use the patch #8.2 in the following wiki to fix the issue.
    processors.wiki.ti.com/.../Sitara_Linux_SDK_MUSB_Issues
  • Is there a patch for the 3.12 kernel?  The patch referenced here is for the 4.x kernel, and it does work in 3.x  I have tried to port over enough of the 4.x USB logic to get this working, but clearly something is missing.

    
    
    diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
    index 0205a31..c6430d0 100644
    --- a/drivers/usb/musb/musb_core.c
    +++ b/drivers/usb/musb/musb_core.c
    @@ -479,6 +479,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
     						| MUSB_PORT_STAT_RESUME;
     				musb->rh_timer = jiffies
     						+ msecs_to_jiffies(20);
    +				musb->need_finish_resume = 1;
     
     				musb->xceiv->state = OTG_STATE_A_HOST;
     				musb->is_active = 1;
    @@ -1891,6 +1892,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
     
     	/* Init IRQ workqueue before request_irq */
     	INIT_WORK(&musb->irq_work, musb_irq_work);
    +	INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume);
     
     	/* setup musb parts of the core (especially endpoints) */
     	status = musb_core_init(plat->config->multipoint
    @@ -1975,6 +1977,7 @@ fail4:
     
     fail3:
     	cancel_work_sync(&musb->irq_work);
    +	cancel_delayed_work_sync(&musb->finish_resume_work);
     	if (musb->dma_controller)
     		dma_controller_destroy(musb->dma_controller);
     	pm_runtime_put_sync(musb->controller);
    @@ -2037,6 +2040,7 @@ static int musb_remove(struct platform_device *pdev)
     		dma_controller_destroy(musb->dma_controller);
     
     	cancel_work_sync(&musb->irq_work);
    +	cancel_delayed_work_sync(&musb->finish_resume_work);
     	musb_free(musb);
     	device_init_wakeup(dev, 0);
     	return 0;
    @@ -2215,10 +2219,39 @@ static int musb_suspend(struct device *dev)
     
     static int musb_resume_noirq(struct device *dev)
     {
    -	/* for static cmos like DaVinci, register values were preserved
    +	struct musb	*musb = dev_to_musb(dev);
    +	u8		devctl;
    +	u8		mask;
    +
    +	/*
    +	 * For static cmos like DaVinci, register values were preserved
     	 * unless for some reason the whole soc powered down or the USB
     	 * module got reset through the PSC (vs just being disabled).
    +	 *
    +	 * For the DSPS glue layer though, a full register restore has to
    +	 * be done. As it shouldn't harm other platforms, we do it
    +	 * unconditionally.
    +	 */
    +
    +	musb_restore_context(musb);
    +
    +	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
    +	mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV;
    +	if ((devctl & mask) != (musb->context.devctl & mask))
    +		musb->port1_status = 0;
    +	if (musb->need_finish_resume) {
    +		musb->need_finish_resume = 0;
    +		schedule_delayed_work(&musb->finish_resume_work,
    +				msecs_to_jiffies(40));
    +	}
    +
    +	/*
    +	 * The USB HUB code expects the device to be in RPM_ACTIVE once it came
    +	 * out of suspend
     	 */
    +	pm_runtime_disable(dev);
    +	pm_runtime_set_active(dev);
    +	pm_runtime_enable(dev);
     	return 0;
     }
     
    @@ -2249,6 +2282,12 @@ static int musb_runtime_resume(struct device *dev)
     		musb_restore_context(musb);
     	first = 0;
     
    +	if (musb->need_finish_resume) {
    +		musb->need_finish_resume = 0;
    +		schedule_delayed_work(&musb->finish_resume_work,
    +				msecs_to_jiffies(40));
    +	}
    +
     	return 0;
     }
     
    diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
    index 1c5bf75..7e23e32 100644
    --- a/drivers/usb/musb/musb_core.h
    +++ b/drivers/usb/musb/musb_core.h
    @@ -294,6 +294,7 @@ struct musb {
     
     	irqreturn_t		(*isr)(int, void *);
     	struct work_struct	irq_work;
    +	struct delayed_work	finish_resume_work;
     	u16			hwvers;
     
     	u16			intrrxe;
    @@ -382,6 +383,7 @@ struct musb {
     
     	/* is_suspended means USB B_PERIPHERAL suspend */
     	unsigned		is_suspended:1;
    +	unsigned		need_finish_resume :1;
     
     	/* may_wakeup means remote wakeup is enabled */
     	unsigned		may_wakeup:1;
    diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
    index 960d735..f3e4b32 100644
    --- a/drivers/usb/musb/musb_host.h
    +++ b/drivers/usb/musb/musb_host.h
    @@ -92,6 +92,7 @@ extern void musb_host_rx(struct musb *, u8);
     extern void musb_root_disconnect(struct musb *musb);
     extern void musb_host_resume_root_hub(struct musb *musb);
     extern void musb_host_poke_root_hub(struct musb *musb);
    +extern void musb_host_finish_resume(struct work_struct *work);
     #else
     static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
     {
    @@ -121,6 +122,7 @@ static inline void musb_root_disconnect(struct musb *musb)	{}
     static inline void musb_host_resume_root_hub(struct musb *musb)	{}
     static inline void musb_host_poll_rh_status(struct musb *musb)	{}
     static inline void musb_host_poke_root_hub(struct musb *musb)	{}
    +static inline void musb_host_finish_resume(struct work_struct *work) {}
     #endif
     
     struct usb_hcd;
    diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
    index 9af6bba..fd147a2 100644
    --- a/drivers/usb/musb/musb_virthub.c
    +++ b/drivers/usb/musb/musb_virthub.c
    @@ -44,6 +44,37 @@
     
     #include "musb_core.h"
     
    +void musb_host_finish_resume(struct work_struct *work)
    +{
    +	struct musb *musb;
    +	unsigned long flags;
    +	u8 power;
    +
    +	musb = container_of(work, struct musb, finish_resume_work.work);
    +
    +	spin_lock_irqsave(&musb->lock, flags);
    +
    +	power = musb_readb(musb->mregs, MUSB_POWER);
    +	power &= ~MUSB_POWER_RESUME;
    +	dev_dbg(musb->controller, "root port resume stopped, power %02x\n",
    +		power);
    +	musb_writeb(musb->mregs, MUSB_POWER, power);
    +
    +	/*
    +	 * ISSUE:  DaVinci (RTL 1.300) disconnects after
    +	 * resume of high speed peripherals (but not full
    +	 * speed ones).
    +	 */
    +	musb->is_active = 1;
    +	musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME);
    +	musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
    +	usb_hcd_poll_rh_status(musb->hcd);
    +	/* NOTE: it might really be A_WAIT_BCON ... */
    +	musb->xceiv->state = OTG_STATE_A_HOST;
    +
    +	spin_unlock_irqrestore(&musb->lock, flags);
    +}
    +
     static void musb_port_suspend(struct musb *musb, bool do_suspend)
     {
     	struct usb_otg	*otg = musb->xceiv->otg;
    

    
    
  • Kenneth,

    Please explain where the patch you referred comes from, a kernel commit ID will be helpful.

    Please note that this thread is for the issue which is fixed by patch #8.2 mentioned above. This issue does not exist in 3.12 kernel. If you have an issue with USB hub, it might be irrelevant to the discussion in this thread.

  • I miss-typed, I meant the 3.17 kernel.  This really looks like my issue.  Hubs used to work with the 3.2 kernel, but they are now broken after upgrading to the 3.17.  If a device is attached to the hub when the hub is connected, the device is detected and works.

    This patch is from my local source. I am trying to apply enough of the logic from 4.0 to get the fix from #8.2 working.

  • I don't have any issue to apply patch #8.2 to kernel 3.17:

    build03:master$ git checkout v3.17
    Checking out files: 100% (27435/27435), done.
    Previous HEAD position was 70371a6... omap2plus_defconfig: Update defconfig to use USERSPACE governor by default
    HEAD is now at bfe01a5... Linux 3.17
    build03:master$ git log --oneline origin/linux-master | grep 'musb: fix device hotplug'
    9298b4a usb: musb: fix device hotplug behind hub
    ^C
    build03:master$ git cherry-pick 9298b4a
    [detached HEAD 0438bbf] usb: musb: fix device hotplug behind hub
     1 file changed, 6 insertions(+)
    build03:master$
    
  • The patch applies ok, but it does not compile. The variables 'need_finish_resume' and 'finish_resume_work' do not exist on 'musb'. My patch above adds this code, but it still does not work. I am now attempting to port more of the musb driver from 4.0 on the assumption that I am missing some other behavior. Unfortunately I have still not had any luck getting it to work.
  • Where do you get the 3.17 kernel from? I have no issue to compile the kernel 3.17 tag after applied patch #8.2 as shown in my previous post.
  • That was my mistake again. I have been looking at too many versions. I am running 3.12.20 (just confirmed with make kernelversion.)

    You said this issue does not exist in 3.12, but my behavior matches this description quite well.

    I am not sure exactly where this kernel comes from. (The engineer that set up the kernel is gone.) We track kernel.org, but I do not know where the TI logic came from. (Possibly only what is included there.) I am coning the TI kernel now to see the difference.
  • Kenneth Kassing said:
    That was my mistake again. I have been looking at too many versions. I am running 3.12.20 (just confirmed with make kernelversion.)

    I am confused. so you have such issue in v3.12.20, then in which kernel you did not have the issue?

    Kenneth Kassing said:
    We track kernel.org, but I do not know where the TI logic came from.

    What do you mean by 'TI logic'?

  • I did not have the issue on 3.2.0 kernel.

    by 'TI logic', I meant any code from TI not in kernel.org. I just compared the musb driver from the v3.12 tag in your git repository to mine, and the changes are very minor. (So no missing logic that I can see.)
  • Kenneth,

    The difference from 3.2.0 to 3.12 is huge, I don't think it is easy to tell which patch causes the issue you have.

    The comments in patch #8.2 states it fixes the issue caused by commit 889ad3b which is only in v3.14.23. So your issue in 3.12.20 is not this one.

    Please try to add 'usbcore.autosuspend=-1' in your kernel cmdline (uboot bootargs) to see if the issue still exists.
  • The issue still exists.

  • Is this on any TI reference board or your custom board?
    Can you please describe again about your problem? plug in the hub before and after the board booted, is the hub enumerated? if works, then plug a device behind the hub, is the device enumerated? In the failure case is there any log on the serial console? have you tried different hub?

  • This is my custom board based on the BeagleBone Rev A6. I am attempting to get my source up and running on a BeagleBone now to test it there.

    1. If I connect the HUB it is always enumerated both before and after boot.
    2. If the HUB is connected, a device plugged into the HUB is not enumerated.
    3. If the device is connected to the HUB before boot, both the HUB and device are enumerated at startup.
    4. If the device is connected to the HUB, and *then* the HUB is plugged to the host both the HUB and device are enumerated.
  • This still sounds usb auto-suspend related. Can you please try the following test?

    # cd /sys/bus/usb/devices/usb2/power    <---- assuming you use USB1 port, otherwise change the directory to usb1/power/
    # cat runtime_status    <--- it should be suspended
    # echo on > control
    # cat runtime_status    <--- it should be active now

    Then plug the hub, it should be enumerated. Finally connect the usb device to see if it works or not.

  • The HUB is enumerated, but the device is not.
  • Ok, then I run out of ideas, except debugging if the hub reports the device insertion or if the musb process the event or not.

    Can you please switch the kernel to AMSDK7.0, which has kernel 3.12.10? I mean the TI 3.12.10 kernel, not any version from kernel.org or elsewhere.
  • I can try that.