diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-exynos.c | 117 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 46 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 327 | ||||
-rw-r--r-- | drivers/usb/host/ohci.h | 136 | ||||
-rw-r--r-- | drivers/usb/host/usb-uclass.c | 63 | ||||
-rw-r--r-- | drivers/usb/host/xhci-exynos5.c | 108 |
6 files changed, 316 insertions, 481 deletions
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 86cf6312fe..18e9251b64 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -25,14 +25,12 @@ /* Declare global data pointer */ DECLARE_GLOBAL_DATA_PTR; -#ifdef CONFIG_DM_USB struct exynos_ehci_platdata { struct usb_platdata usb_plat; fdt_addr_t hcd_base; fdt_addr_t phy_base; struct gpio_desc vbus_gpio; }; -#endif /** * Contains pointers to register base addresses @@ -42,16 +40,8 @@ struct exynos_ehci { struct ehci_ctrl ctrl; struct exynos_usb_phy *usb; struct ehci_hccr *hcd; -#ifndef CONFIG_DM_USB - struct gpio_desc vbus_gpio; -#endif }; -#ifndef CONFIG_DM_USB -static struct exynos_ehci exynos; -#endif - -#ifdef CONFIG_DM_USB static int ehci_usb_ofdata_to_platdata(struct udevice *dev) { struct exynos_ehci_platdata *plat = dev_get_platdata(dev); @@ -91,55 +81,6 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev) return 0; } -#else -static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos) -{ - fdt_addr_t addr; - unsigned int node; - int depth; - - node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_EHCI); - if (node <= 0) { - debug("EHCI: Can't get device node for ehci\n"); - return -ENODEV; - } - - /* - * Get the base address for EHCI controller from the device node - */ - addr = fdtdec_get_addr(blob, node, "reg"); - if (addr == FDT_ADDR_T_NONE) { - debug("Can't get the EHCI register address\n"); - return -ENXIO; - } - - exynos->hcd = (struct ehci_hccr *)addr; - - /* Vbus gpio */ - gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0, - &exynos->vbus_gpio, GPIOD_IS_OUT); - - depth = 0; - node = fdtdec_next_compatible_subnode(blob, node, - COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth); - if (node <= 0) { - debug("EHCI: Can't get device node for usb-phy controller\n"); - return -ENODEV; - } - - /* - * Get the base address for usbphy from the device node - */ - exynos->usb = (struct exynos_usb_phy *)fdtdec_get_addr(blob, node, - "reg"); - if (exynos->usb == NULL) { - debug("Can't get the usbphy register address\n"); - return -ENXIO; - } - - return 0; -} -#endif static void exynos5_setup_usb_phy(struct exynos_usb_phy *usb) { @@ -270,63 +211,6 @@ static void reset_usb_phy(struct exynos_usb_phy *usb) set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE); } -#ifndef CONFIG_DM_USB -/* - * EHCI-initialization - * Create the appropriate control structures to manage - * a new EHCI host controller. - */ -int ehci_hcd_init(int index, enum usb_init_type init, - struct ehci_hccr **hccr, struct ehci_hcor **hcor) -{ - struct exynos_ehci *ctx = &exynos; - -#ifdef CONFIG_OF_CONTROL - if (exynos_usb_parse_dt(gd->fdt_blob, ctx)) { - debug("Unable to parse device tree for ehci-exynos\n"); - return -ENODEV; - } -#else - ctx->usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy(); - ctx->hcd = (struct ehci_hccr *)samsung_get_base_usb_ehci(); -#endif - -#ifdef CONFIG_OF_CONTROL - /* setup the Vbus gpio here */ - if (dm_gpio_is_valid(&ctx->vbus_gpio)) - dm_gpio_set_value(&ctx->vbus_gpio, 1); -#endif - - setup_usb_phy(ctx->usb); - - board_usb_init(index, init); - - *hccr = ctx->hcd; - *hcor = (struct ehci_hcor *)((uint32_t) *hccr - + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); - - debug("Exynos5-ehci: init hccr %x and hcor %x hc_length %d\n", - (uint32_t)*hccr, (uint32_t)*hcor, - (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); - - return 0; -} - -/* - * Destroy the appropriate control structures corresponding - * the EHCI host controller. - */ -int ehci_hcd_stop(int index) -{ - struct exynos_ehci *ctx = &exynos; - - reset_usb_phy(ctx->usb); - - return 0; -} -#endif - -#ifdef CONFIG_DM_USB static int ehci_usb_probe(struct udevice *dev) { struct exynos_ehci_platdata *plat = dev_get_platdata(dev); @@ -377,4 +261,3 @@ U_BOOT_DRIVER(usb_ehci) = { .platdata_auto_alloc_size = sizeof(struct exynos_ehci_platdata), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; -#endif diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index bd9861dd68..46d01d40e8 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -125,14 +125,7 @@ static struct descriptor { static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev) { #ifdef CONFIG_DM_USB - struct udevice *dev; - - /* Find the USB controller */ - for (dev = udev->dev; - device_get_uclass_id(dev) != UCLASS_USB; - dev = dev->parent) - ; - return dev_get_priv(dev); + return dev_get_priv(usb_get_bus(udev->dev)); #else return udev->controller; #endif @@ -310,23 +303,33 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *udev, * in the tree before that one! */ #ifdef CONFIG_DM_USB + /* + * When called from usb-uclass.c: usb_scan_device() udev->dev points + * to the parent udevice, not the actual udevice belonging to the + * udev as the device is not instantiated yet. So when searching + * for the first usb-2 parent start with udev->dev not + * udev->dev->parent . + */ struct udevice *parent; + struct usb_device *uparent; + + ttdev = udev; + parent = udev->dev; + uparent = dev_get_parentdata(parent); - for (ttdev = udev; ; ) { - struct udevice *dev = ttdev->dev; + while (uparent->speed != USB_SPEED_HIGH) { + struct udevice *dev = parent; - if (dev->parent && - device_get_uclass_id(dev->parent) == UCLASS_USB_HUB) - parent = dev->parent; - else - parent = NULL; - if (!parent) + if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) { + printf("ehci: Error cannot find high speed parent of usb-1 device\n"); return; - ttdev = dev_get_parentdata(parent); - if (!ttdev->speed != USB_SPEED_HIGH) - break; + } + + ttdev = dev_get_parentdata(dev); + parent = dev->parent; + uparent = dev_get_parentdata(parent); } - parent_devnum = ttdev->devnum; + parent_devnum = uparent->devnum; #else ttdev = udev; while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH) @@ -1576,12 +1579,15 @@ int ehci_register(struct udevice *dev, struct ehci_hccr *hccr, struct ehci_hcor *hcor, const struct ehci_ops *ops, uint tweaks, enum usb_init_type init) { + struct usb_bus_priv *priv = dev_get_uclass_priv(dev); struct ehci_ctrl *ctrl = dev_get_priv(dev); int ret; debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__, dev->name, ctrl, hccr, hcor, init); + priv->desc_before_addr = true; + ehci_setup_ops(ctrl, ops); ctrl->hccr = hccr; ctrl->hcor = hcor; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 97a7edeb53..494b760761 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -103,16 +103,91 @@ static struct pci_device_id ehci_pci_ids[] = { # define m32_swap(x) cpu_to_le32(x) #endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */ +#ifdef CONFIG_DM_USB +/* + * We really should do proper cache flushing everywhere, but for now we only + * do it for new (driver-model) usb code to avoid regressions. + */ +#define flush_dcache_buffer(addr, size) \ + flush_dcache_range((unsigned long)(addr), \ + ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN)) +#define invalidate_dcache_buffer(addr, size) \ + invalidate_dcache_range((unsigned long)(addr), \ + ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN)) +#else +#define flush_dcache_buffer(addr, size) +#define invalidate_dcache_buffer(addr, size) +#endif + +/* Do not use sizeof(ed / td) as our ed / td structs contain extra members */ +#define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16) +#define flush_dcache_td(addr) flush_dcache_buffer(addr, 16) +#define flush_dcache_iso_td(addr) flush_dcache_buffer(addr, 32) +#define flush_dcache_hcca(addr) flush_dcache_buffer(addr, 256) +#define invalidate_dcache_ed(addr) invalidate_dcache_buffer(addr, 16) +#define invalidate_dcache_td(addr) invalidate_dcache_buffer(addr, 16) +#define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32) +#define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256) + /* global ohci_t */ static ohci_t gohci; /* this must be aligned to a 256 byte boundary */ struct ohci_hcca ghcca[1]; -/* a pointer to the aligned storage */ -struct ohci_hcca *phcca; -/* this allocates EDs for all possible endpoints */ -struct ohci_device ohci_dev; -/* device which was disconnected */ -struct usb_device *devgone; + +/* mapping of the OHCI CC status to error codes */ +static int cc_to_error[16] = { + /* No Error */ 0, + /* CRC Error */ USB_ST_CRC_ERR, + /* Bit Stuff */ USB_ST_BIT_ERR, + /* Data Togg */ USB_ST_CRC_ERR, + /* Stall */ USB_ST_STALLED, + /* DevNotResp */ -1, + /* PIDCheck */ USB_ST_BIT_ERR, + /* UnExpPID */ USB_ST_BIT_ERR, + /* DataOver */ USB_ST_BUF_ERR, + /* DataUnder */ USB_ST_BUF_ERR, + /* reservd */ -1, + /* reservd */ -1, + /* BufferOver */ USB_ST_BUF_ERR, + /* BuffUnder */ USB_ST_BUF_ERR, + /* Not Access */ -1, + /* Not Access */ -1 +}; + +static const char *cc_to_string[16] = { + "No Error", + "CRC: Last data packet from endpoint contained a CRC error.", + "BITSTUFFING: Last data packet from endpoint contained a bit " \ + "stuffing violation", + "DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \ + "that did not match the expected value.", + "STALL: TD was moved to the Done Queue because the endpoint returned" \ + " a STALL PID", + "DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \ + "not provide a handshake (OUT)", + "PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\ + "(IN) or handshake (OUT)", + "UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \ + "value is not defined.", + "DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \ + "either the size of the maximum data packet allowed\n" \ + "from the endpoint (found in MaximumPacketSize field\n" \ + "of ED) or the remaining buffer size.", + "DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \ + "and that amount was not sufficient to fill the\n" \ + "specified buffer", + "reserved1", + "reserved2", + "BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \ + "than it could be written to system memory", + "BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \ + "system memory fast enough to keep up with data USB " \ + "data rate.", + "NOT ACCESSED: This code is set by software before the TD is placed" \ + "on a list to be processed by the HC.(1)", + "NOT ACCESSED: This code is set by software before the TD is placed" \ + "on a list to be processed by the HC.(2)", +}; static inline u32 roothub_a(struct ohci *hc) { return ohci_readl(&hc->regs->roothub.a); } @@ -124,11 +199,42 @@ static inline u32 roothub_portstatus(struct ohci *hc, int i) { return ohci_readl(&hc->regs->roothub.portstatus[i]); } /* forward declaration */ -static int hc_interrupt(void); -static void td_submit_job(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, +static int hc_interrupt(ohci_t *ohci); +static void td_submit_job(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval); +static int ep_link(ohci_t * ohci, ed_t * ed); +static int ep_unlink(ohci_t * ohci, ed_t * ed); +static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev, + unsigned long pipe, int interval, int load); + +/*-------------------------------------------------------------------------*/ + +/* TDs ... */ +static struct td *td_alloc(ohci_dev_t *ohci_dev, struct usb_device *usb_dev) +{ + int i; + struct td *td; + + td = NULL; + for (i = 0; i < NUM_TD; i++) + { + if (ohci_dev->tds[i].usb_dev == NULL) + { + td = &ohci_dev->tds[i]; + td->usb_dev = usb_dev; + break; + } + } + + return td; +} + +static inline void ed_free(struct ed *ed) +{ + ed->usb_dev = NULL; +} /*-------------------------------------------------------------------------* * URB support functions @@ -158,18 +264,18 @@ static void urb_free_priv(urb_priv_t *urb) /*-------------------------------------------------------------------------*/ #ifdef DEBUG -static int sohci_get_current_frame_number(struct usb_device *dev); +static int sohci_get_current_frame_number(ohci_t *ohci); /* debug| print the main components of an URB * small: 0) header + data packets 1) just header */ -static void pkt_print(urb_priv_t *purb, struct usb_device *dev, +static void pkt_print(ohci_t *ohci, urb_priv_t *purb, struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup, char *str, int small) { dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx", str, - sohci_get_current_frame_number(dev), + sohci_get_current_frame_number(ohci), usb_pipedevice(pipe), usb_pipeendpoint(pipe), usb_pipeout(pipe)? 'O': 'I', @@ -213,9 +319,11 @@ void ep_print_int_eds(ohci_t *ohci, char *str) ed_p = &(ohci->hcca->int_table [i]); if (*ed_p == 0) continue; + invalidate_dcache_ed(ed_p); printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i); while (*ed_p != 0 && j--) { ed_t *ed = (ed_t *)m32_swap(ed_p); + invalidate_dcache_ed(ed); printf(" ed: %4x;", ed->hwINFO); ed_p = &ed->hwNextED; } @@ -246,6 +354,7 @@ static void maybe_print_eds(char *label, __u32 value) if (value) { dbg("%s %08x", label, value); + invalidate_dcache_ed(edp); dbg("%08x", edp->hwINFO); dbg("%08x", edp->hwTailP); dbg("%08x", edp->hwHeadP); @@ -380,6 +489,7 @@ static void ohci_dump(ohci_t *controller, int verbose) ohci_dump_status(controller); if (verbose) ep_print_int_eds(controller, "hcca"); + invalidate_dcache_hcca(controller->hcca); dbg("hcca frame #%04x", controller->hcca->frame_no); ohci_dump_roothub(controller, 1); } @@ -391,9 +501,9 @@ static void ohci_dump(ohci_t *controller, int verbose) /* get a transfer request */ -int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) +int sohci_submit_job(ohci_t *ohci, ohci_dev_t *ohci_dev, urb_priv_t *urb, + struct devrequest *setup) { - ohci_t *ohci; ed_t *ed; urb_priv_t *purb_priv = urb; int i, size = 0; @@ -403,8 +513,6 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) int transfer_len = urb->transfer_buffer_length; int interval = urb->interval; - ohci = &gohci; - /* when controller's hung, permit only roothub cleanup attempts * such as powering down ports */ if (ohci->disabled) { @@ -417,7 +525,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) urb->finished = 0; /* every endpoint has a ed, locate and fill it */ - ed = ep_add_ed(dev, pipe, interval, 1); + ed = ep_add_ed(ohci_dev, dev, pipe, interval, 1); if (!ed) { err("sohci_submit_job: ENOMEM"); return -1; @@ -453,7 +561,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) /* allocate the TDs */ /* note that td[0] was allocated in ep_add_ed */ for (i = 0; i < size; i++) { - purb_priv->td[i] = td_alloc(dev); + purb_priv->td[i] = td_alloc(ohci_dev, dev); if (!purb_priv->td[i]) { purb_priv->length = i; urb_free_priv(purb_priv); @@ -473,7 +581,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) ep_link(ohci, ed); /* fill the TDs and link it to the ed */ - td_submit_job(dev, pipe, buffer, transfer_len, + td_submit_job(ohci, dev, pipe, buffer, transfer_len, setup, purb_priv, interval); return 0; @@ -495,7 +603,7 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb) ohci_readl(®s->intrdisable); /* PCI posting flush */ } urb->actual_length = 0; - td_submit_job( + td_submit_job( hc, urb->dev, urb->pipe, urb->transfer_buffer, @@ -517,11 +625,9 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb) #ifdef DEBUG /* tell us the current USB frame number */ - -static int sohci_get_current_frame_number(struct usb_device *usb_dev) +static int sohci_get_current_frame_number(ohci_t *ohci) { - ohci_t *ohci = &gohci; - + invalidate_dcache_hcca(ohci->hcca); return m16_swap(ohci->hcca->frame_no); } #endif @@ -600,6 +706,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi) switch (ed->type) { case PIPE_CONTROL: ed->hwNextED = 0; + flush_dcache_ed(ed); if (ohci->ed_controltail == NULL) ohci_writel(ed, &ohci->regs->ed_controlhead); else @@ -617,6 +724,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi) case PIPE_BULK: ed->hwNextED = 0; + flush_dcache_ed(ed); if (ohci->ed_bulktail == NULL) ohci_writel(ed, &ohci->regs->ed_bulkhead); else @@ -649,7 +757,9 @@ static int ep_link(ohci_t *ohci, ed_t *edi) inter = ep_rev(6, ((ed_t *)ed_p)->int_interval); ed->hwNextED = *ed_p; + flush_dcache_ed(ed); *ed_p = m32_swap((unsigned long)ed); + flush_dcache_hcca(ohci->hcca); } break; } @@ -662,6 +772,8 @@ static int ep_link(ohci_t *ohci, ed_t *edi) static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed, unsigned index, unsigned period) { + __maybe_unused unsigned long aligned_ed_p; + for (; index < NUM_INTS; index += period) { __u32 *ed_p = &ohci->hcca->int_table [index]; @@ -670,6 +782,12 @@ static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed, if (((struct ed *) m32_swap((unsigned long)ed_p)) == ed) { *ed_p = ed->hwNextED; +#ifdef CONFIG_DM_USB + aligned_ed_p = (unsigned long)ed_p; + aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1); + flush_dcache_range(aligned_ed_p, + aligned_ed_p + ARCH_DMA_MINALIGN); +#endif break; } ed_p = &(((struct ed *) @@ -689,6 +807,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) int i; ed->hwINFO |= m32_swap(OHCI_ED_SKIP); + flush_dcache_ed(ed); switch (ed->type) { case PIPE_CONTROL: @@ -702,6 +821,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) &ohci->regs->ed_controlhead); } else { ed->ed_prev->hwNextED = ed->hwNextED; + flush_dcache_ed(ed->ed_prev); } if (ohci->ed_controltail == ed) { ohci->ed_controltail = ed->ed_prev; @@ -722,6 +842,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) &ohci->regs->ed_bulkhead); } else { ed->ed_prev->hwNextED = ed->hwNextED; + flush_dcache_ed(ed->ed_prev); } if (ohci->ed_bulktail == ed) { ohci->ed_bulktail = ed->ed_prev; @@ -751,14 +872,14 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) * info fields are setted anyway even though most of them should not * change */ -static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe, - int interval, int load) +static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev, + unsigned long pipe, int interval, int load) { td_t *td; ed_t *ed_ret; volatile ed_t *ed; - ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) | + ed = ed_ret = &ohci_dev->ed[(usb_pipeendpoint(pipe) << 1) | (usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))]; if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { @@ -769,12 +890,12 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe, if (ed->state == ED_NEW) { /* dummy td; end of td list for ed */ - td = td_alloc(usb_dev); + td = td_alloc(ohci_dev, usb_dev); ed->hwTailP = m32_swap((unsigned long)td); ed->hwHeadP = ed->hwTailP; ed->state = ED_UNLINK; ed->type = usb_pipetype(pipe); - ohci_dev.ed_cnt++; + ohci_dev->ed_cnt++; } ed->hwINFO = m32_swap(usb_pipedevice(pipe) @@ -790,6 +911,8 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe, ed->int_load = load; } + flush_dcache_ed(ed); + return ed_ret; } @@ -815,6 +938,7 @@ static void td_fill(ohci_t *ohci, unsigned int info, /* use this td as the next dummy */ td_pt = urb_priv->td [index]; td_pt->hwNextTD = 0; + flush_dcache_td(td_pt); /* fill the old dummy TD */ td = urb_priv->td [index] = @@ -842,27 +966,30 @@ static void td_fill(ohci_t *ohci, unsigned int info, td->hwBE = 0; td->hwNextTD = m32_swap((unsigned long)td_pt); + flush_dcache_td(td); /* append to queue */ td->ed->hwTailP = td->hwNextTD; + flush_dcache_ed(td->ed); } /*-------------------------------------------------------------------------*/ /* prepare all TDs of a transfer */ -static void td_submit_job(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, +static void td_submit_job(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval) { - ohci_t *ohci = &gohci; int data_len = transfer_len; void *data; int cnt = 0; __u32 info = 0; unsigned int toggle = 0; + flush_dcache_buffer(buffer, data_len); + /* OHCI handles the DATA-toggles itself, we just use the USB-toggle * bits for reseting */ if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { @@ -902,6 +1029,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe, case PIPE_CONTROL: /* Setup phase */ info = TD_CC | TD_DP_SETUP | TD_T_DATA0; + flush_dcache_buffer(setup, 8); td_fill(ohci, info, setup, 8, dev, cnt++, urb); /* Optional Data phase */ @@ -914,7 +1042,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe, } /* Status phase */ - info = usb_pipeout(pipe)? + info = (usb_pipeout(pipe) || data_len == 0) ? TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; td_fill(ohci, info, data, 0, dev, cnt++, urb); @@ -973,6 +1101,7 @@ static void check_status(td_t *td_list) if (cc) { err(" USB-error: %s (%x)", cc_to_string[cc], cc); + invalidate_dcache_ed(td_list->ed); if (*phwHeadP & m32_swap(0x1)) { if (lurb_priv && ((td_list->index + 1) < urb_len)) { @@ -985,9 +1114,11 @@ static void check_status(td_t *td_list) td_list->index - 1; } else *phwHeadP &= m32_swap(0xfffffff2); + flush_dcache_ed(td_list->ed); } #ifdef CONFIG_MPC5200 td_list->hwNextTD = 0; + flush_dcache_td(td_list); #endif } } @@ -1000,11 +1131,14 @@ static td_t *dl_reverse_done_list(ohci_t *ohci) td_t *td_rev = NULL; td_t *td_list = NULL; + invalidate_dcache_hcca(ohci->hcca); td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0; ohci->hcca->done_head = 0; + flush_dcache_hcca(ohci->hcca); while (td_list_hc) { td_list = (td_t *)td_list_hc; + invalidate_dcache_td(td_list); check_status(td_list); td_list->next_dl_td = td_rev; td_rev = td_list; @@ -1039,6 +1173,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) urb_priv_t *lurb_priv; __u32 tdINFO, edHeadP, edTailP; + invalidate_dcache_td(td_list); tdINFO = m32_swap(td_list->hwINFO); ed = td_list->ed; @@ -1064,6 +1199,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) lurb_priv->td_cnt, lurb_priv->length); if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) { + invalidate_dcache_ed(ed); edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0; edTailP = m32_swap(ed->hwTailP); @@ -1100,16 +1236,16 @@ static int dl_done_list(ohci_t *ohci) #define OK(x) len = (x); break #ifdef DEBUG #define WR_RH_STAT(x) {info("WR:status %#8x", (x)); ohci_writel((x), \ - &gohci.regs->roothub.status); } + &ohci->regs->roothub.status); } #define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, \ - (x)); ohci_writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); } + (x)); ohci_writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); } #else -#define WR_RH_STAT(x) ohci_writel((x), &gohci.regs->roothub.status) +#define WR_RH_STAT(x) ohci_writel((x), &ohci->regs->roothub.status) #define WR_RH_PORTSTAT(x) ohci_writel((x), \ - &gohci.regs->roothub.portstatus[wIndex-1]) + &ohci->regs->roothub.portstatus[wIndex-1]) #endif -#define RD_RH_STAT roothub_status(&gohci) -#define RD_RH_PORTSTAT roothub_portstatus(&gohci, wIndex-1) +#define RD_RH_STAT roothub_status(ohci) +#define RD_RH_PORTSTAT roothub_portstatus(ohci, wIndex-1) /* request to virtual root hub */ @@ -1137,8 +1273,9 @@ int rh_check_port_status(ohci_t *controller) return res; } -static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, struct devrequest *cmd) +static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, + struct devrequest *cmd) { void *data = buffer; int leni = transfer_len; @@ -1151,7 +1288,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, ALLOC_ALIGN_BUFFER(__u8, databuf, 16, sizeof(u32)); #ifdef DEBUG -pkt_print(NULL, dev, pipe, buffer, transfer_len, +pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); #else mdelay(1); @@ -1245,7 +1382,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, break; case RH_SET_ADDRESS: - gohci.rh.devnum = wValue; + ohci->rh.devnum = wValue; OK(0); case RH_GET_DESCRIPTOR: @@ -1290,7 +1427,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, case RH_GET_DESCRIPTOR | RH_CLASS: { - __u32 temp = roothub_a(&gohci); + __u32 temp = roothub_a(ohci); databuf[0] = 9; /* min length; */ databuf[1] = 0x29; @@ -1309,7 +1446,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, databuf[4] = 0; databuf[5] = (temp & RH_A_POTPGT) >> 24; databuf[6] = 0; - temp = roothub_b(&gohci); + temp = roothub_b(ohci); databuf[7] = temp & RH_B_DR; if (databuf[2] < 7) { databuf[8] = 0xff; @@ -1338,7 +1475,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, } #ifdef DEBUG - ohci_dump_roothub(&gohci, 1); + ohci_dump_roothub(ohci, 1); #else mdelay(1); #endif @@ -1350,7 +1487,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, dev->status = stat; #ifdef DEBUG - pkt_print(NULL, dev, pipe, buffer, + pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); #else mdelay(1); @@ -1363,8 +1500,9 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, /* common code for handling submit messages - used for all but root hub */ /* accesses. */ -int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, int interval) +static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, + struct devrequest *setup, int interval) { int stat = 0; int maxsize = usb_maxpacket(dev, pipe); @@ -1380,15 +1518,9 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, urb->transfer_buffer_length = transfer_len; urb->interval = interval; - /* device pulled? Shortcut the action. */ - if (devgone == dev) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - #ifdef DEBUG urb->actual_length = 0; - pkt_print(urb, dev, pipe, buffer, transfer_len, + pkt_print(ohci, urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else mdelay(1); @@ -1399,14 +1531,14 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return -1; } - if (sohci_submit_job(urb, setup) < 0) { + if (sohci_submit_job(ohci, &ohci->ohci_dev, urb, setup) < 0) { err("sohci_submit_job failed"); return -1; } #if 0 mdelay(10); - /* ohci_dump_status(&gohci); */ + /* ohci_dump_status(ohci); */ #endif timeout = USB_TIMEOUT_MS(pipe); @@ -1414,7 +1546,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, /* wait for it to complete */ for (;;) { /* check whether the controller is done */ - stat = hc_interrupt(); + stat = hc_interrupt(ohci); if (stat < 0) { stat = USB_ST_CRC_ERR; break; @@ -1440,7 +1572,8 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, dbg("*"); } else { - err("CTL:TIMEOUT "); + if (!usb_pipeint(pipe)) + err("CTL:TIMEOUT "); dbg("submit_common_msg: TO status %x\n", stat); urb->finished = 1; stat = USB_ST_CRC_ERR; @@ -1451,8 +1584,11 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, dev->status = stat; dev->act_len = urb->actual_length; + if (usb_pipein(pipe) && dev->status == 0 && dev->act_len) + invalidate_dcache_buffer(buffer, dev->act_len); + #ifdef DEBUG - pkt_print(urb, dev, pipe, buffer, transfer_len, + pkt_print(ohci, urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe)); #else mdelay(1); @@ -1469,17 +1605,27 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len) { info("submit_bulk_msg"); - return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0); + return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, + NULL, 0); } -int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup) +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, int interval) +{ + info("submit_int_msg"); + return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, NULL, + interval); +} + +static int _ohci_submit_control_msg(ohci_t *ohci, struct usb_device *dev, + unsigned long pipe, void *buffer, int transfer_len, + struct devrequest *setup) { int maxsize = usb_maxpacket(dev, pipe); info("submit_control_msg"); #ifdef DEBUG - pkt_print(NULL, dev, pipe, buffer, transfer_len, + pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else mdelay(1); @@ -1489,22 +1635,15 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, pipe); return -1; } - if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) { - gohci.rh.dev = dev; + if (((pipe >> 8) & 0x7f) == ohci->rh.devnum) { + ohci->rh.dev = dev; /* root hub - redirect */ - return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len, - setup); + return ohci_submit_rh_msg(ohci, dev, pipe, buffer, + transfer_len, setup); } - return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0); -} - -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, int interval) -{ - info("submit_int_msg"); - return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, - interval); + return submit_common_msg(ohci, dev, pipe, buffer, transfer_len, + setup, 0); } /*-------------------------------------------------------------------------* @@ -1648,13 +1787,14 @@ static int hc_start(ohci_t *ohci) /* an interrupt happens */ -static int hc_interrupt(void) +static int hc_interrupt(ohci_t *ohci) { - ohci_t *ohci = &gohci; struct ohci_regs *regs = ohci->regs; int ints; int stat = -1; + invalidate_dcache_hcca(ohci->hcca); + if ((ohci->hcca->done_head != 0) && !(m32_swap(ohci->hcca->done_head) & 0x01)) { ints = OHCI_INTR_WDH; @@ -1702,7 +1842,7 @@ static int hc_interrupt(void) mdelay(1); ohci_writel(OHCI_INTR_WDH, ®s->intrdisable); (void)ohci_readl(®s->intrdisable); /* flush */ - stat = dl_done_list(&gohci); + stat = dl_done_list(ohci); ohci_writel(OHCI_INTR_WDH, ®s->intrenable); (void)ohci_readl(®s->intrdisable); /* flush */ } @@ -1772,21 +1912,9 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) err("HCCA not aligned!!"); return -1; } - phcca = &ghcca[0]; - info("aligned ghcca %p", phcca); - memset(&ohci_dev, 0, sizeof(struct ohci_device)); - if ((__u32)&ohci_dev.ed[0] & 0x7) { - err("EDs not aligned!!"); - return -1; - } - memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1)); - if ((__u32)gtd & 0x7) { - err("TDs not aligned!!"); - return -1; - } - ptd = gtd; - gohci.hcca = phcca; - memset(phcca, 0, sizeof(struct ohci_hcca)); + gohci.hcca = &ghcca[0]; + info("aligned ghcca %p", gohci.hcca); + memset(gohci.hcca, 0, sizeof(struct ohci_hcca)); gohci.disabled = 1; gohci.sleeping = 0; @@ -1880,3 +2008,10 @@ int usb_lowlevel_stop(int index) ohci_inited = 0; return 0; } + +int submit_control_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, struct devrequest *setup) +{ + return _ohci_submit_control_msg(&gohci, dev, pipe, buffer, + transfer_len, setup); +} diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 9a4a2c2475..f52b4c1bb5 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -18,6 +18,18 @@ # define ohci_writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a)) #endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */ +#if defined CONFIG_DM_USB && ARCH_DMA_MINALIGN > 16 +#define ED_ALIGNMENT ARCH_DMA_MINALIGN +#else +#define ED_ALIGNMENT 16 +#endif + +#if defined CONFIG_DM_USB && ARCH_DMA_MINALIGN > 32 +#define TD_ALIGNMENT ARCH_DMA_MINALIGN +#else +#define TD_ALIGNMENT 32 +#endif + /* functions for doing board or CPU specific setup/cleanup */ int usb_board_stop(void); @@ -25,64 +37,7 @@ int usb_cpu_init(void); int usb_cpu_stop(void); int usb_cpu_init_fail(void); -static int cc_to_error[16] = { - -/* mapping of the OHCI CC status to error codes */ - /* No Error */ 0, - /* CRC Error */ USB_ST_CRC_ERR, - /* Bit Stuff */ USB_ST_BIT_ERR, - /* Data Togg */ USB_ST_CRC_ERR, - /* Stall */ USB_ST_STALLED, - /* DevNotResp */ -1, - /* PIDCheck */ USB_ST_BIT_ERR, - /* UnExpPID */ USB_ST_BIT_ERR, - /* DataOver */ USB_ST_BUF_ERR, - /* DataUnder */ USB_ST_BUF_ERR, - /* reservd */ -1, - /* reservd */ -1, - /* BufferOver */ USB_ST_BUF_ERR, - /* BuffUnder */ USB_ST_BUF_ERR, - /* Not Access */ -1, - /* Not Access */ -1 -}; - -static const char *cc_to_string[16] = { - "No Error", - "CRC: Last data packet from endpoint contained a CRC error.", - "BITSTUFFING: Last data packet from endpoint contained a bit " \ - "stuffing violation", - "DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \ - "that did not match the expected value.", - "STALL: TD was moved to the Done Queue because the endpoint returned" \ - " a STALL PID", - "DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \ - "not provide a handshake (OUT)", - "PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\ - "(IN) or handshake (OUT)", - "UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \ - "value is not defined.", - "DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \ - "either the size of the maximum data packet allowed\n" \ - "from the endpoint (found in MaximumPacketSize field\n" \ - "of ED) or the remaining buffer size.", - "DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \ - "and that amount was not sufficient to fill the\n" \ - "specified buffer", - "reserved1", - "reserved2", - "BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \ - "than it could be written to system memory", - "BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \ - "system memory fast enough to keep up with data USB " \ - "data rate.", - "NOT ACCESSED: This code is set by software before the TD is placed" \ - "on a list to be processed by the HC.(1)", - "NOT ACCESSED: This code is set by software before the TD is placed" \ - "on a list to be processed by the HC.(2)", -}; - /* ED States */ - #define ED_NEW 0x00 #define ED_UNLINK 0x01 #define ED_OPER 0x02 @@ -109,7 +64,7 @@ struct ed { struct usb_device *usb_dev; void *purb; __u32 unused[2]; -} __attribute__((aligned(16))); +} __attribute__((aligned(ED_ALIGNMENT))); typedef struct ed ed_t; @@ -169,7 +124,7 @@ struct td { __u32 data; __u32 unused2[2]; -} __attribute__((aligned(32))); +} __attribute__((aligned(TD_ALIGNMENT))); typedef struct td td_t; #define OHCI_ED_SKIP (1 << 14) @@ -408,6 +363,16 @@ typedef struct } urb_priv_t; #define URB_DEL 1 +#define NUM_EDS 8 /* num of preallocated endpoint descriptors */ + +#define NUM_TD 64 /* we need more TDs than EDs */ + +typedef struct ohci_device { + ed_t ed[NUM_EDS] __aligned(ED_ALIGNMENT); + td_t tds[NUM_TD] __aligned(TD_ALIGNMENT); + int ed_cnt; +} ohci_dev_t; + /* * This is the full ohci controller description * @@ -417,6 +382,8 @@ typedef struct typedef struct ohci { + /* this allocates EDs for all possible endpoints */ + struct ohci_device ohci_dev __aligned(TD_ALIGNMENT); struct ohci_hcca *hcca; /* hcca */ /*dma_addr_t hcca_dma;*/ @@ -438,54 +405,3 @@ typedef struct ohci { const char *slot_name; } ohci_t; - -#define NUM_EDS 8 /* num of preallocated endpoint descriptors */ - -struct ohci_device { - ed_t ed[NUM_EDS]; - int ed_cnt; -}; - -/* hcd */ -/* endpoint */ -static int ep_link(ohci_t * ohci, ed_t * ed); -static int ep_unlink(ohci_t * ohci, ed_t * ed); -static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe, - int interval, int load); - -/*-------------------------------------------------------------------------*/ - -/* we need more TDs than EDs */ -#define NUM_TD 64 - -/* +1 so we can align the storage */ -td_t gtd[NUM_TD+1]; -/* pointers to aligned storage */ -td_t *ptd; - -/* TDs ... */ -static inline struct td * -td_alloc (struct usb_device *usb_dev) -{ - int i; - struct td *td; - - td = NULL; - for (i = 0; i < NUM_TD; i++) - { - if (ptd[i].usb_dev == NULL) - { - td = &ptd[i]; - td->usb_dev = usb_dev; - break; - } - } - - return td; -} - -static inline void -ed_free (struct ed *ed) -{ - ed->usb_dev = NULL; -} diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 714bc0e958..c5ece58407 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -145,9 +145,8 @@ int usb_init(void) uclass_foreach_dev(bus, uc) { /* init low_level USB */ + printf("USB%d: ", count); count++; - printf("USB"); - printf("%d: ", bus->seq); ret = device_probe(bus); if (ret == -ENODEV) { /* No such device. */ puts("Port not available.\n"); @@ -477,9 +476,7 @@ int usb_scan_device(struct udevice *parent, int port, *devp = NULL; memset(udev, '\0', sizeof(*udev)); - ret = usb_get_bus(parent, &udev->controller_dev); - if (ret) - return ret; + udev->controller_dev = usb_get_bus(parent); priv = dev_get_uclass_priv(udev->controller_dev); /* @@ -536,11 +533,7 @@ int usb_scan_device(struct udevice *parent, int port, plat = dev_get_parent_platdata(dev); debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat); plat->devnum = udev->devnum; - plat->speed = udev->speed; - plat->slot_id = udev->slot_id; - plat->portnr = port; - debug("** device '%s': stashing slot_id=%d\n", dev->name, - plat->slot_id); + plat->udev = udev; priv->next_addr++; ret = device_probe(dev); if (ret) { @@ -579,45 +572,55 @@ int usb_child_post_bind(struct udevice *dev) return 0; } -int usb_get_bus(struct udevice *dev, struct udevice **busp) +struct udevice *usb_get_bus(struct udevice *dev) { struct udevice *bus; - *busp = NULL; for (bus = dev; bus && device_get_uclass_id(bus) != UCLASS_USB; ) bus = bus->parent; if (!bus) { /* By design this cannot happen */ assert(bus); debug("USB HUB '%s' does not have a controller\n", dev->name); - return -EXDEV; } - *busp = bus; - return 0; + return bus; } int usb_child_pre_probe(struct udevice *dev) { - struct udevice *bus; struct usb_device *udev = dev_get_parentdata(dev); struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); int ret; - ret = usb_get_bus(dev, &bus); - if (ret) - return ret; - udev->controller_dev = bus; - udev->dev = dev; - udev->devnum = plat->devnum; - udev->slot_id = plat->slot_id; - udev->portnr = plat->portnr; - udev->speed = plat->speed; - debug("** device '%s': getting slot_id=%d\n", dev->name, plat->slot_id); - - ret = usb_select_config(udev); - if (ret) - return ret; + if (plat->udev) { + /* + * Copy over all the values set in the on stack struct + * usb_device in usb_scan_device() to our final struct + * usb_device for this dev. + */ + *udev = *(plat->udev); + /* And clear plat->udev as it will not be valid for long */ + plat->udev = NULL; + udev->dev = dev; + } else { + /* + * This happens with devices which are explicitly bound + * instead of being discovered through usb_scan_device() + * such as sandbox emul devices. + */ + udev->dev = dev; + udev->controller_dev = usb_get_bus(dev); + udev->devnum = plat->devnum; + + /* + * udev did not go through usb_scan_device(), so we need to + * select the config and read the config descriptors. + */ + ret = usb_select_config(udev); + if (ret) + return ret; + } return 0; } diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c index 23c7ecc5d8..a27a79632b 100644 --- a/drivers/usb/host/xhci-exynos5.c +++ b/drivers/usb/host/xhci-exynos5.c @@ -33,36 +33,24 @@ /* Declare global data pointer */ DECLARE_GLOBAL_DATA_PTR; -#ifdef CONFIG_DM_USB struct exynos_xhci_platdata { fdt_addr_t hcd_base; fdt_addr_t phy_base; struct gpio_desc vbus_gpio; }; -#endif /** * Contains pointers to register base addresses * for the usb controller. */ struct exynos_xhci { -#ifdef CONFIG_DM_USB struct usb_platdata usb_plat; -#endif struct xhci_ctrl ctrl; struct exynos_usb3_phy *usb3_phy; struct xhci_hccr *hcd; struct dwc3 *dwc3_reg; -#ifndef CONFIG_DM_USB - struct gpio_desc vbus_gpio; -#endif }; -#ifndef CONFIG_DM_USB -static struct exynos_xhci exynos; -#endif - -#ifdef CONFIG_DM_USB static int xhci_usb_ofdata_to_platdata(struct udevice *dev) { struct exynos_xhci_platdata *plat = dev_get_platdata(dev); @@ -102,54 +90,6 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) return 0; } -#else -static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos) -{ - fdt_addr_t addr; - unsigned int node; - int depth; - - node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI); - if (node <= 0) { - debug("XHCI: Can't get device node for xhci\n"); - return -ENODEV; - } - - /* - * Get the base address for XHCI controller from the device node - */ - addr = fdtdec_get_addr(blob, node, "reg"); - if (addr == FDT_ADDR_T_NONE) { - debug("Can't get the XHCI register base address\n"); - return -ENXIO; - } - exynos->hcd = (struct xhci_hccr *)addr; - - /* Vbus gpio */ - gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0, - &exynos->vbus_gpio, GPIOD_IS_OUT); - - depth = 0; - node = fdtdec_next_compatible_subnode(blob, node, - COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth); - if (node <= 0) { - debug("XHCI: Can't get device node for usb3-phy controller\n"); - return -ENODEV; - } - - /* - * Get the base address for usbphy from the device node - */ - exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node, - "reg"); - if (exynos->usb3_phy == NULL) { - debug("Can't get the usbphy register address\n"); - return -ENXIO; - } - - return 0; -} -#endif static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy) { @@ -340,53 +280,6 @@ static void exynos_xhci_core_exit(struct exynos_xhci *exynos) exynos5_usb3_phy_exit(exynos->usb3_phy); } -#ifndef CONFIG_DM_USB -int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) -{ - struct exynos_xhci *ctx = &exynos; - int ret; - -#ifdef CONFIG_OF_CONTROL - exynos_usb3_parse_dt(gd->fdt_blob, ctx); -#else - ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy(); - ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci(); -#endif - - ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); - -#ifdef CONFIG_OF_CONTROL - /* setup the Vbus gpio here */ - if (dm_gpio_is_valid(&ctx->vbus_gpio)) - dm_gpio_set_value(&ctx->vbus_gpio, 1); -#endif - - ret = exynos_xhci_core_init(ctx); - if (ret) { - puts("XHCI: failed to initialize controller\n"); - return -EINVAL; - } - - *hccr = (ctx->hcd); - *hcor = (struct xhci_hcor *)((uint32_t) *hccr - + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); - - debug("Exynos5-xhci: init hccr %x and hcor %x hc_length %d\n", - (uint32_t)*hccr, (uint32_t)*hcor, - (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); - - return 0; -} - -void xhci_hcd_stop(int index) -{ - struct exynos_xhci *ctx = &exynos; - - exynos_xhci_core_exit(ctx); -} -#endif - -#ifdef CONFIG_DM_USB static int xhci_usb_probe(struct udevice *dev) { struct exynos_xhci_platdata *plat = dev_get_platdata(dev); @@ -443,4 +336,3 @@ U_BOOT_DRIVER(usb_xhci) = { .priv_auto_alloc_size = sizeof(struct exynos_xhci), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; -#endif |