18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Carsten Langgaard, carstenl@mips.com 78c2ecf20Sopenharmony_ci * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. 88c2ecf20Sopenharmony_ci * Copyright (C) 2001 Ralf Baechle 98c2ecf20Sopenharmony_ci * Copyright (C) 2013 Imagination Technologies Ltd. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Routines for generic manipulation of the interrupts found on the MIPS 128c2ecf20Sopenharmony_ci * Malta board. The interrupt controller is located in the South Bridge 138c2ecf20Sopenharmony_ci * a PIIX4 device with two internal 82C95 interrupt controllers. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/irq.h> 178c2ecf20Sopenharmony_ci#include <linux/irqchip.h> 188c2ecf20Sopenharmony_ci#include <linux/sched.h> 198c2ecf20Sopenharmony_ci#include <linux/smp.h> 208c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 238c2ecf20Sopenharmony_ci#include <linux/kernel_stat.h> 248c2ecf20Sopenharmony_ci#include <linux/kernel.h> 258c2ecf20Sopenharmony_ci#include <linux/random.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <asm/traps.h> 288c2ecf20Sopenharmony_ci#include <asm/i8259.h> 298c2ecf20Sopenharmony_ci#include <asm/irq_cpu.h> 308c2ecf20Sopenharmony_ci#include <asm/irq_regs.h> 318c2ecf20Sopenharmony_ci#include <asm/mips-boards/malta.h> 328c2ecf20Sopenharmony_ci#include <asm/mips-boards/maltaint.h> 338c2ecf20Sopenharmony_ci#include <asm/mips-cps.h> 348c2ecf20Sopenharmony_ci#include <asm/gt64120.h> 358c2ecf20Sopenharmony_ci#include <asm/mips-boards/generic.h> 368c2ecf20Sopenharmony_ci#include <asm/mips-boards/msc01_pci.h> 378c2ecf20Sopenharmony_ci#include <asm/msc01_ic.h> 388c2ecf20Sopenharmony_ci#include <asm/setup.h> 398c2ecf20Sopenharmony_ci#include <asm/rtlx.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic inline int mips_pcibios_iack(void) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int irq; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* 468c2ecf20Sopenharmony_ci * Determine highest priority pending interrupt by performing 478c2ecf20Sopenharmony_ci * a PCI Interrupt Acknowledge cycle. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci switch (mips_revision_sconid) { 508c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCIT: 518c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_ROCIT: 528c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSC: 538c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSCP: 548c2ecf20Sopenharmony_ci MSC_READ(MSC01_PCI_IACK, irq); 558c2ecf20Sopenharmony_ci irq &= 0xff; 568c2ecf20Sopenharmony_ci break; 578c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_GT64120: 588c2ecf20Sopenharmony_ci irq = GT_READ(GT_PCI0_IACK_OFS); 598c2ecf20Sopenharmony_ci irq &= 0xff; 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_BONITO: 628c2ecf20Sopenharmony_ci /* The following will generate a PCI IACK cycle on the 638c2ecf20Sopenharmony_ci * Bonito controller. It's a little bit kludgy, but it 648c2ecf20Sopenharmony_ci * was the easiest way to implement it in hardware at 658c2ecf20Sopenharmony_ci * the given time. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci BONITO_PCIMAP_CFG = 0x20000; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Flush Bonito register block */ 708c2ecf20Sopenharmony_ci (void) BONITO_PCIMAP_CFG; 718c2ecf20Sopenharmony_ci iob(); /* sync */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg); 748c2ecf20Sopenharmony_ci iob(); /* sync */ 758c2ecf20Sopenharmony_ci irq &= 0xff; 768c2ecf20Sopenharmony_ci BONITO_PCIMAP_CFG = 0; 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci default: 798c2ecf20Sopenharmony_ci pr_emerg("Unknown system controller.\n"); 808c2ecf20Sopenharmony_ci return -1; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci return irq; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void corehi_irqdispatch(void) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci unsigned int intedge, intsteer, pcicmd, pcibadaddr; 888c2ecf20Sopenharmony_ci unsigned int pcimstat, intisr, inten, intpol; 898c2ecf20Sopenharmony_ci unsigned int intrcause, datalo, datahi; 908c2ecf20Sopenharmony_ci struct pt_regs *regs = get_irq_regs(); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n"); 938c2ecf20Sopenharmony_ci pr_emerg("epc : %08lx\nStatus: %08lx\n" 948c2ecf20Sopenharmony_ci "Cause : %08lx\nbadVaddr : %08lx\n", 958c2ecf20Sopenharmony_ci regs->cp0_epc, regs->cp0_status, 968c2ecf20Sopenharmony_ci regs->cp0_cause, regs->cp0_badvaddr); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* Read all the registers and then print them as there is a 998c2ecf20Sopenharmony_ci problem with interspersed printk's upsetting the Bonito controller. 1008c2ecf20Sopenharmony_ci Do it for the others too. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci switch (mips_revision_sconid) { 1048c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCIT: 1058c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_ROCIT: 1068c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSC: 1078c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSCP: 1088c2ecf20Sopenharmony_ci ll_msc_irq(); 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_GT64120: 1118c2ecf20Sopenharmony_ci intrcause = GT_READ(GT_INTRCAUSE_OFS); 1128c2ecf20Sopenharmony_ci datalo = GT_READ(GT_CPUERR_ADDRLO_OFS); 1138c2ecf20Sopenharmony_ci datahi = GT_READ(GT_CPUERR_ADDRHI_OFS); 1148c2ecf20Sopenharmony_ci pr_emerg("GT_INTRCAUSE = %08x\n", intrcause); 1158c2ecf20Sopenharmony_ci pr_emerg("GT_CPUERR_ADDR = %02x%08x\n", 1168c2ecf20Sopenharmony_ci datahi, datalo); 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_BONITO: 1198c2ecf20Sopenharmony_ci pcibadaddr = BONITO_PCIBADADDR; 1208c2ecf20Sopenharmony_ci pcimstat = BONITO_PCIMSTAT; 1218c2ecf20Sopenharmony_ci intisr = BONITO_INTISR; 1228c2ecf20Sopenharmony_ci inten = BONITO_INTEN; 1238c2ecf20Sopenharmony_ci intpol = BONITO_INTPOL; 1248c2ecf20Sopenharmony_ci intedge = BONITO_INTEDGE; 1258c2ecf20Sopenharmony_ci intsteer = BONITO_INTSTEER; 1268c2ecf20Sopenharmony_ci pcicmd = BONITO_PCICMD; 1278c2ecf20Sopenharmony_ci pr_emerg("BONITO_INTISR = %08x\n", intisr); 1288c2ecf20Sopenharmony_ci pr_emerg("BONITO_INTEN = %08x\n", inten); 1298c2ecf20Sopenharmony_ci pr_emerg("BONITO_INTPOL = %08x\n", intpol); 1308c2ecf20Sopenharmony_ci pr_emerg("BONITO_INTEDGE = %08x\n", intedge); 1318c2ecf20Sopenharmony_ci pr_emerg("BONITO_INTSTEER = %08x\n", intsteer); 1328c2ecf20Sopenharmony_ci pr_emerg("BONITO_PCICMD = %08x\n", pcicmd); 1338c2ecf20Sopenharmony_ci pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr); 1348c2ecf20Sopenharmony_ci pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat); 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci die("CoreHi interrupt", regs); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic irqreturn_t corehi_handler(int irq, void *dev_id) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci corehi_irqdispatch(); 1448c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic msc_irqmap_t msc_irqmap[] __initdata = { 1488c2ecf20Sopenharmony_ci {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, 1498c2ecf20Sopenharmony_ci {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_cistatic int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic msc_irqmap_t msc_eicirqmap[] __initdata = { 1548c2ecf20Sopenharmony_ci {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, 1558c2ecf20Sopenharmony_ci {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, 1568c2ecf20Sopenharmony_ci {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, 1578c2ecf20Sopenharmony_ci {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0}, 1588c2ecf20Sopenharmony_ci {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0}, 1598c2ecf20Sopenharmony_ci {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0}, 1608c2ecf20Sopenharmony_ci {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, 1618c2ecf20Sopenharmony_ci {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, 1628c2ecf20Sopenharmony_ci {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, 1638c2ecf20Sopenharmony_ci {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_civoid __init arch_init_irq(void) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci int corehi_irq; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * Preallocate the i8259's expected virq's here. Since irqchip_init() 1748c2ecf20Sopenharmony_ci * will probe the irqchips in hierarchial order, i8259 is probed last. 1758c2ecf20Sopenharmony_ci * If anything allocates a virq before the i8259 is probed, it will 1768c2ecf20Sopenharmony_ci * be given one of the i8259's expected range and consequently setup 1778c2ecf20Sopenharmony_ci * of the i8259 will fail. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci WARN(irq_alloc_descs(I8259A_IRQ_BASE, I8259A_IRQ_BASE, 1808c2ecf20Sopenharmony_ci 16, numa_node_id()) < 0, 1818c2ecf20Sopenharmony_ci "Cannot reserve i8259 virqs at IRQ%d\n", I8259A_IRQ_BASE); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci i8259_set_poll(mips_pcibios_iack); 1848c2ecf20Sopenharmony_ci irqchip_init(); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci switch (mips_revision_sconid) { 1878c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCIT: 1888c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_ROCIT: 1898c2ecf20Sopenharmony_ci if (cpu_has_veic) 1908c2ecf20Sopenharmony_ci init_msc_irqs(MIPS_MSC01_IC_REG_BASE, 1918c2ecf20Sopenharmony_ci MSC01E_INT_BASE, msc_eicirqmap, 1928c2ecf20Sopenharmony_ci msc_nr_eicirqs); 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci init_msc_irqs(MIPS_MSC01_IC_REG_BASE, 1958c2ecf20Sopenharmony_ci MSC01C_INT_BASE, msc_irqmap, 1968c2ecf20Sopenharmony_ci msc_nr_irqs); 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSC: 2008c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSCP: 2018c2ecf20Sopenharmony_ci if (cpu_has_veic) 2028c2ecf20Sopenharmony_ci init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, 2038c2ecf20Sopenharmony_ci MSC01E_INT_BASE, msc_eicirqmap, 2048c2ecf20Sopenharmony_ci msc_nr_eicirqs); 2058c2ecf20Sopenharmony_ci else 2068c2ecf20Sopenharmony_ci init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, 2078c2ecf20Sopenharmony_ci MSC01C_INT_BASE, msc_irqmap, 2088c2ecf20Sopenharmony_ci msc_nr_irqs); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (mips_gic_present()) { 2128c2ecf20Sopenharmony_ci corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; 2138c2ecf20Sopenharmony_ci } else if (cpu_has_veic) { 2148c2ecf20Sopenharmony_ci set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch); 2158c2ecf20Sopenharmony_ci corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI; 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (request_irq(corehi_irq, corehi_handler, IRQF_NO_THREAD, "CoreHi", 2218c2ecf20Sopenharmony_ci NULL)) 2228c2ecf20Sopenharmony_ci pr_err("Failed to request irq %d (CoreHi)\n", corehi_irq); 2238c2ecf20Sopenharmony_ci} 224