]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - arch/arm/mach-versatile/pci.c
ARM: PCI: versatile: Fix map_irq function to match hardware
[linux-3.10.git] / arch / arm / mach-versatile / pci.c
index 722fbabc9cfb21b1a9bcf563412bd9bdf8a47009..234740d9038584bdbb087a8ef13ea040a5ac591b 100644 (file)
  * 14/04/2005 Initial version, colin.king@philips.com
  *
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/hardware.h>
-#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/mach/pci.h>
 
 /*
  * Cfg   42000000 - 42FFFFFF     PCI config
  *
  */
-#define SYS_PCICTL                     IO_ADDRESS(VERSATILE_SYS_PCICTL)
-#define PCI_IMAP0                      IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
-#define PCI_IMAP1                      IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
-#define PCI_IMAP2                      IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
-#define PCI_SMAP0                      IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
-#define PCI_SMAP1                      IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
-#define PCI_SMAP2                      IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
-#define PCI_SELFID                     IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
+#define __IO_ADDRESS(n) ((void __iomem *)(unsigned long)IO_ADDRESS(n))
+#define SYS_PCICTL             __IO_ADDRESS(VERSATILE_SYS_PCICTL)
+#define PCI_IMAP0              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
+#define PCI_IMAP1              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
+#define PCI_IMAP2              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
+#define PCI_SMAP0              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
+#define PCI_SMAP1              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
+#define PCI_SMAP2              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
+#define PCI_SELFID             __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
 
 #define DEVICE_ID_OFFSET               0x00
 #define CSR_OFFSET                     0x04
@@ -77,7 +75,7 @@ static int __init versatile_pci_slot_ignore(char *str)
 __setup("pci_slot_ignore=", versatile_pci_slot_ignore);
 
 
