[U-Boot] [RFC PATCH 0/1] Add ehci core

Remy Bohmer linux at bohmer.net
Tue Nov 25 12:31:53 CET 2008


Hello Michael,

Thanks for inlining these patches... But you forgot at least a
Signed-off-by line...
And sorry... I have to mention that the code is also not very clean
related to Coding rules (see attached)
Can you please clean it up and make sure the build problems Markus
mentioned this morning are solved?
(Coding Style logging is generated by the Linux checkpatch.pl script)

Remy


2008/11/25 Michael Trimarchi <trimarchi at gandalf.sssup.it>:
> Add ehci core functionality
>
> ---
>  common/cmd_usb.c            |    3 +-
>  drivers/usb/usb_ehci.h      |  120 ++++++++
>  drivers/usb/usb_ehci_core.c |  633 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/usb_ehci_core.h |   29 ++
>  include/usb.h               |   15 +-
>  include/usb_defs.h          |   10 +
>  6 files changed, 803 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/usb/usb_ehci.h
>  create mode 100644 drivers/usb/usb_ehci_core.c
>  create mode 100644 drivers/usb/usb_ehci_core.h
>
> diff --git a/common/cmd_usb.c b/common/cmd_usb.c
> index 99e551f..532df37 100644
> --- a/common/cmd_usb.c
> +++ b/common/cmd_usb.c
> @@ -276,7 +276,8 @@ void usb_show_tree_graph(struct usb_device *dev,char *pre)
>        pre[index++]= has_child ? '|' : ' ';
>        pre[index]=0;
>        printf(" %s (%s, %dmA)\n",usb_get_class_desc(dev->config.if_desc[0].bInterfaceClass),
> -               dev->slow ? "1.5MBit/s" : "12MBit/s",dev->config.MaxPower * 2);
> +               (dev->speed == USB_SPEED_LOW) ? "1.5MBit/s" : (dev->speed == USB_SPEED_FULL)
> +               ? "12MBit/s" : "480MBit/s", dev->config.MaxPower * 2);
>        if (strlen(dev->mf) ||
>           strlen(dev->prod) ||
>           strlen(dev->serial))
> diff --git a/drivers/usb/usb_ehci.h b/drivers/usb/usb_ehci.h
> new file mode 100644
> index 0000000..821082a
> --- /dev/null
> +++ b/drivers/usb/usb_ehci.h
> @@ -0,0 +1,120 @@
> +/*-
> + * Copyright (c) 2007-2008, Juniper Networks, Inc.
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2 of
> + * the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef USB_EHCI_H
> +#define USB_EHCI_H
> +
> +/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
> +#define DeviceRequest \
> +       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
> +#define DeviceOutRequest \
> +       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
> +
> +#define InterfaceRequest \
> +       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
> +
> +#define EndpointRequest \
> +       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
> +#define EndpointOutRequest \
> +       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
> +
> +/*
> + * Register Space.
> + */
> +struct ehci_hccr {
> +       uint8_t cr_caplength;
> +       uint16_t cr_hciversion;
> +       uint32_t cr_hcsparams;
> +       uint32_t cr_hccparams;
> +       uint8_t cr_hcsp_portrt[8];
> +};
> +
> +struct ehci_hcor {
> +       uint32_t or_usbcmd;
> +       uint32_t or_usbsts;
> +       uint32_t or_usbintr;
> +       uint32_t or_frindex;
> +       uint32_t or_ctrldssegment;
> +       uint32_t or_periodiclistbase;
> +       uint32_t or_asynclistaddr;
> +       uint32_t _reserved_[9];
> +       uint32_t or_configflag;
> +       uint32_t or_portsc[2];
> +       uint32_t or_systune;
> +};
> +
> +#define EHCI_PS_WKOC_E         0x00400000      /* RW wake on over current */
> +#define EHCI_PS_WKDSCNNT_E     0x00200000      /* RW wake on disconnect */
> +#define EHCI_PS_WKCNNT_E       0x00100000      /* RW wake on connect */
> +#define EHCI_PS_PTC            0x000f0000      /* RW port test control */
> +#define EHCI_PS_PIC            0x0000c000      /* RW port indicator control */
> +#define EHCI_PS_PO             0x00002000      /* RW port owner */
> +#define EHCI_PS_PP             0x00001000      /* RW,RO port power */
> +#define EHCI_PS_LS             0x00000c00      /* RO line status */
> +#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == 0x00000400)
> +#define EHCI_PS_PR             0x00000100      /* RW port reset */
> +#define EHCI_PS_SUSP           0x00000080      /* RW suspend */
> +#define EHCI_PS_FPR            0x00000040      /* RW force port resume */
> +#define EHCI_PS_OCC            0x00000020      /* RWC over current change */
> +#define EHCI_PS_OCA            0x00000010      /* RO over current active */
> +#define EHCI_PS_PEC            0x00000008      /* RWC port enable change */
> +#define EHCI_PS_PE             0x00000004      /* RW port enable */
> +#define EHCI_PS_CSC            0x00000002      /* RWC connect status change */
> +#define EHCI_PS_CS             0x00000001      /* RO connect status */
> +#define EHCI_PS_CLEAR          (EHCI_PS_OCC|EHCI_PS_PEC|EHCI_PS_CSC)
> +
> +/*
> + * Schedule Interface Space.
> + *
> + * IMPORTANT: Software must ensure that no interface data structure
> + * reachable by the EHCI host controller spans a 4K page boundary!
> + *
> + * Periodic transfers (i.e. isochronous and interrupt transfers) are
> + * not supported.
> + */
> +
> +/* Queue Element Transfer Descriptor (qTD). */
> +struct qTD {
> +       uint32_t qt_next;
> +#define        QT_NEXT_TERMINATE       1
> +       uint32_t qt_altnext;
> +       uint32_t qt_token;
> +       uint32_t qt_buffer[5];
> +};
> +
> +/* Queue Head (QH). */
> +struct QH {
> +       uint32_t qh_link;
> +#define        QH_LINK_TERMINATE       1
> +#define        QH_LINK_TYPE_ITD        0
> +#define        QH_LINK_TYPE_QH         2
> +#define        QH_LINK_TYPE_SITD       4
> +#define        QH_LINK_TYPE_FSTN       6
> +       uint32_t qh_endpt1;
> +       uint32_t qh_endpt2;
> +       uint32_t qh_curtd;
> +       struct qTD qh_overlay;
> +};
> +
> +/* Low level intit functions */
> +
> +int ehci_hcd_init (void);
> +int ehci_hcd_stop (void);
> +#endif /* USB_EHCI_H */
> diff --git a/drivers/usb/usb_ehci_core.c b/drivers/usb/usb_ehci_core.c
> new file mode 100644
> index 0000000..ef947d5
> --- /dev/null
> +++ b/drivers/usb/usb_ehci_core.c
> @@ -0,0 +1,633 @@
> +/*-
> + * Copyright (c) 2007-2008, Juniper Networks, Inc.
> + * Copyright (c) 2008, Excito Elektronik i Skåne AB
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2 of
> + * the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <usb.h>
> +#include <asm/io.h>
> +#include "usb_ehci.h"
> +
> +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)));
> +
> +struct usb_device_descriptor device = {
> +       sizeof(struct usb_device_descriptor),   /* bLength */
> +       1,              /* bDescriptorType: UDESC_DEVICE */
> +       0x0002,         /* bcdUSB: v2.0 */
> +       9,              /* bDeviceClass: UDCLASS_HUB */
> +       0,              /* bDeviceSubClass: UDSUBCLASS_HUB */
> +       1,              /* bDeviceProtocol: UDPROTO_HSHUBSTT */
> +       64,             /* bMaxPacketSize: 64 bytes */
> +       0x0000,         /* idVendor */
> +       0x0000,         /* idProduct */
> +        0x0001,         /* bcdDevice */
> +       1,              /* iManufacturer */
> +       2,              /* iProduct */
> +       0,              /* iSerialNumber */
> +       1               /* bNumConfigurations: 1 */
> +};
> +
> +struct usb_config_descriptor config = {
> +       sizeof(struct usb_config_descriptor),
> +       2,              /* bDescriptorType: UDESC_CONFIG */
> +       sizeof(struct usb_config_descriptor) +
> +       sizeof(struct usb_interface_descriptor) +
> +       sizeof(struct usb_endpoint_descriptor),
> +       0,
> +       1,              /* bNumInterface */
> +       1,              /* bConfigurationValue */
> +       0,              /* iConfiguration */
> +       0x40,           /* bmAttributes: UC_SELF_POWER */
> +       0               /* bMaxPower */
> +};
> +
> +struct usb_interface_descriptor interface = {
> +       sizeof(struct usb_interface_descriptor),        /* bLength */
> +       4,              /* bDescriptorType: UDESC_INTERFACE */
> +       0,              /* bInterfaceNumber */
> +       0,              /* bAlternateSetting */
> +       1,              /* bNumEndpoints */
> +       9,              /* bInterfaceClass: UICLASS_HUB */
> +       0,              /* bInterfaceSubClass: UISUBCLASS_HUB */
> +       0,              /* bInterfaceProtocol: UIPROTO_HSHUBSTT */
> +       0               /* iInterface */
> +};
> +
> +struct usb_endpoint_descriptor endpoint = {
> +sizeof(struct usb_endpoint_descriptor),         /* bLength */
> +       5,              /* bDescriptorType: UDESC_ENDPOINT */
> +       0x81,           /* bEndpointAddress: UE_DIR_IN | EHCI_INTR_ENDPT */
> +       3,              /* bmAttributes: UE_INTERRUPT */
> +       8, 0,           /* wMaxPacketSize */
> +       255             /* bInterval */
> +};
> +
> +struct usb_hub_descriptor hub = {
> +       sizeof(struct usb_hub_descriptor),      /* bDescLength */
> +       0x29,           /* bDescriptorType: hub
> +                          descriptor */
> +       2,              /* bNrPorts -- runtime modified */
> +        0, 0,          /* wHubCharacteristics */
> +        0xff,          /* bPwrOn2PwrGood */
> +       {},             /* bHubCntrCurrent */
> +       {}              /* at most 7 ports! XXX */
> +};
> +
> +static void *ehci_alloc (size_t sz, size_t align)
> +{
> +       static struct QH qh __attribute__ ((aligned (32)));
> +       static struct qTD td[3] __attribute__ ((aligned (32)));
> +       static int ntds = 0;
> +       void *p;
> +
> +       switch (sz) {
> +       case sizeof (struct QH):
> +               p = &qh;
> +               ntds = 0;
> +               break;
> +       case sizeof (struct qTD):
> +               if (ntds == 3) {
> +                       debug ("out of TDs");
> +                       return (NULL);
> +               }
> +               p = &td[ntds];
> +               ntds++;
> +               break;
> +       default:
> +               debug ("unknown allocation size");
> +               return (NULL);
> +       }
> +
> +       memset (p, sz, 0);
> +       return (p);
> +}
> +
> +static void ehci_free (void *p, size_t sz)
> +{
> +}
> +
> +static int ehci_td_buffer (struct qTD *td, void *buf, size_t sz)
> +{
> +       uint32_t addr, delta, next;
> +       int idx;
> +
> +       addr = (uint32_t) buf;
> +       idx = 0;
> +       while (idx < 5) {
> +               td->qt_buffer[idx] = cpu_to_le32 (addr);
> +               next = (addr + 4096) & ~4095;
> +               delta = next - addr;
> +               if (delta >= sz)
> +                       break;
> +               sz -= delta;
> +               addr = next;
> +               idx++;
> +       }
> +
> +       if (idx == 5) {
> +               debug ("out of buffer pointers (%u bytes left)", sz);
> +               return (-1);
> +       }
> +
> +       return (0);
> +}
> +
> +static int
> +ehci_submit_async (struct usb_device *dev, unsigned long pipe, void *buffer,
> +                  int length, struct devrequest *req)
> +{
> +       struct QH *qh;
> +       struct qTD *td;
> +       volatile struct qTD *vtd;
> +       unsigned long ts;
> +       uint32_t *tdp;
> +       uint32_t endpt, token, usbsts;
> +       uint32_t c, toggle;
> +
> +       debug ("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p", dev, pipe,
> +              buffer, length, req);
> +       if (req != NULL)
> +               debug ("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u",
> +                      req->request, req->request,
> +                      req->requesttype, req->requesttype,
> +                      le16_to_cpu (req->value), le16_to_cpu (req->value),
> +                      le16_to_cpu (req->index), le16_to_cpu (req->index));
> +
> +       qh = ehci_alloc (sizeof (struct QH), 32);
> +       if (qh == NULL) {
> +               debug ("unable to allocate QH");
> +               return (-1);
> +       }
> +       qh->qh_link = cpu_to_le32 ((uint32_t) & qh_list | QH_LINK_TYPE_QH);
> +       c = (usb_pipespeed (pipe) != USB_SPEED_HIGH &&
> +            usb_pipeendpoint (pipe) == 0) ? 1 : 0;
> +       endpt = (8 << 28) |
> +           (c << 27) |
> +           (usb_maxpacket (dev, pipe) << 16) |
> +           (0 << 15) |
> +           (1 << 14) |
> +           (usb_pipespeed (pipe) << 12) |
> +           (usb_pipeendpoint (pipe) << 8) |
> +           (0 << 7) | (usb_pipedevice (pipe) << 0);
> +       qh->qh_endpt1 = cpu_to_le32 (endpt);
> +       endpt = (1 << 30) |
> +           (dev->portnr << 23) |
> +           (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
> +       qh->qh_endpt2 = cpu_to_le32 (endpt);
> +       qh->qh_overlay.qt_next = cpu_to_le32 (QT_NEXT_TERMINATE);
> +       qh->qh_overlay.qt_altnext = cpu_to_le32 (QT_NEXT_TERMINATE);
> +
> +       td = NULL;
> +       tdp = &qh->qh_overlay.qt_next;
> +
> +       toggle =
> +           usb_gettoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
> +
> +       if (req != NULL) {
> +               td = ehci_alloc (sizeof (struct qTD), 32);
> +               if (td == NULL) {
> +                       debug ("unable to allocate SETUP td");
> +                       goto fail;
> +               }
> +               td->qt_next = cpu_to_le32 (QT_NEXT_TERMINATE);
> +               td->qt_altnext = cpu_to_le32 (QT_NEXT_TERMINATE);
> +               token = (0 << 31) |
> +                   (sizeof (*req) << 16) |
> +                   (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
> +               td->qt_token = cpu_to_le32 (token);
> +               if (ehci_td_buffer (td, req, sizeof (*req)) != 0) {
> +                       debug ("unable construct SETUP td");
> +                       ehci_free (td, sizeof (*td));
> +                       goto fail;
> +               }
> +               *tdp = cpu_to_le32 ((uint32_t) td);
> +               tdp = &td->qt_next;
> +               toggle = 1;
> +       }
> +
> +       if (length > 0 || req == NULL) {
> +               td = ehci_alloc (sizeof (struct qTD), 32);
> +               if (td == NULL) {
> +                       debug ("unable to allocate DATA td");
> +                       goto fail;
> +               }
> +               td->qt_next = cpu_to_le32 (QT_NEXT_TERMINATE);
> +               td->qt_altnext = cpu_to_le32 (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);
> +               td->qt_token = cpu_to_le32 (token);
> +               if (ehci_td_buffer (td, buffer, length) != 0) {
> +                       debug ("unable construct DATA td");
> +                       ehci_free (td, sizeof (*td));
> +                       goto fail;
> +               }
> +               *tdp = cpu_to_le32 ((uint32_t) td);
> +               tdp = &td->qt_next;
> +       }
> +
> +       if (req != NULL) {
> +               td = ehci_alloc (sizeof (struct qTD), 32);
> +               if (td == NULL) {
> +                       debug ("unable to allocate ACK td");
> +                       goto fail;
> +               }
> +               td->qt_next = cpu_to_le32 (QT_NEXT_TERMINATE);
> +               td->qt_altnext = cpu_to_le32 (QT_NEXT_TERMINATE);
> +               token = (toggle << 31) |
> +                   (0 << 16) |
> +                   (1 << 15) |
> +                   (0 << 12) |
> +                   (3 << 10) |
> +                   ((usb_pipein (pipe) ? 0 : 1) << 8) | (0x80 << 0);
> +               td->qt_token = cpu_to_le32 (token);
> +               *tdp = cpu_to_le32 ((uint32_t) td);
> +               tdp = &td->qt_next;
> +       }
> +
> +       qh_list.qh_link = cpu_to_le32 ((uint32_t) qh | QH_LINK_TYPE_QH);
> +
> +       usbsts = le32_to_cpu (hcor->or_usbsts);
> +       hcor->or_usbsts = cpu_to_le32 (usbsts & 0x3f);
> +
> +       /* Enable async. schedule. */
> +       hcor->or_usbcmd |= cpu_to_le32 (0x20);
> +       while ((hcor->or_usbsts & cpu_to_le32 (0x8000)) == 0)
> +               udelay (1);
> +
> +       /* Wait for TDs to be processed. */
> +       ts = get_timer (0);
> +       vtd = td;
> +       do {
> +               token = le32_to_cpu (vtd->qt_token);
> +               if (!(token & 0x80))
> +                       break;
> +       } while (get_timer (ts) < CONFIG_SYS_HZ);
> +
> +       /* Disable async schedule. */
> +       hcor->or_usbcmd &= ~cpu_to_le32 (0x20);
> +       while ((hcor->or_usbsts & cpu_to_le32 (0x8000)) != 0)
> +               udelay (1);
> +
> +       qh_list.qh_link = cpu_to_le32 ((uint32_t) & qh_list | QH_LINK_TYPE_QH);
> +
> +       token = le32_to_cpu (qh->qh_overlay.qt_token);
> +       if (!(token & 0x80)) {
> +               // debug ("TOKEN=%#x", token);
> +               switch (token & 0xfc) {
> +               case 0:
> +                       toggle = token >> 31;
> +                       usb_settoggle (dev, usb_pipeendpoint (pipe),
> +                                      usb_pipeout (pipe), toggle);
> +                       dev->status = 0;
> +                       break;
> +               case 0x40:
> +                       dev->status = USB_ST_STALLED;
> +                       break;
> +               case 0xa0:
> +               case 0x20:
> +                       dev->status = USB_ST_BUF_ERR;
> +                       break;
> +               case 0x50:
> +               case 0x10:
> +                       dev->status = USB_ST_BABBLE_DET;
> +                       break;
> +               default:
> +                       dev->status = USB_ST_CRC_ERR;
> +                       break;
> +               }
> +               dev->act_len = length - ((token >> 16) & 0x7fff);
> +       } else {
> +               dev->act_len = 0;
> +               debug ("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x",
> +                      dev->devnum, le32_to_cpu (hcor->or_usbsts),
> +                      le32_to_cpu (hcor->or_portsc[0]),
> +                      le32_to_cpu (hcor->or_portsc[1]));
> +       }
> +
> +       return ((dev->status != USB_ST_NOT_PROC) ? 0 : -1);
> +
> +      fail:
> +       td = (void *)le32_to_cpu (qh->qh_overlay.qt_next);
> +       while (td != (void *)QT_NEXT_TERMINATE) {
> +               qh->qh_overlay.qt_next = td->qt_next;
> +               ehci_free (td, sizeof (*td));
> +               td = (void *)le32_to_cpu (qh->qh_overlay.qt_next);
> +       }
> +       ehci_free (qh, sizeof (*qh));
> +       return (-1);
> +}
> +
> +static __inline int min3 (int a, int b, int c)
> +{
> +
> +       if (b < a)
> +               a = b;
> +       if (c < a)
> +               a = c;
> +       return (a);
> +}
> +
> +ehci_submit_root (struct usb_device *dev, unsigned long pipe, void *buffer,
> +                 int length, struct devrequest *req)
> +{
> +       uint8_t tmpbuf[4];
> +       u16 typeReq;
> +       void *srcptr;
> +       int len, srclen;
> +       uint32_t reg;
> +
> +       srclen = 0;
> +       srcptr = NULL;
> +
> +       debug ("req=%u (%#x), type=%u (%#x), value=%u, index=%u",
> +              req->request, req->request,
> +              req->requesttype, req->requesttype,
> +              le16_to_cpu (req->value), le16_to_cpu (req->index));
> +
> +       typeReq = req->request << 8 | req->requesttype;
> +
> +       switch (typeReq) {
> +       case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
> +               switch (le16_to_cpu (req->value) >> 8) {
> +               case USB_DT_DEVICE:
> +                       srcptr = &device;
> +                       srclen = sizeof(struct usb_device_descriptor);
> +                       break;
> +               case USB_DT_CONFIG:
> +                       srcptr = &config;
> +                       srclen = sizeof(config) +
> +                               sizeof (struct usb_interface_descriptor) +
> +                               sizeof (struct usb_hub_descriptor);
> +                       break;
> +               case USB_DT_STRING:
> +                       switch (le16_to_cpu (req->value) & 0xff) {
> +                       case 0: /* Language */
> +                               srcptr = "\4\3\1\0";
> +                               srclen = 4;
> +                               break;
> +                       case 1: /* Vendor */
> +                               srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
> +                               srclen = 14;
> +                               break;
> +                       case 2: /* Product */
> +                               srcptr = "\52\3E\0H\0C\0I\0 "
> +                                        "\0H\0o\0s\0t\0 "
> +                                        "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
> +                               srclen = 42;
> +                               break;
> +                       default:
> +                               goto unknown;
> +                       }
> +                       break;
> +               default:
> +                       debug ("unknown value %x", le16_to_cpu (req->value));
> +                       goto unknown;
> +               }
> +               break;
> +       case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
> +               switch (le16_to_cpu (req->value) >> 8) {
> +               case USB_DT_HUB:
> +                       srcptr = &hub;
> +                       srclen = sizeof(hub);
> +                       break;
> +               default:
> +                       debug ("unknown value %x", le16_to_cpu (req->value));
> +                       goto unknown;
> +               }
> +               break;
> +       case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
> +               rootdev = le16_to_cpu (req->value);
> +               break;
> +       case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
> +               /* Nothing to do */
> +               break;
> +       case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
> +               tmpbuf[0] = 1;  /* USB_STATUS_SELFPOWERED */
> +               tmpbuf[1] = 0;
> +               srcptr = tmpbuf;
> +               srclen = 2;
> +               break;
> +       case DeviceRequest | USB_REQ_GET_STATUS:
> +               memset (tmpbuf, 0, 4);
> +               reg = le32_to_cpu (hcor->or_portsc[le16_to_cpu(req->index)
> +                                  - 1]);
> +               if (reg & EHCI_PS_CS)
> +                       tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
> +               if (reg & EHCI_PS_PE)
> +                       tmpbuf[0] |= USB_PORT_STAT_ENABLE;
> +               if (reg & EHCI_PS_SUSP)
> +                       tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
> +               if (reg & EHCI_PS_OCA)
> +                       tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
> +               if (reg & EHCI_PS_PR)
> +                       tmpbuf[0] |= USB_PORT_STAT_RESET;
> +               if (reg & EHCI_PS_PP)
> +                       tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
> +               tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
> +
> +               if (reg & EHCI_PS_CSC)
> +                       tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
> +               if (reg & EHCI_PS_PEC)
> +                       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)))
> +                       tmpbuf[2] |= USB_PORT_STAT_C_RESET;
> +               srcptr = tmpbuf;
> +               srclen = 4;
> +               break;
> +       case DeviceOutRequest | USB_REQ_SET_FEATURE:
> +               reg = le32_to_cpu (hcor->or_portsc[le16_to_cpu (req->index) - 1]);
> +               reg &= ~EHCI_PS_CLEAR;
> +               switch (le16_to_cpu (req->value)) {
> +               case USB_PORT_FEAT_POWER:
> +                       reg |= EHCI_PS_PP;
> +                       break;
> +               case USB_PORT_FEAT_RESET:
> +                       if (EHCI_PS_IS_LOWSPEED (reg)) {
> +                               /* Low speed device, give up ownership. */
> +                               reg |= EHCI_PS_PO;
> +                               break;
> +                       }
> +                       /* Start reset sequence. */
> +                       reg &= ~EHCI_PS_PE;
> +                       reg |= EHCI_PS_PR;
> +                       hcor->or_portsc[le16_to_cpu (req->index) - 1] =
> +                           cpu_to_le32 (reg);
> +                       /* Wait for reset to complete. */
> +                       udelay (500000);
> +                       /* Terminate reset sequence. */
> +                       reg &= ~EHCI_PS_PR;
> +                       /* TODO: is it only fsl chip that requires this
> +                        * manual setting of port enable?
> +                        */
> +                       reg |= EHCI_PS_PE;
> +                       hcor->or_portsc[le16_to_cpu (req->index) - 1] =
> +                           cpu_to_le32 (reg);
> +                       /* Wait for HC to complete reset. */
> +                       udelay (2000);
> +                       reg =
> +                           le32_to_cpu (hcor->or_portsc[le16_to_cpu (req->index) - 1]);
> +                       reg &= ~EHCI_PS_CLEAR;
> +                       if ((reg & EHCI_PS_PE) == 0) {
> +                               /* Not a high speed device, give up ownership. */
> +                               reg |= EHCI_PS_PO;
> +                               break;
> +                       }
> +                       portreset |= 1 << le16_to_cpu (req->index);
> +                       break;
> +               default:
> +                       debug ("unknown feature %x", le16_to_cpu (req->value));
> +                       goto unknown;
> +               }
> +               hcor->or_portsc[le16_to_cpu (req->index) - 1] = cpu_to_le32 (reg);
> +               break;
> +       case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
> +               reg = le32_to_cpu (hcor->or_portsc[le16_to_cpu (req->index) - 1]);
> +               reg &= ~EHCI_PS_CLEAR;
> +               switch (le16_to_cpu (req->value)) {
> +               case USB_PORT_FEAT_ENABLE:
> +                       reg &= ~EHCI_PS_PE;
> +                       break;
> +               case USB_PORT_FEAT_C_CONNECTION:
> +                       reg |= EHCI_PS_CSC;
> +                       break;
> +               case USB_PORT_FEAT_C_RESET:
> +                       portreset &= ~(1 << le16_to_cpu (req->index));
> +                       break;
> +               default:
> +                       debug ("unknown feature %x", le16_to_cpu (req->value));
> +                       goto unknown;
> +               }
> +               hcor->or_portsc[le16_to_cpu (req->index) - 1] = cpu_to_le32 (reg);
> +               break;
> +       default:
> +               debug ("Unknown request %x",
> +                      C (req->request, req->requesttype));
> +               goto unknown;
> +       }
> +
> +       len = min3 (srclen, le16_to_cpu (req->length), length);
> +       if (srcptr != NULL && len > 0)
> +               memcpy (buffer, srcptr, len);
> +       dev->act_len = len;
> +       dev->status = 0;
> +       return (0);
> +
> +      unknown:
> +       debug ("requesttype=%x, request=%x, value=%x, index=%x, length=%x",
> +              req->requesttype, req->request, le16_to_cpu (req->value),
> +              le16_to_cpu (req->index), le16_to_cpu (req->length));
> +
> +       dev->act_len = 0;
> +       dev->status = USB_ST_STALLED;
> +       return (-1);
> +}
> +
> +int usb_lowlevel_stop (void)
> +{
> +       return ehci_hcd_stop ();
> +}
> +
> +int usb_lowlevel_init (void)
> +{
> +       uint32_t reg;
> +
> +       if (ehci_hcd_init () != 0) {
> +               return -1;
> +       }
> +
> +       /* Set head of reclaim list */
> +       memset (&qh_list, 0, sizeof (qh_list));
> +       qh_list.qh_link = cpu_to_le32 ((uint32_t) & qh_list | QH_LINK_TYPE_QH);
> +       qh_list.qh_endpt1 = cpu_to_le32 ((1 << 15) | (USB_SPEED_HIGH << 12));
> +       qh_list.qh_curtd = cpu_to_le32 (QT_NEXT_TERMINATE);
> +       qh_list.qh_overlay.qt_next = cpu_to_le32 (QT_NEXT_TERMINATE);
> +       qh_list.qh_overlay.qt_altnext = cpu_to_le32 (QT_NEXT_TERMINATE);
> +       qh_list.qh_overlay.qt_token = cpu_to_le32 (0x40);
> +
> +       /* Set async. queue head pointer. */
> +       hcor->or_asynclistaddr = cpu_to_le32 ((uint32_t) & qh_list);
> +
> +       reg = le32_to_cpu (hccr->cr_hcsparams);
> +       hub.bNbrPorts = reg & 0xf;
> +       if (reg & 0x10000)      /* Port Indicators */
> +               hub.wHubCharacteristics |= 0x80;
> +       if (reg & 0x10)         /* Port Power Control */
> +               hub.wHubCharacteristics |= 0x01;
> +
> +       /* take control over the ports */
> +       hcor->or_configflag |= cpu_to_le32 (1);
> +
> +       /* Start the host controller. */
> +       hcor->or_usbcmd |= cpu_to_le32 (1);
> +
> +       rootdev = 0;
> +
> +       return 0;
> +}
> +
> +int
> +submit_bulk_msg (struct usb_device *dev, unsigned long pipe, void *buffer,
> +                int length)
> +{
> +
> +       if (usb_pipetype (pipe) != PIPE_BULK) {
> +               debug ("non-bulk pipe (type=%lu)", usb_pipetype (pipe));
> +               return (-1);
> +       }
> +       return (ehci_submit_async (dev, pipe, buffer, length, NULL));
> +}
> +
> +int
> +submit_control_msg (struct usb_device *dev, unsigned long pipe, void *buffer,
> +                   int length, struct devrequest *setup)
> +{
> +
> +       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)
> +                       dev->speed = USB_SPEED_HIGH;
> +               return (ehci_submit_root (dev, pipe, buffer, length, setup));
> +       }
> +       return (ehci_submit_async (dev, pipe, buffer, length, setup));
> +}
> +
> +int
> +submit_int_msg (struct usb_device *dev, unsigned long pipe, void *buffer,
> +               int length, int interval)
> +{
> +
> +       debug ("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d", dev, pipe,
> +              buffer, length, interval);
> +       return (-1);
> +}
> diff --git a/drivers/usb/usb_ehci_core.h b/drivers/usb/usb_ehci_core.h
> new file mode 100644
> index 0000000..39e5c5e
> --- /dev/null
> +++ b/drivers/usb/usb_ehci_core.h
> @@ -0,0 +1,29 @@
> +/*-
> + * Copyright (c) 2007-2008, Juniper Networks, Inc.
> + * Copyright (c) 2008, Excito Elektronik i Skåne AB
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2 of
> + * the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef USB_EHCI_CORE_H
> +#define USB_EHCI_CORE_H
> +
> +extern int rootdev;
> +extern struct ehci_hccr *hccr;
> +extern volatile struct ehci_hcor *hcor;
> +
> +#endif
> diff --git a/include/usb.h b/include/usb.h
> index 9a2e72c..840e657 100644
> --- a/include/usb.h
> +++ b/include/usb.h
> @@ -139,7 +139,7 @@ enum {
>
>  struct usb_device {
>        int devnum;                     /* Device number on USB bus */
> -       int slow;                       /* Slow device? */
> +       int speed;                      /* full/low/high */
>        char mf[32];                    /* manufacturer */
>        char prod[32];                  /* product */
>        char serial[32];                /* serial number */
> @@ -171,6 +171,7 @@ struct usb_device {
>        unsigned long status;
>        int act_len;                    /* transfered bytes */
>        int maxchild;                   /* Number of ports if hub */
> +       int portnr;
>        struct usb_device *parent;
>        struct usb_device *children[USB_MAXCHILDREN];
>  };
> @@ -180,6 +181,7 @@ struct usb_device {
>  */
>
>  #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
> +       defined(CONFIG_USB_EHCI) || \
>        defined(CONFIG_USB_OHCI_NEW) || defined (CONFIG_USB_SL811HS) || \
>        defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_R8A66597_HCD)
>
> @@ -274,7 +276,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate);
>  *  - endpoint number (4 bits)
>  *  - current Data0/1 state (1 bit)
>  *  - direction (1 bit)
> - *  - speed (1 bit)
> + *  - speed (2 bits)
>  *  - max packet size (2 bits: 8, 16, 32 or 64)
>  *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
>  *
> @@ -290,7 +292,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate);
>  *  - device:          bits 8-14
>  *  - endpoint:                bits 15-18
>  *  - Data0/1:         bit 19
> - *  - speed:           bit 26          (0 = Full, 1 = Low Speed)
> + *  - speed:           bits 26-27      (0 = Full, 1 = Low, 2 = High)
>  *  - pipe type:       bits 30-31      (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
>  *
>  * Why? Because it's arbitrary, and whatever encoding we select is really
> @@ -300,8 +302,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate);
>  */
>  /* Create various pipes... */
>  #define create_pipe(dev,endpoint) \
> -               (((dev)->devnum << 8) | (endpoint << 15) | ((dev)->slow << 26) | (dev)->maxpacketsize)
> -#define default_pipe(dev) ((dev)->slow <<26)
> +               (((dev)->devnum << 8) | (endpoint << 15) | ((dev)->speed << 26) | (dev)->maxpacketsize)
> +#define default_pipe(dev) ((dev)->speed << 26)
>
>  #define usb_sndctrlpipe(dev,endpoint)  ((PIPE_CONTROL << 30) | create_pipe(dev,endpoint))
>  #define usb_rcvctrlpipe(dev,endpoint)  ((PIPE_CONTROL << 30) | create_pipe(dev,endpoint) | USB_DIR_IN)
> @@ -333,7 +335,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate);
>  #define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
>  #define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
>  #define usb_pipedata(pipe)     (((pipe) >> 19) & 1)
> -#define usb_pipeslow(pipe)     (((pipe) >> 26) & 1)
> +#define usb_pipespeed(pipe)    (((pipe) >> 26) & 3)
> +#define usb_pipeslow(pipe)     (usb_pipespeed(pipe) == USB_SPEED_LOW)
>  #define usb_pipetype(pipe)     (((pipe) >> 30) & 3)
>  #define usb_pipeisoc(pipe)     (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
>  #define usb_pipeint(pipe)      (usb_pipetype((pipe)) == PIPE_INTERRUPT)
> diff --git a/include/usb_defs.h b/include/usb_defs.h
> index 353019f..8032e57 100644
> --- a/include/usb_defs.h
> +++ b/include/usb_defs.h
> @@ -80,6 +80,12 @@
>  #define USB_DIR_OUT           0
>  #define USB_DIR_IN            0x80
>
> +/* USB device speeds */
> +#define USB_SPEED_FULL         0x0     /* 12Mbps */
> +#define USB_SPEED_LOW          0x1     /* 1.5Mbps */
> +#define USB_SPEED_HIGH         0x2     /* 480Mbps */
> +#define USB_SPEED_RESERVED     0x3
> +
>  /* Descriptor types */
>  #define USB_DT_DEVICE        0x01
>  #define USB_DT_CONFIG        0x02
> @@ -202,6 +208,7 @@
>  #define USB_PORT_FEAT_RESET          4
>  #define USB_PORT_FEAT_POWER          8
>  #define USB_PORT_FEAT_LOWSPEED       9
> +#define USB_PORT_FEAT_HIGHSPEED      10
>  #define USB_PORT_FEAT_C_CONNECTION   16
>  #define USB_PORT_FEAT_C_ENABLE       17
>  #define USB_PORT_FEAT_C_SUSPEND      18
> @@ -216,6 +223,9 @@
>  #define USB_PORT_STAT_RESET         0x0010
>  #define USB_PORT_STAT_POWER         0x0100
>  #define USB_PORT_STAT_LOW_SPEED     0x0200
> +#define USB_PORT_STAT_HIGH_SPEED    0x0400     /* support for EHCI */
> +#define USB_PORT_STAT_SPEED    \
> +       (USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED)
>
>  /* wPortChange bits */
>  #define USB_PORT_STAT_C_CONNECTION  0x0001
> --
> 1.5.6.5
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ehci-uboot-checkpatch.log
Type: application/octet-stream
Size: 33430 bytes
Desc: not available
Url : http://lists.denx.de/pipermail/u-boot/attachments/20081125/b8898ffb/attachment-0001.obj 


More information about the U-Boot mailing list