Message ID | 4B9C9637D5087840A465BDCB251780E9E2D750F10C@HKMAIL02.nvidia.com |
---|---|
State | Superseded |
Headers | show |
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.
>-----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
>-----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
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>
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
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 --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_ */
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