#include <asm/pci-direct.h>
#include <asm/fixmap.h>
+#ifdef DBGP_DEBUG
+# define dbgp_printk printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
static struct ehci_caps __iomem *ehci_caps;
static struct ehci_regs __iomem *ehci_regs;
static struct ehci_dbg_port __iomem *ehci_debug;
u32 delay_time, delay;
int loop;
+ dbgp_printk("ehci_reset_port %i\n", port);
/* Reset the usb debug port */
portsc = readl(&ehci_regs->port_status[port - 1]);
portsc &= ~PORT_PE;
for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
delay_time += delay) {
dbgp_mdelay(delay);
-
portsc = readl(&ehci_regs->port_status[port - 1]);
+ if (!(portsc & PORT_RESET))
+ break;
+ }
if (portsc & PORT_RESET) {
/* force reset to complete */
- loop = 2;
+ loop = 100 * 1000;
writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
&ehci_regs->port_status[port - 1]);
do {
+ udelay(1);
portsc = readl(&ehci_regs->port_status[port-1]);
} while ((portsc & PORT_RESET) && (--loop > 0));
}
/* If we've finished resetting, then break out of the loop */
if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
return 0;
- }
return -EBUSY;
}
u32 status;
int ret, reps;
- for (reps = 0; reps < 3; reps++) {
- dbgp_mdelay(100);
+ for (reps = 0; reps < 300; reps++) {
status = readl(&ehci_regs->status);
- if (status & STS_PCD) {
- ret = ehci_reset_port(port);
- if (ret == 0)
- return 0;
- }
+ if (status & STS_PCD)
+ break;
+ dbgp_mdelay(1);
}
+ ret = ehci_reset_port(port);
+ if (ret == 0)
+ return 0;
return -ENOTCONN;
}
-#ifdef DBGP_DEBUG
-# define dbgp_printk early_printk
-#else
-static inline void dbgp_printk(const char *fmt, ...) { }
-#endif
-
typedef void (*set_debug_port_t)(int port);
static void __init default_set_debug_port(int port)
}
}
+/* The code in early_ehci_bios_handoff() is derived from the usb pci
+ * quirk initialization, but altered so as to use the early PCI
+ * routines. */
+#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
+#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
+static void __init early_ehci_bios_handoff(void)
+{
+ u32 hcc_params = readl(&ehci_caps->hcc_params);
+ int offset = (hcc_params >> 8) & 0xff;
+ u32 cap;
+ int msec;
+
+ if (!offset)
+ return;
+
+ cap = read_pci_config(ehci_dev.bus, ehci_dev.slot,
+ ehci_dev.func, offset);
+ dbgp_printk("dbgp: ehci BIOS state %08x\n", cap);
+
+ if ((cap & 0xff) == 1 && (cap & EHCI_USBLEGSUP_BIOS)) {
+ dbgp_printk("dbgp: BIOS handoff\n");
+ write_pci_config_byte(ehci_dev.bus, ehci_dev.slot,
+ ehci_dev.func, offset + 3, 1);
+ }
+
+ /* if boot firmware now owns EHCI, spin till it hands it over. */
+ msec = 1000;
+ while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
+ mdelay(10);
+ msec -= 10;
+ cap = read_pci_config(ehci_dev.bus, ehci_dev.slot,
+ ehci_dev.func, offset);
+ }
+
+ if (cap & EHCI_USBLEGSUP_BIOS) {
+ /* well, possibly buggy BIOS... try to shut it down,
+ * and hope nothing goes too wrong */
+ dbgp_printk("dbgp: BIOS handoff failed: %08x\n", cap);
+ write_pci_config_byte(ehci_dev.bus, ehci_dev.slot,
+ ehci_dev.func, offset + 2, 0);
+ }
+
+ /* just in case, always disable EHCI SMIs */
+ write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+ offset + EHCI_USBLEGCTLSTS, 0);
+}
+
static int __init ehci_setup(void)
{
struct usb_debug_descriptor dbgp_desc;
int port_map_tried;
int playtimes = 3;
+ early_ehci_bios_handoff();
+
try_next_time:
port_map_tried = 0;
return -1;
}
- loop = 100000;
+ loop = 250 * 1000;
/* Reset the EHCI controller */
cmd = readl(&ehci_regs->command);
cmd |= CMD_RESET;
ctrl |= DBGP_OWNER;
ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
writel(ctrl, &ehci_debug->control);
+ udelay(1);
/* Start the ehci running */
cmd = readl(&ehci_regs->command);
loop = 10;
do {
status = readl(&ehci_regs->status);
- } while ((status & STS_HALT) && (--loop > 0));
+ if (!(status & STS_HALT))
+ break;
+ udelay(1);
+ } while (--loop > 0);
if (!loop) {
- dbgp_printk("ehci can be started\n");
+ dbgp_printk("ehci can not be started\n");
return -1;
}
dbgp_printk("ehci started\n");
static void early_dbgp_write(struct console *con, const char *str, u32 n)
{
int chunk, ret;
+ char buf[DBGP_MAX_PACKET];
+ int use_cr = 0;
if (!ehci_debug)
return;
while (n > 0) {
- chunk = n;
- if (chunk > DBGP_MAX_PACKET)
- chunk = DBGP_MAX_PACKET;
+ for (chunk = 0; chunk < DBGP_MAX_PACKET && n > 0;
+ str++, chunk++, n--) {
+ if (!use_cr && *str == '\n') {
+ use_cr = 1;
+ buf[chunk] = '\r';
+ str--;
+ n++;
+ continue;
+ }
+ if (use_cr)
+ use_cr = 0;
+ buf[chunk] = *str;
+ }
ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
- dbgp_endpoint_out, str, chunk);
- str += chunk;
- n -= chunk;
+ dbgp_endpoint_out, buf, chunk);
}
}