diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-01-27 01:05:20 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-01-27 01:05:20 +0000 |
commit | 546db14ee74118296f425f3b91634fb767d67290 (patch) | |
tree | 22b613a3da8d4bf663eec5e155af01b87fdf9094 /arch/arm/kernel/dec21285.c | |
parent | 1e25e41c4f5474e14452094492dbc169b800e4c8 (diff) |
Merge with Linux 2.3.23. The new bootmem stuff has broken various
platforms. At this time I've only verified that IP22 support compiles
and IP27 actually works.
Diffstat (limited to 'arch/arm/kernel/dec21285.c')
-rw-r--r-- | arch/arm/kernel/dec21285.c | 399 |
1 files changed, 238 insertions, 161 deletions
diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c index 6a4988b15..42a9a616f 100644 --- a/arch/arm/kernel/dec21285.c +++ b/arch/arm/kernel/dec21285.c @@ -13,241 +13,318 @@ #include <linux/init.h> #include <linux/ioport.h> +#include <asm/dec21285.h> +#include <asm/io.h> #include <asm/irq.h> #include <asm/system.h> -#include <asm/hardware.h> #define MAX_SLOTS 21 -extern void pcibios_fixup_ebsa285(struct pci_dev *dev); -extern void pcibios_init_ebsa285(void); - -int -pcibios_present(void) -{ - return 1; -} +extern int setup_arm_irq(int, struct irqaction *); +extern void pcibios_report_device_errors(void); +extern int (*pci_irq_fixup)(struct pci_dev *dev); static unsigned long -pcibios_base_address(unsigned char bus, unsigned char dev_fn) +dc21285_base_address(struct pci_dev *dev, int where) { - if (bus == 0) { - int slot = PCI_SLOT(dev_fn); - - if (slot < MAX_SLOTS) - return PCICFG0_BASE + 0xc00000 + - (slot << 11) + (PCI_FUNC(dev_fn) << 8); - else - return 0; - } else - return PCICFG1_BASE | (bus << 16) | (dev_fn << 8); + unsigned long addr = 0; + unsigned int devfn = dev->devfn; + + if (dev->bus->number != 0) + addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8); + else if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) + addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); + + return addr; } -int -pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char *val) +static int +dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); - unsigned char v; + unsigned long addr = dc21285_base_address(dev, where); + u8 v; if (addr) - __asm__("ldr%?b %0, [%1, %2]" - : "=r" (v) - : "r" (addr), "r" (where)); + asm("ldr%?b %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); else v = 0xff; - *val = v; + + *value = v; + return PCIBIOS_SUCCESSFUL; } -int -pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short *val) +static int +dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); - unsigned short v; + unsigned long addr = dc21285_base_address(dev, where); + u16 v; if (addr) - __asm__("ldr%?h %0, [%1, %2]" - : "=r" (v) - : "r" (addr), "r" (where)); + asm("ldr%?h %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); else v = 0xffff; - *val = v; + + *value = v; + return PCIBIOS_SUCCESSFUL; } -int -pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int *val) +static int +dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); - unsigned int v; + unsigned long addr = dc21285_base_address(dev, where); + u32 v; if (addr) - __asm__("ldr%? %0, [%1, %2]" - : "=r" (v) - : "r" (addr), "r" (where)); + asm("ldr%? %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); else v = 0xffffffff; - *val = v; + + *value = v; + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char val) +static int +dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); + unsigned long addr = dc21285_base_address(dev, where); if (addr) - __asm__("str%?b %0, [%1, %2]" - : : "r" (val), "r" (addr), "r" (where)); + asm("str%?b %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short val) +static int +dc21285_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); + unsigned long addr = dc21285_base_address(dev, where); if (addr) - __asm__("str%?h %0, [%1, %2]" - : : "r" (val), "r" (addr), "r" (where)); + asm("str%?h %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int val) +static int +dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value) { - unsigned long addr = pcibios_base_address(bus, dev_fn); + unsigned long addr = dc21285_base_address(dev, where); if (addr) - __asm__("str%? %0, [%1, %2]" - : : "r" (val), "r" (addr), "r" (where)); + asm("str%? %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + return PCIBIOS_SUCCESSFUL; } -void __init pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set) +static struct pci_ops dc21285_ops = { + dc21285_read_config_byte, + dc21285_read_config_word, + dc21285_read_config_dword, + dc21285_write_config_byte, + dc21285_write_config_word, + dc21285_write_config_dword, +}; + +/* + * Warn on PCI errors. + */ +static void +dc21285_error(int irq, void *dev_id, struct pt_regs *regs) { - unsigned short cmd; + static unsigned long next_warn; + unsigned long cmd = *CSR_PCICMD & 0x0000ffff; + unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07; + unsigned long irqstatus = *CSR_IRQ_RAWSTATUS; + int warn = time_after_eq(jiffies, next_warn); - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd = (cmd & ~clear) | set; - pci_write_config_word(dev, PCI_COMMAND, cmd); -} + ctrl |= SA110_CNTL_DISCARDTIMER; -void __init pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr) -{ - int reg = PCI_BASE_ADDRESS_0 + (idx << 2); + if (warn) { + next_warn = jiffies + HZ; + printk(KERN_DEBUG "PCI: "); + } - pci_write_config_dword(dev, reg, addr); - pci_read_config_dword(dev, reg, &addr); + if (irqstatus & (1 << 31)) { + if (warn) + printk("parity error "); + cmd |= 1 << 31; + } - dev->base_address[idx] = addr; -} + if (irqstatus & (1 << 30)) { + if (warn) + printk("target abort "); + cmd |= 1 << 28; + } -void __init pcibios_fixup(void) -{ - struct pci_dev *dev; + if (irqstatus & (1 << 29)) { + if (warn) + printk("master abort "); + cmd |= 1 << 29; + } - for (dev = pci_devices; dev; dev = dev->next) { - pcibios_fixup_ebsa285(dev); + if (irqstatus & (1 << 28)) { + if (warn) + printk("data parity error "); + cmd |= 1 << 24; + } - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); + if (irqstatus & (1 << 27)) { + if (warn) + printk("discard timer expired "); + ctrl &= ~SA110_CNTL_DISCARDTIMER; + } - printk(KERN_DEBUG - "PCI: %02x:%02x [%04x/%04x] on irq %d\n", - dev->bus->number, dev->devfn, - dev->vendor, dev->device, dev->irq); + if (irqstatus & (1 << 23)) { + if (warn) + printk("system error "); + ctrl |= SA110_CNTL_RXSERR; } - hw_init(); + if (warn) + printk("pc=[<%08lX>]\n", instruction_pointer(regs)); + + pcibios_report_device_errors(); + + *CSR_PCICMD = cmd; + *CSR_SA110_CNTL = ctrl; } -void __init pcibios_init(void) -{ - unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET; - unsigned long cntl; +static struct irqaction dc21285_error_action = { + dc21285_error, SA_INTERRUPT, 0, "PCI error", NULL, NULL +}; - *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; - *CSR_SDRAMBASEOFFSET = 0; - *CSR_ROMBASEMASK = 0x80000000; - *CSR_CSRBASEMASK = 0; - *CSR_CSRBASEOFFSET = 0; - *CSR_PCIADDR_EXTN = 0; +static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; -#ifdef CONFIG_HOST_FOOTBRIDGE - /* - * Against my better judgement, Philip Blundell still seems - * to be saying that we should initialise the PCI stuff here - * when the PCI_CFN bit is not set, dispite my comment below, - * which he decided to remove. If it is not set, then - * the card is in add-in mode, and we're in a machine where - * the bus is set up by 'others'. - * - * We should therefore not mess about with the mapping in - * anyway, and we should not be using the virt_to_bus functions - * that exist in the HOST architecture mode (since they assume - * a fixed mapping). - * - * Instead, you should be using ADDIN mode, which allows for - * this situation. This does assume that you have correctly - * initialised the PCI bus, which you must have done to get - * your PC booted. - * - * Unfortunately, he seems to be blind to this. I guess he'll - * also remove all this. - * - * And THIS COMMENT STAYS, even if this gets patched, thank - * you. - */ - - /* - * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is - * necessary, since some VGA cards forcefully use PCI addresses - * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). - * - * NOTE! If you need to chec the PCI_CFN bit in the SA110 - * control register then you've configured the kernel wrong. - * If you're not using host mode, then DO NOT set - * CONFIG_HOST_FOOTBRIDGE, but use CONFIG_ADDIN_FOOTBRIDGE - * instead. In this case, you MUST supply some firmware - * to allow your PC to boot, plus we should not modify the - * mappings that the PC BIOS has set up for us. - */ - *CSR_PCICACHELINESIZE = 0x00002008; - *CSR_PCICSRBASE = 0; - *CSR_PCICSRIOBASE = 0; - *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); - *CSR_PCIROMBASE = 0; - *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | - PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | - (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); -#endif +static int __init ebsa_irqval(struct pci_dev *dev) +{ + u8 pin; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - /* - * Clear any existing errors - we aren't - * interested in historical data... - */ - cntl = *CSR_SA110_CNTL & 0xffffde07; - *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; +} - pcibios_init_ebsa285(); +static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; - printk(KERN_DEBUG"PCI: DEC21285 revision %02lX\n", *CSR_CLASSREV & 0xff); +static int __init cats_irqval(struct pci_dev *dev) +{ + if (dev->irq >= 128) + return 16 + (dev->irq & 0x1f); + + switch (dev->irq) { + case 1 ... 4: + return irqmap_cats[dev->irq - 1]; + + default: + printk("PCI: device %02x:%02x has unknown irq line %x\n", + dev->bus->number, dev->devfn, dev->irq); + case 0: + break; + } + return 0; } -void __init pcibios_fixup_bus(struct pci_bus *bus) +static int __init netwinder_irqval(struct pci_dev *dev) { +#define DEV(v,d) ((v)<<16|(d)) + switch (DEV(dev->vendor, dev->device)) { + case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): + return IRQ_NETWINDER_ETHER100; + + case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): + return IRQ_NETWINDER_ETHER10; + + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553): + return 0; + + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105): + return IRQ_ISA_HARDDISK1; + + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): + return IRQ_NETWINDER_VGA; + + default: + printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n", + dev->bus->number, dev->devfn, + dev->vendor, dev->device); + return 0; + } } -char * __init pcibios_setup(char *str) +struct pci_ops * __init dc21285_init(int pass) { - return str; + unsigned int mem_size; + unsigned long cntl; + + if (pass == 0) { + mem_size = (unsigned int)high_memory - PAGE_OFFSET; + *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; + *CSR_SDRAMBASEOFFSET = 0; + *CSR_ROMBASEMASK = 0x80000000; + *CSR_CSRBASEMASK = 0; + *CSR_CSRBASEOFFSET = 0; + *CSR_PCIADDR_EXTN = 0; + +#ifdef CONFIG_HOST_FOOTBRIDGE + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). + */ + *CSR_PCICACHELINESIZE = 0x00002008; + *CSR_PCICSRBASE = 0; + *CSR_PCICSRIOBASE = 0; + *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | + PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | + (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); +#endif + + printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n", + *CSR_CLASSREV & 0xff); + + switch (machine_arch_type) { + case MACH_TYPE_EBSA285: + pci_irq_fixup = ebsa_irqval; + break; + + case MACH_TYPE_CATS: + pci_irq_fixup = cats_irqval; + break; + + case MACH_TYPE_NETWINDER: + pci_irq_fixup = netwinder_irqval; + break; + } + + return &dc21285_ops; + } else { + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + cntl = *CSR_SA110_CNTL & 0xffffde07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + cntl = *CSR_PCICMD & 0x0000ffff; + *CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; + + /* + * Initialise PCI error IRQ after we've finished probing + */ + setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action); + + return NULL; + } } |