diff options
author | Hans de Goede <hdegoede@redhat.com> | 2015-01-11 20:34:51 +0100 |
---|---|---|
committer | Marek Vasut <marex@denx.de> | 2015-01-18 12:31:36 +0100 |
commit | 90cdc1039d0bf6d85bb497dbb93d317ad234e846 (patch) | |
tree | 753472c23d0d45336216db7e9a6c06634c71f732 | |
parent | e8672e3f0ec571d0ca7ccd8cbbeb113802c1d443 (diff) | |
download | u-boot-imx-90cdc1039d0bf6d85bb497dbb93d317ad234e846.zip u-boot-imx-90cdc1039d0bf6d85bb497dbb93d317ad234e846.tar.gz u-boot-imx-90cdc1039d0bf6d85bb497dbb93d317ad234e846.tar.bz2 |
musb-new: Fix reset sequence when in host mode
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>
-rw-r--r-- | common/usb.c | 2 | ||||
-rw-r--r-- | drivers/usb/musb-new/musb_uboot.c | 31 | ||||
-rw-r--r-- | include/usb.h | 5 |
3 files changed, 27 insertions, 11 deletions
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); |