#include <usb.h>
#include <asm/io.h>
#include <malloc.h>
+#include <watchdog.h>
+#ifdef CONFIG_USB_KEYBOARD
+#include <stdio_dev.h>
+extern unsigned char new[];
+#endif
#include "ehci.h"
0x29, /* bDescriptorType: hub descriptor */
2, /* bNrPorts -- runtime modified */
0, /* wHubCharacteristics */
- 0xff, /* bPwrOn2PwrGood */
+ 10, /* bPwrOn2PwrGood */
0, /* bHubCntrCurrent */
{}, /* Device removable */
{} /* at most 7 ports! XXX */
{
0x12, /* bLength */
1, /* bDescriptorType: UDESC_DEVICE */
- 0x0002, /* bcdUSB: v2.0 */
+ cpu_to_le16(0x0200), /* bcdUSB: v2.0 */
9, /* bDeviceClass: UDCLASS_HUB */
0, /* bDeviceSubClass: UDSUBCLASS_HUB */
1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */
64, /* bMaxPacketSize: 64 bytes */
0x0000, /* idVendor */
0x0000, /* idProduct */
- 0x0001, /* bcdDevice */
+ cpu_to_le16(0x0100), /* bcdDevice */
1, /* iManufacturer */
2, /* iProduct */
0, /* iSerialNumber */
}
#endif /* CONFIG_EHCI_DCACHE */
+void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+{
+ mdelay(50);
+}
+
+void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+ __attribute__((weak, alias("__ehci_powerup_fixup")));
+
static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
{
uint32_t result;
do {
result = ehci_readl(ptr);
+ udelay(5);
if (result == ~(uint32_t)0)
return -1;
result &= mask;
if (result == done)
return 0;
- udelay(1);
usec--;
} while (usec > 0);
return -1;
int ret = 0;
cmd = ehci_readl(&hcor->or_usbcmd);
- cmd |= CMD_RESET;
+ cmd = (cmd & ~CMD_RUN) | CMD_RESET;
ehci_writel(&hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000);
if (ret < 0) {
return NULL;
}
- memset(p, sz, 0);
+ memset(p, 0, sz);
return p;
}
idx = 0;
while (idx < 5) {
td->qt_buffer[idx] = cpu_to_hc32(addr);
+ td->qt_buffer_hi[idx] = 0;
next = (addr + 4096) & ~4095;
delta = next - addr;
if (delta >= sz)
uint32_t endpt, token, usbsts;
uint32_t c, toggle;
uint32_t cmd;
+ int timeout;
int ret = 0;
debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
(dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
qh->qh_endpt2 = cpu_to_hc32(endpt);
qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
- qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
td = NULL;
tdp = &qh->qh_overlay.qt_next;
/* Wait for TDs to be processed. */
ts = get_timer(0);
vtd = td;
+ timeout = USB_TIMEOUT_MS(pipe);
do {
/* Invalidate dcache */
ehci_invalidate_dcache(&qh_list);
token = hc32_to_cpu(vtd->qt_token);
if (!(token & 0x80))
break;
- } while (get_timer(ts) < CONFIG_SYS_HZ);
+ WATCHDOG_RESET();
+ } while (get_timer(ts) < timeout);
+
+ /* Check that the TD processing happened */
+ if (token & 0x80) {
+ printf("EHCI timed out on TD - token=%#x\n", token);
+ }
/* Disable async schedule. */
cmd = ehci_readl(&hcor->or_usbcmd);
break;
default:
dev->status = USB_ST_CRC_ERR;
+ if ((token & 0x40) == 0x40)
+ dev->status |= USB_ST_STALLED;
break;
}
dev->act_len = length - ((token >> 16) & 0x7fff);
uint32_t reg;
uint32_t *status_reg;
- if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+ if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
printf("The request port(%d) is not configured\n",
le16_to_cpu(req->index) - 1);
return -1;
tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
if (reg & EHCI_PS_OCA)
tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
- if (reg & EHCI_PS_PR &&
- (portreset & (1 << le16_to_cpu(req->index)))) {
- int ret;
- /* force reset to complete */
- reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
- ehci_writel(status_reg, reg);
- ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000);
- if (!ret)
- tmpbuf[0] |= USB_PORT_STAT_RESET;
- else
- printf("port(%d) reset error\n",
- le16_to_cpu(req->index) - 1);
- }
+ if (reg & EHCI_PS_PR)
+ tmpbuf[0] |= USB_PORT_STAT_RESET;
if (reg & EHCI_PS_PP)
tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
ehci_writel(status_reg, reg);
break;
} else {
+ int ret;
+
reg |= EHCI_PS_PR;
reg &= ~EHCI_PS_PE;
ehci_writel(status_reg, reg);
* usb 2.0 specification say 50 ms resets on
* root
*/
- wait_ms(50);
- portreset |= 1 << le16_to_cpu(req->index);
+ ehci_powerup_fixup(status_reg, ®);
+
+ ehci_writel(status_reg, reg & ~EHCI_PS_PR);
+ /*
+ * A host controller must terminate the reset
+ * and stabilize the state of the port within
+ * 2 milliseconds
+ */
+ ret = handshake(status_reg, EHCI_PS_PR, 0,
+ 2 * 1000);
+ if (!ret)
+ portreset |=
+ 1 << le16_to_cpu(req->index);
+ else
+ printf("port(%d) reset error\n",
+ le16_to_cpu(req->index) - 1);
}
break;
default:
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
dev, pipe, buffer, length, interval);
- return -1;
+ return ehci_submit_async(dev, pipe, buffer, length, NULL);
+}
+
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+/*
+ * This function polls for USB keyboard data.
+ */
+void usb_event_poll()
+{
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ int pipe;
+ int maxp;
+
+ /* Get the pointer to USB Keyboard device pointer */
+ dev = stdio_get_by_name("usbkbd");
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ iface = &usb_kbd_dev->config.if_desc[0];
+ ep = &iface->ep_desc[0];
+ pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
+
+ /* Submit a interrupt transfer request */
+ maxp = usb_maxpacket(usb_kbd_dev, pipe);
+ usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
+ maxp > 8 ? 8 : maxp, ep->bInterval);
}
+#endif /* CONFIG_SYS_USB_EVENT_POLL */