]>
Commit | Line | Data |
---|---|---|
ec500af3 | 1 | /* |
f84f1f46 | 2 | * Copyright (C) 2011-2012 Texas Instruments Incorporated |
ec500af3 AJ |
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 ([email protected]) | |
10 | * Updated and modified by Cort Dougan <[email protected]> | |
11 | * Copyright (C) 1996-2001 Cort Dougan | |
12 | * Adapted for Power Macintosh by Paul Mackerras | |
13 | * Copyright (C) 1996 Paul Mackerras ([email protected]) | |
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> | |
6a846f3f | 30 | #include <asm/special_insns.h> |
ec500af3 AJ |
31 | |
32 | unsigned long irq_err_count; | |
33 | ||
34 | static DEFINE_RAW_SPINLOCK(core_irq_lock); | |
35 | ||
36 | static void mask_core_irq(struct irq_data *data) | |
37 | { | |
f84f1f46 | 38 | unsigned int prio = data->hwirq; |
ec500af3 AJ |
39 | |
40 | raw_spin_lock(&core_irq_lock); | |
41 | and_creg(IER, ~(1 << prio)); | |
42 | raw_spin_unlock(&core_irq_lock); | |
43 | } | |
44 | ||
45 | static void unmask_core_irq(struct irq_data *data) | |
46 | { | |
f84f1f46 | 47 | unsigned int prio = data->hwirq; |
ec500af3 AJ |
48 | |
49 | raw_spin_lock(&core_irq_lock); | |
50 | or_creg(IER, 1 << prio); | |
51 | raw_spin_unlock(&core_irq_lock); | |
52 | } | |
53 | ||
54 | static struct irq_chip core_chip = { | |
55 | .name = "core", | |
56 | .irq_mask = mask_core_irq, | |
57 | .irq_unmask = unmask_core_irq, | |
58 | }; | |
59 | ||
f84f1f46 MS |
60 | static int prio_to_virq[NR_PRIORITY_IRQS]; |
61 | ||
ec500af3 AJ |
62 | asmlinkage 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 | ||
f84f1f46 | 68 | generic_handle_irq(prio_to_virq[prio]); |
ec500af3 AJ |
69 | |
70 | irq_exit(); | |
71 | ||
72 | set_irq_regs(old_regs); | |
73 | } | |
74 | ||
0bd761e1 | 75 | static struct irq_domain *core_domain; |
ec500af3 | 76 | |
0bd761e1 MS |
77 | static int core_domain_map(struct irq_domain *h, unsigned int virq, |
78 | irq_hw_number_t hw) | |
ec500af3 AJ |
79 | { |
80 | if (hw < 4 || hw >= NR_PRIORITY_IRQS) | |
81 | return -EINVAL; | |
82 | ||
f84f1f46 MS |
83 | prio_to_virq[hw] = virq; |
84 | ||
ec500af3 AJ |
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 | ||
15a25980 | 90 | static const struct irq_domain_ops core_domain_ops = { |
0bd761e1 | 91 | .map = core_domain_map, |
c1e572e6 | 92 | .xlate = irq_domain_xlate_onecell, |
ec500af3 AJ |
93 | }; |
94 | ||
95 | void __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 */ | |
f84f1f46 MS |
105 | core_domain = irq_domain_add_linear(np, NR_PRIORITY_IRQS, |
106 | &core_domain_ops, NULL); | |
0bd761e1 MS |
107 | if (core_domain) |
108 | irq_set_default_host(core_domain); | |
ec500af3 AJ |
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 | ||
121 | void ack_bad_irq(int irq) | |
122 | { | |
123 | printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); | |
124 | irq_err_count++; | |
125 | } | |
126 | ||
127 | int 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 | } |