-static unsigned long __pci_addr(struct pci_bus *bus,
+static void __iomem *__pci_addr(struct pci_bus *bus,
                                unsigned int devfn, int offset)
 {
        unsigned int busnr = bus->number;
@@ -92,14 +90,14 @@ static unsigned long __pci_addr(struct pci_bus *bus,
        if (devfn > 255)
                BUG();
 
-       return (VERSATILE_PCI_CFG_VIRT_BASE | (busnr << 16) |
+       return VERSATILE_PCI_CFG_VIRT_BASE + ((busnr << 16) |
                (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset);
 }
 
 static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where,
                                 int size, u32 *val)
 {
-       unsigned long addr = __pci_addr(bus, devfn, where);
+       void __iomem *addr = __pci_addr(bus, devfn, where & ~3);
        u32 v;
        int slot = PCI_SLOT(devfn);
 
@@ -118,18 +116,19 @@ static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int wh
        } else {
                switch (size) {
                case 1:
-                       addr &= ~3;
-                       v = __raw_readb(addr);
+                       v = __raw_readl(addr);
+                       if (where & 2) v >>= 16;
+                       if (where & 1) v >>= 8;
+                       v &= 0xff;
                        break;
 
                case 2:
-                       v = __raw_readl(addr & ~3);
-                       if (addr & 2) v >>= 16;
+                       v = __raw_readl(addr);
+                       if (where & 2) v >>= 16;
                        v &= 0xffff;
                        break;
 
                default:
-                       addr &= ~3;
                        v = __raw_readl(addr);
                        break;
                }
@@ -142,7 +141,7 @@ static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int wh
 static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where,
                                  int size, u32 val)
 {
-       unsigned long addr = __pci_addr(bus, devfn, where);
+       void __iomem *addr = __pci_addr(bus, devfn, where);
        int slot = PCI_SLOT(devfn);
 
        if (pci_slot_ignore & (1 << slot)) {
@@ -175,7 +174,7 @@ static struct resource io_mem = {
        .name   = "PCI I/O space",
        .start  = VERSATILE_PCI_MEM_BASE0,
        .end    = VERSATILE_PCI_MEM_BASE0+VERSATILE_PCI_MEM_BASE0_SIZE-1,
-       .flags  = IORESOURCE_IO,
+       .flags  = IORESOURCE_MEM,
 };
 
 static struct resource non_mem = {
@@ -192,7 +191,7 @@ static struct resource pre_mem = {
        .flags  = IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
-static int __init pci_versatile_setup_resources(struct resource **resource)
+static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
 {
        int ret = 0;
 
@@ -216,13 +215,11 @@ static int __init pci_versatile_setup_resources(struct resource **resource)
        }
 
        /*
-        * bus->resource[0] is the IO resource for this bus
-        * bus->resource[1] is the mem resource for this bus
-        * bus->resource[2] is the prefetch mem resource for this bus
+        * the mem resource for this bus
+        * the prefetch mem resource for this bus
         */
-       resource[0] = &io_mem;
-       resource[1] = &non_mem;
-       resource[2] = &pre_mem;
+       pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
        goto out;
 
@@ -249,9 +246,12 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
                goto out;
        }
 
+       ret = pci_ioremap_io(0, VERSATILE_PCI_MEM_BASE0);
+       if (ret)
+               goto out;
+
        if (nr == 0) {
-               sys->mem_offset = 0;
-               ret = pci_versatile_setup_resources(sys->resource);
+               ret = pci_versatile_setup_resources(sys);
                if (ret < 0) {
                        printk("pci_versatile_setup: resources... oops?\n");
                        goto out;
@@ -281,7 +281,7 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
        printk("PCI core found (slot %d)\n",myslot);
 
        __raw_writel(myslot, PCI_SELFID);
-       local_pci_cfg_base = (void *) VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
+       local_pci_cfg_base = VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
 
        val = __raw_readl(local_pci_cfg_base + CSR_OFFSET);
        val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
@@ -294,6 +294,19 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
        __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1);
        __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2);
 
+       /*
+        * For many years the kernel and QEMU were symbiotically buggy
+        * in that they both assumed the same broken IRQ mapping.
+        * QEMU therefore attempts to auto-detect old broken kernels
+        * so that they still work on newer QEMU as they did on old
+        * QEMU. Since we now use the correct (ie matching-hardware)
+        * IRQ mapping we write a definitely different value to a
+        * PCI_INTERRUPT_LINE register to tell QEMU that we expect
+        * real hardware behaviour and it need not be backwards
+        * compatible for us. This write is harmless on real hardware.
+        */
+       __raw_writel(0, VERSATILE_PCI_VIRT_BASE+PCI_INTERRUPT_LINE);
+
        /*
         * Do not to map Versatile FPGA PCI device into memory space
         */
@@ -305,13 +318,10 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 }
 
 
-struct pci_bus *pci_versatile_scan_bus(int nr, struct pci_sys_data *sys)
-{
-       return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys);
-}
-
 void __init pci_versatile_preinit(void)
 {
+       pcibios_min_mem = 0x50000000;
+
        __raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28, PCI_IMAP0);
        __raw_writel(VERSATILE_PCI_MEM_BASE1 >> 28, PCI_IMAP1);
        __raw_writel(VERSATILE_PCI_MEM_BASE2 >> 28, PCI_IMAP2);
@@ -326,30 +336,26 @@ void __init pci_versatile_preinit(void)
 /*
  * map the specified device/slot/pin to an IRQ.   Different backplanes may need to modify this.
  */
-static int __init versatile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
-       int devslot = PCI_SLOT(dev->devfn);
 
-       /* slot,  pin,  irq
-        *  24     1     27
-        *  25     1     28
-        *  26     1     29
-        *  27     1     30
+       /*
+        * Slot INTA    INTB    INTC    INTD
+        * 31   PCI1    PCI2    PCI3    PCI0
+        * 30   PCI0    PCI1    PCI2    PCI3
+        * 29   PCI3    PCI0    PCI1    PCI2
         */
-       irq = 27 + ((slot + pin - 1) & 3);
-
-       printk("PCI map irq: slot %d, pin %d, devslot %d, irq: %d\n",slot,pin,devslot,irq);
+       irq = IRQ_SIC_PCI0 + ((slot + 2 + pin - 1) & 3);
 
        return irq;
 }
 
 static struct hw_pci versatile_pci __initdata = {
-       .swizzle                = NULL,
        .map_irq                = versatile_map_irq,
        .nr_controllers         = 1,
+       .ops                    = &pci_versatile_ops,
        .setup                  = pci_versatile_setup,
-       .scan                   = pci_versatile_scan_bus,
        .preinit                = pci_versatile_preinit,
 };