diff mbox

[U-Boot,v2,1/1] USB: EHCI: Initialize multiple USB controllers at once

Message ID 4B9C9637D5087840A465BDCB251780E9E2D750F10C@HKMAIL02.nvidia.com
State Superseded
Headers show

Commit Message

Jim Lin Aug. 8, 2012, 9:48 a.m. UTC
Add support for command line "usb reset" or "usb start" to initialize
, "usb stop" to stop multiple USB controllers at once.
Other command like "usb tree" also supports multiple controllers.

New added definitions in header file are:
CONFIG_USB_MULTI
CONFIG_USB_MAX_CONTROLLER_COUNT

Signed-off-by: Jim Lin <jilin@nvidia.com>
---
Changes in v2:
- Renaming from CONFIG_USB_INIT_MULTI to CONFIG_USB_MULTI
- Define CONFIG_USB_MAX_CONTROLLER_COUNT as 1 if not defined
- Remove volatile from structure ehci_ctrl of ehci-hcd.c for a checkpatch.pl warning

 common/cmd_usb.c            |   10 +++
 common/usb.c                |   98 +++++++++++++++++++++++++-
 common/usb_hub.c            |    4 +
 drivers/usb/host/ehci-hcd.c |  167 +++++++++++++++++++++++++++++++-----------
 drivers/usb/host/ehci.h     |    5 ++
 include/usb.h               |   12 +++
 6 files changed, 251 insertions(+), 45 deletions(-)

--
1.7.3

nvpublic

Comments

Marek Vasut Aug. 11, 2012, 11:46 p.m. UTC | #1
Dear Jim Lin,

