summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c26
-rw-r--r--drivers/usb/host/ehci-tegra.c150
-rw-r--r--drivers/usb/host/ehci-vf.c8
-rw-r--r--drivers/usb/host/usb-uclass.c43
5 files changed, 71 insertions, 158 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 5fd618df87b..97b7f145425 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -76,7 +76,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
break;
default:
printf("ERROR: wrong controller index!!\n");
- break;
+ return -EINVAL;
};
*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1e5a6e2b20c..bf02221c9f0 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1214,6 +1214,7 @@ static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
struct int_queue {
int elementsize;
+ unsigned long pipe;
struct QH *first;
struct QH *current;
struct QH *last;
@@ -1269,7 +1270,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
{
struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
struct int_queue *result = NULL;
- int i;
+ uint32_t i, toggle;
/*
* Interrupt transfers requiring several transactions are not supported
@@ -1309,6 +1310,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
goto fail1;
}
result->elementsize = elementsize;
+ result->pipe = pipe;
result->first = memalign(USB_DMA_MINALIGN,
sizeof(struct QH) * queuesize);
if (!result->first) {
@@ -1326,6 +1328,8 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
memset(result->first, 0, sizeof(struct QH) * queuesize);
memset(result->tds, 0, sizeof(struct qTD) * queuesize);
+ toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
for (i = 0; i < queuesize; i++) {
struct QH *qh = result->first + i;
struct qTD *td = result->tds + i;
@@ -1357,7 +1361,9 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
debug("communication direction is '%s'\n",
usb_pipein(pipe) ? "in" : "out");
- td->qt_token = cpu_to_hc32((elementsize << 16) |
+ td->qt_token = cpu_to_hc32(
+ QT_TOKEN_DT(toggle) |
+ (elementsize << 16) |
((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */
0x80); /* active */
td->qt_buffer[0] =
@@ -1372,6 +1378,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff);
*buf = buffer + i * elementsize;
+ toggle ^= 1;
}
flush_dcache_range((unsigned long)buffer,
@@ -1426,6 +1433,8 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
{
struct QH *cur = queue->current;
struct qTD *cur_td;
+ uint32_t token, toggle;
+ unsigned long pipe = queue->pipe;
/* depleted queue */
if (cur == NULL) {
@@ -1436,12 +1445,15 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
cur_td = &queue->tds[queue->current - queue->first];
invalidate_dcache_range((unsigned long)cur_td,
ALIGN_END_ADDR(struct qTD, cur_td, 1));
- if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) &
- QT_TOKEN_STATUS_ACTIVE) {
- debug("Exit poll_int_queue with no completed intr transfer. token is %x\n",
- hc32_to_cpu(cur_td->qt_token));
+ token = hc32_to_cpu(cur_td->qt_token);
+ if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) {
+ debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token);
return NULL;
}
+
+ toggle = QT_TOKEN_GET_DT(token);
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle);
+
if (!(cur->qh_link & QH_LINK_TERMINATE))
queue->current++;
else
@@ -1452,7 +1464,7 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
queue->elementsize));
debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
- hc32_to_cpu(cur_td->qt_token), cur, queue->first);
+ token, cur, queue->first);
return cur->buffer;
}
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 27705d66271..e2574d7958e 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -35,12 +35,6 @@ DECLARE_GLOBAL_DATA_PTR;
#endif
#endif
-#ifndef CONFIG_DM_USB
-enum {
- USB_PORTS_MAX = 3, /* Maximum ports we allow */
-};
-#endif
-
/* Parameters we need for USB */
enum {
PARAM_DIVN, /* PLL FEEDBACK DIVIDer */
@@ -82,9 +76,6 @@ struct fdt_usb {
unsigned ulpi:1; /* 1 if port has external ULPI transceiver */
unsigned enabled:1; /* 1 to enable, 0 to disable */
unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */
-#ifndef CONFIG_DM_USB
- unsigned initialized:1; /* has this port already been initialized? */
-#endif
enum usb_ctlr_type type;
enum usb_init_type init_type;
enum dr_mode dr_mode; /* dual role mode */
@@ -93,11 +84,6 @@ struct fdt_usb {
struct gpio_desc phy_reset_gpio; /* GPIO to reset ULPI phy */
};
-#ifndef CONFIG_DM_USB
-static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */
-static unsigned port_count; /* Number of available ports */
-#endif
-
/*
* This table has USB timing parameters for each Oscillator frequency we
* support. There are four sets of values:
@@ -173,8 +159,6 @@ static const u8 utmip_elastic_limit = 16;
static const u8 utmip_hs_sync_start_delay = 9;
struct fdt_usb_controller {
- /* TODO(sjg@chromium.org): Remove when we only use driver model */
- int compat;
/* flag to determine whether controller supports hostpc register */
u32 has_hostpc:1;
const unsigned *pll_parameter;
@@ -182,17 +166,14 @@ struct fdt_usb_controller {
static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
{
- .compat = COMPAT_NVIDIA_TEGRA20_USB,
.has_hostpc = 0,
.pll_parameter = (const unsigned *)T20_usb_pll,
},
{
- .compat = COMPAT_NVIDIA_TEGRA30_USB,
.has_hostpc = 1,
.pll_parameter = (const unsigned *)T30_usb_pll,
},
{
- .compat = COMPAT_NVIDIA_TEGRA114_USB,
.has_hostpc = 1,
.pll_parameter = (const unsigned *)T114_usb_pll,
},
@@ -754,12 +735,6 @@ int usb_common_init(struct fdt_usb *config, enum usb_init_type init)
return -1;
}
-#ifndef CONFIG_DM_USB
- /* skip init, if the port is already initialized */
- if (config->initialized && config->init_type == init)
- return 0;
-#endif
-
debug("%d, %d\n", config->utmi, config->ulpi);
if (config->utmi)
ret = init_utmi_usb_controller(config, init);
@@ -796,130 +771,6 @@ static const struct ehci_ops tegra_ehci_ops = {
.powerup_fixup = tegra_ehci_powerup_fixup,
};
-#ifndef CONFIG_DM_USB
-/*
- * process_usb_nodes() - Process a list of USB nodes, adding them to our list
- * of USB ports.
- * @blob: fdt blob
- * @node_list: list of nodes to process (any <=0 are ignored)
- * @count: number of nodes to process
- * @id: controller type (enum usb_ctlr_type)
- *
- * Return: 0 - ok, -1 - error
- */
-static int process_usb_nodes(const void *blob, int node_list[], int count,
- enum usb_ctlr_type id)
-{
- struct fdt_usb config;
- int node, i;
- int clk_done = 0;
-
- port_count = 0;
- for (i = 0; i < count; i++) {
- if (port_count == USB_PORTS_MAX) {
- printf("tegrausb: Cannot register more than %d ports\n",
- USB_PORTS_MAX);
- return -1;
- }
-
- debug("USB %d: ", i);
- node = node_list[i];
- if (!node)
- continue;
- if (fdt_decode_usb(blob, node, &config)) {
- debug("Cannot decode USB node %s\n",
- fdt_get_name(blob, node, NULL));
- return -1;
- }
- if (!clk_done) {
- config_clock(get_pll_timing(
- &fdt_usb_controllers[id]));
- clk_done = 1;
- }
- config.type = id;
- config.initialized = 0;
-
- /* add new USB port to the list of available ports */
- port[port_count++] = config;
- }
-
- return 0;
-}
-
-int usb_process_devicetree(const void *blob)
-{
- int node_list[USB_PORTS_MAX];
- int count, err = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(fdt_usb_controllers); i++) {
- count = fdtdec_find_aliases_for_id(blob, "usb",
- fdt_usb_controllers[i].compat, node_list,
- USB_PORTS_MAX);
- if (count) {
- err = process_usb_nodes(blob, node_list, count, i);
- if (err)
- printf("%s: Error processing USB node!\n",
- __func__);
- return err;
- }
- }
-
- return err;
-}
-
-/**
- * Start up the given port number (ports are numbered from 0 on each board).
- * This returns values for the appropriate hccr and hcor addresses to use for
- * USB EHCI operations.
- *
- * @param index port number to start
- * @param hccr returns start address of EHCI HCCR registers
- * @param hcor returns start address of EHCI HCOR registers
- * @return 0 if ok, -1 on error (generally invalid port number)
- */
-int ehci_hcd_init(int index, enum usb_init_type init,
- struct ehci_hccr **hccr, struct ehci_hcor **hcor)
-{
- struct fdt_usb *config;
- struct usb_ctlr *usbctlr;
- int ret;
-
- if (index >= port_count)
- return -1;
-
- config = &port[index];
- ehci_set_controller_priv(index, config, &tegra_ehci_ops);
-
- ret = usb_common_init(config, init);
- if (ret) {
- printf("tegrausb: Cannot init port %d\n", index);
- return ret;
- }
-
- config->initialized = 1;
-
- usbctlr = config->reg;
- *hccr = (struct ehci_hccr *)&usbctlr->cap_length;
- *hcor = (struct ehci_hcor *)&usbctlr->usb_cmd;
-
- return 0;
-}
-
-/*
- * Bring down the specified USB controller
- */
-int ehci_hcd_stop(int index)
-{
- usb_common_uninit(&port[index]);
-
- port[index].initialized = 0;
-
- return 0;
-}
-#endif /* !CONFIG_DM_USB */
-
-#ifdef CONFIG_DM_USB
static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
{
struct fdt_usb *priv = dev_get_priv(dev);
@@ -987,4 +838,3 @@ U_BOOT_DRIVER(usb_ehci) = {
.priv_auto_alloc_size = sizeof(struct fdt_usb),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
-#endif
diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c
index 54548554df3..98e0fc6ca66 100644
--- a/drivers/usb/host/ehci-vf.c
+++ b/drivers/usb/host/ehci-vf.c
@@ -121,6 +121,11 @@ static void usb_oc_config(int index)
setbits_le32(ctrl, UCTRL_OVER_CUR_DIS);
}
+int __weak board_ehci_hcd_init(int port)
+{
+ return 0;
+}
+
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
@@ -136,6 +141,9 @@ int ehci_hcd_init(int index, enum usb_init_type init,
ehci = (struct usb_ehci *)nc_reg_bases[index];
+ /* Do board specific initialisation */
+ board_ehci_hcd_init(index);
+
usb_power_config(index);
usb_oc_config(index);
usb_internal_phy_clock_gate(index);
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 963464cff94..6e86f4a24a4 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -628,6 +628,49 @@ int usb_scan_device(struct udevice *parent, int port,
return 0;
}
+/*
+ * Detect if a USB device has been plugged or unplugged.
+ */
+int usb_detect_change(void)
+{
+ struct udevice *hub;
+ struct uclass *uc;
+ int change = 0;
+ int ret;
+
+ ret = uclass_get(UCLASS_USB_HUB, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev(hub, uc) {
+ struct usb_device *udev;
+ struct udevice *dev;
+
+ if (!device_active(hub))
+ continue;
+ for (device_find_first_child(hub, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ struct usb_port_status status;
+
+ if (!device_active(dev))
+ continue;
+
+ udev = dev_get_parentdata(dev);
+ if (usb_get_port_status(udev, udev->portnr, &status)
+ < 0)
+ /* USB request failed */
+ continue;
+
+ if (le16_to_cpu(status.wPortChange) &
+ USB_PORT_STAT_C_CONNECTION)
+ change++;
+ }
+ }
+
+ return change;
+}
+
int usb_child_post_bind(struct udevice *dev)
{
struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);