[U-Boot] [PATCH 1/1] tegra: seaboard: Initialize multiple USB controllers at once

From: Jim Lin jilin@nvidia.com
Add support for command line "usb reset" or "usb start" to initialize , "usb stop" to stop multiple USB controllers at once. Other commands like "usb tree" also support multiple controllers.
New added definitions in header file are: CONFIG_USB_INIT_MULTI CONFIG_USB_MAX_CONTROLLER_COUNT
Signed-off-by: Jim Lin jilin@nvidia.com --- arch/arm/cpu/armv7/tegra2/usb.c | 15 +++ arch/arm/include/asm/arch-tegra2/usb.h | 4 + common/cmd_usb.c | 10 ++ common/usb.c | 108 ++++++++++++++++++ common/usb_hub.c | 4 + drivers/usb/host/ehci-hcd.c | 192 ++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-tegra.c | 17 +++- drivers/usb/host/ehci.h | 5 + include/configs/seaboard.h | 2 + include/usb.h | 12 ++ 10 files changed, 368 insertions(+), 1 deletions(-)
diff --git a/arch/arm/cpu/armv7/tegra2/usb.c b/arch/arm/cpu/armv7/tegra2/usb.c index c80de7f..3d2cfb9 100644 --- a/arch/arm/cpu/armv7/tegra2/usb.c +++ b/arch/arm/cpu/armv7/tegra2/usb.c @@ -352,7 +352,11 @@ int tegrausb_start_port(unsigned portnum, u32 *hccr, u32 *hcor)
if (portnum >= port_count) return -1; +#ifdef CONFIG_USB_INIT_MULTI + tegrausb_stop_port(portnum); +#else tegrausb_stop_port(); +#endif set_host_mode(&port[portnum]);
usbctlr = port[portnum].reg; @@ -362,6 +366,16 @@ int tegrausb_start_port(unsigned portnum, u32 *hccr, u32 *hcor) return 0; }
+#ifdef CONFIG_USB_INIT_MULTI +int tegrausb_stop_port(unsigned portnum) +{ + struct usb_ctlr *usbctlr; + + if (portnum >= port_count) + return -1; + + usbctlr = port[portnum].reg; +#else int tegrausb_stop_port(void) { struct usb_ctlr *usbctlr; @@ -370,6 +384,7 @@ int tegrausb_stop_port(void) return -1;
usbctlr = port[port_current].reg; +#endif
/* Stop controller */ writel(0, &usbctlr->usb_cmd); diff --git a/arch/arm/include/asm/arch-tegra2/usb.h b/arch/arm/include/asm/arch-tegra2/usb.h index 638033b..119d7b4 100644 --- a/arch/arm/include/asm/arch-tegra2/usb.h +++ b/arch/arm/include/asm/arch-tegra2/usb.h @@ -247,6 +247,10 @@ int tegrausb_start_port(unsigned portnum, u32 *hccr, u32 *hcor); * * @return 0 if ok, -1 if no port was active */ +#ifdef CONFIG_USB_INIT_MULTI +int tegrausb_stop_port(unsigned portnum); +#else int tegrausb_stop_port(void); +#endif
#endif /* _TEGRA_USB_H_ */ diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 9eba271..4c01a78 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -553,7 +553,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_INIT_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 1ec30bc..b4275c5 100644 --- a/common/usb.c +++ b/common/usb.c @@ -81,6 +81,86 @@ char usb_started; /* flag for the started/stopped USB status */ */ static void usb_scan_devices(void);
+#ifdef CONFIG_USB_INIT_MULTI +/*************************************************************************** + * Init USB Device + */ + +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 /*************************************************************************** * Init USB Device */ @@ -126,6 +206,7 @@ int usb_stop(void) } return res; } +#endif
/* * disables the asynch behaviour of the control message. This is used for data @@ -747,7 +828,31 @@ struct usb_device *usb_get_dev_index(int index) return &usb_dev[index]; }
+#ifdef CONFIG_USB_INIT_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) +{ + int i;
+ USB_PRINTF("New Device %d\n", dev_index); + if (dev_index == USB_MAX_DEVICE) { + printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE); + return NULL; + } + /* default Address is 0, real addresses start with 1 */ + usb_dev[dev_index].devnum = dev_index + 1; + usb_dev[dev_index].maxchild = 0; + for (i = 0; i < USB_MAXCHILDREN; i++) + usb_dev[dev_index].children[i] = NULL; + usb_dev[dev_index].parent = NULL; + usb_dev[dev_index].controller = controller; + dev_index++; + return &usb_dev[dev_index - 1]; +} +#else /* returns a pointer of a new device structure or NULL, if * no device struct is available */ @@ -769,6 +874,7 @@ struct usb_device *usb_alloc_new_device(void) return &usb_dev[dev_index - 1]; }
+#endif
/* * By the time we get here, the device has gotten a new device ID @@ -940,6 +1046,7 @@ int usb_new_device(struct usb_device *dev) return 0; }
+#ifndef CONFIG_USB_INIT_MULTI /* build device Tree */ static void usb_scan_devices(void) { @@ -964,5 +1071,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 e0edaad..6c27761 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_INIT_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 38d6ae0..7d9d33a 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -29,12 +29,25 @@
#include "ehci.h"
+#ifdef CONFIG_USB_INIT_MULTI +static struct ehci_ctrl { + struct ehci_hccr *hccr; /* R/O registers, not need for volatile */ + volatile struct ehci_hcor *hcor; + int rootdev; + uint16_t portreset; + struct QH qh_list __attribute__((aligned(32))); + struct QH qh_pool __attribute__((aligned(32))); + struct qTD td_pool[3] __attribute__((aligned (32))); + int ntds; +} ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; +#else int rootdev; struct ehci_hccr *hccr; /* R/O registers, not need for volatile */ volatile struct ehci_hcor *hcor;
static uint16_t portreset; static struct QH qh_list __attribute__((aligned(32))); +#endif
static struct descriptor { struct usb_hub_descriptor hub; @@ -230,7 +243,11 @@ static void ehci_free(void *p, size_t sz)
}
+#ifdef CONFIG_USB_INIT_MULTI +static int ehci_reset(volatile struct ehci_hcor *hcor) +#else static int ehci_reset(void) +#endif { uint32_t cmd; uint32_t tmp; @@ -266,6 +283,33 @@ out: return ret; }
+#ifdef CONFIG_USB_INIT_MULTI +static void *ehci_alloc(struct ehci_ctrl *ctrl, size_t sz, size_t align) +{ + void *p; + + switch (sz) { + case sizeof(struct QH): + p = &ctrl->qh_pool; + ctrl->ntds = 0; + break; + case sizeof(struct qTD): + if (ctrl->ntds == 3) { + debug("out of TDs\n"); + return NULL; + } + p = &ctrl->td_pool[ctrl->ntds]; + ctrl->ntds++; + break; + default: + debug("unknown allocation size\n"); + return NULL; + } + + memset(p, 0, sz); + return p; +} +#else static void *ehci_alloc(size_t sz, size_t align) { static struct QH qh __attribute__((aligned(32))); @@ -294,6 +338,7 @@ static void *ehci_alloc(size_t sz, size_t align) memset(p, 0, sz); return p; } +#endif
static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) { @@ -336,6 +381,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, uint32_t cmd; int timeout; int ret = 0; +#ifdef CONFIG_USB_INIT_MULTI + struct ehci_ctrl *ctrl = dev->controller; + volatile struct ehci_hcor *hcor = ctrl->hcor; +#endif
debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, buffer, length, req); @@ -346,12 +395,20 @@ 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));
+#ifdef CONFIG_USB_INIT_MULTI + qh = (struct QH *) ehci_alloc(ctrl, sizeof(struct QH), 32); +#else qh = ehci_alloc(sizeof(struct QH), 32); +#endif if (qh == NULL) { debug("unable to allocate QH\n"); return -1; } +#ifdef CONFIG_USB_INIT_MULTI + qh->qh_link = cpu_to_hc32((uint32_t)&ctrl->qh_list | QH_LINK_TYPE_QH); +#else qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH); +#endif c = (usb_pipespeed(pipe) != USB_SPEED_HIGH && usb_pipeendpoint(pipe) == 0) ? 1 : 0; endpt = (8 << 28) | @@ -376,7 +433,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
if (req != NULL) { +#ifdef CONFIG_USB_INIT_MULTI + td = ehci_alloc(ctrl, sizeof(struct qTD), 32); +#else td = ehci_alloc(sizeof(struct qTD), 32); +#endif if (td == NULL) { debug("unable to allocate SETUP td\n"); goto fail; @@ -398,7 +459,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, }
if (length > 0 || req == NULL) { +#ifdef CONFIG_USB_INIT_MULTI + td = ehci_alloc(ctrl, sizeof(struct qTD), 32); +#else td = ehci_alloc(sizeof(struct qTD), 32); +#endif if (td == NULL) { debug("unable to allocate DATA td\n"); goto fail; @@ -422,7 +487,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, }
if (req != NULL) { +#ifdef CONFIG_USB_INIT_MULTI + td = ehci_alloc(ctrl, sizeof(struct qTD), 32); +#else td = ehci_alloc(sizeof(struct qTD), 32); +#endif if (td == NULL) { debug("unable to allocate ACK td\n"); goto fail; @@ -440,10 +509,17 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, tdp = &td->qt_next; }
+#ifdef CONFIG_USB_INIT_MULTI + ctrl->qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH); + + /* Flush dcache */ + ehci_flush_dcache(&ctrl->qh_list); +#else qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);
/* Flush dcache */ ehci_flush_dcache(&qh_list); +#endif
usbsts = ehci_readl(&hcor->or_usbsts); ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f)); @@ -466,7 +542,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, timeout = USB_TIMEOUT_MS(pipe); do { /* Invalidate dcache */ +#ifdef CONFIG_USB_INIT_MULTI + ehci_invalidate_dcache(&ctrl->qh_list); +#else ehci_invalidate_dcache(&qh_list); +#endif token = hc32_to_cpu(vtd->qt_token); if (!(token & 0x80)) break; @@ -490,7 +570,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, goto fail; }
+#ifdef CONFIG_USB_INIT_MULTI + ctrl->qh_list.qh_link = cpu_to_hc32((uint32_t)&ctrl->qh_list + | QH_LINK_TYPE_QH); +#else qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH); +#endif
token = hc32_to_cpu(qh->qh_overlay.qt_token); if (!(token & 0x80)) { @@ -561,6 +646,11 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, int len, srclen; uint32_t reg; uint32_t *status_reg; +#ifdef CONFIG_USB_INIT_MULTI + struct ehci_ctrl *ctrl = dev->controller; + struct ehci_hccr *hccr = ctrl->hccr; + volatile struct ehci_hcor *hcor = ctrl->hcor; +#endif
if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { printf("The request port(%d) is not configured\n", @@ -633,7 +723,11 @@ 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"); +#ifdef CONFIG_USB_INIT_MULTI + ctrl->rootdev = le16_to_cpu(req->value); +#else rootdev = le16_to_cpu(req->value); +#endif break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: debug("USB_REQ_SET_CONFIGURATION\n"); @@ -683,7 +777,11 @@ 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; +#ifdef CONFIG_USB_INIT_MULTI + if (ctrl->portreset & (1 << le16_to_cpu(req->index))) +#else if (portreset & (1 << le16_to_cpu(req->index))) +#endif tmpbuf[2] |= USB_PORT_STAT_C_RESET;
srcptr = tmpbuf; @@ -735,8 +833,13 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000); if (!ret) +#ifdef CONFIG_USB_INIT_MULTI + ctrl->portreset |= + 1 << le16_to_cpu(req->index); +#else portreset |= 1 << le16_to_cpu(req->index); +#endif else printf("port(%d) reset error\n", le16_to_cpu(req->index) - 1); @@ -768,7 +871,11 @@ 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: +#ifdef CONFIG_USB_INIT_MULTI + ctrl->portreset &= ~(1 << le16_to_cpu(req->index)); +#else portreset &= ~(1 << le16_to_cpu(req->index)); +#endif break; default: debug("unknown feature %x\n", le16_to_cpu(req->value)); @@ -804,6 +911,82 @@ unknown: return -1; }
+#ifdef CONFIG_USB_INIT_MULTI +int usb_lowlevel_stop(int index) +{ + return ehci_hcd_stop(index); +} + +void *usb_lowlevel_init(int index) +{ + uint32_t reg; + uint32_t cmd; + struct ehci_hccr *hccr; + volatile struct ehci_hcor *hcor; + struct QH *qh_list; + + if (ehci_hcd_init(index, &hccr, (struct ehci_hcor **)&hcor) != 0) + return NULL; + + /* EHCI spec section 4.1 */ + if (ehci_reset(hcor) != 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 + 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)); + qh_list->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH); + qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12)); + qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE); + qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40); + + /* Set async. queue head pointer. */ + ehci_writel(&hcor->or_asynclistaddr, (uint32_t)qh_list); + + reg = ehci_readl(&hccr->cr_hcsparams); + descriptor.hub.bNbrPorts = HCS_N_PORTS(reg); + printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts); + /* Port Indicators */ + if (HCS_INDICATOR(reg)) + descriptor.hub.wHubCharacteristics |= 0x80; + /* Port Power Control */ + if (HCS_PPC(reg)) + descriptor.hub.wHubCharacteristics |= 0x01; + + /* Start the host controller. */ + cmd = ehci_readl(&hcor->or_usbcmd); + /* + * Philips, Intel, and maybe others need CMD_RUN before the + * root hub will detect new devices (why?); NEC doesn't + */ + cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); + cmd |= CMD_RUN; + ehci_writel(&hcor->or_usbcmd, cmd); + + /* take control over the ports */ + cmd = ehci_readl(&hcor->or_configflag); + cmd |= FLAG_CF; + ehci_writel(&hcor->or_configflag, cmd); + /* unblock posted write */ + cmd = ehci_readl(&hcor->or_usbcmd); + mdelay(5); + reg = HC_VERSION(ehci_readl(&hccr->cr_capbase)); + printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff); + + ehcic[index].rootdev = 0; + + return ehcic + index; +} +#else int usb_lowlevel_stop(void) { return ehci_hcd_stop(); @@ -872,6 +1055,7 @@ int usb_lowlevel_init(void)
return 0; } +#endif
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, @@ -889,14 +1073,22 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) { +#ifdef CONFIG_USB_INIT_MULTI + struct ehci_ctrl *ctrl = dev->controller; +#endif
if (usb_pipetype(pipe) != PIPE_CONTROL) { debug("non-control pipe (type=%lu)", usb_pipetype(pipe)); return -1; }
+#ifdef CONFIG_USB_INIT_MULTI + if (usb_pipedevice(pipe) == ctrl->rootdev) { + if (ctrl->rootdev == 0) +#else if (usb_pipedevice(pipe) == rootdev) { if (rootdev == 0) +#endif dev->speed = USB_SPEED_HIGH; return ehci_submit_root(dev, pipe, buffer, length, setup); } diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index a7e105b..f676902 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 NVIDIA Corporation + * Copyright (c) 2009-2012 NVIDIA Corporation * * See file CREDITS for list of people who contributed to this * project. @@ -34,6 +34,12 @@ * Create the appropriate control structures to manage * a new EHCI host controller. */ +#ifdef CONFIG_USB_INIT_MULTI +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) +{ + return tegrausb_start_port(index, hccr, hcor); +} +#else int ehci_hcd_init(void) { u32 our_hccr, our_hcor; @@ -50,13 +56,22 @@ int ehci_hcd_init(void)
return 0; } +#endif
/* * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ +#ifdef CONFIG_USB_INIT_MULTI +int ehci_hcd_stop(int index) +{ + tegrausb_stop_port(index); + return 0; +} +#else int ehci_hcd_stop(void) { tegrausb_stop_port(); return 0; } +#endif diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index cc00ce4..059827a 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_INIT_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/configs/seaboard.h b/include/configs/seaboard.h index f46740e..0c66e16 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -107,6 +107,8 @@ #define CONFIG_USB_EHCI_TEGRA #define CONFIG_USB_STORAGE #define CONFIG_CMD_USB +#define CONFIG_USB_INIT_MULTI +#define CONFIG_USB_MAX_CONTROLLER_COUNT 3
/* USB networking support */ #define CONFIG_USB_HOST_ETHER diff --git a/include/usb.h b/include/usb.h index 48e4bcd..018567c 100644 --- a/include/usb.h +++ b/include/usb.h @@ -128,6 +128,9 @@ struct usb_device { int portnr; struct usb_device *parent; struct usb_device *children[USB_MAXCHILDREN]; +#ifdef CONFIG_USB_INIT_MULTI + void *controller; /* hardware controller private data */ +#endif };
/********************************************************************** @@ -141,8 +144,13 @@ struct usb_device { defined(CONFIG_USB_OMAP3) || defined(CONFIG_USB_DA8XX) || \ defined(CONFIG_USB_BLACKFIN) || defined(CONFIG_USB_AM35X)
+#ifdef CONFIG_USB_INIT_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, @@ -370,7 +378,11 @@ void usb_hub_reset(void); int hub_port_reset(struct usb_device *dev, int port, unsigned short *portstat);
+#ifdef CONFIG_USB_INIT_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

On 06/13/2012 10:17 PM, Jim Lin wrote:
Add support for command line "usb reset" or "usb start" to initialize , "usb stop" to stop multiple USB controllers at once. Other commands like "usb tree" also support multiple controllers.
These patches also need to be sent to the USB maintainer since they touch core USB code. (Now CC'd)
Rather than one mega-patch that touch the USB core, and the Tegra driver, can't the patch be split up a bit so that one patch adds the ability to support multiple controllers, and then another patch modifies the Tegra USB driver to support this, etc. Many smaller patches are much easier to review.
This patch adds a huge number of ifdefs. I'm sure many of them can be removed completely. For example, in the following code, why not /always/ get the rootdev from dev->controller->rootdev, and remove the global variable. I would guess that the code size increase would be extremely minimal, but it would make the code a lot more maintainable by removing all the ifdefs.
submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) { +#ifdef CONFIG_USB_INIT_MULTI
struct ehci_ctrl *ctrl = dev->controller;
+#endif
if (usb_pipetype(pipe) != PIPE_CONTROL) { debug("non-control pipe (type=%lu)", usb_pipetype(pipe)); return -1; }
+#ifdef CONFIG_USB_INIT_MULTI
if (usb_pipedevice(pipe) == ctrl->rootdev) {
if (ctrl->rootdev == 0)
+#else if (usb_pipedevice(pipe) == rootdev) { if (rootdev == 0) +#endif dev->speed = USB_SPEED_HIGH; return ehci_submit_root(dev, pipe, buffer, length, setup); }
The patch above removes the use of the global variable "rootdev", but I don't see anywhere that ifdef's that variable out of existence. Not doing so would allow code to accidentally use the global when it should be using the per-device value; how can you be sure you've patched all the places in the code that you need to? What about future changes to the code by people who aren't aware of the USB_INIT_MULTI feature?
Similarly, why not just outright change the prototype of tegrausb_stop_port() so that it always takes a port number; the existing calls can hard-code a port ID of 0 for compatibility:
+#ifdef CONFIG_USB_INIT_MULTI +int ehci_hcd_stop(int index) +{
tegrausb_stop_port(index);
return 0;
+} +#else int ehci_hcd_stop(void) { tegrausb_stop_port(); return 0; }
+#endif
In the end, I think if you rework the patch to remove all/most of the ifdefs, the only thing that's left will be that the loop to initialize USB would loop over either just device 0 or devices 0..n-1, and even that wouldn't need to be ifdef'd...

Dear Stephen Warren,
On 06/13/2012 10:17 PM, Jim Lin wrote:
Add support for command line "usb reset" or "usb start" to initialize , "usb stop" to stop multiple USB controllers at once. Other commands like "usb tree" also support multiple controllers.
These patches also need to be sent to the USB maintainer since they touch core USB code. (Now CC'd)
Ok, waiting for smaller patches indeed,
Best regards, Marek Vasut
participants (3)
-
Jim Lin
-
Marek Vasut
-
Stephen Warren