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 <ji...@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 + 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_ */ -- 1.7.3 nvpublic _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot