diff options
| author | Catalin Marinas <catalin.marinas@com.rmk.(none)> | 2005-06-20 13:51:06 -0400 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-06-20 13:51:06 -0400 |
| commit | c0da085ad2e6b1419b8a7439538f7f15eb5c4777 (patch) | |
| tree | 3694dc0cc57af4e98dae449eeead8f8f421bc2a7 /arch | |
| parent | 038c5b602524b33447008492e932cdd0a1e806c9 (diff) | |
[PATCH] ARM: 2693/1: Add PCI support for Versatile/PB
Patch from Catalin Marinas
This patch adds PCI support for the Versatile PB926 platform.
Signed-off-by: Colin King
Signed-off-by: Catalin Marinas
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/arm/Kconfig | 2 | ||||
| -rw-r--r-- | arch/arm/mach-versatile/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/mach-versatile/core.c | 14 | ||||
| -rw-r--r-- | arch/arm/mach-versatile/pci.c | 360 |
4 files changed, 371 insertions, 6 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index efdb12d73566..ee8a9ad7bbd9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -280,7 +280,7 @@ config ISA_DMA_API | |||
| 280 | default y | 280 | default y |
| 281 | 281 | ||
| 282 | config PCI | 282 | config PCI |
| 283 | bool "PCI support" if ARCH_INTEGRATOR_AP | 283 | bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB |
| 284 | help | 284 | help |
| 285 | Find out whether you have a PCI motherboard. PCI is the name of a | 285 | Find out whether you have a PCI motherboard. PCI is the name of a |
| 286 | bus system, i.e. the way the CPU talks to the other stuff inside | 286 | bus system, i.e. the way the CPU talks to the other stuff inside |
diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile index 5d608837757a..ba81e70ed813 100644 --- a/arch/arm/mach-versatile/Makefile +++ b/arch/arm/mach-versatile/Makefile | |||
| @@ -5,3 +5,4 @@ | |||
| 5 | obj-y := core.o clock.o | 5 | obj-y := core.o clock.o |
| 6 | obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o | 6 | obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o |
| 7 | obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o | 7 | obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o |
| 8 | obj-$(CONFIG_PCI) += pci.o | ||
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 302c2a7b9b63..6a7cbea5e098 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
| @@ -196,11 +196,15 @@ static struct map_desc versatile_io_desc[] __initdata = { | |||
| 196 | #ifdef CONFIG_DEBUG_LL | 196 | #ifdef CONFIG_DEBUG_LL |
| 197 | { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, | 197 | { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE }, |
| 198 | #endif | 198 | #endif |
| 199 | #ifdef FIXME | 199 | #ifdef CONFIG_PCI |
| 200 | { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, | 200 | { IO_ADDRESS(VERSATILE_PCI_CORE_BASE), VERSATILE_PCI_CORE_BASE, SZ_4K, MT_DEVICE }, |
| 201 | { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, | 201 | { VERSATILE_PCI_VIRT_BASE, VERSATILE_PCI_BASE, VERSATILE_PCI_BASE_SIZE, MT_DEVICE }, |
| 202 | { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K, MT_DEVICE }, | 202 | { VERSATILE_PCI_CFG_VIRT_BASE, VERSATILE_PCI_CFG_BASE, VERSATILE_PCI_CFG_BASE_SIZE, MT_DEVICE }, |
| 203 | { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }, | 203 | #if 0 |
| 204 | { VERSATILE_PCI_VIRT_MEM_BASE0, VERSATILE_PCI_MEM_BASE0, SZ_16M, MT_DEVICE }, | ||
| 205 | { VERSATILE_PCI_VIRT_MEM_BASE1, VERSATILE_PCI_MEM_BASE1, SZ_16M, MT_DEVICE }, | ||
| 206 | { VERSATILE_PCI_VIRT_MEM_BASE2, VERSATILE_PCI_MEM_BASE2, SZ_16M, MT_DEVICE }, | ||
| 207 | #endif | ||
| 204 | #endif | 208 | #endif |
| 205 | }; | 209 | }; |
| 206 | 210 | ||
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c new file mode 100644 index 000000000000..d1565e851f0e --- /dev/null +++ b/arch/arm/mach-versatile/pci.c | |||
| @@ -0,0 +1,360 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-versatile/pci.c | ||
| 3 | * | ||
| 4 | * (C) Copyright Koninklijke Philips Electronics NV 2004. All rights reserved. | ||
| 5 | * You can redistribute and/or modify this software under the terms of version 2 | ||
| 6 | * of the GNU General Public License as published by the Free Software Foundation. | ||
| 7 | * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | ||
| 8 | * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 9 | * General Public License for more details. | ||
| 10 | * Koninklijke Philips Electronics nor its subsidiaries is obligated to provide any support for this software. | ||
| 11 | * | ||
| 12 | * ARM Versatile PCI driver. | ||
| 13 | * | ||
| 14 | * 14/04/2005 Initial version, colin.king@philips.com | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | #include <linux/config.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/pci.h> | ||
| 20 | #include <linux/ptrace.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/ioport.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/spinlock.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | |||
| 27 | #include <asm/hardware.h> | ||
| 28 | #include <asm/io.h> | ||
| 29 | #include <asm/irq.h> | ||
| 30 | #include <asm/system.h> | ||
| 31 | #include <asm/mach/pci.h> | ||
| 32 | #include <asm/mach-types.h> | ||
| 33 | |||
| 34 | /* | ||
| 35 | * these spaces are mapped using the following base registers: | ||
| 36 | * | ||
| 37 | * Usage Local Bus Memory Base/Map registers used | ||
| 38 | * | ||
| 39 | * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0, non prefetch | ||
| 40 | * Mem 60000000 - 6FFFFFFF LB_BASE1/LB_MAP1, prefetch | ||
| 41 | * IO 44000000 - 4FFFFFFF LB_BASE2/LB_MAP2, IO | ||
| 42 | * Cfg 42000000 - 42FFFFFF PCI config | ||
| 43 | * | ||
| 44 | */ | ||
| 45 | #define SYS_PCICTL IO_ADDRESS(VERSATILE_SYS_PCICTL) | ||
| 46 | #define PCI_IMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0) | ||
| 47 | #define PCI_IMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4) | ||
| 48 | #define PCI_IMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8) | ||
| 49 | #define PCI_SMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10) | ||
| 50 | #define PCI_SMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14) | ||
| 51 | #define PCI_SMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18) | ||
| 52 | #define PCI_SELFID IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc) | ||
| 53 | |||
| 54 | #define DEVICE_ID_OFFSET 0x00 | ||
| 55 | #define CSR_OFFSET 0x04 | ||
| 56 | #define CLASS_ID_OFFSET 0x08 | ||
| 57 | |||
| 58 | #define VP_PCI_DEVICE_ID 0x030010ee | ||
| 59 | #define VP_PCI_CLASS_ID 0x0b400000 | ||
| 60 | |||
| 61 | static unsigned long pci_slot_ignore = 0; | ||
| 62 | |||
| 63 | static int __init versatile_pci_slot_ignore(char *str) | ||
| 64 | { | ||
| 65 | int retval; | ||
| 66 | int slot; | ||
| 67 | |||
| 68 | while ((retval = get_option(&str,&slot))) { | ||
| 69 | if ((slot < 0) || (slot > 31)) { | ||
| 70 | printk("Illegal slot value: %d\n",slot); | ||
| 71 | } else { | ||
| 72 | pci_slot_ignore |= (1 << slot); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | return 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | __setup("pci_slot_ignore=", versatile_pci_slot_ignore); | ||
| 79 | |||
| 80 | |||
| 81 | static unsigned long __pci_addr(struct pci_bus *bus, | ||
| 82 | unsigned int devfn, int offset) | ||
| 83 | { | ||
| 84 | unsigned int busnr = bus->number; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Trap out illegal values | ||
| 88 | */ | ||
| 89 | if (offset > 255) | ||
| 90 | BUG(); | ||
| 91 | if (busnr > 255) | ||
| 92 | BUG(); | ||
| 93 | if (devfn > 255) | ||
| 94 | BUG(); | ||
| 95 | |||
| 96 | return (VERSATILE_PCI_CFG_VIRT_BASE | (busnr << 16) | | ||
| 97 | (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset); | ||
| 98 | } | ||
| 99 | |||
| 100 | static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where, | ||
| 101 | int size, u32 *val) | ||
| 102 | { | ||
| 103 | unsigned long addr = __pci_addr(bus, devfn, where); | ||
| 104 | u32 v; | ||
| 105 | int slot = PCI_SLOT(devfn); | ||
| 106 | |||
| 107 | if (pci_slot_ignore & (1 << slot)) { | ||
| 108 | /* Ignore this slot */ | ||
| 109 | switch (size) { | ||
| 110 | case 1: | ||
| 111 | v = 0xff; | ||
| 112 | break; | ||
| 113 | case 2: | ||
| 114 | v = 0xffff; | ||
| 115 | break; | ||
| 116 | default: | ||
| 117 | v = 0xffffffff; | ||
| 118 | } | ||
| 119 | } else { | ||
| 120 | switch (size) { | ||
| 121 | case 1: | ||
| 122 | addr &= ~3; | ||
| 123 | v = __raw_readb(addr); | ||
| 124 | break; | ||
| 125 | |||
| 126 | case 2: | ||
| 127 | v = __raw_readl(addr & ~3); | ||
| 128 | if (addr & 2) v >>= 16; | ||
| 129 | v &= 0xffff; | ||
| 130 | break; | ||
| 131 | |||
| 132 | default: | ||
| 133 | addr &= ~3; | ||
| 134 | v = __raw_readl(addr); | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | *val = v; | ||
| 140 | return PCIBIOS_SUCCESSFUL; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where, | ||
| 144 | int size, u32 val) | ||
| 145 | { | ||
| 146 | unsigned long addr = __pci_addr(bus, devfn, where); | ||
| 147 | int slot = PCI_SLOT(devfn); | ||
| 148 | |||
| 149 | if (pci_slot_ignore & (1 << slot)) { | ||
| 150 | return PCIBIOS_SUCCESSFUL; | ||
| 151 | } | ||
| 152 | |||
| 153 | switch (size) { | ||
| 154 | case 1: | ||
| 155 | __raw_writeb((u8)val, addr); | ||
| 156 | break; | ||
| 157 | |||
| 158 | case 2: | ||
| 159 | __raw_writew((u16)val, addr); | ||
| 160 | break; | ||
| 161 | |||
| 162 | case 4: | ||
| 163 | __raw_writel(val, addr); | ||
| 164 | break; | ||
| 165 | } | ||
| 166 | |||
| 167 | return PCIBIOS_SUCCESSFUL; | ||
| 168 | } | ||
| 169 | |||
| 170 | static struct pci_ops pci_versatile_ops = { | ||
| 171 | .read = versatile_read_config, | ||
| 172 | .write = versatile_write_config, | ||
| 173 | }; | ||
| 174 | |||
| 175 | static struct resource io_mem = { | ||
| 176 | .name = "PCI I/O space", | ||
| 177 | .start = VERSATILE_PCI_MEM_BASE0, | ||
| 178 | .end = VERSATILE_PCI_MEM_BASE0+VERSATILE_PCI_MEM_BASE0_SIZE-1, | ||
| 179 | .flags = IORESOURCE_IO, | ||
| 180 | }; | ||
| 181 | |||
| 182 | static struct resource non_mem = { | ||
| 183 | .name = "PCI non-prefetchable", | ||
| 184 | .start = VERSATILE_PCI_MEM_BASE1, | ||
| 185 | .end = VERSATILE_PCI_MEM_BASE1+VERSATILE_PCI_MEM_BASE1_SIZE-1, | ||
| 186 | .flags = IORESOURCE_MEM, | ||
| 187 | }; | ||
| 188 | |||
| 189 | static struct resource pre_mem = { | ||
| 190 | .name = "PCI prefetchable", | ||
| 191 | .start = VERSATILE_PCI_MEM_BASE2, | ||
| 192 | .end = VERSATILE_PCI_MEM_BASE2+VERSATILE_PCI_MEM_BASE2_SIZE-1, | ||
| 193 | .flags = IORESOURCE_MEM | IORESOURCE_PREFETCH, | ||
| 194 | }; | ||
| 195 | |||
| 196 | static int __init pci_versatile_setup_resources(struct resource **resource) | ||
| 197 | { | ||
| 198 | int ret = 0; | ||
| 199 | |||
| 200 | ret = request_resource(&iomem_resource, &io_mem); | ||
| 201 | if (ret) { | ||
| 202 | printk(KERN_ERR "PCI: unable to allocate I/O " | ||
| 203 | "memory region (%d)\n", ret); | ||
| 204 | goto out; | ||
| 205 | } | ||
| 206 | ret = request_resource(&iomem_resource, &non_mem); | ||
| 207 | if (ret) { | ||
| 208 | printk(KERN_ERR "PCI: unable to allocate non-prefetchable " | ||
| 209 | "memory region (%d)\n", ret); | ||
| 210 | goto release_io_mem; | ||
| 211 | } | ||
| 212 | ret = request_resource(&iomem_resource, &pre_mem); | ||
| 213 | if (ret) { | ||
| 214 | printk(KERN_ERR "PCI: unable to allocate prefetchable " | ||
| 215 | "memory region (%d)\n", ret); | ||
| 216 | goto release_non_mem; | ||
| 217 | } | ||
| 218 | |||
| 219 | /* | ||
| 220 | * bus->resource[0] is the IO resource for this bus | ||
| 221 | * bus->resource[1] is the mem resource for this bus | ||
| 222 | * bus->resource[2] is the prefetch mem resource for this bus | ||
| 223 | */ | ||
| 224 | resource[0] = &io_mem; | ||
| 225 | resource[1] = &non_mem; | ||
| 226 | resource[2] = &pre_mem; | ||
| 227 | |||
| 228 | goto out; | ||
| 229 | |||
| 230 | release_non_mem: | ||
| 231 | release_resource(&non_mem); | ||
| 232 | release_io_mem: | ||
| 233 | release_resource(&io_mem); | ||
| 234 | out: | ||
| 235 | return ret; | ||
| 236 | } | ||
| 237 | |||
| 238 | int __init pci_versatile_setup(int nr, struct pci_sys_data *sys) | ||
| 239 | { | ||
| 240 | int ret = 0; | ||
| 241 | int i; | ||
| 242 | int myslot = -1; | ||
| 243 | unsigned long val; | ||
| 244 | |||
| 245 | if (nr == 0) { | ||
| 246 | sys->mem_offset = 0; | ||
| 247 | ret = pci_versatile_setup_resources(sys->resource); | ||
| 248 | if (ret < 0) { | ||
| 249 | printk("pci_versatile_setup: resources... oops?\n"); | ||
| 250 | goto out; | ||
| 251 | } | ||
| 252 | } else { | ||
| 253 | printk("pci_versatile_setup: resources... nr == 0??\n"); | ||
| 254 | goto out; | ||
| 255 | } | ||
| 256 | |||
| 257 | __raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28,PCI_IMAP0); | ||
| 258 | __raw_writel(VERSATILE_PCI_MEM_BASE1 >> 28,PCI_IMAP1); | ||
| 259 | __raw_writel(VERSATILE_PCI_MEM_BASE2 >> 28,PCI_IMAP2); | ||
| 260 | |||
| 261 | __raw_writel(1, SYS_PCICTL); | ||
| 262 | |||
| 263 | val = __raw_readl(SYS_PCICTL); | ||
| 264 | if (!(val & 1)) { | ||
| 265 | printk("Not plugged into PCI backplane!\n"); | ||
| 266 | ret = -EIO; | ||
| 267 | goto out; | ||
| 268 | } | ||
| 269 | |||
| 270 | /* | ||
| 271 | * We need to discover the PCI core first to configure itself | ||
| 272 | * before the main PCI probing is performed | ||
| 273 | */ | ||
| 274 | for (i=0; i<32; i++) { | ||
| 275 | if ((__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+DEVICE_ID_OFFSET) == VP_PCI_DEVICE_ID) && | ||
| 276 | (__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+CLASS_ID_OFFSET) == VP_PCI_CLASS_ID)) { | ||
| 277 | myslot = i; | ||
| 278 | |||
| 279 | __raw_writel(myslot, PCI_SELFID); | ||
| 280 | val = __raw_readl(VERSATILE_PCI_CFG_VIRT_BASE+(myslot<<11)+CSR_OFFSET); | ||
| 281 | val |= (1<<2); | ||
| 282 | __raw_writel(val, VERSATILE_PCI_CFG_VIRT_BASE+(myslot<<11)+CSR_OFFSET); | ||
| 283 | break; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | if (myslot == -1) { | ||
| 288 | printk("Cannot find PCI core!\n"); | ||
| 289 | ret = -EIO; | ||
| 290 | } else { | ||
| 291 | printk("PCI core found (slot %d)\n",myslot); | ||
| 292 | /* Do not to map Versatile FPGA PCI device | ||
| 293 | into memory space as we are short of | ||
| 294 | mappable memory */ | ||
| 295 | pci_slot_ignore |= (1 << myslot); | ||
| 296 | ret = 1; | ||
| 297 | } | ||
| 298 | |||
| 299 | out: | ||
| 300 | return ret; | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
| 304 | struct pci_bus *pci_versatile_scan_bus(int nr, struct pci_sys_data *sys) | ||
| 305 | { | ||
| 306 | return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys); | ||
| 307 | } | ||
| 308 | |||
| 309 | /* | ||
| 310 | * V3_LB_BASE? - local bus address | ||
| 311 | * V3_LB_MAP? - pci bus address | ||
| 312 | */ | ||
| 313 | void __init pci_versatile_preinit(void) | ||
| 314 | { | ||
| 315 | } | ||
| 316 | |||
| 317 | void __init pci_versatile_postinit(void) | ||
| 318 | { | ||
| 319 | } | ||
| 320 | |||
| 321 | |||
| 322 | /* | ||
| 323 | * map the specified device/slot/pin to an IRQ. Different backplanes may need to modify this. | ||
| 324 | */ | ||
| 325 | static int __init versatile_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
| 326 | { | ||
| 327 | int irq; | ||
| 328 | int devslot = PCI_SLOT(dev->devfn); | ||
| 329 | |||
| 330 | /* slot, pin, irq | ||
| 331 | 24 1 27 | ||
| 332 | 25 1 28 untested | ||
| 333 | 26 1 29 | ||
| 334 | 27 1 30 untested | ||
| 335 | */ | ||
| 336 | |||
| 337 | irq = 27 + ((slot + pin + 2) % 3); /* Fudged */ | ||
| 338 | |||
| 339 | printk("map irq: slot %d, pin %d, devslot %d, irq: %d\n",slot,pin,devslot,irq); | ||
| 340 | |||
| 341 | return irq; | ||
| 342 | } | ||
| 343 | |||
| 344 | static struct hw_pci versatile_pci __initdata = { | ||
| 345 | .swizzle = NULL, | ||
| 346 | .map_irq = versatile_map_irq, | ||
| 347 | .nr_controllers = 1, | ||
| 348 | .setup = pci_versatile_setup, | ||
| 349 | .scan = pci_versatile_scan_bus, | ||
| 350 | .preinit = pci_versatile_preinit, | ||
| 351 | .postinit = pci_versatile_postinit, | ||
| 352 | }; | ||
| 353 | |||
| 354 | static int __init versatile_pci_init(void) | ||
| 355 | { | ||
| 356 | pci_common_init(&versatile_pci); | ||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | subsys_initcall(versatile_pci_init); | ||