> Add support for command line "usb reset" or "usb start" to initialize
> , "usb stop" to stop multiple USB controllers at once.
> Other command like "usb tree" also supports multiple controllers.
> 
> New added definitions in header file are:
> CONFIG_USB_MULTI
> CONFIG_USB_MAX_CONTROLLER_COUNT
> 
> Signed-off-by: Jim Lin <jilin@nvidia.com>
> ---
> Changes in v2:
> - Renaming from CONFIG_USB_INIT_MULTI to CONFIG_USB_MULTI
> - Define CONFIG_USB_MAX_CONTROLLER_COUNT as 1 if not defined
> - Remove volatile from structure ehci_ctrl of ehci-hcd.c for a
> checkpatch.pl warning
> 
>  common/cmd_usb.c            |   10 +++
>  common/usb.c                |   98 +++++++++++++++++++++++++-
>  common/usb_hub.c            |    4 +
>  drivers/usb/host/ehci-hcd.c |  167
> +++++++++++++++++++++++++++++++----------- drivers/usb/host/ehci.h     |  
>  5 ++
>  include/usb.h               |   12 +++
>  6 files changed, 251 insertions(+), 45 deletions(-)
> 
> diff --git a/common/cmd_usb.c b/common/cmd_usb.c
> index a8e3ae5..8d3093b 100644
> --- a/common/cmd_usb.c
> +++ b/common/cmd_usb.c
> @@ -554,7 +554,17 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char
> * const argv[]) }
>         if (strncmp(argv[1], "tree", 4) == 0) {
>                 printf("\nDevice Tree:\n");
> +#ifdef CONFIG_USB_MULTI

How's this supposed to work? Shouldn't this call usb_show_tree on roots of all 
the trees?

> +               for (i = 0; i < USB_MAX_DEVICE; i++) {
> +                       dev = usb_get_dev_index(i);
> +                       if (dev == NULL)
> +                               break;
> +                       if (dev->parent == NULL)
> +                               usb_show_tree(dev);
> +               }
> +#else
>                 usb_show_tree(usb_get_dev_index(0));
> +#endif
>                 return 0;
>         }
>         if (strncmp(argv[1], "inf", 3) == 0) {
> diff --git a/common/usb.c b/common/usb.c
> index 1b40228..065c70c 100644
> --- a/common/usb.c
> +++ b/common/usb.c
> @@ -77,6 +77,89 @@ static int asynch_allowed;
> 
>  char usb_started; /* flag for the started/stopped USB status */
> 
> +#ifdef CONFIG_USB_MULTI
> +/*************************************************************************
> ** + * Init USB Device
> + */
> +#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
> +#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
> +#endif
> +
> +int usb_init(void)
> +{
> +       void *ctrl;
> +       int i;
> +       struct usb_device *dev;
> +
> +       running = 0;
> +       dev_index = 0;
> +       asynch_allowed = 1;
> +       usb_hub_reset();
> +
> +       /* first make all devices unknown */
> +       for (i = 0; i < USB_MAX_DEVICE; i++) {
> +               memset(&usb_dev[i], 0, sizeof(struct usb_device));
> +               usb_dev[i].devnum = -1;
> +       }
> +
> +       /* init low_level USB */
> +       printf("USB:   ");
> +       for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
> +               /* init low_level USB */
> +               ctrl = usb_lowlevel_init(i);
> +               /*
> +                * if lowlevel init is OK, scan the bus for devices
> +                * i.e. search HUBs and configure them
> +                */
> +               if (ctrl) {
> +                       running = 1;
> +
> +                       printf("scanning bus for devices... ");
> +                       dev = usb_alloc_new_device(ctrl);
> +                       /*
> +                        * device 0 is always present
> +                        * (root hub, so let it analyze)
> +                        */
> +                       if (dev)
> +                               usb_new_device(dev);
> +               }
> +       }
> +
> +       if (running) {
> +               if (!dev_index)
> +                       printf("No USB Device found\n");
> +               else
> +                       printf("%d USB Device(s) found\n", dev_index);
> +#ifdef CONFIG_USB_KEYBOARD
> +       drv_usb_kbd_init();

Will the keyboard driver survive this?

> +#endif
> +       USB_PRINTF("scan end\n");
> +               usb_started = 1;
> +               return 0;
> +       } else {
> +               printf("Error, couldn't init Lowlevel part\n");
> +               usb_started = 0;
> +               return -1;
> +       }
> +}
> +
> +/*************************************************************************
> ***** + * Stop USB this stops the LowLevel Part and deregisters USB
> devices. + */
> +int usb_stop(void)
> +{
> +       int i;
> +
> +       if (usb_started) {
> +               asynch_allowed = 1;
> +               usb_started = 0;
> +               usb_hub_reset();
> +               for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++)
> +                       usb_lowlevel_stop(i);
> +       }
> +       return 0;
> +}
> +#else
>  /**********************************************************************
>   * some forward declerations...
>   */
> @@ -127,6 +210,7 @@ int usb_stop(void)
>         }
>         return res;
>  }
> +#endif
> 
>  /*
>   * disables the asynch behaviour of the control message. This is used for
> data @@ -750,11 +834,18 @@ struct usb_device *usb_get_dev_index(int index)
> return &usb_dev[index];
>  }
> 
> -
> +#ifdef CONFIG_USB_MULTI

I still believe it's possible to get rid of this MULTI crap, simply set the 
"multiness" to 1 for non-multi setups. How big overhead will that generate?
[...]
btw you might want to rebase on top of latest u-boot-usb.
Jim Lin Aug. 13, 2012, 10:25 a.m. UTC | #2
>-----Original Message-----
>From: Marek Vasut [mailto:marex@denx.de] 
>Sent: Sunday, August 12, 2012 7:47 AM
>To: Jim Lin
>Cc: u-boot@lists.denx.de; Wolfgang Denk; Tom Warren
>Subject: Re: [U-Boot] [PATCH v2 1/1] USB: EHCI: Initialize multiple USB controllers at once
>
>> diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 
>> a8e3ae5..8d3093b 100644
>> --- a/common/cmd_usb.c
>> +++ b/common/cmd_usb.c
>> @@ -554,7 +554,17 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, 
>> char
>> * const argv[]) }
>>         if (strncmp(argv[1], "tree", 4) == 0) {
>>                 printf("\nDevice Tree:\n");
>> +#ifdef CONFIG_USB_MULTI
>
>How's this supposed to work? Shouldn't this call usb_show_tree on roots of all the trees?

You see the following  if dev->parent is NULL that means it's the only root hub under a controller
, then we show devices under this root hub of the controller by usb_show_tree.
Root hub under different controller is listed as separate device.

>> +               for (i = 0; i < USB_MAX_DEVICE; i++) {
>> +                       dev = usb_get_dev_index(i);
>> +                       if (dev == NULL)
>> +                               break;
>> +                       if (dev->parent == NULL)
>> +                               usb_show_tree(dev);
>> +               }
>> +#else
>>                 usb_show_tree(usb_get_dev_index(0));
>> +#endif
>>                 return 0;
>>         }
>>         if (strncmp(argv[1], "inf", 3) == 0) { diff --git 
>> a/common/usb.c b/common/usb.c index 1b40228..065c70c 100644
>> --- a/common/usb.c
>> +++ b/common/usb.c
>
>> +#endif
>> +       USB_PRINTF("scan end\n");
>> +               usb_started = 1;
>> +               return 0;
>> +       } else {
>> +               printf("Error, couldn't init Lowlevel part\n");
>> +               usb_started = 0;
>> +               return -1;
>> +       }
>> +}
>> +
>> +/********************************************************************
>> +*****
>> ***** + * Stop USB this stops the LowLevel Part and deregisters USB 
>> devices. + */
>> +int usb_stop(void)
>> +{
>> +       int i;
>> +
>> +       if (usb_started) {
>> +               asynch_allowed = 1;
>> +               usb_started = 0;
>> +               usb_hub_reset();
>> +               for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++)
>> +                       usb_lowlevel_stop(i);
>> +       }
>> +       return 0;
>> +}
>> +#else
>>  /**********************************************************************
>>   * some forward declerations...
>>   */
>> @@ -127,6 +210,7 @@ int usb_stop(void)
>>         }
>>         return res;
>>  }
>> +#endif
>> 
>>  /*
>>   * disables the asynch behaviour of the control message. This is used 
>> for data @@ -750,11 +834,18 @@ struct usb_device 
>> *usb_get_dev_index(int index) return &usb_dev[index];  }
>> 
>> -
>> +#ifdef CONFIG_USB_MULTI
>
>I still believe it's possible to get rid of this MULTI crap, simply set the "multiness" to 1 for non-multi setups. How big overhead will that generate?
I assume you want me to use code in ifdef CONFIG_USB_MULTI block,
remove CONFIG_USB_MULTI and if  CONFIG_USB_MAX_CONTROLLER_COUNT is 1
, then do non-multi setups.

nvpublic
Jim Lin Aug. 14, 2012, 4:22 a.m. UTC | #3
>-----Original Message-----
>From: Marek Vasut [mailto:marex@denx.de] 
>Sent: Sunday, August 12, 2012 7:47 AM
>To: Jim Lin
>Cc: u-boot@lists.denx.de; Wolfgang Denk; Tom Warren
>Subject: Re: [U-Boot] [PATCH v2 1/1] USB: EHCI: Initialize multiple USB controllers at once
>
>Dear Jim Lin,
>
>> Add support for command line "usb reset" or "usb start" to initialize 
>> , "usb stop" to stop multiple USB controllers at once.
>> Other command like "usb tree" also supports multiple controllers.
>> 
>> New added definitions in header file are:
>> CONFIG_USB_MULTI
>> CONFIG_USB_MAX_CONTROLLER_COUNT
>> 
>> Signed-off-by: Jim Lin <jilin@nvidia.com>
> ---
>> Changes in v2:
>> - Renaming from CONFIG_USB_INIT_MULTI to CONFIG_USB_MULTI
>> - Define CONFIG_USB_MAX_CONTROLLER_COUNT as 1 if not defined
>> - Remove volatile from structure ehci_ctrl of ehci-hcd.c for a 
>> checkpatch.pl warning
>> 
>>  common/cmd_usb.c            |   10 +++
>>  common/usb.c                |   98 +++++++++++++++++++++++++-
>>  common/usb_hub.c            |    4 +
>>  drivers/usb/host/ehci-hcd.c |  167
>> +++++++++++++++++++++++++++++++----------- drivers/usb/host/ehci.h     |  
>>  5 ++
>>  include/usb.h               |   12 +++
>>  6 files changed, 251 insertions(+), 45 deletions(-)
>> 
>> diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 
>> a8e3ae5..8d3093b 100644
>> --- a/common/cmd_usb.c
>> +++ b/common/cmd_usb.c
>> @@ -554,7 +554,17 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, 
>> char
>> * const argv[]) }
>>         if (strncmp(argv[1], "tree", 4) == 0) {
>>                 printf("\nDevice Tree:\n");
>> +#ifdef CONFIG_USB_MULTI
>
>How's this supposed to work? Shouldn't this call usb_show_tree on roots of all the trees?
See the following code, if dev->parent is NULL, then current device is  root hub, we show devices below it

>> +               for (i = 0; i < USB_MAX_DEVICE; i++) {
>> +                       dev = usb_get_dev_index(i);
>> +                       if (dev == NULL)
>> +                               break;
>> +                       if (dev->parent == NULL)
>> +                               usb_show_tree(dev);
>> +               }
>> +#else
>>                 usb_show_tree(usb_get_dev_index(0));
>> +#endif
>>                 return 0;
>>         }
>>         if (strncmp(argv[1], "inf", 3) == 0) { diff --git 
>> a/common/usb.c b/common/usb.c index 1b40228..065c70c 100644
>> --- a/common/usb.c
>> +++ b/common/usb.c
>> @@ -77,6 +77,89 @@ static int asynch_allowed;
>> 
>>  char usb_started; /* flag for the started/stopped USB status */
>> 
>> +#ifdef CONFIG_USB_MULTI
>> +/********************************************************************
>> +*****
>> ** + * Init USB Device
>> + */
>> +#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT #define 
>> +CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif
>> +
>> +int usb_init(void)
>> +{
>> +       void *ctrl;
>> +       int i;
>> +       struct usb_device *dev;
>> +
>> +       running = 0;
>> +       dev_index = 0;
>> +       asynch_allowed = 1;
>> +       usb_hub_reset();
>> +
>> +       /* first make all devices unknown */
>> +       for (i = 0; i < USB_MAX_DEVICE; i++) {
>> +               memset(&usb_dev[i], 0, sizeof(struct usb_device));
>> +               usb_dev[i].devnum = -1;
>> +       }
>> +
>> +       /* init low_level USB */
>> +       printf("USB:   ");
>> +       for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
>> +               /* init low_level USB */
>> +               ctrl = usb_lowlevel_init(i);
>> +               /*
>> +                * if lowlevel init is OK, scan the bus for devices
>> +                * i.e. search HUBs and configure them
>> +                */
>> +               if (ctrl) {
>> +                       running = 1;
>> +
>> +                       printf("scanning bus for devices... ");
>> +                       dev = usb_alloc_new_device(ctrl);
>> +                       /*
>> +                        * device 0 is always present
>> +                        * (root hub, so let it analyze)
>> +                        */
>> +                       if (dev)
>> +                               usb_new_device(dev);
>> +               }
>> +       }
>> +
>> +       if (running) {
>> +               if (!dev_index)
>> +                       printf("No USB Device found\n");
>> +               else
>> +                       printf("%d USB Device(s) found\n", dev_index); 
>> +#ifdef CONFIG_USB_KEYBOARD
>> +       drv_usb_kbd_init();
>
>Will the keyboard driver survive this?
Yes I have tried it after doing the following.
1. Define CONFIG_USB_KEYBOARD, CONFIG_SYS_USB_EVENT_POLL, CONFIG_USB_MULTI, and CONFIG_USB_MAX_CONTROLLER_COUNT 3
 in config header file like seaboard.h to compile
2. Install USB keyboard
3. Run "usb reset" in u-boot serial console
4. Run "coninfo" to see usbkbd appeared
5. Run "setenv stdin usbkbd"
6. Typing u-boot console command on USB keyboard

--
nvpublic
Stephen Warren Aug. 14, 2012, 4:18 p.m. UTC | #4
On 08/13/2012 10:22 PM, Jim Lin wrote:
> Marek Vasut wrote at Sunday, August 12, 2012 7:47 AM:
>> Dear Jim Lin,
>>
>>> Add support for command line "usb reset" or "usb start" to initialize 
>>> , "usb stop" to stop multiple USB controllers at once.
>>> Other command like "usb tree" also supports multiple controllers.
...
>>> +#ifdef CONFIG_USB_KEYBOARD
>>> +       drv_usb_kbd_init();
>>
>> Will the keyboard driver survive this?
>
> Yes I have tried it after doing the following.
> 1. Define CONFIG_USB_KEYBOARD, CONFIG_SYS_USB_EVENT_POLL, CONFIG_USB_MULTI, and CONFIG_USB_MAX_CONTROLLER_COUNT 3
>  in config header file like seaboard.h to compile
> 2. Install USB keyboard
> 3. Run "usb reset" in u-boot serial console
> 4. Run "coninfo" to see usbkbd appeared
> 5. Run "setenv stdin usbkbd"
> 6. Typing u-boot console command on USB keyboard

I've also tested this on Springbank, which has a built-in USB keyboard
and an external USB port via a separate host controller, which I
connected to an Ethernet device, and it appears to all work very well
for me.

So,

Tested-by: Stephen Warren <swarren@wwwdotorg.org>
Marek Vasut Aug. 14, 2012, 5:29 p.m. UTC | #5
Dear Jim Lin,

> >-----Original Message-----
> >From: Marek Vasut [mailto:marex@denx.de]
> >Sent: Sunday, August 12, 2012 7:47 AM
> >To: Jim Lin
> >Cc: u-boot@lists.denx.de; Wolfgang Denk; Tom Warren
> >Subject: Re: [U-Boot] [PATCH v2 1/1] USB: EHCI: Initialize multiple USB
> >controllers at once
> >
> >> diff --git a/common/cmd_usb.c b/common/cmd_usb.c index
> >> a8e3ae5..8d3093b 100644
> >> --- a/common/cmd_usb.c
> >> +++ b/common/cmd_usb.c
> >> @@ -554,7 +554,17 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc,
> >> char
> >> * const argv[]) }
> >> 
> >>         if (strncmp(argv[1], "tree", 4) == 0) {
> >>         
> >>                 printf("\nDevice Tree:\n");
> >> 
> >> +#ifdef CONFIG_USB_MULTI
> >
> >How's this supposed to work? Shouldn't this call usb_show_tree on roots of
> >all the trees?
> 
> You see the following  if dev->parent is NULL that means it's the only root
> hub under a controller , then we show devices under this root hub of the
> controller by usb_show_tree. Root hub under different controller is listed
> as separate device.

So if you set USB_MAX_DEVICE to 1, this code won't need the ifdefs? :)

> >> +               for (i = 0; i < USB_MAX_DEVICE; i++) {
> >> +                       dev = usb_get_dev_index(i);
> >> +                       if (dev == NULL)
> >> +                               break;
> >> +                       if (dev->parent == NULL)
> >> +                               usb_show_tree(dev);
> >> +               }
> >> +#else
> >> 
> >>                 usb_show_tree(usb_get_dev_index(0));
> >> 
> >> +#endif
> >> 
> >>                 return 0;
> >>         
> >>         }
> >>         if (strncmp(argv[1], "inf", 3) == 0) { diff --git
> >> 
> >> a/common/usb.c b/common/usb.c index 1b40228..065c70c 100644
> >> --- a/common/usb.c
> >> +++ b/common/usb.c
> >> 
> >> +#endif
> >> +       USB_PRINTF("scan end\n");
> >> +               usb_started = 1;
> >> +               return 0;
> >> +       } else {
> >> +               printf("Error, couldn't init Lowlevel part\n");

puts();

> >> +               usb_started = 0;
> >> +               return -1;
> >> +       }
> >> +}
> >> +
> >> +/********************************************************************
> >> +*****
> >> ***** + * Stop USB this stops the LowLevel Part and deregisters USB
> >> devices. + */
> >> +int usb_stop(void)
> >> +{
> >> +       int i;
> >> +

if (!started)
  return 0;

... do the work ...

;-)

