summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/dec21285.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
commit03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch)
tree88db8dba75ae06ba3bad08e42c5e52efc162535c /arch/arm/kernel/dec21285.c
parent257730f99381dd26e10b832fce4c94cae7ac1176 (diff)
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'arch/arm/kernel/dec21285.c')
-rw-r--r--arch/arm/kernel/dec21285.c161
1 files changed, 110 insertions, 51 deletions
diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c
index 11ea39e7a..de4861b82 100644
--- a/arch/arm/kernel/dec21285.c
+++ b/arch/arm/kernel/dec21285.c
@@ -1,31 +1,42 @@
/*
* arch/arm/kernel/dec21285.c: PCI functions for DEC 21285
*
- * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998 Russell King, Phil Blundell
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
-int pcibios_present(void)
+#include <asm/system.h>
+
+#define MAX_SLOTS 20
+
+int
+pcibios_present(void)
{
return 1;
}
-static unsigned long pcibios_base_address(unsigned char dev_fn)
+static unsigned long
+pcibios_base_address(unsigned char bus, unsigned char dev_fn)
{
- int slot = PCI_SLOT(dev_fn);
-
- if (slot < 4)
- return 0xf8000000 + (1 << (19 - slot));
- else
- return 0;
+ if (bus == 0) {
+ int slot = PCI_SLOT(dev_fn);
+
+ if (slot < MAX_SLOTS)
+ return 0xf8c00000 + (slot << 11);
+ else
+ return 0;
+ } else {
+ return 0xf9000000 | (bus << 16) | (dev_fn << 8);
+ }
}
-int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned char *val)
+int
+pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned char *val)
{
- unsigned long addr = pcibios_base_address(dev_fn);
+ unsigned long addr = pcibios_base_address(bus, dev_fn);
unsigned char v;
if (addr)
@@ -38,10 +49,11 @@ int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned short *val)
+int
+pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned short *val)
{
- unsigned long addr = pcibios_base_address(dev_fn);
+ unsigned long addr = pcibios_base_address(bus, dev_fn);
unsigned short v;
if (addr)
@@ -54,10 +66,11 @@ int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned int *val)
+int
+pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned int *val)
{
- unsigned long addr = pcibios_base_address(dev_fn);
+ unsigned long addr = pcibios_base_address(bus, dev_fn);
unsigned int v;
if (addr)
@@ -70,10 +83,11 @@ int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned char val)
+int
+pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned char val)
{
- unsigned long addr = pcibios_base_address(dev_fn);
+ unsigned long addr = pcibios_base_address(bus, dev_fn);
if (addr)
__asm__("str%?b %0, [%1, %2]"
@@ -81,10 +95,11 @@ int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned short val)
+int
+pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned short val)
{
- unsigned long addr = pcibios_base_address(dev_fn);
+ unsigned long addr = pcibios_base_address(bus, dev_fn);
if (addr)
__asm__("str%?h %0, [%1, %2]"
@@ -92,10 +107,11 @@ int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned int val)
+int
+pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned int val)
{
- unsigned long addr = pcibios_base_address(dev_fn);
+ unsigned long addr = pcibios_base_address(bus, dev_fn);
if (addr)
__asm__("str%? %0, [%1, %2]"
@@ -103,35 +119,72 @@ int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
-static int irq[] = { 18, 8, 9, 11 };
+static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 };
+static int irqmap_cats[] __initdata = { 18, 8, 9, 11 };
-__initfunc(void pcibios_fixup(void))
+__initfunc(static int ebsa_irqval(struct pci_dev *dev))
{
- struct pci_dev *dev;
unsigned char pin;
- unsigned int cmd;
+
+ pcibios_read_config_byte(dev->bus->number,
+ dev->devfn,
+ PCI_INTERRUPT_PIN,
+ &pin);
+
+ return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
+}
- for (dev = pci_devices; dev; dev = dev->next) {
- pcibios_read_config_byte(dev->bus->number,
- dev->devfn,
- PCI_INTERRUPT_PIN,
- &pin);
+__initfunc(static int cats_irqval(struct pci_dev *dev))
+{
+ if (dev->irq >= 128)
+ return 32 + (dev->irq & 0x1f);
+
+ switch (dev->irq) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return irqmap_cats[dev->irq - 1];
+ case 0:
+ return 0;
+ }
- dev->irq = irq[(PCI_SLOT(dev->devfn) + pin) & 3];
+ printk("PCI: device %02x:%02x has unknown irq line %x\n",
+ dev->bus->number, dev->devfn, dev->irq);
+ return 0;
+}
- pcibios_write_config_byte(dev->bus->number,
- dev->devfn,
- PCI_INTERRUPT_LINE,
- dev->irq);
+__initfunc(void pcibios_fixup(void))
+{
+ struct pci_dev *dev;
+ unsigned char cmd;
- printk("PCI: %02x:%02x [%04x/%04x] pin %d irq %d\n",
+ for (dev = pci_devices; dev; dev = dev->next) {
+ /* sort out the irq mapping for this device */
+ switch (machine_type) {
+ case MACH_TYPE_EBSA285:
+ dev->irq = ebsa_irqval(dev);
+ break;
+ case MACH_TYPE_CATS:
+ dev->irq = cats_irqval(dev);
+ break;
+ }
+ pcibios_write_config_byte(dev->bus->number, dev->devfn,
+ PCI_INTERRUPT_LINE, dev->irq);
+
+ printk(KERN_DEBUG
+ "PCI: %02x:%02x [%04x/%04x] on irq %d\n",
dev->bus->number, dev->devfn,
- dev->vendor, dev->device,
- pin, dev->irq);
-
- /* Turn on bus mastering - boot loader doesn't - perhaps it should! */
- pcibios_read_config_byte(dev->bus->number, dev->devfn, PCI_COMMAND, &cmd);
- pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+ dev->vendor, dev->device, dev->irq);
+
+ /* Turn on bus mastering - boot loader doesn't
+ * - perhaps it should! - dag
+ */
+ pcibios_read_config_byte(dev->bus->number, dev->devfn,
+ PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pcibios_write_config_byte(dev->bus->number, dev->devfn,
+ PCI_COMMAND, cmd);
}
}
@@ -141,10 +194,16 @@ __initfunc(void pcibios_init(void))
rev = *(unsigned char *)0xfe000008;
printk("DEC21285 PCI revision %02X\n", rev);
-}
-__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
-{
+ /*
+ * Map our SDRAM at a known address in PCI space, just in case
+ * the firmware had other ideas. Using a nonzero base is slightly
+ * bizarre but apparently necessary to avoid problems with some
+ * video cards.
+ *
+ * We should really only do this if we are the configuration master.
+ */
+ *((unsigned long *)0xfe000018) = 0x10000000;
}
__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))