aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/kernel/pci_64.c35
-rw-r--r--arch/powerpc/kernel/prom.c26
-rw-r--r--arch/powerpc/kernel/udbg.c2
-rw-r--r--arch/powerpc/platforms/maple/setup.c4
-rw-r--r--arch/powerpc/platforms/powermac/feature.c65
-rw-r--r--arch/powerpc/platforms/powermac/pci.c210
-rw-r--r--arch/powerpc/platforms/powermac/pic.c72
-rw-r--r--arch/powerpc/platforms/powermac/setup.c13
-rw-r--r--arch/powerpc/platforms/powermac/smp.c319
-rw-r--r--arch/powerpc/sysdev/Makefile2
-rw-r--r--arch/powerpc/sysdev/dart.h41
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c (renamed from arch/powerpc/sysdev/u3_iommu.c)173
-rw-r--r--arch/powerpc/sysdev/mpic.c199
-rw-r--r--drivers/ide/ppc/pmac.c2
-rw-r--r--drivers/macintosh/smu.c8
-rw-r--r--include/asm-powerpc/iommu.h6
-rw-r--r--include/asm-powerpc/mpic.h3
-rw-r--r--include/asm-powerpc/pmac_feature.h2
-rw-r--r--include/linux/pci_regs.h1
20 files changed, 807 insertions, 377 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 773b880d557..5692edb3491 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -300,6 +300,7 @@ config PPC_PMAC64
bool
depends on PPC_PMAC && POWER4
select U3_DART
+ select MPIC_BROKEN_U3
select GENERIC_TBSYNC
default y
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 523f35087e8..f73a16e9867 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -34,7 +34,7 @@
#ifdef DEBUG
#include <asm/udbg.h>
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG(fmt...) printk(fmt)
#else
#define DBG(fmt...)
#endif
@@ -323,6 +323,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
if (!addrs)
return;
+ DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
for (; proplen >= 20; proplen -= 20, addrs += 5) {
flags = pci_parse_of_flags(addrs[0]);
if (!flags)
@@ -332,6 +333,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
if (!size)
continue;
i = addrs[0] & 0xff;
+ DBG(" base: %llx, size: %llx, i: %x\n",
+ (unsigned long long)base, (unsigned long long)size, i);
+
if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
} else if (i == dev->rom_base_reg) {
@@ -362,6 +366,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
if (type == NULL)
type = "";
+ DBG(" create device, devfn: %x, type: %s\n", devfn, type);
+
memset(dev, 0, sizeof(struct pci_dev));
dev->bus = bus;
dev->sysdata = node;
@@ -381,6 +387,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
dev->class = get_int_prop(node, "class-code", 0);
+ DBG(" class: 0x%x\n", dev->class);
+
dev->current_state = 4; /* unknown power state */
if (!strcmp(type, "pci")) {
@@ -402,6 +410,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
pci_parse_of_addrs(node, dev);
+ DBG(" adding to system ...\n");
+
pci_device_add(dev, bus);
/* XXX pci_scan_msi_device(dev); */
@@ -418,15 +428,21 @@ void __devinit of_scan_bus(struct device_node *node,
int reglen, devfn;
struct pci_dev *dev;
+ DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number);
+
while ((child = of_get_next_child(node, child)) != NULL) {
+ DBG(" * %s\n", child->full_name);
reg = (u32 *) get_property(child, "reg", &reglen);
if (reg == NULL || reglen < 20)
continue;
devfn = (reg[0] >> 8) & 0xff;
+
/* create a new pci_dev for this device */
dev = of_create_pci_dev(child, bus, devfn);
if (!dev)
continue;
+ DBG("dev header type: %x\n", dev->hdr_type);
+
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
of_scan_pci_bridge(child, dev);
@@ -446,16 +462,18 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
unsigned int flags;
u64 size;
+ DBG("of_scan_pci_bridge(%s)\n", node->full_name);
+
/* parse bus-range property */
busrange = (u32 *) get_property(node, "bus-range", &len);
if (busrange == NULL || len != 8) {
- printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n",
+ printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
node->full_name);
return;
}
ranges = (u32 *) get_property(node, "ranges", &len);
if (ranges == NULL) {
- printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n",
+ printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
node->full_name);
return;
}
@@ -509,10 +527,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
}
sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
bus->number);
+ DBG(" bus name: %s\n", bus->name);
mode = PCI_PROBE_NORMAL;
if (ppc_md.pci_probe_mode)
mode = ppc_md.pci_probe_mode(bus);
+ DBG(" probe mode: %d\n", mode);
+
if (mode == PCI_PROBE_DEVTREE)
of_scan_bus(node, bus);
else if (mode == PCI_PROBE_NORMAL)
@@ -528,6 +549,8 @@ void __devinit scan_phb(struct pci_controller *hose)
int i, mode;
struct resource *res;
+ DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
+
bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
if (bus == NULL) {
printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
@@ -552,8 +575,9 @@ void __devinit scan_phb(struct pci_controller *hose)
mode = PCI_PROBE_NORMAL;
#ifdef CONFIG_PPC_MULTIPLATFORM
- if (ppc_md.pci_probe_mode)
+ if (node && ppc_md.pci_probe_mode)
mode = ppc_md.pci_probe_mode(bus);
+ DBG(" probe mode: %d\n", mode);
if (mode == PCI_PROBE_DEVTREE) {
bus->subordinate = hose->last_busno;
of_scan_bus(node, bus);
@@ -842,8 +866,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
* Returns a negative error code on failure, zero on success.
*/
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state,
- int write_combine)
+ enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 1b97e13657e..977ee3adaf2 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -298,6 +298,16 @@ static int __devinit finish_node_interrupts(struct device_node *np,
int i, j, n, sense;
unsigned int *irq, virq;
struct device_node *ic;
+ int trace = 0;
+
+ //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0)
+#define TRACE(fmt...)
+
+ if (!strcmp(np->name, "smu-doorbell"))
+ trace = 1;
+
+ TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n",
+ num_interrupt_controllers);
if (num_interrupt_controllers == 0) {
/*
@@ -332,11 +342,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
}
ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+ TRACE("ints=%p, intlen=%d\n", ints, intlen);
if (ints == NULL)
return 0;
intrcells = prom_n_intr_cells(np);
intlen /= intrcells * sizeof(unsigned int);
-
+ TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen);
np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
if (!np->intrs)
return -ENOMEM;
@@ -347,6 +358,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
intrcount = 0;
for (i = 0; i < intlen; ++i, ints += intrcells) {
n = map_interrupt(&irq, &ic, np, ints, intrcells);
+ TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n);
if (n <= 0)
continue;
@@ -357,6 +369,7 @@ static int __devinit finish_node_interrupts(struct device_node *np,
np->intrs[intrcount].sense = map_isa_senses[sense];
} else {
virq = virt_irq_create_mapping(irq[0]);
+ TRACE("virq=%d\n", virq);
#ifdef CONFIG_PPC64
if (virq == NO_IRQ) {
printk(KERN_CRIT "Could not allocate interrupt"
@@ -366,6 +379,12 @@ static int __devinit finish_node_interrupts(struct device_node *np,
#endif
np->intrs[intrcount].line = irq_offset_up(virq);
sense = (n > 1)? (irq[1] & 3): 1;
+
+ /* Apple uses bits in there in a different way, let's
+ * only keep the real sense bit on macs
+ */
+ if (_machine == PLATFORM_POWERMAC)
+ sense &= 0x1;
np->intrs[intrcount].sense = map_mpic_senses[sense];
}
@@ -375,12 +394,13 @@ static int __devinit finish_node_interrupts(struct device_node *np,
char *name = get_property(ic->parent, "name", NULL);
if (name && !strcmp(name, "u3"))
np->intrs[intrcount].line += 128;
- else if (!(name && !strcmp(name, "mac-io")))
+ else if (!(name && (!strcmp(name, "mac-io") ||
+ !strcmp(name, "u4"))))
/* ignore other cascaded controllers, such as
the k2-sata-root */
break;
}
-#endif
+#endif /* CONFIG_PPC64 */
if (n > 2) {
printk("hmmm, got %d intr cells for %s:", n,
np->full_name);
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index a058285a70e..9567d9474c8 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -110,10 +110,12 @@ static int early_console_initialized;
void __init disable_early_printk(void)
{
+#if 1
if (!early_console_initialized)
return;
unregister_console(&udbg_console);
early_console_initialized = 0;
+#endif
}
/* called by setup_system */
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 65fe4c166a6..dd73e38bfb7 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -195,7 +195,7 @@ static void __init maple_init_early(void)
/* Setup interrupt mapping options */
ppc64_interrupt_controller = IC_OPEN_PIC;
- iommu_init_early_u3();
+ iommu_init_early_dart();
DBG(" <- maple_init_early\n");
}
@@ -257,7 +257,7 @@ static int __init maple_probe(int platform)
* occupies having to be broken up so the DART itself is not
* part of the cacheable linar mapping
*/
- alloc_u3_dart_table();
+ alloc_dart_table();
return 1;
}
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index b1f896952b1..d2915d64d45 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -101,7 +101,8 @@ static const char *macio_names[] =
"Keylargo",
"Pangea",
"Intrepid",
- "K2"
+ "K2",
+ "Shasta",
};
@@ -119,7 +120,7 @@ static const char *macio_names[] =
static struct device_node *uninorth_node;
static u32 __iomem *uninorth_base;
static u32 uninorth_rev;
-static int uninorth_u3;
+static int uninorth_maj;
static void __iomem *u3_ht;
/*
@@ -1399,8 +1400,15 @@ static long g5_fw_enable(struct device_node *node, long param, long value)
static long g5_mpic_enable(struct device_node *node, long param, long value)
{
unsigned long flags;
+ struct device_node *parent = of_get_parent(node);
+ int is_u3;
- if (node->parent == NULL || strcmp(node->parent->name, "u3"))
+ if (parent == NULL)
+ return 0;
+ is_u3 = strcmp(parent->name, "u3") == 0 ||
+ strcmp(parent->name, "u4") == 0;
+ of_node_put(parent);
+ if (!is_u3)
return 0;
LOCK(flags);
@@ -1464,7 +1472,7 @@ static long g5_i2s_enable(struct device_node *node, long param, long value)
},
};
- if (macio->type != macio_keylargo2 /* && macio->type != macio_shasta*/)
+ if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
return -ENODEV;
if (strncmp(node->name, "i2s-", 4))
return -ENODEV;
@@ -1473,11 +1481,9 @@ static long g5_i2s_enable(struct device_node *node, long param, long value)
case 0:
case 1:
break;
-#if 0
case 2:
if (macio->type == macio_shasta)
break;
-#endif
default:
return -ENODEV;
}
@@ -1508,7 +1514,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
struct device_node *np;
macio = &macio_chips[0];
- if (macio->type != macio_keylargo2)
+ if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
return -ENODEV;
np = find_path_device("/cpus");
@@ -1547,7 +1553,8 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
*/
void g5_phy_disable_cpu1(void)
{
- UN_OUT(U3_API_PHY_CONFIG_1, 0);
+ if (uninorth_maj == 3)
+ UN_OUT(U3_API_PHY_CONFIG_1, 0);
}
#endif /* CONFIG_POWER4 */
@@ -2462,6 +2469,14 @@ static struct pmac_mb_def pmac_mb_defs[] = {
PMAC_TYPE_POWERMAC_G5_U3L, g5_features,
0,
},
+ { "PowerMac11,2", "PowerMac G5 Dual Core",
+ PMAC_TYPE_POWERMAC_G5_U3L, g5_features,
+ 0,
+ },
+ { "PowerMac12,1", "iMac G5 (iSight)",
+ PMAC_TYPE_POWERMAC_G5_U3L, g5_features,
+ 0,
+ },
{ "RackMac3,1", "XServe G5",
PMAC_TYPE_XSERVE_G5, g5_features,
0,
@@ -2574,6 +2589,11 @@ static int __init probe_motherboard(void)
pmac_mb.model_name = "Unknown K2-based";
pmac_mb.features = g5_features;
break;
+ case macio_shasta:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA;
+ pmac_mb.model_name = "Unknown Shasta-based";
+ pmac_mb.features = g5_features;
+ break;
#endif /* CONFIG_POWER4 */
default:
return -ENODEV;
@@ -2651,7 +2671,12 @@ static void __init probe_uninorth(void)
/* Locate G5 u3 */
if (uninorth_node == NULL) {
uninorth_node = of_find_node_by_name(NULL, "u3");
- uninorth_u3 = 1;
+ uninorth_maj = 3;
+ }
+ /* Locate G5 u4 */
+ if (uninorth_node == NULL) {
+ uninorth_node = of_find_node_by_name(NULL, "u4");
+ uninorth_maj = 4;
}
if (uninorth_node == NULL)
return;
@@ -2664,12 +2689,13 @@ static void __init probe_uninorth(void)
return;
uninorth_base = ioremap(address, 0x40000);
uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
- if (uninorth_u3)
+ if (uninorth_maj == 3 || uninorth_maj == 4)
u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
- printk(KERN_INFO "Found %s memory controller & host bridge,"
- " revision: %d\n", uninorth_u3 ? "U3" : "UniNorth",
- uninorth_rev);
+ printk(KERN_INFO "Found %s memory controller & host bridge"
+ " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :
+ uninorth_maj == 4 ? "U4" : "UniNorth",
+ (unsigned int)address, uninorth_rev);
printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
/* Set the arbitrer QAck delay according to what Apple does
@@ -2677,7 +2703,8 @@ static void __init probe_uninorth(void)
if (uninorth_rev < 0x11) {
actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
- UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+ UNI_N_ARB_CTRL_QACK_DELAY) <<
+ UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
UN_OUT(UNI_N_ARB_CTRL, actrl);
}
@@ -2685,7 +2712,8 @@ static void __init probe_uninorth(void)
* revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
* memory timeout
*/
- if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
+ if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) ||
+ uninorth_rev == 0xc0)
UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
}
@@ -2736,12 +2764,14 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
node->full_name);
return;
}
- if (type == macio_keylargo) {
+ if (type == macio_keylargo || type == macio_keylargo2) {
u32 *did = (u32 *)get_property(node, "device-id", NULL);
if (*did == 0x00000025)
type = macio_pangea;
if (*did == 0x0000003e)
type = macio_intrepid;
+ if (*did == 0x0000004f)
+ type = macio_shasta;
}
macio_chips[i].of_node = node;
macio_chips[i].type = type;
@@ -2840,7 +2870,8 @@ set_initial_features(void)
}
#ifdef CONFIG_POWER4
- if (macio_chips[0].type == macio_keylargo2) {
+ if (macio_chips[0].type == macio_keylargo2 ||
+ macio_chips[0].type == macio_shasta) {
#ifndef CONFIG_SMP
/* On SMP machines running UP, we have the second CPU eating
* bus cycles. We need to take it off the bus. This is done
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 5aab261075d..f671ed25390 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1,7 +1,7 @@
/*
* Support for PCI bridges found on Power Macintoshes.
*
- * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
+ * Copyright (C) 2003-2005 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
* Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
*
* This program is free software; you can redistribute it and/or
@@ -25,7 +25,7 @@
#include <asm/pmac_feature.h>
#include <asm/grackle.h>
#ifdef CONFIG_PPC64
-#include <asm/iommu.h>
+//#include <asm/iommu.h>
#include <asm/ppc-pci.h>
#endif
@@ -44,6 +44,7 @@ static int add_bridge(struct device_node *dev);
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;
#endif /* CONFIG_PPC64 */
@@ -97,11 +98,8 @@ static void __init fixup_bus_range(struct device_node *bridge)
/* Lookup the "bus-range" property for the hose */
bus_range = (int *) get_property(bridge, "bus-range", &len);
- if (bus_range == NULL || len < 2 * sizeof(int)) {
- printk(KERN_WARNING "Can't get bus-range for %s\n",
- bridge->full_name);
+ if (bus_range == NULL || len < 2 * sizeof(int))
return;
- }
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
}
@@ -128,14 +126,14 @@ static void __init fixup_bus_range(struct device_node *bridge)
*/
#define MACRISC_CFA0(devfn, off) \
- ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
- | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
- | (((unsigned long)(off)) & 0xFCUL))
+ ((1 << (unsigned int)PCI_SLOT(dev_fn)) \
+ | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
+ | (((unsigned int)(off)) & 0xFCUL))
#define MACRISC_CFA1(bus, devfn, off) \
- ((((unsigned long)(bus)) << 16) \
- |(((unsigned long)(devfn)) << 8) \
- |(((unsigned long)(off)) & 0xFCUL) \
+ ((((unsigned int)(bus)) << 16) \
+ |(((unsigned int)(devfn)) << 8) \
+ |(((unsigned int)(off)) & 0xFCUL) \
|1UL)
static unsigned long macrisc_cfg_access(struct pci_controller* hose,
@@ -168,7 +166,8 @@ static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
-
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -199,7 +198,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
hose = pci_bus_to_host(bus);
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
-
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -234,12 +234,13 @@ static struct pci_ops macrisc_pci_ops =
/*
* Verify that a specific (bus, dev_fn) exists on chaos
*/
-static int
-chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
+static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
{
struct device_node *np;
u32 *vendor, *device;
+ if (offset >= 0x100)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
np = pci_busdev_to_OF_node(bus, devfn);
if (np == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -341,10 +342,10 @@ static int u3_ht_skip_device(struct pci_controller *hose,
}
#define U3_HT_CFA0(devfn, off) \
- ((((unsigned long)devfn) << 8) | offset)
+ ((((unsigned int)devfn) << 8) | offset)
#define U3_HT_CFA1(bus, devfn, off) \
(U3_HT_CFA0(devfn, off) \
- + (((unsigned long)bus) << 16) \
+ + (((unsigned int)bus) << 16) \
+ 0x01000000UL)
static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
@@ -370,7 +371,8 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
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);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -419,7 +421,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
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);
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -459,6 +462,112 @@ static struct pci_ops u3_ht_pci_ops =
u3_ht_read_config,
u3_ht_write_config
};
+
+#define U4_PCIE_CFA0(devfn, off) \
+ ((1 << ((unsigned int)PCI_SLOT(dev_fn))) \
+ | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
+ | ((((unsigned int)(off)) >> 8) << 28) \
+ | (((unsigned int)(off)) & 0xfcU))
+
+#define U4_PCIE_CFA1(bus, devfn, off) \
+ ((((unsigned int)(bus)) << 16) \
+ |(((unsigned int)(devfn)) << 8) \
+ | ((((unsigned int)(off)) >> 8) << 28) \
+ |(((unsigned int)(off)) & 0xfcU) \
+ |1UL)
+
+static unsigned long u4_pcie_cfg_access(struct pci_controller* hose,
+ u8 bus, u8 dev_fn, int offset)
+{
+ unsigned int caddr;
+
+ if (bus == hose->first_busno) {
+ caddr = U4_PCIE_CFA0(dev_fn, offset);
+ } else
+ caddr = U4_PCIE_CFA1(bus, dev_fn, offset);
+
+ /* Uninorth will return garbage if we don't read back the value ! */
+ do {
+ out_le32(hose->cfg_addr, caddr);
+ } while (in_le32(hose->cfg_addr) != caddr);
+
+ offset &= 0x03;
+ return ((unsigned long)hose->cfg_data) + offset;
+}
+
+static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 *val)
+{
+ struct pci_controller *hose;
+ unsigned long addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset >= 0x1000)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ *val = in_8((u8 *)addr);
+ break;
+ case 2:
+ *val = in_le16((u16 *)addr);
+ break;
+ default:
+ *val = in_le32((u32 *)addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 val)
+{
+ struct pci_controller *hose;
+ unsigned long addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset >= 0x1000)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ out_8((u8 *)addr, val);
+ (void) in_8((u8 *)addr);
+ break;
+ case 2:
+ out_le16((u16 *)addr, val);
+ (void) in_le16((u16 *)addr);
+ break;
+ default:
+ out_le32((u32 *)addr, val);
+ (void) in_le32((u32 *)addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u4_pcie_pci_ops =
+{
+ u4_pcie_read_config,
+ u4_pcie_write_config
+};
+
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC32
@@ -628,15 +737,36 @@ static void __init setup_u3_agp(struct pci_controller* hose)
hose->ops = &macrisc_pci_ops;
hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
-
u3_agp = hose;
}
+static void __init setup_u4_pcie(struct pci_controller* hose)
+{
+ /* We currently only implement the "non-atomic" config space, to
+ * be optimised later.
+ */
+ hose->ops = &u4_pcie_pci_ops;
+ hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+ /* The bus contains a bridge from root -> device, we need to
+ * make it visible on bus 0 so that we pick the right type
+ * of config cycles. If we didn't, we would have to force all
+ * config cycles to be type 1. So we override the "bus-range"
+ * property here
+ */
+ hose->first_busno = 0x00;
+ hose->last_busno = 0xff;
+ u4_pcie = hose;
+}
+
static void __init setup_u3_ht(struct pci_controller* hose)
{
struct device_node *np = (struct device_node *)hose->arch_data;
+ struct pci_controller *other = NULL;
int i, cur;
+
hose->ops = &u3_ht_pci_ops;
/* We hard code the address because of the different size of
@@ -670,11 +800,20 @@ static void __init setup_u3_ht(struct pci_controller* hose)
u3_ht = hose;
- if (u3_agp == NULL) {
- DBG("U3 has no AGP, using full resource range\n");
+ 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;
}
+ /* Fixup bus range vs. PCIE */
+ if (u4_pcie)
+ hose->last_busno = u4_pcie->first_busno - 1;
+
/* 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
@@ -682,7 +821,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
*/
cur = 0;
for (i=0; i<3; i++) {
- struct resource *res = &u3_agp->mem_resources[i];
+ struct resource *res = &other->mem_resources[i];
if (res->flags != IORESOURCE_MEM)
continue;
/* We don't care about "fine" resources */
@@ -777,9 +916,13 @@ static int __init add_bridge(struct device_node *dev)
setup_u3_ht(hose);
disp_name = "U3-HT";
primary = 1;
+ } else if (device_is_compatible(dev, "u4-pcie")) {
+ setup_u4_pcie(hose);
+ disp_name = "U4-PCIE";
+ primary = 0;
}
- printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
- disp_name, hose->first_busno, hose->last_busno);
+ printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number:"
+ " %d->%d\n", disp_name, hose->first_busno, hose->last_busno);
#endif /* CONFIG_PPC64 */
/* 32 bits only bridges */
@@ -900,6 +1043,8 @@ void __init pmac_pci_init(void)
pci_setup_phb_io(u3_ht, 1);
if (u3_agp)
pci_setup_phb_io(u3_agp, 0);
+ if (u4_pcie)
+ pci_setup_phb_io(u4_pcie, 0);
/*
* On ppc64, fixup the IO resources on our host bridges as
@@ -912,7 +1057,8 @@ void __init pmac_pci_init(void)
/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
* assume there is no P2P bridge on the AGP bus, which should be a
- * safe assumptions hopefully.
+ * safe assumptions for now. We should do something better in the
+ * future though
*/
if (u3_agp) {
struct device_node *np = u3_agp->arch_data;
@@ -920,7 +1066,6 @@ void __init pmac_pci_init(void)
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 */
@@ -1127,7 +1272,8 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
good:
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 5) != 5) {
- printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
+ printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n",
+ pci_name(dev));
(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
(progif & 5) != 5)
@@ -1153,7 +1299,8 @@ static void fixup_k2_sata(struct pci_dev* dev)
for (i = 0; i < 6; i++) {
dev->resource[i].start = dev->resource[i].end = 0;
dev->resource[i].flags = 0;
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+ 0);
}
} else {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
@@ -1162,7 +1309,8 @@ static void fixup_k2_sata(struct pci_dev* dev)
for (i = 0; i < 5; i++) {
dev->resource[i].start = dev->resource[i].end = 0;
dev->resource[i].flags = 0;
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
+ 0);
}
}
}
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index dbb524a851a..18bf3011d1e 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -524,18 +524,56 @@ static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */
}
+static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
+ int master)
+{
+ unsigned char senses[128];
+ int offset = master ? 0 : 128;
+ int count = master ? 128 : 124;
+ const char *name = master ? " MPIC 1 " : " MPIC 2 ";
+ struct resource r;
+ struct mpic *mpic;
+ unsigned int flags = master ? MPIC_PRIMARY : 0;
+ int rc;
+
+ rc = of_address_to_resource(np, 0, &r);
+ if (rc)
+ return NULL;
+
+ pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
+
+ prom_get_irq_senses(senses, offset, offset + count);
+
+ flags |= MPIC_WANTS_RESET;
+ if (get_property(np, "big-endian", NULL))
+ flags |= MPIC_BIG_ENDIAN;
+
+ /* Primary Big Endian means HT interrupts. This is quite dodgy
+ * but works until I find a better way
+ */
+ if (master && (flags & MPIC_BIG_ENDIAN))
+ flags |= MPIC_BROKEN_U3;
+
+ mpic = mpic_alloc(r.start, flags, 0, offset, count, master ? 252 : 0,
+ senses, count, name);
+ if (mpic == NULL)
+ return NULL;
+
+ mpic_init(mpic);
+
+ return mpic;
+ }
+
static int __init pmac_pic_probe_mpic(void)
{
struct mpic *mpic1, *mpic2;
struct device_node *np, *master = NULL, *slave = NULL;
- unsigned char senses[128];
- struct resource r;
/* We can have up to 2 MPICs cascaded */
for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
!= NULL;) {
if (master == NULL &&
- get_property(np, "interrupt-parent", NULL) != NULL)
+ get_property(np, "interrupts", NULL) == NULL)
master = of_node_get(np);
else if (slave == NULL)
slave = of_node_get(np);
@@ -557,13 +595,8 @@ static int __init pmac_pic_probe_mpic(void)
ppc_md.get_irq = mpic_get_irq;
/* Setup master */
- BUG_ON(of_address_to_resource(master, 0, &r));
- pmac_call_feature(PMAC_FTR_ENABLE_MPIC, master, 0, 0);
- prom_get_irq_senses(senses, 0, 128);
- mpic1 = mpic_alloc(r.start, MPIC_PRIMARY | MPIC_WANTS_RESET,
- 0, 0, 128, 252, senses, 128, " OpenPIC ");
+ mpic1 = pmac_setup_one_mpic(master, 1);
BUG_ON(mpic1 == NULL);
- mpic_init(mpic1);
/* Install NMI if any */
pmac_pic_setup_mpic_nmi(mpic1