> >> +       if (usb_started) {
> >> +               asynch_allowed = 1;
> >> +               usb_started = 0;
> >> +               usb_hub_reset();
> >> +               for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++)
> >> +                       usb_lowlevel_stop(i);
> >> +       }
> >> +       return 0;
> >> +}
> >> +#else
> >> 
> >>  /**********************************************************************
> >>  
> >>   * some forward declerations...
> >>   */
> >> 
> >> @@ -127,6 +210,7 @@ int usb_stop(void)
> >> 
> >>         }
> >>         return res;
> >>  
> >>  }
> >> 
> >> +#endif
> >> 
> >>  /*
> >>  
> >>   * disables the asynch behaviour of the control message. This is used
> >> 
> >> for data @@ -750,11 +834,18 @@ struct usb_device
> >> *usb_get_dev_index(int index) return &usb_dev[index];  }
> >> 
> >> -
> >> +#ifdef CONFIG_USB_MULTI
> >
> >I still believe it's possible to get rid of this MULTI crap, simply set
> >the "multiness" to 1 for non-multi setups. How big overhead will that
> >generate?
> 
> I assume you want me to use code in ifdef CONFIG_USB_MULTI block,
> remove CONFIG_USB_MULTI

Yes!

> and if  CONFIG_USB_MAX_CONTROLLER_COUNT is 1
> , then do non-multi setups.

No ;-) Why can't the "multi setups" be used for "non-multi" configuration?

> nvpublic
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
Marek Vasut Aug. 14, 2012, 5:30 p.m. UTC | #6
Dear Stephen Warren,

> On 08/13/2012 10:22 PM, Jim Lin wrote:
> > Marek Vasut wrote at Sunday, August 12, 2012 7:47 AM:
> >> Dear Jim Lin,
> >> 
> >>> Add support for command line "usb reset" or "usb start" to initialize
> >>> , "usb stop" to stop multiple USB controllers at once.
> >>> Other command like "usb tree" also supports multiple controllers.
> 
> ...
> 
> >>> +#ifdef CONFIG_USB_KEYBOARD
> >>> +       drv_usb_kbd_init();
> >> 
> >> Will the keyboard driver survive this?
> > 
> > Yes I have tried it after doing the following.
> > 1. Define CONFIG_USB_KEYBOARD, CONFIG_SYS_USB_EVENT_POLL,
> > CONFIG_USB_MULTI, and CONFIG_USB_MAX_CONTROLLER_COUNT 3
> > 
> >  in config header file like seaboard.h to compile
> > 
> > 2. Install USB keyboard
> > 3. Run "usb reset" in u-boot serial console
> > 4. Run "coninfo" to see usbkbd appeared
> > 5. Run "setenv stdin usbkbd"
> > 6. Typing u-boot console command on USB keyboard
> 
> I've also tested this on Springbank, which has a built-in USB keyboard
> and an external USB port via a separate host controller, which I
> connected to an Ethernet device, and it appears to all work very well
> for me.
> 
> So,
> 
> Tested-by: Stephen Warren <swarren@wwwdotorg.org>

Good, thanks! :)

Best regards,
Marek Vasut
diff mbox

Patch

diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index a8e3ae5..8d3093b 100644
--- a/common/cmd_usb.c
+++ b/common/cmd_usb.c
@@ -554,7 +554,17 @@  int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        }
        if (strncmp(argv[1], "tree", 4) == 0) {
                printf("\nDevice Tree:\n");
+#ifdef CONFIG_USB_MULTI
+               for (i = 0; i < USB_MAX_DEVICE; i++) {
+                       dev = usb_get_dev_index(i);
+                       if (dev == NULL)
+                               break;
+                       if (dev->parent == NULL)
+                               usb_show_tree(dev);
+               }
+#else
                usb_show_tree(usb_get_dev_index(0));
+#endif
                return 0;
        }
        if (strncmp(argv[1], "inf", 3) == 0) {
diff --git a/common/usb.c b/common/usb.c
index 1b40228..065c70c 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -77,6 +77,89 @@  static int asynch_allowed;

 char usb_started; /* flag for the started/stopped USB status */

