summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/powermac/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powermac/pci.c')
-rw-r--r--arch/powerpc/platforms/powermac/pci.c248
1 files changed, 130 insertions, 118 deletions
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index f852ae3e0ee4..1c58db9d42cb 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -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 */
@@ -314,12 +312,15 @@ static int u3_ht_skip_device(struct pci_controller *hose,
/* We only allow config cycles to devices that are in OF device-tree
* as we are apparently having some weird things going on with some
- * revs of K2 on recent G5s
+ * revs of K2 on recent G5s, except for the host bridge itself, which
+ * is missing from the tree but we know we can probe.
*/
if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
+ else if (devfn == 0)
+ return 0;
else
- busdn = hose->arch_data;
+ busdn = hose->dn;
for (dn = busdn->child; dn; dn = dn->sibling)
if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn)
break;
@@ -344,14 +345,15 @@ static int u3_ht_skip_device(struct pci_controller *hose,
+ (((unsigned int)bus) << 16) \
+ 0x01000000UL)
-static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose,
- u8 bus, u8 devfn, u8 offset)
+static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus,
+ u8 devfn, u8 offset, int *swap)
{
+ *swap = 1;
if (bus == hose->first_busno) {
- /* For now, we don't self probe U3 HT bridge */
- if (PCI_SLOT(devfn) == 0)
- return NULL;
- return hose->cfg_data + U3_HT_CFA0(devfn, offset);
+ if (devfn != 0)
+ return hose->cfg_data + U3_HT_CFA0(devfn, offset);
+ *swap = 0;
+ return ((void __iomem *)hose->cfg_addr) + (offset << 2);
} else
return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset);
}
@@ -360,14 +362,15 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct pci_controller *hose;
- volatile void __iomem *addr;
+ void __iomem *addr;
+ int swap;
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -397,10 +400,10 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
*val = in_8(addr);
break;
case 2:
- *val = in_le16(addr);
+ *val = swap ? in_le16(addr) : in_be16(addr);
break;
default:
- *val = in_le32(addr);
+ *val = swap ? in_le32(addr) : in_be32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -410,14 +413,15 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct pci_controller *hose;
- volatile void __iomem *addr;
+ void __iomem *addr;
+ int swap;
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
if (offset >= 0x100)
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -439,10 +443,10 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
out_8(addr, val);
break;
case 2:
- out_le16(addr, val);
+ swap ? out_le16(addr, val) : out_be16(addr, val);
break;
default:
- out_le32((u32 __iomem *)addr, val);
+ swap ? out_le32(addr, val) : out_be32(addr, val);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -725,7 +729,7 @@ static void __init setup_bandit(struct pci_controller *hose,
static int __init setup_uninorth(struct pci_controller *hose,
struct resource *addr)
{
- pci_assign_all_buses = 1;
+ ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
has_uninorth = 1;
hose->ops = &macrisc_pci_ops;
hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
@@ -773,31 +777,72 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
*/
hose->first_busno = 0x00;
hose->last_busno = 0xff;
- u4_pcie = hose;
}
-static void __init setup_u3_ht(struct pci_controller* hose)
+static void __init parse_region_decode(struct pci_controller *hose,
+ u32 decode)
{
- struct device_node *np = (struct device_node *)hose->arch_data;
- struct pci_controller *other = NULL;
- int i, cur;
+ 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 resource cfg_res, self_res;
+ u32 decode;
hose->ops = &u3_ht_pci_ops;
- /* We hard code the address because of the different size of
- * the reg address cell, we shall fix that by killing struct
- * reg_property and using some accessor functions instead
+ /* Get base addresses from OF tree
*/
- hose->cfg_data = ioremap(0xf2000000, 0x02000000);
+ if (of_address_to_resource(np, 0, &cfg_res) ||
+ of_address_to_resource(np, 1, &self_res)) {
+ printk(KERN_ERR "PCI: Failed to get U3/U4 HT resources !\n");
+ return;
+ }
+
+ /* Map external cfg space access into cfg_data and self registers
+ * into cfg_addr
+ */
+ hose->cfg_data = ioremap(cfg_res.start, 0x02000000);
+ hose->cfg_addr = ioremap(self_res.start,
+ 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;
@@ -808,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 */
@@ -994,6 +996,8 @@ void __init pmac_pci_init(void)
struct device_node *np, *root;
struct device_node *ht = NULL;
+ ppc_pci_flags = PPC_PCI_CAN_SKIP_ISA_ALIGN;
+
root = of_find_node_by_path("/");
if (root == NULL) {
printk(KERN_CRIT "pmac_pci_init: can't find root "
@@ -1032,15 +1036,15 @@ void __init pmac_pci_init(void)
* future though
*/
if (u3_agp) {
- struct device_node *np = u3_agp->arch_data;
+ struct device_node *np = u3_agp->dn;
PCI_DN(np)->busno = 0xf0;
for (np = np->child; np; np = np->sibling)
PCI_DN(np)->busno = 0xf0;
}
/* pmac_check_ht_link(); */
- /* Tell pci.c to not use the common resource allocation mechanism */
- pci_probe_only = 1;
+ /* We can allocate missing resources if any */
+ pci_probe_only = 0;
#else /* CONFIG_PPC64 */
init_p2pbridge();
@@ -1051,13 +1055,13 @@ void __init pmac_pci_init(void)
* some offset between bus number and domains for now when we
* assign all busses should help for now
*/
- if (pci_assign_all_buses)
+ if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_BUS)
pcibios_assign_bus_offset = 0x10;
#endif
}
-int
-pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
+#ifdef CONFIG_PPC32
+int pmac_pci_enable_device_hook(struct pci_dev *dev)
{
struct device_node* node;
int updatecfg = 0;
@@ -1099,24 +1103,21 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
updatecfg = 1;
}
+ /*
+ * Fixup various header fields on 32 bits. We don't do that on
+ * 64 bits as some of these have strange values behind the HT
+ * bridge and we must not, for example, enable MWI or set the
+ * cache line size on them.
+ */
if (updatecfg) {
u16 cmd;
- /*
- * Make sure PCI is correctly configured
- *
- * We use old pci_bios versions of the function since, by
- * default, gmac is not powered up, and so will be absent
- * from the kernel initial PCI lookup.
- *
- * Should be replaced by 2.4 new PCI mechanisms and really
- * register the device.
- */
pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
| PCI_COMMAND_INVALIDATE;
pci_write_config_word(dev, PCI_COMMAND, cmd);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
+
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
L1_CACHE_BYTES >> 2);
}
@@ -1124,6 +1125,18 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
return 0;
}
+void __devinit pmac_pci_fixup_ohci(struct pci_dev *dev)
+{
+ struct device_node *node = pci_device_to_OF_node(dev);
+
+ /* We don't want to assign resources to USB controllers
+ * absent from the OF tree (iBook second controller)
+ */
+ if (dev->class == PCI_CLASS_SERIAL_USB_OHCI && !node)
+ dev->resource[0].flags = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_ANY_ID, pmac_pci_fixup_ohci);
+
/* We power down some devices after they have been probed. They'll
* be powered back on later on
*/
@@ -1171,7 +1184,6 @@ void __init pmac_pcibios_after_init(void)
of_node_put(nd);
}
-#ifdef CONFIG_PPC32
void pmac_pci_fixup_cardbus(struct pci_dev* dev)
{
if (!machine_is(powermac))
@@ -1259,7 +1271,7 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
}
}
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
-#endif
+#endif /* CONFIG_PPC32 */
/*
* Disable second function on K2-SATA, it's broken