From 7c38e90aff5f5b8b7f7ebc27d8d07c51aececde3 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Thu, 13 Dec 2012 22:58:27 -0800 Subject: 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 --- drivers/usb/host/ehci-pci.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'drivers/usb/host/ehci-pci.c') diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 29af02dc5b4..001d141e0d4 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -19,6 +19,7 @@ */ #include +#include #include #include @@ -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; } -- cgit v1.2.3 From ae003d057077d792c1f2131753a7596c94e0bba4 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Tue, 12 Mar 2013 03:45:31 +0000 Subject: usb: Add multiple controllers support for EHCI PCI Use the ability to have several active EHCI controller on a system in the PCI EHCI controller implementation. Signed-off-by: Simon Glass --- drivers/usb/host/ehci-pci.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/usb/host/ehci-pci.c') diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 001d141e0d4..90d7a6feb56 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -34,7 +34,7 @@ static struct pci_device_id ehci_pci_ids[] = { {0, 0} }; #else -static pci_dev_t ehci_find_class(void) +static pci_dev_t ehci_find_class(int index) { int bus; int devnum; @@ -54,7 +54,8 @@ static pci_dev_t ehci_find_class(void) bdf += PCI_BDF(0, 0, 1)) { pci_read_config_dword(bdf, PCI_CLASS_REVISION, &class); - if (class >> 8 == PCI_CLASS_SERIAL_USB_EHCI) + if ((class >> 8 == PCI_CLASS_SERIAL_USB_EHCI) + && !index--) return bdf; } } @@ -68,29 +69,35 @@ static pci_dev_t ehci_find_class(void) * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) +int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr, + struct ehci_hcor **ret_hcor) { pci_dev_t pdev; uint32_t cmd; + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; #ifdef CONFIG_PCI_EHCI_DEVICE pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE); #else - pdev = ehci_find_class(); + pdev = ehci_find_class(index); #endif if (pdev < 0) { printf("EHCI host controller not found\n"); return -1; } - *hccr = (struct ehci_hccr *)pci_map_bar(pdev, + hccr = (struct ehci_hccr *)pci_map_bar(pdev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM); - *hcor = (struct ehci_hcor *)((uint32_t) *hccr + - HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); + hcor = (struct ehci_hcor *)((uint32_t) hccr + + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n", - (uint32_t)*hccr, (uint32_t)*hcor, - (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); + (uint32_t)hccr, (uint32_t)hcor, + (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + + *ret_hccr = hccr; + *ret_hcor = hcor; /* enable busmaster */ pci_read_config_dword(pdev, PCI_COMMAND, &cmd); -- cgit v1.2.3