]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/platforms/powermac/pci.c
Merge branch 'for-rmk' of git://git.marvell.com/orion
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / powermac / pci.c
index 6c93e7c0da152d0678a1ba26c53c809caa65c14d..bcf50d7056e933a6236e3f192390f8035901923e 100644 (file)
@@ -40,8 +40,6 @@
 static int has_uninorth;
 #ifdef CONFIG_PPC64
 static struct pci_controller *u3_agp;
-static struct pci_controller *u4_pcie;
-static struct pci_controller *u3_ht;
 #else
 static int has_second_ohare;
 #endif /* CONFIG_PPC64 */
@@ -779,16 +777,50 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
         */
        hose->first_busno = 0x00;
        hose->last_busno = 0xff;
-       u4_pcie = hose;
+}
+
+static void __init parse_region_decode(struct pci_controller *hose,
+                                      u32 decode)
+{
+       unsigned long base, end, next = -1;
+       int i, cur = -1;
+
+       /* Iterate through all bits. We ignore the last bit as this region is
+        * reserved for the ROM among other niceties
+        */
+       for (i = 0; i < 31; i++) {
+               if ((decode & (0x80000000 >> i)) == 0)
+                       continue;
+               if (i < 16) {
+                       base = 0xf0000000 | (((u32)i) << 24);
+                       end = base + 0x00ffffff;
+               } else {
+                       base = ((u32)i-16) << 28;
+                       end = base + 0x0fffffff;
+               }
+               if (base != next) {
+                       if (++cur >= 3) {
+                               printk(KERN_WARNING "PCI: Too many ranges !\n");
+                               break;
+                       }
+                       hose->mem_resources[cur].flags = IORESOURCE_MEM;
+                       hose->mem_resources[cur].name = hose->dn->full_name;
+                       hose->mem_resources[cur].start = base;
+                       hose->mem_resources[cur].end = end;
+                       DBG("  %d: 0x%08lx-0x%08lx\n", cur, base, end);
+               } else {
+                       DBG("   :           -0x%08lx\n", end);
+                       hose->mem_resources[cur].end = end;
+               }
+               next = end + 1;
+       }
 }
 
 static void __init setup_u3_ht(struct pci_controller* hose)
 {
        struct device_node *np = hose->dn;
-       struct pci_controller *other = NULL;
        struct resource cfg_res, self_res;
-       int i, cur;
-
+       u32 decode;
 
        hose->ops = &u3_ht_pci_ops;
 
@@ -808,12 +840,9 @@ static void __init setup_u3_ht(struct pci_controller* hose)
                                 self_res.end - self_res.start + 1);
 
        /*
-        * /ht node doesn't expose a "ranges" property, so we "remove"
-        * regions that have been allocated to AGP. So far, this version of
-        * the code doesn't assign any of the 0xfxxxxxxx "fine" memory regions
-        * to /ht. We need to fix that sooner or later by either parsing all
-        * child "ranges" properties or figuring out the U3 address space
-        * decoding logic and then read its configuration register (if any).
+        * /ht node doesn't expose a "ranges" property, we read the register
+        * that controls the decoding logic and use that for memory regions.
+        * The IO region is hard coded since it is fixed in HW as well.
         */
        hose->io_base_phys = 0xf4000000;
        hose->pci_io_size = 0x00400000;
@@ -824,76 +853,33 @@ static void __init setup_u3_ht(struct pci_controller* hose)
        hose->pci_mem_offset = 0;
        hose->first_busno = 0;
        hose->last_busno = 0xef;
-       hose->mem_resources[0].name = np->full_name;
-       hose->mem_resources[0].start = 0x80000000;
-       hose->mem_resources[0].end = 0xefffffff;
-       hose->mem_resources[0].flags = IORESOURCE_MEM;
-
-       u3_ht = hose;
-
-       if (u3_agp != NULL)
-               other = u3_agp;
-       else if (u4_pcie != NULL)
-               other = u4_pcie;
 
-       if (other == NULL) {
-               DBG("U3/4 has no AGP/PCIE, using full resource range\n");
-               return;
-       }
+       /* Note: fix offset when cfg_addr becomes a void * */
+       decode = in_be32(hose->cfg_addr + 0x80);
 
