2005-09-26 14:04:21 +08:00
|
|
|
/*
|
|
|
|
* Support for PCI bridges found on Power Macintoshes.
|
|
|
|
*
|
2005-12-14 10:10:10 +08:00
|
|
|
* Copyright (C) 2003-2005 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
|
2005-09-26 14:04:21 +08:00
|
|
|
* Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/bootmem.h>
|
[PATCH] powerpc: fix trigger handling in the new irq code
This patch slightly reworks the new irq code to fix a small design error. I
removed the passing of the trigger to the map() calls entirely, it was not a
good idea to have one call do two different things. It also fixes a couple of
corner cases.
Mapping a linux virtual irq to a physical irq now does only that. Setting the
trigger is a different action which has a different call.
The main changes are:
- I no longer call host->ops->map() for an already mapped irq, I just return
the virtual number that was already mapped. It was called before to give an
opportunity to change the trigger, but that was causing issues as that could
happen while the interrupt was in use by a device, and because of the
trigger change, map would potentially muck around with things in a racy way.
That was causing much burden on a given's controller implementation of
map() to get it right. This is much simpler now. map() is only called on
the initial mapping of an irq, meaning that you know that this irq is _not_
being used. You can initialize the hardware if you want (though you don't
have to).
- Controllers that can handle different type of triggers (level/edge/etc...)
now implement the standard irq_chip->set_type() call as defined by the
generic code. That means that you can use the standard set_irq_type() to
configure an irq line manually if you wish or (though I don't like that
interface), pass explicit trigger flags to request_irq() as defined by the
generic kernel interfaces. Also, using those interfaces guarantees that
your controller set_type callback is called with the descriptor lock held,
thus providing locking against activity on the same interrupt (including
mask/unmask/etc...) automatically. A result is that, for example, MPIC's
own map() implementation calls irq_set_type(NONE) to configure the hardware
to the default triggers.
- To allow the above, the irq_map array entry for the new mapped interrupt
is now set before map() callback is called for the controller.
- The irq_create_of_mapping() (also used by irq_of_parse_and_map()) function
for mapping interrupts from the device-tree now also call the separate
set_irq_type(), and only does so if there is a change in the trigger type.
- While I was at it, I changed pci_read_irq_line() (which is the helper I
would expect most archs to use in their pcibios_fixup() to get the PCI
interrupt routing from the device tree) to also handle a fallback when the
DT mapping fails consisting of reading the PCI_INTERRUPT_PIN to know wether
the device has an interrupt at all, and the the PCI_INTERRUPT_LINE to get an
interrupt number from the device. That number is then mapped using the
default controller, and the trigger is set to level low. That default
behaviour works for several platforms that don't have a proper interrupt
tree like Pegasos. If it doesn't work for your platform, then either
provide a proper interrupt tree from the firmware so that fallback isn't
needed, or don't call pci_read_irq_line()
- Add back a bit that got dropped by my main rework patch for properly
clearing pending IPIs on pSeries when using a kexec
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-07-10 19:44:42 +08:00
|
|
|
#include <linux/irq.h>
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
#include <asm/sections.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/prom.h>
|
|
|
|
#include <asm/pci-bridge.h>
|
|
|
|
#include <asm/machdep.h>
|
|
|
|
#include <asm/pmac_feature.h>
|
2005-10-26 15:16:38 +08:00
|
|
|
#include <asm/grackle.h>
|
2005-10-10 20:58:41 +08:00
|
|
|
#include <asm/ppc-pci.h>
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
#undef DEBUG
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define DBG(x...) printk(x)
|
|
|
|
#else
|
|
|
|
#define DBG(x...)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* XXX Could be per-controller, but I don't think we risk anything by
|
|
|
|
* assuming we won't have both UniNorth and Bandit */
|
|
|
|
static int has_uninorth;
|
2005-10-22 14:02:39 +08:00
|
|
|
#ifdef CONFIG_PPC64
|
2005-09-26 14:04:21 +08:00
|
|
|
static struct pci_controller *u3_agp;
|
2006-07-03 19:36:01 +08:00
|
|
|
#else
|
|
|
|
static int has_second_ohare;
|
2005-10-22 14:02:39 +08:00
|
|
|
#endif /* CONFIG_PPC64 */
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
extern int pcibios_assign_bus_offset;
|
|
|
|
|
|
|
|
struct device_node *k2_skiplist[2];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Magic constants for enabling cache coherency in the bandit/PSX bridge.
|
|
|
|
*/
|
|
|
|
#define BANDIT_DEVID_2 8
|
|
|
|
#define BANDIT_REVID 3
|
|
|
|
|
|
|
|
#define BANDIT_DEVNUM 11
|
|
|
|
#define BANDIT_MAGIC 0x50
|
|
|
|
#define BANDIT_COHERENT 0x40
|
|
|
|
|
|
|
|
static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
|
|
|
|
{
|
|
|
|
for (; node != 0;node = node->sibling) {
|
2006-07-12 13:40:29 +08:00
|
|
|
const int * bus_range;
|
|
|
|
const unsigned int *class_code;
|
2005-09-26 14:04:21 +08:00
|
|
|
int len;
|
|
|
|
|
|
|
|
/* For PCI<->PCI bridges or CardBus bridges, we go down */
|
2007-04-03 20:26:41 +08:00
|
|
|
class_code = of_get_property(node, "class-code", NULL);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
|
|
|
|
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
|
|
|
|
continue;
|
2007-04-03 20:26:41 +08:00
|
|
|
bus_range = of_get_property(node, "bus-range", &len);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (bus_range != NULL && len > 2 * sizeof(int)) {
|
|
|
|
if (bus_range[1] > higher)
|
|
|
|
higher = bus_range[1];
|
|
|
|
}
|
|
|
|
higher = fixup_one_level_bus_range(node->child, higher);
|
|
|
|
}
|
|
|
|
return higher;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This routine fixes the "bus-range" property of all bridges in the
|
|
|
|
* system since they tend to have their "last" member wrong on macs
|
|
|
|
*
|
|
|
|
* Note that the bus numbers manipulated here are OF bus numbers, they
|
|
|
|
* are not Linux bus numbers.
|
|
|
|
*/
|
|
|
|
static void __init fixup_bus_range(struct device_node *bridge)
|
|
|
|
{
|
2006-07-12 13:40:29 +08:00
|
|
|
int *bus_range, len;
|
|
|
|
struct property *prop;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
/* Lookup the "bus-range" property for the hose */
|
2006-07-12 13:40:29 +08:00
|
|
|
prop = of_find_property(bridge, "bus-range", &len);
|
|
|
|
if (prop == NULL || prop->length < 2 * sizeof(int))
|
2005-09-26 14:04:21 +08:00
|
|
|
return;
|
2006-07-12 13:40:29 +08:00
|
|
|
|
2007-04-03 08:58:52 +08:00
|
|
|
bus_range = prop->value;
|
2005-09-26 14:04:21 +08:00
|
|
|
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers.
|
|
|
|
*
|
|
|
|
* The "Bandit" version is present in all early PCI PowerMacs,
|
|
|
|
* and up to the first ones using Grackle. Some machines may
|
|
|
|
* have 2 bandit controllers (2 PCI busses).
|
|
|
|
*
|
|
|
|
* "Chaos" is used in some "Bandit"-type machines as a bridge
|
|
|
|
* for the separate display bus. It is accessed the same
|
|
|
|
* way as bandit, but cannot be probed for devices. It therefore
|
|
|
|
* has its own config access functions.
|
|
|
|
*
|
|
|
|
* The "UniNorth" version is present in all Core99 machines
|
|
|
|
* (iBook, G4, new IMacs, and all the recent Apple machines).
|
|
|
|
* It contains 3 controllers in one ASIC.
|
|
|
|
*
|
|
|
|
* The U3 is the bridge used on G5 machines. It contains an
|
|
|
|
* AGP bus which is dealt with the old UniNorth access routines
|
|
|
|
* and a HyperTransport bus which uses its own set of access
|
|
|
|
* functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MACRISC_CFA0(devfn, off) \
|
2005-12-14 10:10:10 +08:00
|
|
|
((1 << (unsigned int)PCI_SLOT(dev_fn)) \
|
|
|
|
| (((unsigned int)PCI_FUNC(dev_fn)) << 8) \
|
|
|
|
| (((unsigned int)(off)) & 0xFCUL))
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
#define MACRISC_CFA1(bus, devfn, off) \
|
2005-12-14 10:10:10 +08:00
|
|
|
((((unsigned int)(bus)) << 16) \
|
|
|
|
|(((unsigned int)(devfn)) << 8) \
|
|
|
|
|(((unsigned int)(off)) & 0xFCUL) \
|
2005-09-26 14:04:21 +08:00
|
|
|
|1UL)
|
|
|
|
|
2006-02-01 18:18:43 +08:00
|
|
|
static volatile void __iomem *macrisc_cfg_access(struct pci_controller* hose,
|
2005-09-26 14:04:21 +08:00
|
|
|
u8 bus, u8 dev_fn, u8 offset)
|
|
|
|
{
|
|
|
|
unsigned int caddr;
|
|
|
|
|
|
|
|
if (bus == hose->first_busno) {
|
|
|
|
if (dev_fn < (11 << 3))
|
2006-02-01 18:18:43 +08:00
|
|
|
return NULL;
|
2005-09-26 14:04:21 +08:00
|
|
|
caddr = MACRISC_CFA0(dev_fn, offset);
|
|
|
|
} else
|
|
|
|
caddr = MACRISC_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 &= has_uninorth ? 0x07 : 0x03;
|
2006-02-01 18:18:43 +08:00
|
|
|
return hose->cfg_data + offset;
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
|
|
|
|
int offset, int len, u32 *val)
|
|
|
|
{
|
2005-10-10 20:58:41 +08:00
|
|
|
struct pci_controller *hose;
|
2006-02-01 18:18:43 +08:00
|
|
|
volatile void __iomem *addr;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
2005-10-10 20:58:41 +08:00
|
|
|
hose = pci_bus_to_host(bus);
|
|
|
|
if (hose == NULL)
|
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
2005-12-14 10:10:10 +08:00
|
|
|
if (offset >= 0x100)
|
|
|
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
2005-09-26 14:04:21 +08:00
|
|
|
addr = macrisc_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:
|
2006-02-01 18:18:43 +08:00
|
|
|
*val = in_8(addr);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
2006-02-01 18:18:43 +08:00
|
|
|
*val = in_le16(addr);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
default:
|
2006-02-01 18:18:43 +08:00
|
|
|
*val = in_le32(addr);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
|
|
|
|
int offset, int len, u32 val)
|
|
|
|
{
|
2005-10-10 20:58:41 +08:00
|
|
|
struct pci_controller *hose;
|
2006-02-01 18:18:43 +08:00
|
|
|
volatile void __iomem *addr;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
2005-10-10 20:58:41 +08:00
|
|
|
hose = pci_bus_to_host(bus);
|
|
|
|
if (hose == NULL)
|
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
2005-12-14 10:10:10 +08:00
|
|
|
if (offset >= 0x100)
|
|
|
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
2005-09-26 14:04:21 +08:00
|
|
|
addr = macrisc_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:
|
2006-02-01 18:18:43 +08:00
|
|
|
out_8(addr, val);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
2006-02-01 18:18:43 +08:00
|
|
|
out_le16(addr, val);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
default:
|
2006-02-01 18:18:43 +08:00
|
|
|
out_le32(addr, val);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct pci_ops macrisc_pci_ops =
|
|
|
|
{
|
2007-08-10 03:18:41 +08:00
|
|
|
.read = macrisc_read_config,
|
|
|
|
.write = macrisc_write_config,
|
2005-09-26 14:04:21 +08:00
|
|
|
};
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
#ifdef CONFIG_PPC32
|
2005-09-26 14:04:21 +08:00
|
|
|
/*
|
2005-10-10 20:58:41 +08:00
|
|
|
* Verify that a specific (bus, dev_fn) exists on chaos
|
2005-09-26 14:04:21 +08:00
|
|
|
*/
|
2005-12-14 10:10:10 +08:00
|
|
|
static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
struct device_node *np;
|
2006-07-12 13:40:29 +08:00
|
|
|
const u32 *vendor, *device;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
2005-12-14 10:10:10 +08:00
|
|
|
if (offset >= 0x100)
|
|
|
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
2005-09-26 14:04:21 +08:00
|
|
|
np = pci_busdev_to_OF_node(bus, devfn);
|
|
|
|
if (np == NULL)
|
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
|
|
2007-04-03 20:26:41 +08:00
|
|
|
vendor = of_get_property(np, "vendor-id", NULL);
|
|
|
|
device = of_get_property(np, "device-id", NULL);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (vendor == NULL || device == NULL)
|
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
|
|
|
|
|
if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10)
|
|
|
|
&& (offset != 0x14) && (offset != 0x18) && (offset <= 0x24))
|
|
|
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
|
|
|
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
|
|
|
|
int len, u32 *val)
|
|
|
|
{
|
|
|
|
int result = chaos_validate_dev(bus, devfn, offset);
|
|
|
|
if (result == PCIBIOS_BAD_REGISTER_NUMBER)
|
|
|
|
*val = ~0U;
|
|
|
|
if (result != PCIBIOS_SUCCESSFUL)
|
|
|
|
return result;
|
|
|
|
return macrisc_read_config(bus, devfn, offset, len, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
|
|
|
|
int len, u32 val)
|
|
|
|
{
|
|
|
|
int result = chaos_validate_dev(bus, devfn, offset);
|
|
|
|
if (result != PCIBIOS_SUCCESSFUL)
|
|
|
|
return result;
|
|
|
|
return macrisc_write_config(bus, devfn, offset, len, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct pci_ops chaos_pci_ops =
|
|
|
|
{
|
2007-08-10 03:18:41 +08:00
|
|
|
.read = chaos_read_config,
|
|
|
|
.write = chaos_write_config,
|
2005-09-26 14:04:21 +08:00
|
|
|
};
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
static void __init setup_chaos(struct pci_controller *hose,
|
2005-12-13 15:01:21 +08:00
|
|
|
struct resource *addr)
|
2005-10-22 14:02:39 +08:00
|
|
|
{
|
|
|
|
/* assume a `chaos' bridge */
|
|
|
|
hose->ops = &chaos_pci_ops;
|
2005-12-13 15:01:21 +08:00
|
|
|
hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
|
|
|
|
hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
|
2005-10-22 14:02:39 +08:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_PPC32 */
|
|
|
|
|
|
|
|
#ifdef CONFIG_PPC64
|
2005-09-26 14:04:21 +08:00
|
|
|
/*
|
|
|
|
* These versions of U3 HyperTransport config space access ops do not
|
|
|
|
* implement self-view of the HT host yet
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function deals with some "special cases" devices.
|
|
|
|
*
|
|
|
|
* 0 -> No special case
|
|
|
|
* 1 -> Skip the device but act as if the access was successfull
|
|
|
|
* (return 0xff's on reads, eventually, cache config space
|
|
|
|
* accesses in a later version)
|
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 23:09:05 +08:00
|
|
|
* -1 -> Hide the device (unsuccessful access)
|
2005-09-26 14:04:21 +08:00
|
|
|
*/
|
|
|
|
static int u3_ht_skip_device(struct pci_controller *hose,
|
|
|
|
struct pci_bus *bus, unsigned int devfn)
|
|
|
|
{
|
|
|
|
struct device_node *busdn, *dn;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* 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
|
2007-12-20 11:55:01 +08:00
|
|
|
* revs of K2 on recent G5s, except for the host bridge itself, which
|
|
|
|
* is missing from the tree but we know we can probe.
|
2005-09-26 14:04:21 +08:00
|
|
|
*/
|
|
|
|
if (bus->self)
|
|
|
|
busdn = pci_device_to_OF_node(bus->self);
|
2007-12-20 11:55:01 +08:00
|
|
|
else if (devfn == 0)
|
|
|
|
return 0;
|
2005-09-26 14:04:21 +08:00
|
|
|
else
|
2007-12-10 11:33:21 +08:00
|
|
|
busdn = hose->dn;
|
2005-09-26 14:04:21 +08:00
|
|
|
for (dn = busdn->child; dn; dn = dn->sibling)
|
2005-12-06 09:37:35 +08:00
|
|
|
if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn)
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
if (dn == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When a device in K2 is powered down, we die on config
|
|
|
|
* cycle accesses. Fix that here.
|
|
|
|
*/
|
|
|
|
for (i=0; i<2; i++)
|
|
|
|
if (k2_skiplist[i] == dn)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define U3_HT_CFA0(devfn, off) \
|
2005-12-14 10:10:10 +08:00
|
|
|
((((unsigned int)devfn) << 8) | offset)
|
2005-09-26 14:04:21 +08:00
|
|
|
#define U3_HT_CFA1(bus, devfn, off) \
|
|
|
|
(U3_HT_CFA0(devfn, off) \
|
2005-12-14 10:10:10 +08:00
|
|
|
+ (((unsigned int)bus) << 16) \
|
2005-09-26 14:04:21 +08:00
|
|
|
+ 0x01000000UL)
|
|
|
|
|
2007-12-20 11:55:01 +08:00
|
|
|
static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus,
|
|
|
|
u8 devfn, u8 offset, int *swap)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
2007-12-20 11:55:01 +08:00
|
|
|
*swap = 1;
|
2005-09-26 14:04:21 +08:00
|
|
|
if (bus == hose->first_busno) {
|
2007-12-20 11:55:01 +08:00
|
|
|
if (devfn != 0)
|
|
|
|
return hose->cfg_data + U3_HT_CFA0(devfn, offset);
|
|
|
|
*swap = 0;
|
|
|
|
return ((void __iomem *)hose->cfg_addr) + (offset << 2);
|
2005-09-26 14:04:21 +08:00
|
|
|
} else
|
2006-02-01 18:18:43 +08:00
|
|
|
return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset);
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
|
|
|
|
int offset, int len, u32 *val)
|
|
|
|
{
|
2005-10-10 20:58:41 +08:00
|
|
|
struct pci_controller *hose;
|
2007-12-20 11:55:01 +08:00
|
|
|
void __iomem *addr;
|
|
|
|
int swap;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
2005-10-10 20:58:41 +08:00
|
|
|
hose = pci_bus_to_host(bus);
|
|
|
|
if (hose == NULL)
|
2005-09-26 14:04:21 +08:00
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
2005-12-14 10:10:10 +08:00
|
|
|
if (offset >= 0x100)
|
|
|
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
2007-12-20 11:55:01 +08:00
|
|
|
addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (!addr)
|
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
|
|
|
|
|
switch (u3_ht_skip_device(hose, bus, devfn)) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
2005-10-10 20:58:41 +08:00
|
|
|
switch (len) {
|
|
|
|
case 1:
|
|
|
|
*val = 0xff; break;
|
|
|
|
case 2:
|
|
|
|
*val = 0xffff; break;
|
|
|
|
default:
|
|
|
|
*val = 0xfffffffful; break;
|
|
|
|
}
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
2005-09-26 14:04:21 +08:00
|
|
|
default:
|
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
2005-10-10 20:58:41 +08:00
|
|
|
}
|
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
/*
|
|
|
|
* Note: the caller has already checked that offset is
|
|
|
|
* suitably aligned and that len is 1, 2 or 4.
|
|
|
|
*/
|
|
|
|
switch (len) {
|
|
|
|
case 1:
|
2006-02-01 18:18:43 +08:00
|
|
|
*val = in_8(addr);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
2007-12-20 11:55:01 +08:00
|
|
|
*val = swap ? in_le16(addr) : in_be16(addr);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
default:
|
2007-12-20 11:55:01 +08:00
|
|
|
*val = swap ? in_le32(addr) : in_be32(addr);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
|
|
|
|
int offset, int len, u32 val)
|
|
|
|
{
|
2005-10-10 20:58:41 +08:00
|
|
|
struct pci_controller *hose;
|
2007-12-20 11:55:01 +08:00
|
|
|
void __iomem *addr;
|
|
|
|
int swap;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
2005-10-10 20:58:41 +08:00
|
|
|
hose = pci_bus_to_host(bus);
|
|
|
|
if (hose == NULL)
|
2005-09-26 14:04:21 +08:00
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
2005-12-14 10:10:10 +08:00
|
|
|
if (offset >= 0x100)
|
|
|
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
2007-12-20 11:55:01 +08:00
|
|
|
addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (!addr)
|
|
|
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
|
|
|
|
|
switch (u3_ht_skip_device(hose, bus, devfn)) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
|
|
default:
|
|
|
|
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:
|
2006-02-01 18:18:43 +08:00
|
|
|
out_8(addr, val);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
2007-12-20 11:55:01 +08:00
|
|
|
swap ? out_le16(addr, val) : out_be16(addr, val);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
default:
|
2007-12-20 11:55:01 +08:00
|
|
|
swap ? out_le32(addr, val) : out_be32(addr, val);
|
2005-09-26 14:04:21 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct pci_ops u3_ht_pci_ops =
|
|
|
|
{
|
2007-08-10 03:18:41 +08:00
|
|
|
.read = u3_ht_read_config,
|
|
|
|
.write = u3_ht_write_config,
|
2005-09-26 14:04:21 +08:00
|
|
|
};
|
2005-12-14 10:10:10 +08:00
|
|
|
|
|
|
|
#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)
|
|
|
|
|
2006-02-01 18:18:43 +08:00
|
|
|
static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose,
|
2005-12-14 10:10:10 +08:00
|
|
|
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;
|
2006-02-01 18:18:43 +08:00
|
|
|
return hose->cfg_data + offset;
|
2005-12-14 10:10:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
|
|
|
|
int offset, int len, u32 *val)
|
|
|
|
{
|
|
|
|
struct pci_controller *hose;
|
2006-02-01 18:18:43 +08:00
|
|
|
volatile void __iomem *addr;
|
2005-12-14 10:10:10 +08:00
|
|
|
|
|
|
|
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:
|
2006-02-01 18:18:43 +08:00
|
|
|
*val = in_8(addr);
|
2005-12-14 10:10:10 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
2006-02-01 18:18:43 +08:00
|
|
|
*val = in_le16(addr);
|
2005-12-14 10:10:10 +08:00
|
|
|
break;
|
|
|
|
default:
|
2006-02-01 18:18:43 +08:00
|
|
|
*val = in_le32(addr);
|
2005-12-14 10:10:10 +08:00
|
|
|
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;
|
2006-02-01 18:18:43 +08:00
|
|
|
volatile void __iomem *addr;
|
2005-12-14 10:10:10 +08:00
|
|
|
|
|
|
|
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:
|
2006-02-01 18:18:43 +08:00
|
|
|
out_8(addr, val);
|
2005-12-14 10:10:10 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
2006-02-01 18:18:43 +08:00
|
|
|
out_le16(addr, val);
|
2005-12-14 10:10:10 +08:00
|
|
|
break;
|
|
|
|
default:
|
2006-02-01 18:18:43 +08:00
|
|
|
out_le32(addr, val);
|
2005-12-14 10:10:10 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct pci_ops u4_pcie_pci_ops =
|
|
|
|
{
|
2007-08-10 03:18:41 +08:00
|
|
|
.read = u4_pcie_read_config,
|
|
|
|
.write = u4_pcie_write_config,
|
2005-12-14 10:10:10 +08:00
|
|
|
};
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
#endif /* CONFIG_PPC64 */
|
2005-09-26 14:04:21 +08:00
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
#ifdef CONFIG_PPC32
|
2005-09-26 14:04:21 +08:00
|
|
|
/*
|
|
|
|
* For a bandit bridge, turn on cache coherency if necessary.
|
|
|
|
* N.B. we could clean this up using the hose ops directly.
|
|
|
|
*/
|
2005-10-10 20:58:41 +08:00
|
|
|
static void __init init_bandit(struct pci_controller *bp)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
unsigned int vendev, magic;
|
|
|
|
int rev;
|
|
|
|
|
|
|
|
/* read the word at offset 0 in config space for device 11 */
|
|
|
|
out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
|
|
|
|
udelay(2);
|
|
|
|
vendev = in_le32(bp->cfg_data);
|
|
|
|
if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) +
|
|
|
|
PCI_VENDOR_ID_APPLE) {
|
|
|
|
/* read the revision id */
|
|
|
|
out_le32(bp->cfg_addr,
|
|
|
|
(1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
|
|
|
|
udelay(2);
|
|
|
|
rev = in_8(bp->cfg_data);
|
|
|
|
if (rev != BANDIT_REVID)
|
|
|
|
printk(KERN_WARNING
|
|
|
|
"Unknown revision %d for bandit\n", rev);
|
|
|
|
} else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
|
|
|
|
printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read the word at offset 0x50 */
|
|
|
|
out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
|
|
|
|
udelay(2);
|
|
|
|
magic = in_le32(bp->cfg_data);
|
|
|
|
if ((magic & BANDIT_COHERENT) != 0)
|
|
|
|
return;
|
|
|
|
magic |= BANDIT_COHERENT;
|
|
|
|
udelay(2);
|
|
|
|
out_le32(bp->cfg_data, magic);
|
|
|
|
printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tweak the PCI-PCI bridge chip on the blue & white G3s.
|
|
|
|
*/
|
2005-10-10 20:58:41 +08:00
|
|
|
static void __init init_p2pbridge(void)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
struct device_node *p2pbridge;
|
|
|
|
struct pci_controller* hose;
|
|
|
|
u8 bus, devfn;
|
|
|
|
u16 val;
|
|
|
|
|
|
|
|
/* XXX it would be better here to identify the specific
|
|
|
|
PCI-PCI bridge chip we have. */
|
2007-04-24 11:53:04 +08:00
|
|
|
p2pbridge = of_find_node_by_name(NULL, "pci-bridge");
|
|
|
|
if (p2pbridge == NULL
|
2005-09-26 14:04:21 +08:00
|
|
|
|| p2pbridge->parent == NULL
|
|
|
|
|| strcmp(p2pbridge->parent->name, "pci") != 0)
|
2007-04-24 11:53:04 +08:00
|
|
|
goto done;
|
2005-09-26 14:04:21 +08:00
|
|
|
if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
|
|
|
|
DBG("Can't find PCI infos for PCI<->PCI bridge\n");
|
2007-04-24 11:53:04 +08:00
|
|
|
goto done;
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
/* Warning: At this point, we have not yet renumbered all busses.
|
|
|
|
* So we must use OF walking to find out hose
|
|
|
|
*/
|
|
|
|
hose = pci_find_hose_for_OF_device(p2pbridge);
|
|
|
|
if (!hose) {
|
|
|
|
DBG("Can't find hose for PCI<->PCI bridge\n");
|
2007-04-24 11:53:04 +08:00
|
|
|
goto done;
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
if (early_read_config_word(hose, bus, devfn,
|
|
|
|
PCI_BRIDGE_CONTROL, &val) < 0) {
|
2005-12-13 15:01:21 +08:00
|
|
|
printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
|
|
|
|
" control\n");
|
2007-04-24 11:53:04 +08:00
|
|
|
goto done;
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
|
|
|
|
early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
|
2007-04-24 11:53:04 +08:00
|
|
|
done:
|
|
|
|
of_node_put(p2pbridge);
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
|
2006-07-03 19:36:01 +08:00
|
|
|
static void __init init_second_ohare(void)
|
|
|
|
{
|
|
|
|
struct device_node *np = of_find_node_by_name(NULL, "pci106b,7");
|
|
|
|
unsigned char bus, devfn;
|
|
|
|
unsigned short cmd;
|
|
|
|
|
|
|
|
if (np == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* This must run before we initialize the PICs since the second
|
|
|
|
* ohare hosts a PIC that will be accessed there.
|
|
|
|
*/
|
|
|
|
if (pci_device_from_OF_node(np, &bus, &devfn) == 0) {
|
|
|
|
struct pci_controller* hose =
|
|
|
|
pci_find_hose_for_OF_device(np);
|
|
|
|
if (!hose) {
|
|
|
|
printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
|
2008-12-03 08:25:03 +08:00
|
|
|
of_node_put(np);
|
2006-07-03 19:36:01 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
|
|
|
|
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
|
|
|
|
cmd &= ~PCI_COMMAND_IO;
|
|
|
|
early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
|
|
|
|
}
|
|
|
|
has_second_ohare = 1;
|
2008-12-03 08:25:03 +08:00
|
|
|
of_node_put(np);
|
2006-07-03 19:36:01 +08:00
|
|
|
}
|
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
/*
|
|
|
|
* Some Apple desktop machines have a NEC PD720100A USB2 controller
|
|
|
|
* on the motherboard. Open Firmware, on these, will disable the
|
|
|
|
* EHCI part of it so it behaves like a pair of OHCI's. This fixup
|
|
|
|
* code re-enables it ;)
|
|
|
|
*/
|
2005-10-10 20:58:41 +08:00
|
|
|
static void __init fixup_nec_usb2(void)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
struct device_node *nec;
|
|
|
|
|
|
|
|
for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
|
|
|
|
struct pci_controller *hose;
|
2006-07-12 13:40:29 +08:00
|
|
|
u32 data;
|
|
|
|
const u32 *prop;
|
2005-09-26 14:04:21 +08:00
|
|
|
u8 bus, devfn;
|
2005-10-22 14:02:39 +08:00
|
|
|
|
2007-04-03 20:26:41 +08:00
|
|
|
prop = of_get_property(nec, "vendor-id", NULL);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (prop == NULL)
|
|
|
|
continue;
|
|
|
|
if (0x1033 != *prop)
|
|
|
|
continue;
|
2007-04-03 20:26:41 +08:00
|
|
|
prop = of_get_property(nec, "device-id", NULL);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (prop == NULL)
|
|
|
|
continue;
|
|
|
|
if (0x0035 != *prop)
|
|
|
|
continue;
|
2007-04-03 20:26:41 +08:00
|
|
|
prop = of_get_property(nec, "reg", NULL);
|
2005-09-26 14:04:21 +08:00
|
|
|
if (prop == NULL)
|
|
|
|
continue;
|
|
|
|
devfn = (prop[0] >> 8) & 0xff;
|
|
|
|
bus = (prop[0] >> 16) & 0xff;
|
|
|
|
if (PCI_FUNC(devfn) != 0)
|
|
|
|
continue;
|
|
|
|
hose = pci_find_hose_for_OF_device(nec);
|
|
|
|
if (!hose)
|
|
|
|
continue;
|
|
|
|
early_read_config_dword(hose, bus, devfn, 0xe4, &data);
|
|
|
|
if (data & 1UL) {
|
2005-12-13 15:01:21 +08:00
|
|
|
printk("Found NEC PD720100A USB2 chip with disabled"
|
|
|
|
" EHCI, fixing up...\n");
|
2005-09-26 14:04:21 +08:00
|
|
|
data &= ~1UL;
|
|
|
|
early_write_config_dword(hose, bus, devfn, 0xe4, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
static void __init setup_bandit(struct pci_controller *hose,
|
2005-12-13 15:01:21 +08:00
|
|
|
struct resource *addr)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
hose->ops = ¯isc_pci_ops;
|
2005-12-13 15:01:21 +08:00
|
|
|
hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
|
|
|
|
hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
|
2005-09-26 14:04:21 +08:00
|
|
|
init_bandit(hose);
|
|
|
|
}
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
static int __init setup_uninorth(struct pci_controller *hose,
|
2005-12-13 15:01:21 +08:00
|
|
|
struct resource *addr)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
2008-12-11 17:46:44 +08:00
|
|
|
ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
|
2005-10-22 14:02:39 +08:00
|
|
|
has_uninorth = 1;
|
|
|
|
hose->ops = ¯isc_pci_ops;
|
2005-12-13 15:01:21 +08:00
|
|
|
hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
|
|
|
|
hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000);
|
2005-10-22 14:02:39 +08:00
|
|
|
/* We "know" that the bridge at f2000000 has the PCI slots. */
|
2005-12-13 15:01:21 +08:00
|
|
|
return addr->start == 0xf2000000;
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
2005-12-13 15:01:21 +08:00
|
|
|
#endif /* CONFIG_PPC32 */
|
2005-09-26 14:04:21 +08:00
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
#ifdef CONFIG_PPC64
|
2005-09-26 14:04:21 +08:00
|
|
|
static void __init setup_u3_agp(struct pci_controller* hose)
|
|
|
|
{
|
|
|
|
/* On G5, we move AGP up to high bus number so we don't need
|
|
|
|
* to reassign bus numbers for HT. If we ever have P2P bridges
|
2005-10-22 14:02:39 +08:00
|
|
|
* on AGP, we'll have to move pci_assign_all_busses to the
|
2005-09-26 14:04:21 +08:00
|
|
|
* pci_controller structure so we enable it for AGP and not for
|
|
|
|
* HT childs.
|
|
|
|
* 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
|
|
|
|
*/
|
2005-10-10 20:58:41 +08:00
|
|
|
hose->first_busno = 0xf0;
|
2005-09-26 14:04:21 +08:00
|
|
|
hose->last_busno = 0xff;
|
|
|
|
has_uninorth = 1;
|
|
|
|
hose->ops = ¯isc_pci_ops;
|
|
|
|
hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
|
|
|
|
hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
|
|
|
|
u3_agp = hose;
|
|
|
|
}
|
|
|
|
|
2005-12-14 10:10:10 +08:00
|
|
|
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;
|
2007-12-20 11:55:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2005-12-14 10:10:10 +08:00
|
|
|
}
|
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
static void __init setup_u3_ht(struct pci_controller* hose)
|
|
|
|
{
|
2007-12-10 11:33:21 +08:00
|
|
|
struct device_node *np = hose->dn;
|
2007-12-20 11:55:01 +08:00
|
|
|
struct resource cfg_res, self_res;
|
2007-12-20 11:55:02 +08:00
|
|
|
u32 decode;
|
2005-12-14 10:10:10 +08:00
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
hose->ops = &u3_ht_pci_ops;
|
|
|
|
|
2007-12-20 11:55:01 +08:00
|
|
|
/* Get base addresses from OF tree
|
|
|
|
*/
|
|
|
|
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
|
2005-09-26 14:04:21 +08:00
|
|
|
*/
|
2007-12-20 11:55:01 +08:00
|
|
|
hose->cfg_data = ioremap(cfg_res.start, 0x02000000);
|
|
|
|
hose->cfg_addr = ioremap(self_res.start,
|
|
|
|
self_res.end - self_res.start + 1);
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
/*
|
2007-12-20 11:55:02 +08:00
|
|
|
* /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.
|
2005-09-26 14:04:21 +08:00
|
|
|
*/
|
|
|
|
hose->io_base_phys = 0xf4000000;
|
2005-10-22 14:02:39 +08:00
|
|
|
hose->pci_io_size = 0x00400000;
|
2005-09-26 14:04:21 +08:00
|
|
|
hose->io_resource.name = np->full_name;
|
|
|
|
hose->io_resource.start = 0;
|
|
|
|
hose->io_resource.end = 0x003fffff;
|
|
|
|
hose->io_resource.flags = IORESOURCE_IO;
|
|
|
|
hose->pci_mem_offset = 0;
|
|
|
|
hose->first_busno = 0;
|
|
|
|
hose->last_busno = 0xef;
|
|
|
|
|
2007-12-20 11:55:02 +08:00
|
|
|
/* Note: fix offset when cfg_addr becomes a void * */
|
|
|
|
decode = in_be32(hose->cfg_addr + 0x80);
|
|
|
|
|
|
|
|
DBG("PCI: Apple HT bridge decode register: 0x%08x\n", decode);
|
|
|
|
|
|
|
|
/* 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.
|
2005-09-26 14:04:21 +08:00
|
|
|
*/
|
2007-12-20 11:55:02 +08:00
|
|
|
decode &= 0x003fffff;
|
|
|
|
|
|
|
|
/* Now parse the resulting bits and build resources */
|
|
|
|
parse_region_decode(hose, decode);
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
2005-12-13 15:01:21 +08:00
|
|
|
#endif /* CONFIG_PPC64 */
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We assume that if we have a G3 powermac, we have one bridge called
|
|
|
|
* "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
|
|
|
|
* if we have one or more bandit or chaos bridges, we don't have a MPC106.
|
|
|
|
*/
|
2007-06-18 07:06:54 +08:00
|
|
|
static int __init pmac_add_bridge(struct device_node *dev)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
int len;
|
|
|
|
struct pci_controller *hose;
|
2005-12-13 15:01:21 +08:00
|
|
|
struct resource rsrc;
|
2005-10-22 14:02:39 +08:00
|
|
|
char *disp_name;
|
2006-07-12 13:40:29 +08:00
|
|
|
const int *bus_range;
|
2005-12-13 15:01:21 +08:00
|
|
|
int primary = 1, has_address = 0;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
DBG("Adding PCI host bridge %s\n", dev->full_name);
|
|
|
|
|
2005-12-13 15:01:21 +08:00
|
|
|
/* Fetch host bridge registers address */
|
|
|
|
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
|
|
|
|
|
|
|
|
/* Get bus range if any */
|
2007-04-03 20:26:41 +08:00
|
|
|
bus_range = of_get_property(dev, "bus-range", &len);
|
2005-10-22 14:02:39 +08:00
|
|
|
if (bus_range == NULL || len < 2 * sizeof(int)) {
|
2005-11-15 13:05:33 +08:00
|
|
|
printk(KERN_WARNING "Can't get bus-range for %s, assume"
|
|
|
|
" bus 0\n", dev->full_name);
|
2005-10-22 14:02:39 +08:00
|
|
|
}
|
|
|
|
|
2005-11-15 13:05:33 +08:00
|
|
|
hose = pcibios_alloc_controller(dev);
|
2005-10-22 14:02:39 +08:00
|
|
|
if (!hose)
|
|
|
|
return -ENOMEM;
|
|
|
|
hose->first_busno = bus_range ? bus_range[0] : 0;
|
|
|
|
hose->last_busno = bus_range ? bus_range[1] : 0xff;
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
disp_name = NULL;
|
2005-12-13 15:01:21 +08:00
|
|
|
|
|
|
|
/* 64 bits only bridges */
|
2005-11-15 13:05:33 +08:00
|
|
|
#ifdef CONFIG_PPC64
|
2007-05-03 15:26:52 +08:00
|
|
|
if (of_device_is_compatible(dev, "u3-agp")) {
|
2005-10-22 14:02:39 +08:00
|
|
|
setup_u3_agp(hose);
|
|
|
|
disp_name = "U3-AGP";
|
|
|
|
primary = 0;
|
2007-05-03 15:26:52 +08:00
|
|
|
} else if (of_device_is_compatible(dev, "u3-ht")) {
|
2005-10-22 14:02:39 +08:00
|
|
|
setup_u3_ht(hose);
|
|
|
|
disp_name = "U3-HT";
|
|
|
|
primary = 1;
|
2007-05-03 15:26:52 +08:00
|
|
|
} else if (of_device_is_compatible(dev, "u4-pcie")) {
|
2005-12-14 10:10:10 +08:00
|
|
|
setup_u4_pcie(hose);
|
|
|
|
disp_name = "U4-PCIE";
|
|
|
|
primary = 0;
|
2005-10-22 14:02:39 +08:00
|
|
|
}
|
2005-12-14 10:10:10 +08:00
|
|
|
printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number:"
|
|
|
|
" %d->%d\n", disp_name, hose->first_busno, hose->last_busno);
|
2005-12-13 15:01:21 +08:00
|
|
|
#endif /* CONFIG_PPC64 */
|
|
|
|
|
|
|
|
/* 32 bits only bridges */
|
|
|
|
#ifdef CONFIG_PPC32
|
2007-05-03 15:26:52 +08:00
|
|
|
if (of_device_is_compatible(dev, "uni-north")) {
|
2005-12-13 15:01:21 +08:00
|
|
|
primary = setup_uninorth(hose, &rsrc);
|
2005-10-22 14:02:39 +08:00
|
|
|
disp_name = "UniNorth";
|
2005-10-10 20:58:41 +08:00
|
|
|
} else if (strcmp(dev->name, "pci") == 0) {
|
2005-10-22 14:02:39 +08:00
|
|
|
/* XXX assume this is a mpc106 (grackle) */
|
|
|
|
setup_grackle(hose);
|
|
|
|
disp_name = "Grackle (MPC106)";
|
|
|
|
} else if (strcmp(dev->name, "bandit") == 0) {
|
2005-12-13 15:01:21 +08:00
|
|
|
setup_bandit(hose, &rsrc);
|
2005-10-22 14:02:39 +08:00
|
|
|
disp_name = "Bandit";
|
|
|
|
} else if (strcmp(dev->name, "chaos") == 0) {
|
2005-12-13 15:01:21 +08:00
|
|
|
setup_chaos(hose, &rsrc);
|
2005-10-22 14:02:39 +08:00
|
|
|
disp_name = "Chaos";
|
|
|
|
primary = 0;
|
|
|
|
}
|
2006-06-13 06:18:31 +08:00
|
|
|
printk(KERN_INFO "Found %s PCI host bridge at 0x%016llx. "
|
2005-12-13 15:01:21 +08:00
|
|
|
"Firmware bus number: %d->%d\n",
|
2006-06-13 06:18:31 +08:00
|
|
|
disp_name, (unsigned long long)rsrc.start, hose->first_busno,
|
|
|
|
hose->last_busno);
|
2005-12-13 15:01:21 +08:00
|
|
|
#endif /* CONFIG_PPC32 */
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
|
|
|
|
hose, hose->cfg_addr, hose->cfg_data);
|
|
|
|
|
|
|
|
/* Interpret the "ranges" property */
|
|
|
|
/* This also maps the I/O region and sets isa_io/mem_base */
|
|
|
|
pci_process_bridge_OF_ranges(hose, dev, primary);
|
|
|
|
|
|
|
|
/* Fixup "bus-range" OF property */
|
|
|
|
fixup_bus_range(dev);
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-11-11 14:24:51 +08:00
|
|
|
void __devinit pmac_pci_irq_fixup(struct pci_dev *dev)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
[PATCH] powerpc: fix trigger handling in the new irq code
This patch slightly reworks the new irq code to fix a small design error. I
removed the passing of the trigger to the map() calls entirely, it was not a
good idea to have one call do two different things. It also fixes a couple of
corner cases.
Mapping a linux virtual irq to a physical irq now does only that. Setting the
trigger is a different action which has a different call.
The main changes are:
- I no longer call host->ops->map() for an already mapped irq, I just return
the virtual number that was already mapped. It was called before to give an
opportunity to change the trigger, but that was causing issues as that could
happen while the interrupt was in use by a device, and because of the
trigger change, map would potentially muck around with things in a racy way.
That was causing much burden on a given's controller implementation of
map() to get it right. This is much simpler now. map() is only called on
the initial mapping of an irq, meaning that you know that this irq is _not_
being used. You can initialize the hardware if you want (though you don't
have to).
- Controllers that can handle different type of triggers (level/edge/etc...)
now implement the standard irq_chip->set_type() call as defined by the
generic code. That means that you can use the standard set_irq_type() to
configure an irq line manually if you wish or (though I don't like that
interface), pass explicit trigger flags to request_irq() as defined by the
generic kernel interfaces. Also, using those interfaces guarantees that
your controller set_type callback is called with the descriptor lock held,
thus providing locking against activity on the same interrupt (including
mask/unmask/etc...) automatically. A result is that, for example, MPIC's
own map() implementation calls irq_set_type(NONE) to configure the hardware
to the default triggers.
- To allow the above, the irq_map array entry for the new mapped interrupt
is now set before map() callback is called for the controller.
- The irq_create_of_mapping() (also used by irq_of_parse_and_map()) function
for mapping interrupts from the device-tree now also call the separate
set_irq_type(), and only does so if there is a change in the trigger type.
- While I was at it, I changed pci_read_irq_line() (which is the helper I
would expect most archs to use in their pcibios_fixup() to get the PCI
interrupt routing from the device tree) to also handle a fallback when the
DT mapping fails consisting of reading the PCI_INTERRUPT_PIN to know wether
the device has an interrupt at all, and the the PCI_INTERRUPT_LINE to get an
interrupt number from the device. That number is then mapped using the
default controller, and the trigger is set to level low. That default
behaviour works for several platforms that don't have a proper interrupt
tree like Pegasos. If it doesn't work for your platform, then either
provide a proper interrupt tree from the firmware so that fallback isn't
needed, or don't call pci_read_irq_line()
- Add back a bit that got dropped by my main rework patch for properly
clearing pending IPIs on pSeries when using a kexec
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-07-10 19:44:42 +08:00
|
|
|
#ifdef CONFIG_PPC32
|
2006-11-11 14:24:51 +08:00
|
|
|
/* Fixup interrupt for the modem/ethernet combo controller.
|
|
|
|
* on machines with a second ohare chip.
|
|
|
|
* The number in the device tree (27) is bogus (correct for
|
|
|
|
* the ethernet-only board but not the combo ethernet/modem
|
|
|
|
* board). The real interrupt is 28 on the second controller
|
|
|
|
* -> 28+32 = 60.
|
|
|
|
*/
|
|
|
|
if (has_second_ohare &&
|
|
|
|
dev->vendor == PCI_VENDOR_ID_DEC &&
|
|
|
|
dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS) {
|
|
|
|
dev->irq = irq_create_mapping(NULL, 60);
|
|
|
|
set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
2006-11-11 14:24:51 +08:00
|
|
|
#endif /* CONFIG_PPC32 */
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
void __init pmac_pci_init(void)
|
2005-10-10 20:58:41 +08:00
|
|
|
{
|
|
|
|
struct device_node *np, *root;
|
|
|
|
struct device_node *ht = NULL;
|
|
|
|
|
2008-12-11 17:46:44 +08:00
|
|
|
ppc_pci_set_flags(PPC_PCI_CAN_SKIP_ISA_ALIGN);
|
2007-12-20 11:54:53 +08:00
|
|
|
|
2005-10-10 20:58:41 +08:00
|
|
|
root = of_find_node_by_path("/");
|
|
|
|
if (root == NULL) {
|
2005-10-22 14:02:39 +08:00
|
|
|
printk(KERN_CRIT "pmac_pci_init: can't find root "
|
|
|
|
"of device tree\n");
|
2005-10-10 20:58:41 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
|
|
|
|
if (np->name == NULL)
|
|
|
|
continue;
|
|
|
|
if (strcmp(np->name, "bandit") == 0
|
|
|
|
|| strcmp(np->name, "chaos") == 0
|
|
|
|
|| strcmp(np->name, "pci") == 0) {
|
2007-06-18 07:06:54 +08:00
|
|
|
if (pmac_add_bridge(np) == 0)
|
2005-10-10 20:58:41 +08:00
|
|
|
of_node_get(np);
|
|
|
|
}
|
|
|
|
if (strcmp(np->name, "ht") == 0) {
|
|
|
|
of_node_get(np);
|
|
|
|
ht = np;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
of_node_put(root);
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
#ifdef CONFIG_PPC64
|
2005-10-10 20:58:41 +08:00
|
|
|
/* Probe HT last as it relies on the agp resources to be already
|
|
|
|
* setup
|
|
|
|
*/
|
2007-06-18 07:06:54 +08:00
|
|
|
if (ht && pmac_add_bridge(ht) != 0)
|
2005-10-10 20:58:41 +08:00
|
|
|
of_node_put(ht);
|
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
/* Setup the linkage between OF nodes and PHBs */
|
|
|
|
pci_devs_phb_init();
|
|
|
|
|
|
|
|
/* 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
|
2005-12-14 10:10:10 +08:00
|
|
|
* safe assumptions for now. We should do something better in the
|
|
|
|
* future though
|
2005-10-22 14:02:39 +08:00
|
|
|
*/
|
|
|
|
if (u3_agp) {
|
2007-12-10 11:33:21 +08:00
|
|
|
struct device_node *np = u3_agp->dn;
|
2005-10-22 14:02:39 +08:00
|
|
|
PCI_DN(np)->busno = 0xf0;
|
|
|
|
for (np = np->child; np; np = np->sibling)
|
|
|
|
PCI_DN(np)->busno = 0xf0;
|
|
|
|
}
|
|
|
|
/* pmac_check_ht_link(); */
|
|
|
|
|
2007-12-20 11:54:58 +08:00
|
|
|
/* We can allocate missing resources if any */
|
|
|
|
pci_probe_only = 0;
|
2005-10-22 14:02:39 +08:00
|
|
|
|
|
|
|
#else /* CONFIG_PPC64 */
|
2005-10-10 20:58:41 +08:00
|
|
|
init_p2pbridge();
|
2006-07-03 19:36:01 +08:00
|
|
|
init_second_ohare();
|
2005-10-10 20:58:41 +08:00
|
|
|
fixup_nec_usb2();
|
2005-10-22 14:02:39 +08:00
|
|
|
|
2005-10-10 20:58:41 +08:00
|
|
|
/* We are still having some issues with the Xserve G4, enabling
|
|
|
|
* some offset between bus number and domains for now when we
|
|
|
|
* assign all busses should help for now
|
|
|
|
*/
|
2008-12-11 17:46:44 +08:00
|
|
|
if (ppc_pci_has_flag(PPC_PCI_REASSIGN_ALL_BUS))
|
2005-10-10 20:58:41 +08:00
|
|
|
pcibios_assign_bus_offset = 0x10;
|
2005-10-22 14:02:39 +08:00
|
|
|
#endif
|
2005-10-10 20:58:41 +08:00
|
|
|
}
|
|
|
|
|
2007-12-20 11:54:57 +08:00
|
|
|
#ifdef CONFIG_PPC32
|
2007-12-20 11:54:57 +08:00
|
|
|
int pmac_pci_enable_device_hook(struct pci_dev *dev)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
struct device_node* node;
|
|
|
|
int updatecfg = 0;
|
|
|
|
int uninorth_child;
|
|
|
|
|
|
|
|
node = pci_device_to_OF_node(dev);
|
|
|
|
|
|
|
|
/* We don't want to enable USB controllers absent from the OF tree
|
|
|
|
* (iBook second controller)
|
|
|
|
*/
|
|
|
|
if (dev->vendor == PCI_VENDOR_ID_APPLE
|
2006-04-10 02:07:35 +08:00
|
|
|
&& dev->class == PCI_CLASS_SERIAL_USB_OHCI
|
2005-09-26 14:04:21 +08:00
|
|
|
&& !node) {
|
|
|
|
printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n",
|
|
|
|
pci_name(dev));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!node)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uninorth_child = node->parent &&
|
2007-05-03 15:26:52 +08:00
|
|
|
of_device_is_compatible(node->parent, "uni-north");
|
2005-10-22 14:02:39 +08:00
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
/* Firewire & GMAC were disabled after PCI probe, the driver is
|
|
|
|
* claiming them, we must re-enable them now.
|
|
|
|
*/
|
|
|
|
if (uninorth_child && !strcmp(node->name, "firewire") &&
|
2007-05-03 15:26:52 +08:00
|
|
|
(of_device_is_compatible(node, "pci106b,18") ||
|
|
|
|
of_device_is_compatible(node, "pci106b,30") ||
|
|
|
|
of_device_is_compatible(node, "pci11c1,5811"))) {
|
2005-09-26 14:04:21 +08:00
|
|
|
pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
|
|
|
|
pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
|
|
|
|
updatecfg = 1;
|
|
|
|
}
|
|
|
|
if (uninorth_child && !strcmp(node->name, "ethernet") &&
|
2007-05-03 15:26:52 +08:00
|
|
|
of_device_is_compatible(node, "gmac")) {
|
2005-09-26 14:04:21 +08:00
|
|
|
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
|
|
|
|
updatecfg = 1;
|
|
|
|
}
|
|
|
|
|
2007-12-20 11:54:57 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-09-26 14:04:21 +08:00
|
|
|
if (updatecfg) {
|
|
|
|
u16 cmd;
|
2005-10-22 14:02:39 +08:00
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
2005-10-22 14:02:39 +08:00
|
|
|
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);
|
2007-12-20 11:54:57 +08:00
|
|
|
|
2005-10-22 14:02:39 +08:00
|
|
|
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
|
|
|
|
L1_CACHE_BYTES >> 2);
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-20 11:54:57 +08:00
|
|
|
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);
|
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
/* We power down some devices after they have been probed. They'll
|
|
|
|
* be powered back on later on
|
|
|
|
*/
|
2005-10-22 14:02:39 +08:00
|
|
|
void __init pmac_pcibios_after_init(void)
|
2005-09-26 14:04:21 +08:00
|
|
|
{
|
|
|
|
struct device_node* nd;
|
|
|
|
|
2007-04-24 11:53:04 +08:00
|
|
|
for_each_node_by_name(nd, "firewire") {
|
2007-05-03 15:26:52 +08:00
|
|
|
if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") ||
|
|
|
|
of_device_is_compatible(nd, "pci106b,30") ||
|
|
|
|
of_device_is_compatible(nd, "pci11c1,5811"))
|
|
|
|
&& of_device_is_compatible(nd->parent, "uni-north")) {
|
2005-09-26 14:04:21 +08:00
|
|
|
pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
|
|
|
|
pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
2007-04-24 11:53:04 +08:00
|
|
|
for_each_node_by_name(nd, "ethernet") {
|
2007-05-03 15:26:52 +08:00
|
|
|
if (nd->parent && of_device_is_compatible(nd, "gmac")
|
|
|
|
&& of_device_is_compatible(nd->parent, "uni-north"))
|
2005-09-26 14:04:21 +08:00
|
|
|
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pmac_pci_fixup_cardbus(struct pci_dev* dev)
|
|
|
|
{
|
2006-03-28 20:15:54 +08:00
|
|
|
if (!machine_is(powermac))
|
2005-09-26 14:04:21 +08:00
|
|
|
return;
|
|
|
|
/*
|
|
|
|
* Fix the interrupt routing on the various cardbus bridges
|
|
|
|
* used on powerbooks
|
|
|
|
*/
|
|
|
|
if (dev->vendor != PCI_VENDOR_ID_TI)
|
|
|
|
return;
|
|
|
|
if (dev->device == PCI_DEVICE_ID_TI_1130 ||
|
|
|
|
dev->device == PCI_DEVICE_ID_TI_1131) {
|
|
|
|
u8 val;
|
2005-10-22 14:02:39 +08:00
|
|
|
/* Enable PCI interrupt */
|
2005-09-26 14:04:21 +08:00
|
|
|
if (pci_read_config_byte(dev, 0x91, &val) == 0)
|
|
|
|
pci_write_config_byte(dev, 0x91, val | 0x30);
|
|
|
|
/* Disable ISA interrupt mode */
|
|
|
|
if (pci_read_config_byte(dev, 0x92, &val) == 0)
|
|
|
|
pci_write_config_byte(dev, 0x92, val & ~0x06);
|
|
|
|
}
|
|
|
|
if (dev->device == PCI_DEVICE_ID_TI_1210 ||
|
|
|
|
dev->device == PCI_DEVICE_ID_TI_1211 ||
|
|
|
|
dev->device == PCI_DEVICE_ID_TI_1410 ||
|
|
|
|
dev->device == PCI_DEVICE_ID_TI_1510) {
|
|
|
|
u8 val;
|
|
|
|
/* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
|
|
|
|
signal out the MFUNC0 pin */
|
|
|
|
if (pci_read_config_byte(dev, 0x8c, &val) == 0)
|
|
|
|
pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
|
|
|
|
/* Disable ISA interrupt mode */
|
|
|
|
if (pci_read_config_byte(dev, 0x92, &val) == 0)
|
|
|
|
pci_write_config_byte(dev, 0x92, val & ~0x06);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus);
|
|
|
|
|
|
|
|
void pmac_pci_fixup_pciata(struct pci_dev* dev)
|
|
|
|
{
|
|
|
|
u8 progif = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On PowerMacs, we try to switch any PCI ATA controller to
|
|
|
|
* fully native mode
|
|
|
|
*/
|
2006-03-28 20:15:54 +08:00
|
|
|
if (!machine_is(powermac))
|
2005-09-26 14:04:21 +08:00
|
|
|
return;
|
2006-03-28 20:15:54 +08:00
|
|
|
|
2005-09-26 14:04:21 +08:00
|
|
|
/* Some controllers don't have the class IDE */
|
|
|
|
if (dev->vendor == PCI_VENDOR_ID_PROMISE)
|
|
|
|
switch(dev->device) {
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20246:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20262:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20263:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20265:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20267:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20268:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20269:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20270:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20271:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20275:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20276:
|
|
|
|
case PCI_DEVICE_ID_PROMISE_20277:
|
|
|
|
goto good;
|
|
|
|
}
|
|
|
|
/* Others, check PCI class */
|
|
|
|
if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
|
|
|
|
return;
|
|
|
|
good:
|
|
|
|
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
|
|
|
|
if ((progif & 5) != 5) {
|
2007-12-10 12:29:22 +08:00
|
|
|
printk(KERN_INFO "PCI: %s Forcing PCI IDE into native mode\n",
|
2005-12-14 10:10:10 +08:00
|
|
|
pci_name(dev));
|
2005-09-26 14:04:21 +08:00
|
|
|
(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
|
|
|
|
if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
|
|
|
|
(progif & 5) != 5)
|
|
|
|
printk(KERN_ERR "Rewrite of PROGIF failed !\n");
|
2007-12-10 12:29:22 +08:00
|
|
|
else {
|
|
|
|
/* Clear IO BARs, they will be reassigned */
|
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);
|
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
|
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, 0);
|
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, 0);
|
|
|
|
}
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
}
|
2007-12-10 12:29:22 +08:00
|
|
|
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
|
2007-12-20 11:54:57 +08:00
|
|
|
#endif /* CONFIG_PPC32 */
|
2005-09-26 14:04:21 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable second function on K2-SATA, it's broken
|
|
|
|
* and disable IO BARs on first one
|
|
|
|
*/
|
|
|
|
static void fixup_k2_sata(struct pci_dev* dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
u16 cmd;
|
|
|
|
|
|
|
|
if (PCI_FUNC(dev->devfn) > 0) {
|
|
|
|
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
|
|
|
cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
|
|
|
|
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
dev->resource[i].start = dev->resource[i].end = 0;
|
|
|
|
dev->resource[i].flags = 0;
|
2005-12-14 10:10:10 +08:00
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
|
|
|
|
0);
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
|
|
|
cmd &= ~PCI_COMMAND_IO;
|
|
|
|
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
|
|
dev->resource[i].start = dev->resource[i].end = 0;
|
|
|
|
dev->resource[i].flags = 0;
|
2005-12-14 10:10:10 +08:00
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i,
|
|
|
|
0);
|
2005-09-26 14:04:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata);
|
|
|
|
|
2009-09-01 05:34:36 +08:00
|
|
|
/*
|
|
|
|
* On U4 (aka CPC945) the PCIe root complex "P2P" bridge resource ranges aren't
|
|
|
|
* configured by the firmware. The bridge itself seems to ignore them but it
|
|
|
|
* causes problems with Linux which then re-assigns devices below the bridge,
|
|
|
|
* thus changing addresses of those devices from what was in the device-tree,
|
|
|
|
* which sucks when those are video cards using offb
|
|
|
|
*
|
|
|
|
* We could just mark it transparent but I prefer fixing up the resources to
|
|
|
|
* properly show what's going on here, as I have some doubts about having them
|
|
|
|
* badly configured potentially being an issue for DMA.
|
|
|
|
*
|
|
|
|
* We leave PIO alone, it seems to be fine
|
|
|
|
*
|
|
|
|
* Oh and there's another funny bug. The OF properties advertize the region
|
|
|
|
* 0xf1000000..0xf1ffffff as being forwarded as memory space. But that's
|
|
|
|
* actually not true, this region is the memory mapped config space. So we
|
|
|
|
* also need to filter it out or we'll map things in the wrong place.
|
|
|
|
*/
|
|
|
|
static void fixup_u4_pcie(struct pci_dev* dev)
|
|
|
|
{
|
|
|
|
struct pci_controller *host = pci_bus_to_host(dev->bus);
|
|
|
|
struct resource *region = NULL;
|
|
|
|
u32 reg;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Only do that on PowerMac */
|
|
|
|
if (!machine_is(powermac))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Find the largest MMIO region */
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
struct resource *r = &host->mem_resources[i];
|
|
|
|
if (!(r->flags & IORESOURCE_MEM))
|
|
|
|
continue;
|
|
|
|
/* Skip the 0xf0xxxxxx..f2xxxxxx regions, we know they
|
|
|
|
* are reserved by HW for other things
|
|
|
|
*/
|
|
|
|
if (r->start >= 0xf0000000 && r->start < 0xf3000000)
|
|
|
|
continue;
|
|
|
|
if (!region || (r->end - r->start) >
|
|
|
|
(region->end - region->start))
|
|
|
|
region = r;
|
|
|
|
}
|
|
|
|
/* Nothing found, bail */
|
|
|
|
if (region == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Print things out */
|
|
|
|
printk(KERN_INFO "PCI: Fixup U4 PCIe bridge range: %pR\n", region);
|
|
|
|
|
|
|
|
/* Fixup bridge config space. We know it's a Mac, resource aren't
|
|
|
|
* offset so let's just blast them as-is. We also know that they
|
|
|
|
* fit in 32 bits
|
|
|
|
*/
|
|
|
|
reg = ((region->start >> 16) & 0xfff0) | (region->end & 0xfff00000);
|
|
|
|
pci_write_config_dword(dev, PCI_MEMORY_BASE, reg);
|
|
|
|
pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0);
|
|
|
|
pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
|
|
|
|
pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0);
|
|
|
|
}
|
|
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_U4_PCIE, fixup_u4_pcie);
|