summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2011-06-13 10:58:13 -0700
committerSimon Glass <sjg@chromium.org>2011-08-29 10:39:24 -0700
commit01d1f9a370e1917b772023a2501acebc72ee6ab5 (patch)
tree3061e9d759ebd93ef99e3276b13c93f26ea75001 /board
parentf8081a7f4eceb454b55d387d7689933acd9f68c5 (diff)
tegra2: Run-time assignment of USB port numbers
USB ports relied on CONFIG_TEGRA2_USBx macros to select the ordering. This change records the order that the ports are configured and uses that to select ports by number. This properly honors CONFIG_TEGRA2_USBx when not using an FDT. Also removed direct access to the USB peripheral address from the Tegra2 EHCI driver. BUG=chromium-os:11623 TEST=usb start; run usb_boot Change-Id: Ib906ec4483bcd95ff9564411f44dc0a2e48fff8c Reviewed-on: http://gerrit.chromium.org/gerrit/2537 Tested-by: Simon Glass <sjg@chromium.org> Reviewed-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Tom Warren <twarren@nvidia.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'board')
-rw-r--r--board/nvidia/common/usb.c107
1 files changed, 99 insertions, 8 deletions
diff --git a/board/nvidia/common/usb.c b/board/nvidia/common/usb.c
index 5f4f345fd1..1838b0f438 100644
--- a/board/nvidia/common/usb.c
+++ b/board/nvidia/common/usb.c
@@ -35,6 +35,18 @@
#include <asm/arch/usb.h>
#include <fdt_decode.h>
+enum {
+ USB_PORTS_MAX = 4, /* Maximum ports we allow */
+};
+
+struct usb_port {
+ struct usb_ctlr *reg;
+};
+
+static struct usb_port port[USB_PORTS_MAX]; /* List of valid USB ports */
+static unsigned port_count; /* Number of available ports */
+static int port_current; /* Current port (-1 = none) */
+
/* Record which controller can switch from host to device mode */
static struct usb_ctlr *host_dev_ctlr;
@@ -276,9 +288,23 @@ static void config_clock(const int params[])
/* TODO: what should we do with stable_time? */
}
-static void config_port(enum periph_id id, struct usb_ctlr *usbctlr,
+/**
+ * Add a new USB port to the list of available ports
+ *
+ * @param id peripheral id of port (PERIPH_ID_USB3, for example)
+ * @param usbctlr register address of controller
+ * @param params timing parameters
+ * @param utmi 1 if it has an external UTMI transceiver
+ * @return 0 if ok, -1 if error (too many ports)
+ */
+static int add_port(enum periph_id id, struct usb_ctlr *usbctlr,
const int params[], int utmi)
{
+ if (port_count == USB_PORTS_MAX) {
+ debug("tegrausb: Cannot register more than %d ports\n",
+ USB_PORTS_MAX);
+ return -1;
+ }
init_usb_controller(id, usbctlr, params);
if (utmi) {
/* Disable ICUSB FS/LS transceiver */
@@ -289,6 +315,72 @@ static void config_port(enum periph_id id, struct usb_ctlr *usbctlr,
bf_writel(STS, 0, &usbctlr->port_sc1);
power_up_port(usbctlr);
}
+ port[port_count++].reg = usbctlr;
+ return 0;
+}
+
+#ifndef CONFIG_OF_CONTROL
+static int probe_port(struct usb_ctlr *usbctlr, const int params[])
+{
+ enum periph_id id;
+ int utmi = 0;
+
+ /*
+ * Get the periph id. Port 1 has an internal transceiver, port 3 is
+ * external
+ */
+ switch ((u32)usbctlr) {
+ case NV_PA_USB1_BASE:
+ id = PERIPH_ID_USBD;
+ break;
+
+ case NV_PA_USB3_BASE:
+ id = PERIPH_ID_USB3;
+ utmi = 1;
+ break;
+
+ default:
+ printf("tegrausb: probe_port: no such port %p\n", usbctlr);
+ return -1;
+ }
+
+ return add_port(id, usbctlr, params, utmi);
+}
+#endif
+
+int tegrausb_start_port(unsigned portnum, u32 *hccr, u32 *hcor)
+{
+ struct usb_ctlr *usbctlr;
+
+ if (portnum >= port_count)
+ return -1;
+ tegrausb_stop_port();
+
+ usbctlr = port[portnum].reg;
+ *hccr = (u32)&usbctlr->cap_length;
+ *hcor = (u32)&usbctlr->usb_cmd;
+ port_current = portnum;
+ return 0;
+}
+
+int tegrausb_stop_port(void)
+{
+ struct usb_ctlr *usbctlr;
+
+ if (port_current == -1)
+ return -1;
+
+ usbctlr = port[port_current].reg;
+
+ /* Stop controller */
+ writel(0, &usbctlr->usb_cmd);
+ udelay(1000);
+
+ /* Initiate controller reset */
+ writel(2, &usbctlr->usb_cmd);
+ udelay(1000);
+ port_current = -1;
+ return 0;
}
int board_usb_init(const void *blob)
@@ -320,8 +412,9 @@ int board_usb_init(const void *blob)
return -1;
host_dev_ctlr = config.reg;
}
- config_port(config.periph_id, config.reg, config.params,
- config.utmi);
+ if (add_port(config.periph_id, config.reg, config.params,
+ config.utmi))
+ return -1;
} while (node);
#else
enum clock_osc_freq freq;
@@ -338,12 +431,10 @@ int board_usb_init(const void *blob)
#ifdef CONFIG_TEGRA2_USB1_HOST
host_dev_ctlr = (struct usb_ctlr *)NV_PA_USB1_BASE;
#endif
- /* Port 1 has an internal transceiver, port 3 is external */
- config_port(PERIPH_ID_USBD, (struct usb_ctlr *)NV_PA_USB1_BASE,
- params, 0);
- config_port(PERIPH_ID_USB3, (struct usb_ctlr *)NV_PA_USB3_BASE,
- params, 1);
+ probe_port((struct usb_ctlr *)CONFIG_TEGRA2_USB0, params);
+ probe_port((struct usb_ctlr *)CONFIG_TEGRA2_USB1, params);
#endif /* CONFIG_OF_CONTROL */
usb_set_host_mode();
+ port_current = -1;
return 0;
}