]> git.sur5r.net Git - u-boot/blobdiff - drivers/pci/pci.c
musb: Program extvbus for OMAP3EVM Rev >= E
[u-boot] / drivers / pci / pci.c
index e2b05d89918f099e54f66fc338d21ae9625f2764..cd64a87fc6d9b200ed805ae1e6f5a7e014180435 100644 (file)
@@ -116,6 +116,25 @@ PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02)
 PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff)
 PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
 
+/* Get a virtual address associated with a BAR region */
+void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
+{
+       pci_addr_t pci_bus_addr;
+       u32 bar_response;
+
+       /* read BAR address */
+       pci_read_config_dword(pdev, bar, &bar_response);
+       pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+
+       /*
+        * Pass "0" as the length argument to pci_bus_to_virt.  The arg
+        * isn't actualy used on any platform because u-boot assumes a static
+        * linear mapping.  In the future, this could read the BAR size
+        * and pass that as the size if needed.
+        */
+       return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+}
+
 /*
  *
  */
@@ -146,6 +165,19 @@ struct pci_controller *pci_bus_to_hose (int bus)
        return NULL;
 }
 
+int pci_last_busno(void)
+{
+       struct pci_controller *hose = hose_head;
+
+       if (!hose)
+               return -1;
+
+       while (hose->next)
+               hose = hose->next;
+
+       return hose->last_busno;
+}
+
 #ifndef CONFIG_IXP425
 pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
 {
@@ -218,67 +250,121 @@ pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
  *
  */
 
-pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose,
-                                   phys_addr_t phys_addr,
-                                   unsigned long flags)
+int __pci_hose_phys_to_bus (struct pci_controller *hose,
+                               phys_addr_t phys_addr,
+                               unsigned long flags,
+                               unsigned long skip_mask,
+                               pci_addr_t *ba)
 {
        struct pci_region *res;
        pci_addr_t bus_addr;
        int i;
 
-       if (!hose) {
-               printf ("pci_hose_phys_to_bus: %s\n", "invalid hose");
-               goto Done;
-       }
-
        for (i = 0; i < hose->region_count; i++) {
                res = &hose->regions[i];
 
                if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
                        continue;
 
+               if (res->flags & skip_mask)
+                       continue;
+
                bus_addr = phys_addr - res->phys_start + res->bus_start;
 
                if (bus_addr >= res->bus_start &&
                        bus_addr < res->bus_start + res->size) {
-                       return bus_addr;
+                       *ba = bus_addr;
+                       return 0;
                }
        }
 
-       printf ("pci_hose_phys_to_bus: %s\n", "invalid physical address");
-
-Done:
-       return 0;
+       return 1;
 }
 
-phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
-                                pci_addr_t bus_addr,
-                                unsigned long flags)
+pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose,
+                                   phys_addr_t phys_addr,
+                                   unsigned long flags)
 {
-       struct pci_region *res;
-       int i;
+       pci_addr_t bus_addr = 0;
+       int ret;
 
        if (!hose) {
-               printf ("pci_hose_bus_to_phys: %s\n", "invalid hose");
-               goto Done;
+               puts ("pci_hose_phys_to_bus: invalid hose\n");
+               return bus_addr;
+       }
+
+       /* if PCI_REGION_MEM is set we do a two pass search with preference
+        * on matches that don't have PCI_REGION_SYS_MEMORY set */
+       if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
+               ret = __pci_hose_phys_to_bus(hose, phys_addr,
+                               flags, PCI_REGION_SYS_MEMORY, &bus_addr);
+               if (!ret)
+                       return bus_addr;
        }
 
+       ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
+
+       if (ret)
+               puts ("pci_hose_phys_to_bus: invalid physical address\n");
+
+       return bus_addr;
+}
+
+int __pci_hose_bus_to_phys (struct pci_controller *hose,
+                               pci_addr_t bus_addr,
+                               unsigned long flags,
+                               unsigned long skip_mask,
+                               phys_addr_t *pa)
+{
+       struct pci_region *res;
+       int i;
+
        for (i = 0; i < hose->region_count; i++) {
                res = &hose->regions[i];
 
                if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
                        continue;
 
+               if (res->flags & skip_mask)
+                       continue;
+
                if (bus_addr >= res->bus_start &&
                        bus_addr < res->bus_start + res->size) {
-                       return bus_addr - res->bus_start + res->phys_start;
+                       *pa = (bus_addr - res->bus_start + res->phys_start);
+                       return 0;
                }
        }
 
-       printf ("pci_hose_bus_to_phys: %s\n", "invalid physical address");
+       return 1;
+}
 
-Done:
-       return 0;
+phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
+                                pci_addr_t bus_addr,
+                                unsigned long flags)
+{
+       phys_addr_t phys_addr = 0;
+       int ret;
+
+       if (!hose) {
+               puts ("pci_hose_bus_to_phys: invalid hose\n");
+               return phys_addr;
+       }
+
+       /* if PCI_REGION_MEM is set we do a two pass search with preference
+        * on matches that don't have PCI_REGION_SYS_MEMORY set */
+       if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
+               ret = __pci_hose_bus_to_phys(hose, bus_addr,
+                               flags, PCI_REGION_SYS_MEMORY, &phys_addr);
+               if (!ret)
+                       return phys_addr;
+       }
+
+       ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
+
+       if (ret)
+               puts ("pci_hose_bus_to_phys: invalid physical address\n");
+
+       return phys_addr;
 }
 
 /*
@@ -302,7 +388,7 @@ int pci_hose_config_device(struct pci_controller *hose,
 
        pci_hose_write_config_dword (hose, dev, PCI_COMMAND, 0);
 
-       for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_5; bar += 4) {
+       for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) {
                pci_hose_write_config_dword (hose, dev, bar, 0xffffffff);
                pci_hose_read_config_dword (hose, dev, bar, &bar_response);