1/* 2 * Copyright (C) 2011-2012 Texas Instruments Incorporated 3 * 4 * This borrows heavily from powerpc version, which is: 5 * 6 * Derived from arch/i386/kernel/irq.c 7 * Copyright (C) 1992 Linus Torvalds 8 * Adapted from arch/i386 by Gary Thomas 9 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 10 * Updated and modified by Cort Dougan <cort@fsmlabs.com> 11 * Copyright (C) 1996-2001 Cort Dougan 12 * Adapted for Power Macintosh by Paul Mackerras 13 * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License 17 * as published by the Free Software Foundation; either version 18 * 2 of the License, or (at your option) any later version. 19 */ 20#include <linux/slab.h> 21#include <linux/seq_file.h> 22#include <linux/radix-tree.h> 23#include <linux/module.h> 24#include <linux/of.h> 25#include <linux/of_irq.h> 26#include <linux/interrupt.h> 27#include <linux/kernel_stat.h> 28 29#include <asm/megamod-pic.h> 30#include <asm/special_insns.h> 31 32unsigned long irq_err_count; 33 34static DEFINE_RAW_SPINLOCK(core_irq_lock); 35 36static void mask_core_irq(struct irq_data *data) 37{ 38 unsigned int prio = data->hwirq; 39 40 raw_spin_lock(&core_irq_lock); 41 and_creg(IER, ~(1 << prio)); 42 raw_spin_unlock(&core_irq_lock); 43} 44 45static void unmask_core_irq(struct irq_data *data) 46{ 47 unsigned int prio = data->hwirq; 48 49 raw_spin_lock(&core_irq_lock); 50 or_creg(IER, 1 << prio); 51 raw_spin_unlock(&core_irq_lock); 52} 53 54static struct irq_chip core_chip = { 55 .name = "core", 56 .irq_mask = mask_core_irq, 57 .irq_unmask = unmask_core_irq, 58}; 59 60static int prio_to_virq[NR_PRIORITY_IRQS]; 61 62asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs) 63{ 64 struct pt_regs *old_regs = set_irq_regs(regs); 65 66 irq_enter(); 67 68 generic_handle_irq(prio_to_virq[prio]); 69 70 irq_exit(); 71 72 set_irq_regs(old_regs); 73} 74 75static struct irq_domain *core_domain; 76 77static int core_domain_map(struct irq_domain *h, unsigned int virq, 78 irq_hw_number_t hw) 79{ 80 if (hw < 4 || hw >= NR_PRIORITY_IRQS) 81 return -EINVAL; 82 83 prio_to_virq[hw] = virq; 84 85 irq_set_status_flags(virq, IRQ_LEVEL); 86 irq_set_chip_and_handler(virq, &core_chip, handle_level_irq); 87 return 0; 88} 89 90static const struct irq_domain_ops core_domain_ops = { 91 .map = core_domain_map, 92 .xlate = irq_domain_xlate_onecell, 93}; 94 95void __init init_IRQ(void) 96{ 97 struct device_node *np; 98 99 /* Mask all priority IRQs */ 100 and_creg(IER, ~0xfff0); 101 102 np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic"); 103 if (np != NULL) { 104 /* create the core host */ 105 core_domain = irq_domain_add_linear(np, NR_PRIORITY_IRQS, 106 &core_domain_ops, NULL); 107 if (core_domain) 108 irq_set_default_host(core_domain); 109 of_node_put(np); 110 } 111 112 printk(KERN_INFO "Core interrupt controller initialized\n"); 113 114 /* now we're ready for other SoC controllers */ 115 megamod_pic_init(); 116 117 /* Clear all general IRQ flags */ 118 set_creg(ICR, 0xfff0); 119} 120 121void ack_bad_irq(int irq) 122{ 123 printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); 124 irq_err_count++; 125} 126 127int arch_show_interrupts(struct seq_file *p, int prec) 128{ 129 seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); 130 return 0; 131} 132