usb: ehci: generic PCI support

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>
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 29af02d..001d141 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -19,6 +19,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <pci.h>
 #include <usb.h>
 
@@ -32,6 +33,35 @@
 	{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 @@
 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 @@
 			(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;
 }