1c066a32aSThomas Bogendoerfer /* 2c066a32aSThomas Bogendoerfer * PCI Tower specific code 3c066a32aSThomas Bogendoerfer * 4c066a32aSThomas Bogendoerfer * This file is subject to the terms and conditions of the GNU General Public 5c066a32aSThomas Bogendoerfer * License. See the file "COPYING" in the main directory of this archive 6c066a32aSThomas Bogendoerfer * for more details. 7c066a32aSThomas Bogendoerfer * 8c066a32aSThomas Bogendoerfer * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 9c066a32aSThomas Bogendoerfer */ 10c066a32aSThomas Bogendoerfer 11c066a32aSThomas Bogendoerfer #include <linux/init.h> 12c066a32aSThomas Bogendoerfer #include <linux/interrupt.h> 13ca4d3e67SDavid Howells #include <linux/irq.h> 14c066a32aSThomas Bogendoerfer #include <linux/pci.h> 15c066a32aSThomas Bogendoerfer #include <linux/serial_8250.h> 16c066a32aSThomas Bogendoerfer 17c066a32aSThomas Bogendoerfer #include <asm/sni.h> 18c066a32aSThomas Bogendoerfer #include <asm/time.h> 19c066a32aSThomas Bogendoerfer #include <asm/irq_cpu.h> 20c066a32aSThomas Bogendoerfer 21c066a32aSThomas Bogendoerfer 22c066a32aSThomas Bogendoerfer #define PORT(_base,_irq) \ 23c066a32aSThomas Bogendoerfer { \ 24c066a32aSThomas Bogendoerfer .iobase = _base, \ 25c066a32aSThomas Bogendoerfer .irq = _irq, \ 26c066a32aSThomas Bogendoerfer .uartclk = 1843200, \ 27c066a32aSThomas Bogendoerfer .iotype = UPIO_PORT, \ 28c066a32aSThomas Bogendoerfer .flags = UPF_BOOT_AUTOCONF, \ 29c066a32aSThomas Bogendoerfer } 30c066a32aSThomas Bogendoerfer 31c066a32aSThomas Bogendoerfer static struct plat_serial8250_port pcit_data[] = { 32c066a32aSThomas Bogendoerfer PORT(0x3f8, 0), 33c066a32aSThomas Bogendoerfer PORT(0x2f8, 3), 34c066a32aSThomas Bogendoerfer { }, 35c066a32aSThomas Bogendoerfer }; 36c066a32aSThomas Bogendoerfer 37c066a32aSThomas Bogendoerfer static struct platform_device pcit_serial8250_device = { 38c066a32aSThomas Bogendoerfer .name = "serial8250", 39c066a32aSThomas Bogendoerfer .id = PLAT8250_DEV_PLATFORM, 40c066a32aSThomas Bogendoerfer .dev = { 41c066a32aSThomas Bogendoerfer .platform_data = pcit_data, 42c066a32aSThomas Bogendoerfer }, 43c066a32aSThomas Bogendoerfer }; 44c066a32aSThomas Bogendoerfer 45c066a32aSThomas Bogendoerfer static struct plat_serial8250_port pcit_cplus_data[] = { 46bea77175SThomas Bogendoerfer PORT(0x3f8, 0), 47c066a32aSThomas Bogendoerfer PORT(0x2f8, 3), 48c066a32aSThomas Bogendoerfer PORT(0x3e8, 4), 49c066a32aSThomas Bogendoerfer PORT(0x2e8, 3), 50c066a32aSThomas Bogendoerfer { }, 51c066a32aSThomas Bogendoerfer }; 52c066a32aSThomas Bogendoerfer 53c066a32aSThomas Bogendoerfer static struct platform_device pcit_cplus_serial8250_device = { 54c066a32aSThomas Bogendoerfer .name = "serial8250", 55c066a32aSThomas Bogendoerfer .id = PLAT8250_DEV_PLATFORM, 56c066a32aSThomas Bogendoerfer .dev = { 57c066a32aSThomas Bogendoerfer .platform_data = pcit_cplus_data, 58c066a32aSThomas Bogendoerfer }, 59c066a32aSThomas Bogendoerfer }; 60c066a32aSThomas Bogendoerfer 6106cf5583SThomas Bogendoerfer static struct resource pcit_cmos_rsrc[] = { 6206cf5583SThomas Bogendoerfer { 6306cf5583SThomas Bogendoerfer .start = 0x70, 6406cf5583SThomas Bogendoerfer .end = 0x71, 6506cf5583SThomas Bogendoerfer .flags = IORESOURCE_IO 6606cf5583SThomas Bogendoerfer }, 6706cf5583SThomas Bogendoerfer { 6806cf5583SThomas Bogendoerfer .start = 8, 6906cf5583SThomas Bogendoerfer .end = 8, 7006cf5583SThomas Bogendoerfer .flags = IORESOURCE_IRQ 7106cf5583SThomas Bogendoerfer } 7206cf5583SThomas Bogendoerfer }; 7306cf5583SThomas Bogendoerfer 7406cf5583SThomas Bogendoerfer static struct platform_device pcit_cmos_device = { 7506cf5583SThomas Bogendoerfer .name = "rtc_cmos", 7606cf5583SThomas Bogendoerfer .num_resources = ARRAY_SIZE(pcit_cmos_rsrc), 7706cf5583SThomas Bogendoerfer .resource = pcit_cmos_rsrc 7806cf5583SThomas Bogendoerfer }; 7906cf5583SThomas Bogendoerfer 8019388fb0SRalf Baechle static struct platform_device pcit_pcspeaker_pdev = { 8119388fb0SRalf Baechle .name = "pcspkr", 8219388fb0SRalf Baechle .id = -1, 8319388fb0SRalf Baechle }; 8419388fb0SRalf Baechle 85c066a32aSThomas Bogendoerfer static struct resource sni_io_resource = { 86bea77175SThomas Bogendoerfer .start = 0x00000000UL, 87c066a32aSThomas Bogendoerfer .end = 0x03bfffffUL, 88bea77175SThomas Bogendoerfer .name = "PCIT IO", 89c066a32aSThomas Bogendoerfer .flags = IORESOURCE_IO, 90c066a32aSThomas Bogendoerfer }; 91c066a32aSThomas Bogendoerfer 92c066a32aSThomas Bogendoerfer static struct resource pcit_io_resources[] = { 93c066a32aSThomas Bogendoerfer { 94c066a32aSThomas Bogendoerfer .start = 0x00, 95c066a32aSThomas Bogendoerfer .end = 0x1f, 96c066a32aSThomas Bogendoerfer .name = "dma1", 97c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY 98c066a32aSThomas Bogendoerfer }, { 99c066a32aSThomas Bogendoerfer .start = 0x40, 100c066a32aSThomas Bogendoerfer .end = 0x5f, 101c066a32aSThomas Bogendoerfer .name = "timer", 102c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY 103c066a32aSThomas Bogendoerfer }, { 104c066a32aSThomas Bogendoerfer .start = 0x60, 105c066a32aSThomas Bogendoerfer .end = 0x6f, 106c066a32aSThomas Bogendoerfer .name = "keyboard", 107c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY 108c066a32aSThomas Bogendoerfer }, { 109c066a32aSThomas Bogendoerfer .start = 0x80, 110c066a32aSThomas Bogendoerfer .end = 0x8f, 111c066a32aSThomas Bogendoerfer .name = "dma page reg", 112c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY 113c066a32aSThomas Bogendoerfer }, { 114c066a32aSThomas Bogendoerfer .start = 0xc0, 115c066a32aSThomas Bogendoerfer .end = 0xdf, 116c066a32aSThomas Bogendoerfer .name = "dma2", 117c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY 118c066a32aSThomas Bogendoerfer }, { 119bea77175SThomas Bogendoerfer .start = 0xcf8, 120bea77175SThomas Bogendoerfer .end = 0xcfb, 121bea77175SThomas Bogendoerfer .name = "PCI config addr", 122bea77175SThomas Bogendoerfer .flags = IORESOURCE_BUSY 123bea77175SThomas Bogendoerfer }, { 124c066a32aSThomas Bogendoerfer .start = 0xcfc, 125c066a32aSThomas Bogendoerfer .end = 0xcff, 126c066a32aSThomas Bogendoerfer .name = "PCI config data", 127c066a32aSThomas Bogendoerfer .flags = IORESOURCE_BUSY 128c066a32aSThomas Bogendoerfer } 129c066a32aSThomas Bogendoerfer }; 130c066a32aSThomas Bogendoerfer 131c066a32aSThomas Bogendoerfer static struct resource sni_mem_resource = { 132bea77175SThomas Bogendoerfer .start = 0x18000000UL, 133bea77175SThomas Bogendoerfer .end = 0x1fbfffffUL, 134c066a32aSThomas Bogendoerfer .name = "PCIT PCI MEM", 135c066a32aSThomas Bogendoerfer .flags = IORESOURCE_MEM 136c066a32aSThomas Bogendoerfer }; 137c066a32aSThomas Bogendoerfer 138c066a32aSThomas Bogendoerfer static void __init sni_pcit_resource_init(void) 139c066a32aSThomas Bogendoerfer { 140c066a32aSThomas Bogendoerfer int i; 141c066a32aSThomas Bogendoerfer 142c066a32aSThomas Bogendoerfer /* request I/O space for devices used on all i[345]86 PCs */ 143c066a32aSThomas Bogendoerfer for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++) 144bea77175SThomas Bogendoerfer request_resource(&sni_io_resource, pcit_io_resources + i); 145c066a32aSThomas Bogendoerfer } 146c066a32aSThomas Bogendoerfer 147c066a32aSThomas Bogendoerfer 148c066a32aSThomas Bogendoerfer extern struct pci_ops sni_pcit_ops; 149c066a32aSThomas Bogendoerfer 150c066a32aSThomas Bogendoerfer static struct pci_controller sni_pcit_controller = { 151c066a32aSThomas Bogendoerfer .pci_ops = &sni_pcit_ops, 152c066a32aSThomas Bogendoerfer .mem_resource = &sni_mem_resource, 153bea77175SThomas Bogendoerfer .mem_offset = 0x00000000UL, 154c066a32aSThomas Bogendoerfer .io_resource = &sni_io_resource, 155bea77175SThomas Bogendoerfer .io_offset = 0x00000000UL, 156bea77175SThomas Bogendoerfer .io_map_base = SNI_PORT_BASE 157c066a32aSThomas Bogendoerfer }; 158c066a32aSThomas Bogendoerfer 159c066a32aSThomas Bogendoerfer static void enable_pcit_irq(unsigned int irq) 160c066a32aSThomas Bogendoerfer { 161c066a32aSThomas Bogendoerfer u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24); 162c066a32aSThomas Bogendoerfer 163c066a32aSThomas Bogendoerfer *(volatile u32 *)SNI_PCIT_INT_REG |= mask; 164c066a32aSThomas Bogendoerfer } 165c066a32aSThomas Bogendoerfer 166c066a32aSThomas Bogendoerfer void disable_pcit_irq(unsigned int irq) 167c066a32aSThomas Bogendoerfer { 168c066a32aSThomas Bogendoerfer u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24); 169c066a32aSThomas Bogendoerfer 170c066a32aSThomas Bogendoerfer *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask; 171c066a32aSThomas Bogendoerfer } 172c066a32aSThomas Bogendoerfer 173c066a32aSThomas Bogendoerfer void end_pcit_irq(unsigned int irq) 174c066a32aSThomas Bogendoerfer { 175c066a32aSThomas Bogendoerfer if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 176c066a32aSThomas Bogendoerfer enable_pcit_irq(irq); 177c066a32aSThomas Bogendoerfer } 178c066a32aSThomas Bogendoerfer 179c066a32aSThomas Bogendoerfer static struct irq_chip pcit_irq_type = { 1808922f79eSThomas Gleixner .name = "PCIT", 181c066a32aSThomas Bogendoerfer .ack = disable_pcit_irq, 182c066a32aSThomas Bogendoerfer .mask = disable_pcit_irq, 183c066a32aSThomas Bogendoerfer .mask_ack = disable_pcit_irq, 184c066a32aSThomas Bogendoerfer .unmask = enable_pcit_irq, 185c066a32aSThomas Bogendoerfer .end = end_pcit_irq, 186c066a32aSThomas Bogendoerfer }; 187c066a32aSThomas Bogendoerfer 188c066a32aSThomas Bogendoerfer static void pcit_hwint1(void) 189c066a32aSThomas Bogendoerfer { 190c066a32aSThomas Bogendoerfer u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG; 191c066a32aSThomas Bogendoerfer int irq; 192c066a32aSThomas Bogendoerfer 193c066a32aSThomas Bogendoerfer clear_c0_status(IE_IRQ1); 194c066a32aSThomas Bogendoerfer irq = ffs((pending >> 16) & 0x7f); 195c066a32aSThomas Bogendoerfer 196c066a32aSThomas Bogendoerfer if (likely(irq > 0)) 197c066a32aSThomas Bogendoerfer do_IRQ(irq + SNI_PCIT_INT_START - 1); 198c066a32aSThomas Bogendoerfer set_c0_status(IE_IRQ1); 199c066a32aSThomas Bogendoerfer } 200c066a32aSThomas Bogendoerfer 201c066a32aSThomas Bogendoerfer static void pcit_hwint0(void) 202c066a32aSThomas Bogendoerfer { 203c066a32aSThomas Bogendoerfer u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG; 204c066a32aSThomas Bogendoerfer int irq; 205c066a32aSThomas Bogendoerfer 206c066a32aSThomas Bogendoerfer clear_c0_status(IE_IRQ0); 207bea77175SThomas Bogendoerfer irq = ffs((pending >> 16) & 0x3f); 208c066a32aSThomas Bogendoerfer 209c066a32aSThomas Bogendoerfer if (likely(irq > 0)) 210c066a32aSThomas Bogendoerfer do_IRQ(irq + SNI_PCIT_INT_START - 1); 211c066a32aSThomas Bogendoerfer set_c0_status(IE_IRQ0); 212c066a32aSThomas Bogendoerfer } 213c066a32aSThomas Bogendoerfer 214c066a32aSThomas Bogendoerfer static void sni_pcit_hwint(void) 215c066a32aSThomas Bogendoerfer { 216119537c0SThiemo Seufer u32 pending = read_c0_cause() & read_c0_status(); 217c066a32aSThomas Bogendoerfer 218c066a32aSThomas Bogendoerfer if (pending & C_IRQ1) 219c066a32aSThomas Bogendoerfer pcit_hwint1(); 220c066a32aSThomas Bogendoerfer else if (pending & C_IRQ2) 221f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 4); 222c066a32aSThomas Bogendoerfer else if (pending & C_IRQ3) 223f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 5); 224c066a32aSThomas Bogendoerfer else if (pending & C_IRQ5) 225f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 7); 226c066a32aSThomas Bogendoerfer } 227c066a32aSThomas Bogendoerfer 228c066a32aSThomas Bogendoerfer static void sni_pcit_hwint_cplus(void) 229c066a32aSThomas Bogendoerfer { 230119537c0SThiemo Seufer u32 pending = read_c0_cause() & read_c0_status(); 231c066a32aSThomas Bogendoerfer 232c066a32aSThomas Bogendoerfer if (pending & C_IRQ0) 233c066a32aSThomas Bogendoerfer pcit_hwint0(); 234bea77175SThomas Bogendoerfer else if (pending & C_IRQ1) 235bea77175SThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 3); 236c066a32aSThomas Bogendoerfer else if (pending & C_IRQ2) 237f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 4); 238c066a32aSThomas Bogendoerfer else if (pending & C_IRQ3) 239f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 5); 240c066a32aSThomas Bogendoerfer else if (pending & C_IRQ5) 241f13cc01dSThomas Bogendoerfer do_IRQ(MIPS_CPU_IRQ_BASE + 7); 242c066a32aSThomas Bogendoerfer } 243c066a32aSThomas Bogendoerfer 244c066a32aSThomas Bogendoerfer void __init sni_pcit_irq_init(void) 245c066a32aSThomas Bogendoerfer { 246c066a32aSThomas Bogendoerfer int i; 247c066a32aSThomas Bogendoerfer 248c066a32aSThomas Bogendoerfer mips_cpu_irq_init(); 249c066a32aSThomas Bogendoerfer for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++) 250c87e0909SRalf Baechle set_irq_chip_and_handler(i, &pcit_irq_type, handle_level_irq); 251c066a32aSThomas Bogendoerfer *(volatile u32 *)SNI_PCIT_INT_REG = 0; 252c066a32aSThomas Bogendoerfer sni_hwint = sni_pcit_hwint; 253c066a32aSThomas Bogendoerfer change_c0_status(ST0_IM, IE_IRQ1); 254c066a32aSThomas Bogendoerfer setup_irq(SNI_PCIT_INT_START + 6, &sni_isa_irq); 255c066a32aSThomas Bogendoerfer } 256c066a32aSThomas Bogendoerfer 257c066a32aSThomas Bogendoerfer void __init sni_pcit_cplus_irq_init(void) 258c066a32aSThomas Bogendoerfer { 259c066a32aSThomas Bogendoerfer int i; 260c066a32aSThomas Bogendoerfer 261c066a32aSThomas Bogendoerfer mips_cpu_irq_init(); 262c066a32aSThomas Bogendoerfer for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++) 263c87e0909SRalf Baechle set_irq_chip_and_handler(i, &pcit_irq_type, handle_level_irq); 264bea77175SThomas Bogendoerfer *(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000; 265c066a32aSThomas Bogendoerfer sni_hwint = sni_pcit_hwint_cplus; 266c066a32aSThomas Bogendoerfer change_c0_status(ST0_IM, IE_IRQ0); 267bea77175SThomas Bogendoerfer setup_irq(MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq); 268c066a32aSThomas Bogendoerfer } 269c066a32aSThomas Bogendoerfer 27006cf5583SThomas Bogendoerfer void __init sni_pcit_init(void) 271c066a32aSThomas Bogendoerfer { 272bea77175SThomas Bogendoerfer ioport_resource.end = sni_io_resource.end; 273c066a32aSThomas Bogendoerfer #ifdef CONFIG_PCI 274bea77175SThomas Bogendoerfer PCIBIOS_MIN_IO = 0x9000; 275c066a32aSThomas Bogendoerfer register_pci_controller(&sni_pcit_controller); 276c066a32aSThomas Bogendoerfer #endif 277bea77175SThomas Bogendoerfer sni_pcit_resource_init(); 278c066a32aSThomas Bogendoerfer } 279c066a32aSThomas Bogendoerfer 280c066a32aSThomas Bogendoerfer static int __init snirm_pcit_setup_devinit(void) 281c066a32aSThomas Bogendoerfer { 282c066a32aSThomas Bogendoerfer switch (sni_brd_type) { 283c066a32aSThomas Bogendoerfer case SNI_BRD_PCI_TOWER: 284c066a32aSThomas Bogendoerfer platform_device_register(&pcit_serial8250_device); 28506cf5583SThomas Bogendoerfer platform_device_register(&pcit_cmos_device); 28619388fb0SRalf Baechle platform_device_register(&pcit_pcspeaker_pdev); 287c066a32aSThomas Bogendoerfer break; 288c066a32aSThomas Bogendoerfer 289c066a32aSThomas Bogendoerfer case SNI_BRD_PCI_TOWER_CPLUS: 290c066a32aSThomas Bogendoerfer platform_device_register(&pcit_cplus_serial8250_device); 29106cf5583SThomas Bogendoerfer platform_device_register(&pcit_cmos_device); 29219388fb0SRalf Baechle platform_device_register(&pcit_pcspeaker_pdev); 293c066a32aSThomas Bogendoerfer break; 294c066a32aSThomas Bogendoerfer } 295c066a32aSThomas Bogendoerfer return 0; 296c066a32aSThomas Bogendoerfer } 297c066a32aSThomas Bogendoerfer 298c066a32aSThomas Bogendoerfer device_initcall(snirm_pcit_setup_devinit); 299