+#ifdef CONFIG_USB_MULTI
+/***************************************************************************
+ * Init USB Device
+ */
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
+int usb_init(void)
+{
+       void *ctrl;
+       int i;
+       struct usb_device *dev;
+
+       running = 0;
+       dev_index = 0;
+       asynch_allowed = 1;
+       usb_hub_reset();
+
+       /* first make all devices unknown */
+       for (i = 0; i < USB_MAX_DEVICE; i++) {
+               memset(&usb_dev[i], 0, sizeof(struct usb_device));
+               usb_dev[i].devnum = -1;
+       }
+
+       /* init low_level USB */
+       printf("USB:   ");
+       for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
+               /* init low_level USB */
+               ctrl = usb_lowlevel_init(i);
+               /*
+                * if lowlevel init is OK, scan the bus for devices
+                * i.e. search HUBs and configure them
+                */
+               if (ctrl) {
+                       running = 1;
+
+                       printf("scanning bus for devices... ");
+                       dev = usb_alloc_new_device(ctrl);
+                       /*
+                        * device 0 is always present
+                        * (root hub, so let it analyze)
+                        */
+                       if (dev)
+                               usb_new_device(dev);
+               }
+       }
+
+       if (running) {
+               if (!dev_index)
+                       printf("No USB Device found\n");
+               else
+                       printf("%d USB Device(s) found\n", dev_index);
+#ifdef CONFIG_USB_KEYBOARD
+       drv_usb_kbd_init();
+#endif
+       USB_PRINTF("scan end\n");
+               usb_started = 1;
+               return 0;
+       } else {
+               printf("Error, couldn't init Lowlevel part\n");
+               usb_started = 0;
+               return -1;
+       }
+}
+
+/******************************************************************************
+ * Stop USB this stops the LowLevel Part and deregisters USB devices.
+ */
+int usb_stop(void)
+{
+       int i;
+
+       if (usb_started) {
+               asynch_allowed = 1;
+               usb_started = 0;
+               usb_hub_reset();
+               for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++)
+                       usb_lowlevel_stop(i);
+       }
+       return 0;
+}
+#else
 /**********************************************************************
  * some forward declerations...
  */