-       /* Fixup bus range vs. PCIE */
-       if (u4_pcie)
-               hose->last_busno = u4_pcie->first_busno - 1;
+       DBG("PCI: Apple HT bridge decode register: 0x%08x\n", decode);
 
-       /* We "remove" the AGP resources from the resources allocated to HT,
-        * that is we create "holes". However, that code does assumptions
-        * that so far happen to be true (cross fingers...), typically that
-        * resources in the AGP node are properly ordered
+       /* NOTE: The decode register setup is a bit weird... region
+        * 0xf8000000 for example is marked as enabled in there while it's
+        & actually the memory controller registers.
+        * That means that we are incorrectly attributing it to HT.
+        *
+        * In a similar vein, region 0xf4000000 is actually the HT IO space but
+        * also marked as enabled in here and 0xf9000000 is used by some other
+        * internal bits of the northbridge.
+        *
+        * Unfortunately, we can't just mask out those bit as we would end
+        * up with more regions than we can cope (linux can only cope with
+        * 3 memory regions for a PHB at this stage).
+        *
+        * So for now, we just do a little hack. We happen to -know- that
+        * Apple firmware doesn't assign things below 0xfa000000 for that
+        * bridge anyway so we mask out all bits we don't want.
         */
-       cur = 0;
-       for (i=0; i<3; i++) {
-               struct resource *res = &other->mem_resources[i];
-               if (res->flags != IORESOURCE_MEM)
-                       continue;
-               /* We don't care about "fine" resources */
-               if (res->start >= 0xf0000000)
-                       continue;
-               /* Check if it's just a matter of "shrinking" us in one
-                * direction
-                */
-               if (hose->mem_resources[cur].start == res->start) {
-                       DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
-                           cur, hose->mem_resources[cur].start,
-                           res->end + 1);
-                       hose->mem_resources[cur].start = res->end + 1;
-                       continue;
-               }
-               if (hose->mem_resources[cur].end == res->end) {
-                       DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
-                           cur, hose->mem_resources[cur].end,
-                           res->start - 1);
-                       hose->mem_resources[cur].end = res->start - 1;
-                       continue;
-               }
-               /* No, it's not the case, we need a hole */
-               if (cur == 2) {
-                       /* not enough resources for a hole, we drop part
-                        * of the range
-                        */
-                       printk(KERN_WARNING "Running out of resources"
-                              " for /ht host !\n");
-                       hose->mem_resources[cur].end = res->start - 1;
-                       continue;
-               }
-               cur++;
-               DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
-                   cur-1, res->start - 1, cur, res->end + 1);
-               hose->mem_resources[cur].name = np->full_name;
-               hose->mem_resources[cur].flags = IORESOURCE_MEM;
-               hose->mem_resources[cur].start = res->end + 1;
-               hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
-               hose->mem_resources[cur-1].end = res->start - 1;
-       }
+       decode &= 0x003fffff;
+
+       /* Now parse the resulting bits and build resources */
+       parse_region_decode(hose, decode);
 }
 #endif /* CONFIG_PPC64 */
 
@@ -1158,28 +1144,6 @@ void __init pmac_pcibios_after_init(void)
 {
        struct device_node* nd;
 
-#ifdef CONFIG_BLK_DEV_IDE
-       struct pci_dev *dev = NULL;
-
-       /* OF fails to initialize IDE controllers on macs
-        * (and maybe other machines)
-        *
-        * Ideally, this should be moved to the IDE layer, but we need
-        * to check specifically with Andre Hedrick how to do it cleanly
-        * since the common IDE code seem to care about the fact that the
-        * BIOS may have disabled a controller.
-        *
-        * -- BenH
-        */
-       for_each_pci_dev(dev) {
-               if ((dev->class >> 16) != PCI_BASE_CLASS_STORAGE)
-                       continue;
-               if (pci_enable_device(dev))
-                       printk(KERN_WARNING
-                              "pci: Failed to enable %s\n", pci_name(dev));
-       }
-#endif /* CONFIG_BLK_DEV_IDE */
-
        for_each_node_by_name(nd, "firewire") {
                if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") ||
                                   of_device_is_compatible(nd, "pci106b,30") ||