summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-exynos.c117
-rw-r--r--drivers/usb/host/ehci-hcd.c46
-rw-r--r--drivers/usb/host/ohci-hcd.c327
-rw-r--r--drivers/usb/host/ohci.h136
-rw-r--r--drivers/usb/host/usb-uclass.c63
-rw-r--r--drivers/usb/host/xhci-exynos5.c108
6 files changed, 316 insertions, 481 deletions
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 86cf631..18e9251 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 bd9861d..46d01d4 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 97a7ede..494b760 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(&regs->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, &regs->intrdisable);
(void)ohci_readl(&regs->intrdisable); /* flush */
- stat = dl_done_list(&gohci);
+ stat = dl_done_list(ohci);
ohci_writel(OHCI_INTR_WDH, &regs->intrenable);
(void)ohci_readl(&regs->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 9a4a2c2..f52b4c1 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 714bc0e..c5ece58 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 23c7ecc..a27a796 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