@@ -127,6 +210,7 @@  int usb_stop(void)
        }
        return res;
 }
+#endif

 /*
  * disables the asynch behaviour of the control message. This is used for data
@@ -750,11 +834,18 @@  struct usb_device *usb_get_dev_index(int index)
                return &usb_dev[index];
 }

-
+#ifdef CONFIG_USB_MULTI
+/* Save input pointer 'controller' into device structure.
+ * returns a pointer of a new device structure or NULL, if
+ * no device struct is available
+ */
+struct usb_device *usb_alloc_new_device(void *controller)
+#else
 /* returns a pointer of a new device structure or NULL, if
  * no device struct is available
  */
 struct usb_device *usb_alloc_new_device(void)
+#endif
 {
        int i;
        USB_PRINTF("New Device %d\n", dev_index);
@@ -768,6 +859,9 @@  struct usb_device *usb_alloc_new_device(void)
        for (i = 0; i < USB_MAXCHILDREN; i++)
                usb_dev[dev_index].children[i] = NULL;
        usb_dev[dev_index].parent = NULL;
+#ifdef CONFIG_USB_MULTI
+       usb_dev[dev_index].controller = controller;
+#endif
        dev_index++;
        return &usb_dev[dev_index - 1];
 }
@@ -945,6 +1039,7 @@  int usb_new_device(struct usb_device *dev)
        return 0;
 }

