diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
commit | 03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch) | |
tree | 88db8dba75ae06ba3bad08e42c5e52efc162535c /arch/arm/kernel/dec21285.c | |
parent | 257730f99381dd26e10b832fce4c94cae7ac1176 (diff) |
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'arch/arm/kernel/dec21285.c')
-rw-r--r-- | arch/arm/kernel/dec21285.c | 161 |
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)) |