| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *	Low-Level PCI Support for the SH7751 | 
|  | 3 | * | 
|  | 4 | *  Dustin McIntire (dustin@sensoria.com) | 
|  | 5 | *	Derived from arch/i386/kernel/pci-*.c which bore the message: | 
|  | 6 | *	(c) 1999--2000 Martin Mares <mj@ucw.cz> | 
|  | 7 | * | 
|  | 8 | *  Ported to the new API by Paul Mundt <lethal@linux-sh.org> | 
|  | 9 | *  With cleanup by Paul van Gool <pvangool@mimotech.com> | 
|  | 10 | * | 
|  | 11 | *  May be copied or modified under the terms of the GNU General Public | 
|  | 12 | *  License.  See linux/COPYING for more information. | 
|  | 13 | * | 
|  | 14 | */ | 
|  | 15 |  | 
|  | 16 | #undef DEBUG | 
|  | 17 |  | 
|  | 18 | #include <linux/config.h> | 
|  | 19 | #include <linux/types.h> | 
|  | 20 | #include <linux/kernel.h> | 
|  | 21 | #include <linux/init.h> | 
|  | 22 | #include <linux/pci.h> | 
|  | 23 | #include <linux/sched.h> | 
|  | 24 | #include <linux/ioport.h> | 
|  | 25 | #include <linux/errno.h> | 
|  | 26 | #include <linux/irq.h> | 
|  | 27 | #include <linux/delay.h> | 
|  | 28 |  | 
|  | 29 | #include <asm/machvec.h> | 
|  | 30 | #include <asm/io.h> | 
|  | 31 | #include "pci-sh7751.h" | 
|  | 32 |  | 
|  | 33 | static unsigned int pci_probe = PCI_PROBE_CONF1; | 
|  | 34 | extern int pci_fixup_pcic(void); | 
|  | 35 |  | 
|  | 36 | void pcibios_fixup_irqs(void) __attribute__ ((weak)); | 
|  | 37 |  | 
|  | 38 | /* | 
|  | 39 | * Direct access to PCI hardware... | 
|  | 40 | */ | 
|  | 41 |  | 
|  | 42 | #define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | 
|  | 43 |  | 
|  | 44 | /* | 
|  | 45 | * Functions for accessing PCI configuration space with type 1 accesses | 
|  | 46 | */ | 
|  | 47 | static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn, | 
|  | 48 | int where, int size, u32 *val) | 
|  | 49 | { | 
|  | 50 | unsigned long flags; | 
|  | 51 | u32 data; | 
|  | 52 |  | 
|  | 53 | /* | 
|  | 54 | * PCIPDR may only be accessed as 32 bit words, | 
|  | 55 | * so we must do byte alignment by hand | 
|  | 56 | */ | 
|  | 57 | local_irq_save(flags); | 
|  | 58 | outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); | 
|  | 59 | data = inl(PCI_REG(SH7751_PCIPDR)); | 
|  | 60 | local_irq_restore(flags); | 
|  | 61 |  | 
|  | 62 | switch (size) { | 
|  | 63 | case 1: | 
|  | 64 | *val = (data >> ((where & 3) << 3)) & 0xff; | 
|  | 65 | break; | 
|  | 66 | case 2: | 
|  | 67 | *val = (data >> ((where & 2) << 3)) & 0xffff; | 
|  | 68 | break; | 
|  | 69 | case 4: | 
|  | 70 | *val = data; | 
|  | 71 | break; | 
|  | 72 | default: | 
|  | 73 | return PCIBIOS_FUNC_NOT_SUPPORTED; | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | return PCIBIOS_SUCCESSFUL; | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | /* | 
|  | 80 | * Since SH7751 only does 32bit access we'll have to do a read, | 
|  | 81 | * mask,write operation. | 
|  | 82 | * We'll allow an odd byte offset, though it should be illegal. | 
|  | 83 | */ | 
|  | 84 | static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn, | 
|  | 85 | int where, int size, u32 val) | 
|  | 86 | { | 
|  | 87 | unsigned long flags; | 
|  | 88 | int shift; | 
|  | 89 | u32 data; | 
|  | 90 |  | 
|  | 91 | local_irq_save(flags); | 
|  | 92 | outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); | 
|  | 93 | data = inl(PCI_REG(SH7751_PCIPDR)); | 
|  | 94 | local_irq_restore(flags); | 
|  | 95 |  | 
|  | 96 | switch (size) { | 
|  | 97 | case 1: | 
|  | 98 | shift = (where & 3) << 3; | 
|  | 99 | data &= ~(0xff << shift); | 
|  | 100 | data |= ((val & 0xff) << shift); | 
|  | 101 | break; | 
|  | 102 | case 2: | 
|  | 103 | shift = (where & 2) << 3; | 
|  | 104 | data &= ~(0xffff << shift); | 
|  | 105 | data |= ((val & 0xffff) << shift); | 
|  | 106 | break; | 
|  | 107 | case 4: | 
|  | 108 | data = val; | 
|  | 109 | break; | 
|  | 110 | default: | 
|  | 111 | return PCIBIOS_FUNC_NOT_SUPPORTED; | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | outl(data, PCI_REG(SH7751_PCIPDR)); | 
|  | 115 |  | 
|  | 116 | return PCIBIOS_SUCCESSFUL; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | #undef CONFIG_CMD | 
|  | 120 |  | 
|  | 121 | struct pci_ops sh7751_pci_ops = { | 
|  | 122 | .read 		= sh7751_pci_read, | 
|  | 123 | .write		= sh7751_pci_write, | 
|  | 124 | }; | 
|  | 125 |  | 
|  | 126 | static int __init pci_check_direct(void) | 
|  | 127 | { | 
|  | 128 | unsigned int tmp, id; | 
|  | 129 |  | 
|  | 130 | /* check for SH7751/SH7751R hardware */ | 
|  | 131 | id = inl(SH7751_PCIREG_BASE+SH7751_PCICONF0); | 
|  | 132 | if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) && | 
|  | 133 | id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) { | 
|  | 134 | pr_debug("PCI: This is not an SH7751(R) (%x)\n", id); | 
|  | 135 | return -ENODEV; | 
|  | 136 | } | 
|  | 137 |  | 
|  | 138 | /* | 
|  | 139 | * Check if configuration works. | 
|  | 140 | */ | 
|  | 141 | if (pci_probe & PCI_PROBE_CONF1) { | 
|  | 142 | tmp = inl (PCI_REG(SH7751_PCIPAR)); | 
|  | 143 | outl (0x80000000, PCI_REG(SH7751_PCIPAR)); | 
|  | 144 | if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) { | 
|  | 145 | outl (tmp, PCI_REG(SH7751_PCIPAR)); | 
|  | 146 | printk(KERN_INFO "PCI: Using configuration type 1\n"); | 
|  | 147 | request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1"); | 
|  | 148 | return 0; | 
|  | 149 | } | 
|  | 150 | outl (tmp, PCI_REG(SH7751_PCIPAR)); | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | pr_debug("PCI: pci_check_direct failed\n"); | 
|  | 154 | return -EINVAL; | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | /***************************************************************************************/ | 
|  | 158 |  | 
|  | 159 | /* | 
|  | 160 | *  Handle bus scanning and fixups .... | 
|  | 161 | */ | 
|  | 162 |  | 
|  | 163 | static void __init pci_fixup_ide_bases(struct pci_dev *d) | 
|  | 164 | { | 
|  | 165 | int i; | 
|  | 166 |  | 
|  | 167 | /* | 
|  | 168 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | 
|  | 169 | */ | 
|  | 170 | if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) | 
|  | 171 | return; | 
|  | 172 | pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d)); | 
|  | 173 | for(i=0; i<4; i++) { | 
|  | 174 | struct resource *r = &d->resource[i]; | 
|  | 175 | if ((r->start & ~0x80) == 0x374) { | 
|  | 176 | r->start |= 2; | 
|  | 177 | r->end = r->start; | 
|  | 178 | } | 
|  | 179 | } | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); | 
|  | 183 |  | 
|  | 184 | /* | 
|  | 185 | *  Called after each bus is probed, but before its children | 
|  | 186 | *  are examined. | 
|  | 187 | */ | 
|  | 188 |  | 
|  | 189 | void __init pcibios_fixup_bus(struct pci_bus *b) | 
|  | 190 | { | 
|  | 191 | pci_read_bridge_bases(b); | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | /* | 
|  | 195 | * Initialization. Try all known PCI access methods. Note that we support | 
|  | 196 | * using both PCI BIOS and direct access: in such cases, we use I/O ports | 
|  | 197 | * to access config space. | 
|  | 198 | * | 
|  | 199 | * Note that the platform specific initialization (BSC registers, and memory | 
|  | 200 | * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it | 
|  | 201 | * exitst and via the platform defined function pcibios_init_platform(). | 
|  | 202 | * See pci_bigsur.c for implementation; | 
|  | 203 | * | 
|  | 204 | * The BIOS version of the pci functions is not yet implemented but it is left | 
|  | 205 | * in for completeness.  Currently an error will be genereated at compile time. | 
|  | 206 | */ | 
|  | 207 |  | 
|  | 208 | static int __init sh7751_pci_init(void) | 
|  | 209 | { | 
|  | 210 | int ret; | 
|  | 211 |  | 
|  | 212 | pr_debug("PCI: Starting intialization.\n"); | 
|  | 213 | if ((ret = pci_check_direct()) != 0) | 
|  | 214 | return ret; | 
|  | 215 |  | 
|  | 216 | return pcibios_init_platform(); | 
|  | 217 | } | 
|  | 218 |  | 
|  | 219 | subsys_initcall(sh7751_pci_init); | 
|  | 220 |  | 
|  | 221 | static int __init __area_sdram_check(unsigned int area) | 
|  | 222 | { | 
|  | 223 | u32 word; | 
|  | 224 |  | 
|  | 225 | word = inl(SH7751_BCR1); | 
|  | 226 | /* check BCR for SDRAM in area */ | 
|  | 227 | if(((word >> area) & 1) == 0) { | 
|  | 228 | printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n", | 
|  | 229 | area, word); | 
|  | 230 | return 0; | 
|  | 231 | } | 
|  | 232 | outl(word, PCI_REG(SH7751_PCIBCR1)); | 
|  | 233 |  | 
|  | 234 | word = (u16)inw(SH7751_BCR2); | 
|  | 235 | /* check BCR2 for 32bit SDRAM interface*/ | 
|  | 236 | if(((word >> (area << 1)) & 0x3) != 0x3) { | 
|  | 237 | printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n", | 
|  | 238 | area, word); | 
|  | 239 | return 0; | 
|  | 240 | } | 
|  | 241 | outl(word, PCI_REG(SH7751_PCIBCR2)); | 
|  | 242 |  | 
|  | 243 | return 1; | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) | 
|  | 247 | { | 
|  | 248 | u32 reg; | 
|  | 249 | u32 word; | 
|  | 250 |  | 
|  | 251 | /* Set the BCR's to enable PCI access */ | 
|  | 252 | reg = inl(SH7751_BCR1); | 
|  | 253 | reg |= 0x80000; | 
|  | 254 | outl(reg, SH7751_BCR1); | 
|  | 255 |  | 
|  | 256 | /* Turn the clocks back on (not done in reset)*/ | 
|  | 257 | outl(0, PCI_REG(SH7751_PCICLKR)); | 
|  | 258 | /* Clear Powerdown IRQ's (not done in reset) */ | 
|  | 259 | word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0; | 
|  | 260 | outl(word, PCI_REG(SH7751_PCIPINT)); | 
|  | 261 |  | 
|  | 262 | /* | 
|  | 263 | * This code is unused for some boards as it is done in the | 
|  | 264 | * bootloader and doing it here means the MAC addresses loaded | 
|  | 265 | * by the bootloader get lost. | 
|  | 266 | */ | 
|  | 267 | if (!(map->flags & SH7751_PCIC_NO_RESET)) { | 
|  | 268 | /* toggle PCI reset pin */ | 
|  | 269 | word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST; | 
|  | 270 | outl(word,PCI_REG(SH7751_PCICR)); | 
|  | 271 | /* Wait for a long time... not 1 sec. but long enough */ | 
|  | 272 | mdelay(100); | 
|  | 273 | word = SH7751_PCICR_PREFIX; | 
|  | 274 | outl(word,PCI_REG(SH7751_PCICR)); | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | /* set the command/status bits to: | 
|  | 278 | * Wait Cycle Control + Parity Enable + Bus Master + | 
|  | 279 | * Mem space enable | 
|  | 280 | */ | 
|  | 281 | word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | | 
|  | 282 | SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES; | 
|  | 283 | outl(word, PCI_REG(SH7751_PCICONF1)); | 
|  | 284 |  | 
|  | 285 | /* define this host as the host bridge */ | 
|  | 286 | word = SH7751_PCI_HOST_BRIDGE << 24; | 
|  | 287 | outl(word, PCI_REG(SH7751_PCICONF2)); | 
|  | 288 |  | 
|  | 289 | /* Set IO and Mem windows to local address | 
|  | 290 | * Make PCI and local address the same for easy 1 to 1 mapping | 
|  | 291 | * Window0 = map->window0.size @ non-cached area base = SDRAM | 
|  | 292 | * Window1 = map->window1.size @ cached area base = SDRAM | 
|  | 293 | */ | 
|  | 294 | word = map->window0.size - 1; | 
|  | 295 | outl(word, PCI_REG(SH7751_PCILSR0)); | 
|  | 296 | word = map->window1.size - 1; | 
|  | 297 | outl(word, PCI_REG(SH7751_PCILSR1)); | 
|  | 298 | /* Set the values on window 0 PCI config registers */ | 
|  | 299 | word = P2SEGADDR(map->window0.base); | 
|  | 300 | outl(word, PCI_REG(SH7751_PCILAR0)); | 
|  | 301 | outl(word, PCI_REG(SH7751_PCICONF5)); | 
|  | 302 | /* Set the values on window 1 PCI config registers */ | 
|  | 303 | word =  PHYSADDR(map->window1.base); | 
|  | 304 | outl(word, PCI_REG(SH7751_PCILAR1)); | 
|  | 305 | outl(word, PCI_REG(SH7751_PCICONF6)); | 
|  | 306 |  | 
|  | 307 | /* Set the local 16MB PCI memory space window to | 
|  | 308 | * the lowest PCI mapped address | 
|  | 309 | */ | 
|  | 310 | word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK; | 
|  | 311 | PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word); | 
|  | 312 | outl(word , PCI_REG(SH7751_PCIMBR)); | 
|  | 313 |  | 
|  | 314 | /* Map IO space into PCI IO window | 
|  | 315 | * The IO window is 64K-PCIBIOS_MIN_IO in size | 
|  | 316 | * IO addresses will be translated to the | 
|  | 317 | * PCI IO window base address | 
|  | 318 | */ | 
|  | 319 | PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO, | 
|  | 320 | (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO); | 
|  | 321 |  | 
|  | 322 | /* | 
|  | 323 | * XXX: For now, leave this board-specific. In the event we have other | 
|  | 324 | * boards that need to do similar work, this can be wrapped. | 
|  | 325 | */ | 
|  | 326 | #ifdef CONFIG_SH_BIGSUR | 
|  | 327 | bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0); | 
|  | 328 | #endif | 
|  | 329 |  | 
|  | 330 | /* Make sure the MSB's of IO window are set to access PCI space correctly */ | 
|  | 331 | word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK; | 
|  | 332 | PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word); | 
|  | 333 | outl(word, PCI_REG(SH7751_PCIIOBR)); | 
|  | 334 |  | 
|  | 335 | /* Set PCI WCRx, BCRx's, copy from BSC locations */ | 
|  | 336 |  | 
|  | 337 | /* check BCR for SDRAM in specified area */ | 
|  | 338 | switch (map->window0.base) { | 
|  | 339 | case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(0); break; | 
|  | 340 | case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(1); break; | 
|  | 341 | case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(2); break; | 
|  | 342 | case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(3); break; | 
|  | 343 | case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(4); break; | 
|  | 344 | case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break; | 
|  | 345 | case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break; | 
|  | 346 | } | 
|  | 347 |  | 
|  | 348 | if (!word) | 
|  | 349 | return 0; | 
|  | 350 |  | 
|  | 351 | /* configure the wait control registers */ | 
|  | 352 | word = inl(SH7751_WCR1); | 
|  | 353 | outl(word, PCI_REG(SH7751_PCIWCR1)); | 
|  | 354 | word = inl(SH7751_WCR2); | 
|  | 355 | outl(word, PCI_REG(SH7751_PCIWCR2)); | 
|  | 356 | word = inl(SH7751_WCR3); | 
|  | 357 | outl(word, PCI_REG(SH7751_PCIWCR3)); | 
|  | 358 | word = inl(SH7751_MCR); | 
|  | 359 | outl(word, PCI_REG(SH7751_PCIMCR)); | 
|  | 360 |  | 
|  | 361 | /* NOTE: I'm ignoring the PCI error IRQs for now.. | 
|  | 362 | * TODO: add support for the internal error interrupts and | 
|  | 363 | * DMA interrupts... | 
|  | 364 | */ | 
|  | 365 |  | 
|  | 366 | #ifdef CONFIG_SH_RTS7751R2D | 
|  | 367 | pci_fixup_pcic(); | 
|  | 368 | #endif | 
|  | 369 |  | 
|  | 370 | /* SH7751 init done, set central function init complete */ | 
|  | 371 | /* use round robin mode to stop a device starving/overruning */ | 
|  | 372 | word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM; | 
|  | 373 | outl(word,PCI_REG(SH7751_PCICR)); | 
|  | 374 |  | 
|  | 375 | return 1; | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 | char * __init pcibios_setup(char *str) | 
|  | 379 | { | 
|  | 380 | if (!strcmp(str, "off")) { | 
|  | 381 | pci_probe = 0; | 
|  | 382 | return NULL; | 
|  | 383 | } | 
|  | 384 |  | 
|  | 385 | return str; | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | /* | 
|  | 389 | * 	IRQ functions | 
|  | 390 | */ | 
|  | 391 | static u8 __init sh7751_no_swizzle(struct pci_dev *dev, u8 *pin) | 
|  | 392 | { | 
|  | 393 | /* no swizzling */ | 
|  | 394 | return PCI_SLOT(dev->devfn); | 
|  | 395 | } | 
|  | 396 |  | 
|  | 397 | static int sh7751_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) | 
|  | 398 | { | 
|  | 399 | int irq = -1; | 
|  | 400 |  | 
|  | 401 | /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ | 
|  | 402 | irq = pcibios_map_platform_irq(slot,pin); | 
|  | 403 | if( irq < 0 ) { | 
|  | 404 | pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); | 
|  | 405 | return irq; | 
|  | 406 | } | 
|  | 407 |  | 
|  | 408 | pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); | 
|  | 409 |  | 
|  | 410 | return irq; | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | void __init pcibios_fixup_irqs(void) | 
|  | 414 | { | 
|  | 415 | pci_fixup_irqs(sh7751_no_swizzle, sh7751_pci_lookup_irq); | 
|  | 416 | } | 
|  | 417 |  |