+#ifndef CONFIG_USB_MULTI
 /* build device Tree  */
 static void usb_scan_devices(void)
 {
@@ -969,5 +1064,6 @@  static void usb_scan_devices(void)
 #endif
        USB_PRINTF("scan end\n");
 }
+#endif

 /* EOF */
diff --git a/common/usb_hub.c b/common/usb_hub.c
index f35ad95..8f2e3e3 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -243,7 +243,11 @@  void usb_hub_port_connect_change(struct usb_device *dev, int port)
        mdelay(200);

        /* Allocate a new device struct for it */
+#ifdef CONFIG_USB_MULTI
+       usb = usb_alloc_new_device(dev->controller);
+#else
        usb = usb_alloc_new_device();
+#endif

        if (portstatus & USB_PORT_STAT_HIGH_SPEED)
                usb->speed = USB_SPEED_HIGH;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 2a82a29..7f8c734 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -29,13 +29,24 @@ 

 #include "ehci.h"

-int rootdev;
+#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#endif
+
+static struct ehci_ctrl {
+       struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
+       struct ehci_hcor *hcor;
+       int rootdev;
+       uint16_t portreset;
+       struct QH qh_list __attribute__((aligned(USB_DMA_MINALIGN)));
+       struct QH qh_pool __attribute__((aligned(USB_DMA_MINALIGN)));
+       struct qTD td_pool[3] __attribute__((aligned(USB_DMA_MINALIGN)));
+       int qtd_counter;
+} ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+
 struct ehci_hccr *hccr;        /* R/O registers, not need for volatile */
 volatile struct ehci_hcor *hcor;

-static uint16_t portreset;
-DEFINE_ALIGN_BUFFER(struct QH, qh_list, 1, USB_DMA_MINALIGN);
-
 #define ALIGN_END_ADDR(type, ptr, size)                        \
        ((uint32_t)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN))

@@ -207,10 +218,8 @@  static int
 ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                   int length, struct devrequest *req)
 {
-       ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
-       ALLOC_ALIGN_BUFFER(struct qTD, qtd, 3, USB_DMA_MINALIGN);
-       int qtd_counter = 0;
-
+       struct QH *qh;
+       struct qTD *qtd;
        volatile struct qTD *vtd;
        unsigned long ts;
        uint32_t *tdp;
@@ -219,6 +228,13 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
        uint32_t cmd;
        int timeout;
        int ret = 0;
+       struct ehci_ctrl *ctrl;
+#ifdef CONFIG_USB_MULTI
+       ctrl = dev->controller;
+#else
+       ctrl = &ehcic[0];
+#endif
+       hcor = ctrl->hcor;

        debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
              buffer, length, req);
@@ -229,6 +245,9 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                      le16_to_cpu(req->value), le16_to_cpu(req->value),
                      le16_to_cpu(req->index));

+       qh = &ctrl->qh_pool;
+       ctrl->qtd_counter = 0;
+       qtd = &ctrl->td_pool;
        memset(qh, 0, sizeof(struct QH));
        memset(qtd, 0, 3 * sizeof(*qtd));

@@ -244,7 +263,7 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
         *   qh_overlay.qt_next ...... 13-10 H
         * - qh_overlay.qt_altnext
         */
-       qh->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH);
+       qh->qh_link = cpu_to_hc32((uint32_t)&ctrl->qh_list | QH_LINK_TYPE_QH);
        c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
             usb_pipeendpoint(pipe) == 0) ? 1 : 0;
        endpt = (8 << 28) |
@@ -274,19 +293,21 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                 *
                 *   [ buffer, buffer_hi ] loaded with "req".
                 */
-               qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
-               qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+               qtd[ctrl->qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+               qtd[ctrl->qtd_counter].qt_altnext =
+                       cpu_to_hc32(QT_NEXT_TERMINATE);
                token = (0 << 31) |
                    (sizeof(*req) << 16) |
                    (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
-               qtd[qtd_counter].qt_token = cpu_to_hc32(token);
-               if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req)) != 0) {
+               qtd[ctrl->qtd_counter].qt_token = cpu_to_hc32(token);
+               if (ehci_td_buffer(&qtd[ctrl->qtd_counter], req, sizeof(*req))
+                       != 0) {
                        printf("unable construct SETUP td\n");
                        goto fail;
                }
                /* Update previous qTD! */
-               *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
-               tdp = &qtd[qtd_counter++].qt_next;
+               *tdp = cpu_to_hc32((uint32_t)&qtd[ctrl->qtd_counter]);
+               tdp = &qtd[ctrl->qtd_counter++].qt_next;
                toggle = 1;
        }

