usb: ehci: generic PCI support
authorVincent Palatin <vpalatin@chromium.org>
Fri, 14 Dec 2012 06:58:27 +0000 (22:58 -0800)
committerMarek Vasut <marex@denx.de>
Sat, 16 Mar 2013 20:12:01 +0000 (21:12 +0100)
Instead of hardcoding the PCI IDs on the USB controller, use the PCI
class to detect them.

Ensure the busmaster bit is properly set in the PCI configuration.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/usb/host/ehci-pci.c

index 29af02dc5b4b9f2eec558b2d75c14e279e2dc044..001d141e0d47a9ae6a5634defadb7d9c4d3a210f 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <pci.h>
 #include <usb.h>
 
@@ -32,6 +33,35 @@ static struct pci_device_id ehci_pci_ids[] = {
        {0x12D8, 0x400F},       /* Pericom */
        {0, 0}
 };
+#else
+static pci_dev_t ehci_find_class(void)
+{
+       int bus;
+       int devnum;
+       pci_dev_t bdf;
+       uint32_t class;
+
+       for (bus = 0; bus <= pci_last_busno(); bus++) {
+               for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) {
+                       pci_read_config_dword(PCI_BDF(bus, devnum, 0),
+                                             PCI_CLASS_REVISION, &class);
+                       if (class >> 16 == 0xffff)
+                               continue;
+
+                       for (bdf = PCI_BDF(bus, devnum, 0);
+                                       bdf <= PCI_BDF(bus, devnum,
+                                               PCI_MAX_PCI_FUNCTIONS - 1);
+                                       bdf += PCI_BDF(0, 0, 1)) {
+                               pci_read_config_dword(bdf, PCI_CLASS_REVISION,
+                                                     &class);
+                               if (class >> 8 == PCI_CLASS_SERIAL_USB_EHCI)
+                                       return bdf;
+                       }
+               }
+       }
+
+       return -ENODEV;
+}
 #endif
 
 /*
@@ -41,9 +71,14 @@ static struct pci_device_id ehci_pci_ids[] = {
 int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
 {
        pci_dev_t pdev;
+       uint32_t cmd;
 
+#ifdef CONFIG_PCI_EHCI_DEVICE
        pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
-       if (pdev == -1) {
+#else
+       pdev = ehci_find_class();
+#endif
+       if (pdev < 0) {
                printf("EHCI host controller not found\n");
                return -1;
        }
@@ -57,6 +92,10 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
                        (uint32_t)*hccr, (uint32_t)*hcor,
                        (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
 
+       /* enable busmaster */
+       pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+       cmd |= PCI_COMMAND_MASTER;
+       pci_write_config_dword(pdev, PCI_COMMAND, cmd);
        return 0;
 }