1 /* 2 * PCIMT specific code 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file "COPYING" in the main directory of this archive 6 * for more details. 7 * 8 * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) 9 * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 10 */ 11 12 #include <linux/init.h> 13 #include <linux/interrupt.h> 14 #include <linux/irq.h> 15 #include <linux/pci.h> 16 #include <linux/serial_8250.h> 17 18 #include <asm/sni.h> 19 #include <asm/time.h> 20 #include <asm/i8259.h> 21 #include <asm/irq_cpu.h> 22 23 #define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF) 24 #define invspace (*(volatile unsigned int *)PCIMT_INVSPACE) 25 26 static void __init sni_pcimt_sc_init(void) 27 { 28 unsigned int scsiz, sc_size; 29 30 scsiz = cacheconf & 7; 31 if (scsiz == 0) { 32 printk("Second level cache is deactivated.\n"); 33 return; 34 } 35 if (scsiz >= 6) { 36 printk("Invalid second level cache size configured, " 37 "deactivating second level cache.\n"); 38 cacheconf = 0; 39 return; 40 } 41 42 sc_size = 128 << scsiz; 43 printk("%dkb second level cache detected, deactivating.\n", sc_size); 44 cacheconf = 0; 45 } 46 47 48 /* 49 * A bit more gossip about the iron we're running on ... 50 */ 51 static inline void sni_pcimt_detect(void) 52 { 53 char boardtype[80]; 54 unsigned char csmsr; 55 char *p = boardtype; 56 unsigned int asic; 57 58 csmsr = *(volatile unsigned char *)PCIMT_CSMSR; 59 60 p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300"); 61 if ((csmsr & 0x80) == 0) 62 p += sprintf(p, ", board revision %s", 63 (csmsr & 0x20) ? "D" : "C"); 64 asic = csmsr & 0x80; 65 asic = (csmsr & 0x08) ? asic : !asic; 66 p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1"); 67 printk("%s.\n", boardtype); 68 } 69 70 #define PORT(_base,_irq) \ 71 { \ 72 .iobase = _base, \ 73 .irq = _irq, \ 74 .uartclk = 1843200, \ 75 .iotype = UPIO_PORT, \ 76 .flags = UPF_BOOT_AUTOCONF, \ 77 } 78 79 static struct plat_serial8250_port pcimt_data[] = { 80 PORT(0x3f8, 4), 81 PORT(0x2f8, 3), 82 { }, 83 }; 84 85 static struct platform_device pcimt_serial8250_device = { 86 .name = "serial8250", 87 .id = PLAT8250_DEV_PLATFORM, 88 .dev = { 89 .platform_data = pcimt_data, 90 }, 91 }; 92 93 static struct resource pcimt_cmos_rsrc[] = { 94 { 95 .start = 0x70, 96 .end = 0x71, 97 .flags = IORESOURCE_IO 98 }, 99 { 100 .start = 8, 101 .end = 8, 102 .flags = IORESOURCE_IRQ 103 } 104 }; 105 106 static struct platform_device pcimt_cmos_device = { 107 .name = "rtc_cmos", 108 .num_resources = ARRAY_SIZE(pcimt_cmos_rsrc), 109 .resource = pcimt_cmos_rsrc 110 }; 111 112 113 static struct resource sni_io_resource = { 114 .start = 0x00000000UL, 115 .end = 0x03bfffffUL, 116 .name = "PCIMT IO MEM", 117 .flags = IORESOURCE_IO, 118 }; 119 120 static struct resource pcimt_io_resources[] = { 121 { 122 .start = 0x00, 123 .end = 0x1f, 124 .name = "dma1", 125 .flags = IORESOURCE_BUSY 126 }, { 127 .start = 0x40, 128 .end = 0x5f, 129 .name = "timer", 130 .flags = IORESOURCE_BUSY 131 }, { 132 .start = 0x60, 133 .end = 0x6f, 134 .name = "keyboard", 135 .flags = IORESOURCE_BUSY 136 }, { 137 .start = 0x80, 138 .end = 0x8f, 139 .name = "dma page reg", 140 .flags = IORESOURCE_BUSY 141 }, { 142 .start = 0xc0, 143 .end = 0xdf, 144 .name = "dma2", 145 .flags = IORESOURCE_BUSY 146 }, { 147 .start = 0xcfc, 148 .end = 0xcff, 149 .name = "PCI config data", 150 .flags = IORESOURCE_BUSY 151 } 152 }; 153 154 static struct resource pcimt_mem_resources[] = { 155 { 156 /* 157 * this region should only be 4 bytes long, 158 * but it's 16MB on all RM300C I've checked 159 */ 160 .start = 0x1a000000, 161 .end = 0x1affffff, 162 .name = "PCI INT ACK", 163 .flags = IORESOURCE_BUSY 164 } 165 }; 166 167 static struct resource sni_mem_resource = { 168 .start = 0x18000000UL, 169 .end = 0x1fbfffffUL, 170 .name = "PCIMT PCI MEM", 171 .flags = IORESOURCE_MEM 172 }; 173 174 static void __init sni_pcimt_resource_init(void) 175 { 176 int i; 177 178 /* request I/O space for devices used on all i[345]86 PCs */ 179 for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++) 180 request_resource(&sni_io_resource, pcimt_io_resources + i); 181 /* request MEM space for devices used on all i[345]86 PCs */ 182 for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++) 183 request_resource(&sni_mem_resource, pcimt_mem_resources + i); 184 } 185 186 extern struct pci_ops sni_pcimt_ops; 187 188 #ifdef CONFIG_PCI 189 static struct pci_controller sni_controller = { 190 .pci_ops = &sni_pcimt_ops, 191 .mem_resource = &sni_mem_resource, 192 .mem_offset = 0x00000000UL, 193 .io_resource = &sni_io_resource, 194 .io_offset = 0x00000000UL, 195 .io_map_base = SNI_PORT_BASE 196 }; 197 #endif 198 199 static void enable_pcimt_irq(struct irq_data *d) 200 { 201 unsigned int mask = 1 << (d->irq - PCIMT_IRQ_INT2); 202 203 *(volatile u8 *) PCIMT_IRQSEL |= mask; 204 } 205 206 void disable_pcimt_irq(struct irq_data *d) 207 { 208 unsigned int mask = ~(1 << (d->irq - PCIMT_IRQ_INT2)); 209 210 *(volatile u8 *) PCIMT_IRQSEL &= mask; 211 } 212 213 static struct irq_chip pcimt_irq_type = { 214 .name = "PCIMT", 215 .irq_mask = disable_pcimt_irq, 216 .irq_unmask = enable_pcimt_irq, 217 }; 218 219 /* 220 * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug 221 * button interrupts. Later ... 222 */ 223 static void pcimt_hwint0(void) 224 { 225 panic("Received int0 but no handler yet ..."); 226 } 227 228 /* 229 * hwint 1 deals with EISA and SCSI interrupts, 230 * 231 * The EISA_INT bit in CSITPEND is high active, all others are low active. 232 */ 233 static void pcimt_hwint1(void) 234 { 235 u8 pend = *(volatile char *)PCIMT_CSITPEND; 236 unsigned long flags; 237 238 if (pend & IT_EISA) { 239 int irq; 240 /* 241 * Note: ASIC PCI's builtin interrupt acknowledge feature is 242 * broken. Using it may result in loss of some or all i8259 243 * interrupts, so don't use PCIMT_INT_ACKNOWLEDGE ... 244 */ 245 irq = i8259_irq(); 246 if (unlikely(irq < 0)) 247 return; 248 249 do_IRQ(irq); 250 } 251 252 if (!(pend & IT_SCSI)) { 253 flags = read_c0_status(); 254 clear_c0_status(ST0_IM); 255 do_IRQ(PCIMT_IRQ_SCSI); 256 write_c0_status(flags); 257 } 258 } 259 260 /* 261 * hwint 3 should deal with the PCI A - D interrupts, 262 */ 263 static void pcimt_hwint3(void) 264 { 265 u8 pend = *(volatile char *)PCIMT_CSITPEND; 266 int irq; 267 268 pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); 269 pend ^= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); 270 clear_c0_status(IE_IRQ3); 271 irq = PCIMT_IRQ_INT2 + ffs(pend) - 1; 272 do_IRQ(irq); 273 set_c0_status(IE_IRQ3); 274 } 275 276 static void sni_pcimt_hwint(void) 277 { 278 u32 pending = read_c0_cause() & read_c0_status(); 279 280 if (pending & C_IRQ5) 281 do_IRQ(MIPS_CPU_IRQ_BASE + 7); 282 else if (pending & C_IRQ4) 283 do_IRQ(MIPS_CPU_IRQ_BASE + 6); 284 else if (pending & C_IRQ3) 285 pcimt_hwint3(); 286 else if (pending & C_IRQ1) 287 pcimt_hwint1(); 288 else if (pending & C_IRQ0) { 289 pcimt_hwint0(); 290 } 291 } 292 293 void __init sni_pcimt_irq_init(void) 294 { 295 int i; 296 297 *(volatile u8 *) PCIMT_IRQSEL = IT_ETH | IT_EISA; 298 mips_cpu_irq_init(); 299 /* Actually we've got more interrupts to handle ... */ 300 for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_SCSI; i++) 301 irq_set_chip_and_handler(i, &pcimt_irq_type, handle_level_irq); 302 sni_hwint = sni_pcimt_hwint; 303 change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3); 304 } 305 306 void __init sni_pcimt_init(void) 307 { 308 sni_pcimt_detect(); 309 sni_pcimt_sc_init(); 310 ioport_resource.end = sni_io_resource.end; 311 #ifdef CONFIG_PCI 312 PCIBIOS_MIN_IO = 0x9000; 313 register_pci_controller(&sni_controller); 314 #endif 315 sni_pcimt_resource_init(); 316 } 317 318 static int __init snirm_pcimt_setup_devinit(void) 319 { 320 switch (sni_brd_type) { 321 case SNI_BRD_PCI_MTOWER: 322 case SNI_BRD_PCI_DESKTOP: 323 case SNI_BRD_PCI_MTOWER_CPLUS: 324 platform_device_register(&pcimt_serial8250_device); 325 platform_device_register(&pcimt_cmos_device); 326 break; 327 } 328 329 return 0; 330 } 331 332 device_initcall(snirm_pcimt_setup_devinit); 333
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.