@@ -300,22 +321,25 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                 *
                 *   [ buffer, buffer_hi ] loaded with "buffer".
                 */
-               qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
-               qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+               qtd[ctrl->qtd_counter].qt_next =
+                       cpu_to_hc32(QT_NEXT_TERMINATE);
+               qtd[ctrl->qtd_counter].qt_altnext =
+                       cpu_to_hc32(QT_NEXT_TERMINATE);
                token = (toggle << 31) |
                    (length << 16) |
                    ((req == NULL ? 1 : 0) << 15) |
                    (0 << 12) |
                    (3 << 10) |
                    ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
-               qtd[qtd_counter].qt_token = cpu_to_hc32(token);
-               if (ehci_td_buffer(&qtd[qtd_counter], buffer, length) != 0) {
+               qtd[ctrl->qtd_counter].qt_token = cpu_to_hc32(token);
+               if (ehci_td_buffer(&qtd[ctrl->qtd_counter], buffer, length)
+                               != 0) {
                        printf("unable construct DATA td\n");
                        goto fail;
                }
                /* Update previous qTD! */
-               *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
-               tdp = &qtd[qtd_counter++].qt_next;
+               *tdp = cpu_to_hc32((uint32_t)&qtd[ctrl->qtd_counter]);
+               tdp = &qtd[ctrl->qtd_counter++].qt_next;
        }

        if (req != NULL) {
@@ -326,30 +350,32 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
                 *   qt_altnext ............. 07-04 H
                 *   qt_token ............... 0B-08 H
                 */
-               qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
-               qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+               qtd[ctrl->qtd_counter].qt_next =
+                       cpu_to_hc32(QT_NEXT_TERMINATE);
+               qtd[ctrl->qtd_counter].qt_altnext =
+                       cpu_to_hc32(QT_NEXT_TERMINATE);
                token = (toggle << 31) |
                    (0 << 16) |
                    (1 << 15) |
                    (0 << 12) |
                    (3 << 10) |
                    ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
-               qtd[qtd_counter].qt_token = cpu_to_hc32(token);
+               qtd[ctrl->qtd_counter].qt_token = cpu_to_hc32(token);
                /* Update previous qTD! */
-               *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]);
-               tdp = &qtd[qtd_counter++].qt_next;
+               *tdp = cpu_to_hc32((uint32_t)&qtd[ctrl->qtd_counter]);
+               tdp = &qtd[ctrl->qtd_counter++].qt_next;
        }

-       qh_list->qh_link = cpu_to_hc32((uint32_t)qh | QH_LINK_TYPE_QH);
+       ctrl->qh_list.qh_link = cpu_to_hc32((uint32_t)qh | QH_LINK_TYPE_QH);

        /* Flush dcache */
-       flush_dcache_range((uint32_t)qh_list,
-               ALIGN_END_ADDR(struct QH, qh_list, 1));
+       flush_dcache_range((uint32_t)&ctrl->qh_list,
+               ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
        flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1));
        flush_dcache_range((uint32_t)qtd, ALIGN_END_ADDR(struct qTD, qtd, 3));

        /* Set async. queue head pointer. */
-       ehci_writel(&hcor->or_asynclistaddr, (uint32_t)qh_list);
+       ehci_writel(&hcor->or_asynclistaddr, (uint32_t)&ctrl->qh_list);

        usbsts = ehci_readl(&hcor->or_usbsts);
        ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));
@@ -368,12 +394,12 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,

        /* Wait for TDs to be processed. */
        ts = get_timer(0);
