All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 1/1] tegra: seaboard: Initialize multiple USB controllers at once
@ 2012-06-14  4:17 Jim Lin
  2012-06-14 18:01 ` Stephen Warren
  0 siblings, 1 reply; 3+ messages in thread
From: Jim Lin @ 2012-06-14  4:17 UTC (permalink / raw)
  To: u-boot

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

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [U-Boot] [PATCH 1/1] tegra: seaboard: Initialize multiple USB controllers at once
  2012-06-14  4:17 [U-Boot] [PATCH 1/1] tegra: seaboard: Initialize multiple USB controllers at once Jim Lin
@ 2012-06-14 18:01 ` Stephen Warren
  2012-06-14 18:47   ` Marek Vasut
  0 siblings, 1 reply; 3+ messages in thread
From: Stephen Warren @ 2012-06-14 18:01 UTC (permalink / raw)
  To: u-boot

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...

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [U-Boot] [PATCH 1/1] tegra: seaboard: Initialize multiple USB controllers at once
  2012-06-14 18:01 ` Stephen Warren
@ 2012-06-14 18:47   ` Marek Vasut
  0 siblings, 0 replies; 3+ messages in thread
From: Marek Vasut @ 2012-06-14 18:47 UTC (permalink / raw)
  To: u-boot

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

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-06-14 18:47 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-14  4:17 [U-Boot] [PATCH 1/1] tegra: seaboard: Initialize multiple USB controllers at once Jim Lin
2012-06-14 18:01 ` Stephen Warren
2012-06-14 18:47   ` Marek Vasut

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.