EHCI or USB 2.0 transaction translator implementations.
It should work for ISO-OUT transfers, like audio.
+config USB_EHCI_ROOT_HUB_TT
+ bool "Root Hub Transaction Translators (EXPERIMENTAL)"
+ depends on USB_EHCI_HCD && EXPERIMENTAL
+ ---help---
+ Some EHCI chips have vendor-specific extensions to integrate
+ transaction translators, so that no OHCI or UHCI companion
+ controller is needed. It's safe to say "y" even if your
+ controller doesn't support this feature.
+
+ This supports the EHCI implementation from ARC International.
+
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB
/* Capability Registers */
i = HC_VERSION(readl (&ehci->caps->hc_capbase));
temp = scnprintf (next, size,
- "PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
- pci_name(to_pci_dev(hcd->self.controller)),
+ "bus %s device %s\n"
+ "EHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
+ hcd->self.controller->bus->name,
+ hcd->self.controller->bus_id,
i >> 8, i & 0x0ff, ehci->hcd.state);
size -= temp;
next += temp;
spin_unlock_irqrestore (&ehci->lock, flags);
}
+#ifdef CONFIG_PCI
+
/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
* off the controller (maybe it can boot from highspeed USB disks).
*/
return 0;
}
+#endif
+
static int
ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
{
dbg_hcs_params (ehci, "reset");
dbg_hcc_params (ehci, "reset");
+#ifdef CONFIG_PCI
/* EHCI 0.96 and later may have "extended capabilities" */
- temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+ if (hcd->self.controller->bus == &pci_bus_type)
+ temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+ else
+ temp = 0;
while (temp) {
u32 cap;
}
temp = (cap >> 8) & 0xff;
}
+#endif
/* cache this readonly data; minimize PCI reads */
ehci->hcs_params = readl (&ehci->caps->hcs_params);
struct usb_bus *bus;
int retval;
u32 hcc_params;
- u8 tempbyte;
+ u8 sbrn = 0;
init_timer (&ehci->watchdog);
ehci->watchdog.function = ehci_watchdog;
writel (INTR_MASK, &ehci->regs->intr_enable);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
+#ifdef CONFIG_PCI
+ if (hcd->self.controller->bus == &pci_bus_type) {
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(hcd->self.controller);
+
+ /* Serial Bus Release Number is at PCI 0x60 offset */
+ pci_read_config_byte(pdev, 0x60, &sbrn);
+
+ /* help hc dma work well with cachelines */
+ pci_set_mwi (pdev);
+
+ /* chip-specific init */
+ switch (pdev->vendor) {
+ case PCI_VENDOR_ID_ARC:
+ if (pdev->device == PCI_DEVICE_ID_ARC_EHCI)
+ ehci->is_arc_rh_tt = 1;
+ break;
+ }
+
+ }
+#endif
+
/*
* dedicate a qh for the async ring head, since we couldn't unlink
* a 'real' qh without stopping the async schedule [4.8]. use it
#endif
}
- /* help hc dma work well with cachelines */
- pci_set_mwi (to_pci_dev(ehci->hcd.self.controller));
-
/* clear interrupt enables, set irq latency */
temp = readl (&ehci->regs->command) & 0x0fff;
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
writel (FLAG_CF, &ehci->regs->configured_flag);
readl (&ehci->regs->command); /* unblock posted write */
- /* PCI Serial Bus Release Number is at 0x60 offset */
- pci_read_config_byte(to_pci_dev(hcd->self.controller), 0x60, &tempbyte);
temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
ehci_info (ehci,
"USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
- ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
+ ((sbrn & 0xf0)>>4), (sbrn & 0x0f),
temp >> 8, temp & 0xff, DRIVER_VERSION);
/*
/*-------------------------------------------------------------------------*/
-/* EHCI spec says PCI is required. */
+/* EHCI 1.0 doesn't require PCI */
+
+#ifdef CONFIG_PCI
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids [] = { {
#endif
};
+#endif /* PCI */
+
+
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
MODULE_DESCRIPTION (DRIVER_INFO);
/* if reset finished and it's still not enabled -- handoff */
if (!(port_status & PORT_PE)) {
+
+ /* with integrated TT, there's nobody to hand it to! */
+ if (ehci_is_ARC(ehci)) {
+ ehci_dbg (ehci,
+ "Failed to enable port %d on root hub TT\n",
+ index+1);
+ return port_status;
+ }
+
ehci_dbg (ehci, "port %d full speed --> companion\n",
index + 1);
if (!(temp & PORT_OWNER)) {
if (temp & PORT_CONNECT) {
status |= 1 << USB_PORT_FEAT_CONNECTION;
- status |= 1 << USB_PORT_FEAT_HIGHSPEED;
+ // status may be from integrated TT
+ status |= ehci_port_speed(ehci, temp);
}
if (temp & PORT_PE)
status |= 1 << USB_PORT_FEAT_ENABLE;
&ehci->regs->port_status [wIndex]);
break;
case USB_PORT_FEAT_RESET:
- /* line status bits may report this as low speed */
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+ && !ehci_is_ARC(ehci)
&& PORT_USB11 (temp)) {
ehci_dbg (ehci,
"port %d low speed --> companion\n",
/* if async CSPLIT failed, try cleaning out the TT buffer */
} else if (urb->dev->tt && !usb_pipeint (urb->pipe)
&& ((token & QTD_STS_MMF) != 0
- || QTD_CERR(token) == 0)) {
+ || QTD_CERR(token) == 0)
+ && (!ehci_is_ARC(ehci)
+ || urb->dev->tt->hub !=
+ ehci->hcd.self.root_hub)) {
#ifdef DEBUG
struct usb_device *tt = urb->dev->tt->hub;
dev_dbg (&tt->dev,
// when each interface/altsetting is established. Unlink
// any previous qh and cancel its urbs first; endpoints are
// implicitly reset then (data toggle too).
-// That'd mean updating how usbcore talks to HCDs. (2.5?)
+// That'd mean updating how usbcore talks to HCDs. (2.7?)
/*
info2 |= (EHCI_TUNE_MULT_TT << 30);
info2 |= urb->dev->ttport << 23;
- info2 |= urb->dev->tt->hub->devnum << 16;
+
+ /* set the address of the TT; for ARC's integrated
+ * root hub tt, leave it zeroed.
+ */
+ if (!ehci_is_ARC(ehci)
+ || urb->dev->tt->hub != ehci->hcd.self.root_hub)
+ info2 |= urb->dev->tt->hub->devnum << 16;
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */
unsigned long actions;
unsigned stamp;
+ unsigned is_arc_rh_tt:1; /* ARC roothub with TT */
+
/* irq statistics */
#ifdef EHCI_STATS
struct ehci_stats stats;
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
+
+/*
+ * Some EHCI controllers have a Transaction Translator built into the
+ * root hub. This is a non-standard feature. Each controller will need
+ * to add code to the following inline functions, and call them as
+ * needed (mostly in root hub code).
+ */
+
+#define ehci_is_ARC(e) ((e)->is_arc_rh_tt)
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int
+ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+{
+ if (ehci_is_ARC(ehci)) {
+ switch ((portsc>>26)&3) {
+ case 0:
+ return 0;
+ case 1:
+ return (1<<USB_PORT_FEAT_LOWSPEED);
+ case 2:
+ default:
+ return (1<<USB_PORT_FEAT_HIGHSPEED);
+ }
+ }
+ return (1<<USB_PORT_FEAT_HIGHSPEED);
+}
+
+#else
+
+#define ehci_is_ARC(e) (0)
+
+#define ehci_port_speed(ehci, portsc) (1<<USB_PORT_FEAT_HIGHSPEED)
+#endif
+
+/*-------------------------------------------------------------------------*/
+
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb
+#define PCI_VENDOR_ID_ARC 0x192E
+#define PCI_DEVICE_ID_ARC_EHCI 0x0101
+
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_DEVICE_ID_SYMPHONY_101 0x0001