-       vtd = &qtd[qtd_counter - 1];
+       vtd = &qtd[ctrl->qtd_counter - 1];
        timeout = USB_TIMEOUT_MS(pipe);
        do {
                /* Invalidate dcache */
-               invalidate_dcache_range((uint32_t)qh_list,
-                       ALIGN_END_ADDR(struct QH, qh_list, 1));
+               invalidate_dcache_range((uint32_t)&ctrl->qh_list,
+                       ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
                invalidate_dcache_range((uint32_t)qh,
                        ALIGN_END_ADDR(struct QH, qh, 1));
                invalidate_dcache_range((uint32_t)qtd,
@@ -476,6 +502,14 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
        int len, srclen;
        uint32_t reg;
        uint32_t *status_reg;
+       struct ehci_ctrl *ctrl;
+#ifdef CONFIG_USB_MULTI
+       ctrl = dev->controller;
+#else
+       ctrl = &ehcic[0];
+#endif
+       hcor = ctrl->hcor;
+       hccr = ctrl->hccr;

        if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
                printf("The request port(%d) is not configured\n",
@@ -548,7 +582,7 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
                break;
        case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
                debug("USB_REQ_SET_ADDRESS\n");
-               rootdev = le16_to_cpu(req->value);
+               ctrl->rootdev = le16_to_cpu(req->value);
                break;
        case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
                debug("USB_REQ_SET_CONFIGURATION\n");
@@ -598,7 +632,7 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
                        tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
                if (reg & EHCI_PS_OCC)
                        tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
-               if (portreset & (1 << le16_to_cpu(req->index)))
+               if (ctrl->portreset & (1 << le16_to_cpu(req->index)))
                        tmpbuf[2] |= USB_PORT_STAT_C_RESET;

                srcptr = tmpbuf;
@@ -650,7 +684,7 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
                                ret = handshake(status_reg, EHCI_PS_PR, 0,
                                                2 * 1000);
                                if (!ret)
-                                       portreset |=
+                                       ctrl->portreset |=
                                                1 << le16_to_cpu(req->index);
                                else
                                        printf("port(%d) reset error\n",
@@ -683,7 +717,7 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
                        reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
                        break;
                case USB_PORT_FEAT_C_RESET:
-                       portreset &= ~(1 << le16_to_cpu(req->index));
+                       ctrl->portreset &= ~(1 << le16_to_cpu(req->index));
                        break;
                default:
                        debug("unknown feature %x\n", le16_to_cpu(req->value));
@@ -719,27 +753,52 @@  unknown:
        return -1;
 }

+#ifdef CONFIG_USB_MULTI
+int usb_lowlevel_stop(int index)
+{
+       return ehci_hcd_stop(index);
+}
+#else
 int usb_lowlevel_stop(void)
 {
        return ehci_hcd_stop();
 }
+#endif

-int usb_lowlevel_init(void)
+void *usb_lowlevel_multi_init(int index)
 {
        uint32_t reg;
        uint32_t cmd;
+       struct QH *qh_list;
+
+#ifdef CONFIG_USB_MULTI
+       if (ehci_hcd_init(index, &hccr, (struct ehci_hcor **)&hcor) != 0)
+               return NULL;
+
+       /* EHCI spec section 4.1 */
+       if (ehci_reset() != 0)
+               return NULL;

+#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
+       if (ehci_hcd_init(index, &hccr, (struct ehci_hcor **)&hcor) != 0)
+               return NULL;
+#endif
+#else
        if (ehci_hcd_init() != 0)
-               return -1;
+               return NULL;

        /* EHCI spec section 4.1 */
        if (ehci_reset() != 0)
-               return -1;
+               return NULL;

 #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
        if (ehci_hcd_init() != 0)
-               return -1;
+               return NULL;
+#endif
 #endif
+       ehcic[index].hccr = hccr;
+       ehcic[index].hcor = hcor;
+       qh_list = &ehcic[index].qh_list;

        /* Set head of reclaim list */
        memset(qh_list, 0, sizeof(*qh_list));
@@ -780,10 +839,24 @@  int usb_lowlevel_init(void)
        reg = HC_VERSION(ehci_readl(&hccr->cr_capbase));
        printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);

-       rootdev = 0;
+       ehcic[index].rootdev = 0;
+
+       return ehcic + index;
+}

+#ifdef CONFIG_USB_MULTI
+void *usb_lowlevel_init(int index)
+{
+       return usb_lowlevel_multi_init(index);
+}
+#else
+int usb_lowlevel_init(void)
+{
+       if (usb_lowlevel_multi_init(0) == NULL)
+               return -1;
        return 0;
 }
+#endif

 int
 submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
@@ -801,14 +874,20 @@  int
 submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
                   int length, struct devrequest *setup)
 {
+       struct ehci_ctrl *ctrl;

        if (usb_pipetype(pipe) != PIPE_CONTROL) {
                debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
                return -1;
        }

-       if (usb_pipedevice(pipe) == rootdev) {
-               if (rootdev == 0)
+#ifdef CONFIG_USB_MULTI
+       ctrl = dev->controller;
+#else
+       ctrl = &ehcic[0];
+#endif
+       if (usb_pipedevice(pipe) == ctrl->rootdev) {
+               if (ctrl->rootdev == 0)
                        dev->speed = USB_SPEED_HIGH;
                return ehci_submit_root(dev, pipe, buffer, length, setup);
        }
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index cc00ce4..1cc5c6e 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -201,7 +201,12 @@  struct QH {
 };

 /* Low level init functions */
+#ifdef CONFIG_USB_MULTI
+int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor);
+int ehci_hcd_stop(int index);
+#else
 int ehci_hcd_init(void);
 int ehci_hcd_stop(void);
+#endif

 #endif /* USB_EHCI_H */
diff --git a/include/usb.h b/include/usb.h
index ba3d169..628cfd5 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -140,6 +140,9 @@  struct usb_device {
        int portnr;
        struct usb_device *parent;
        struct usb_device *children[USB_MAXCHILDREN];
+#ifdef CONFIG_USB_MULTI
+       void *controller;               /* hardware controller private data */
+#endif
 };

 /**********************************************************************
@@ -153,8 +156,13 @@  struct usb_device {
        defined(CONFIG_USB_OMAP3) || defined(CONFIG_USB_DA8XX) || \
        defined(CONFIG_USB_BLACKFIN) || defined(CONFIG_USB_AM35X)

+#ifdef CONFIG_USB_MULTI
+void *usb_lowlevel_init(int index);
+int usb_lowlevel_stop(int index);
+#else
 int usb_lowlevel_init(void);
 int usb_lowlevel_stop(void);
+#endif
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
                        void *buffer, int transfer_len);
 int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
@@ -382,7 +390,11 @@  void usb_hub_reset(void);
 int hub_port_reset(struct usb_device *dev, int port,
                          unsigned short *portstat);

+#ifdef CONFIG_USB_MULTI
+struct usb_device *usb_alloc_new_device(void *controller);
+#else
 struct usb_device *usb_alloc_new_device(void);
+#endif
 int usb_new_device(struct usb_device *dev);

 #endif /*_USB_H_ */