diff mbox

[U-Boot,13/17] musb-new: Fix reset sequence when in host mode

Message ID 1421004895-10896-14-git-send-email-hdegoede@redhat.com
State Accepted
Delegated to: Marek Vasut
Headers show

Commit Message

Hans de Goede Jan. 11, 2015, 7:34 p.m. UTC
This commit fixes a number of issues with the reset sequence of musb-new
in host mode:

1) Our usb device probe relies on a second device reset being done after the
first descriptors read. Factor the musb reset code into a usb_reset_root_port
function (and add this as an empty define for other controllers), and call
this when a device has no parent.

2) Just like with normal usb controllers there needs to be a delay after
reset, for normal usb controllers, this is handled in hub_port_reset, add a
delay to usb_reset_root_port.

3) Sync the musb reset sequence with the upstream kernel, clear all bits of
power except bits 4-7, and increase the time reset is asserted to 50 ms.

With these fixes an usb keyboard I have now always enumerates properly, where
as earlier it would only enumerare properly once every 5 tries.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 common/usb.c                      |  2 ++
 drivers/usb/musb-new/musb_uboot.c | 31 ++++++++++++++++++++-----------
 include/usb.h                     |  5 +++++
 3 files changed, 27 insertions(+), 11 deletions(-)
diff mbox

Patch

diff --git a/common/usb.c b/common/usb.c
index 1eda099..32e15cd 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -970,6 +970,8 @@  int usb_new_device(struct usb_device *dev)
 			printf("\n     Couldn't reset port %i\n", dev->portnr);
 			return 1;
 		}
+	} else {
+		usb_reset_root_port();
 	}
 #endif
 
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index 28500bf..dab6f9b 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -110,9 +110,27 @@  int submit_int_msg(struct usb_device *dev, unsigned long pipe,
 	return submit_urb(&hcd, urb);
 }
 
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+void usb_reset_root_port(void)
 {
+	void *mbase = host->mregs;
 	u8 power;
+
+	power = musb_readb(mbase, MUSB_POWER);
+	power &= 0xf0;
+	musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
+	mdelay(50);
+	power = musb_readb(mbase, MUSB_POWER);
+	musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
+	host->isr(0, host);
+	host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
+			USB_SPEED_HIGH :
+			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
+			USB_SPEED_FULL : USB_SPEED_LOW;
+	mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
 	void *mbase;
 	/* USB spec says it may take up to 1 second for a device to connect */
 	unsigned long timeout = get_timer(0) + 1000;
@@ -131,16 +149,7 @@  int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 	if (get_timer(0) >= timeout)
 		return -ENODEV;
 
-	power = musb_readb(mbase, MUSB_POWER);
-	musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
-	udelay(30000);
-	power = musb_readb(mbase, MUSB_POWER);
-	musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
-	host->isr(0, host);
-	host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
-			USB_SPEED_HIGH :
-			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
-			USB_SPEED_FULL : USB_SPEED_LOW;
+	usb_reset_root_port();
 	host->is_active = 1;
 	hcd.hcd_priv = host;
 
diff --git a/include/usb.h b/include/usb.h
index b921a7f..a083591 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -159,6 +159,11 @@  enum usb_init_type {
 
 int usb_lowlevel_init(int index, enum usb_init_type init, void **controller);
 int usb_lowlevel_stop(int index);
+#ifdef CONFIG_MUSB_HOST
+void usb_reset_root_port(void);
+#else
+#define usb_reset_root_port()
+#endif
 
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
 			void *buffer, int transfer_len);