summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/dec21285.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-27 01:05:20 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-27 01:05:20 +0000
commit546db14ee74118296f425f3b91634fb767d67290 (patch)
tree22b613a3da8d4bf663eec5e155af01b87fdf9094 /arch/arm/kernel/dec21285.c
parent1e25e41c4f5474e14452094492dbc169b800e4c8 (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.c399
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;
+ }
}