Commit | Line | Data |
---|---|---|
ec500af3 AJ |
1 | /* |
2 | * Copyright (C) 2011 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 | ||
31 | unsigned long irq_err_count; | |
32 | ||
33 | static DEFINE_RAW_SPINLOCK(core_irq_lock); | |
34 | ||
35 | static void mask_core_irq(struct irq_data *data) | |
36 | { | |
37 | unsigned int prio = data->irq; | |
38 | ||
39 | BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS); | |
40 | ||
41 | raw_spin_lock(&core_irq_lock); | |
42 | and_creg(IER, ~(1 << prio)); | |
43 | raw_spin_unlock(&core_irq_lock); | |
44 | } | |
45 | ||
46 | static void unmask_core_irq(struct irq_data *data) | |
47 | { | |
48 | unsigned int prio = data->irq; | |
49 | ||
50 | raw_spin_lock(&core_irq_lock); | |
51 | or_creg(IER, 1 << prio); | |
52 | raw_spin_unlock(&core_irq_lock); | |
53 | } | |
54 | ||
55 | static struct irq_chip core_chip = { | |
56 | .name = "core", | |
57 | .irq_mask = mask_core_irq, | |
58 | .irq_unmask = unmask_core_irq, | |
59 | }; | |
60 | ||
61 | asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs) | |
62 | { | |
63 | struct pt_regs *old_regs = set_irq_regs(regs); | |
64 | ||
65 | irq_enter(); | |
66 | ||
67 | BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS); | |
68 | ||
69 | generic_handle_irq(prio); | |
70 | ||
71 | irq_exit(); | |
72 | ||
73 | set_irq_regs(old_regs); | |
74 | } | |
75 | ||
0bd761e1 | 76 | static struct irq_domain *core_domain; |
ec500af3 | 77 | |
0bd761e1 MS |
78 | static int core_domain_map(struct irq_domain *h, unsigned int virq, |
79 | irq_hw_number_t hw) | |
ec500af3 AJ |
80 | { |
81 | if (hw < 4 || hw >= NR_PRIORITY_IRQS) | |
82 | return -EINVAL; | |
83 | ||
84 | irq_set_status_flags(virq, IRQ_LEVEL); | |
85 | irq_set_chip_and_handler(virq, &core_chip, handle_level_irq); | |
86 | return 0; | |
87 | } | |
88 | ||
15a25980 | 89 | static const struct irq_domain_ops core_domain_ops = { |
0bd761e1 | 90 | .map = core_domain_map, |
ec500af3 AJ |
91 | }; |
92 | ||
93 | void __init init_IRQ(void) | |
94 | { | |
95 | struct device_node *np; | |
96 | ||
97 | /* Mask all priority IRQs */ | |
98 | and_creg(IER, ~0xfff0); | |
99 | ||
100 | np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic"); | |
101 | if (np != NULL) { | |
102 | /* create the core host */ | |
0bd761e1 MS |
103 | core_domain = irq_domain_add_legacy(np, NR_PRIORITY_IRQS, |
104 | 0, 0, &core_domain_ops, | |
105 | NULL); | |
106 | if (core_domain) | |
107 | irq_set_default_host(core_domain); | |
ec500af3 AJ |
108 | of_node_put(np); |
109 | } | |
110 | ||
111 | printk(KERN_INFO "Core interrupt controller initialized\n"); | |
112 | ||
113 | /* now we're ready for other SoC controllers */ | |
114 | megamod_pic_init(); | |
115 | ||
116 | /* Clear all general IRQ flags */ | |
117 | set_creg(ICR, 0xfff0); | |
118 | } | |
119 | ||
120 | void ack_bad_irq(int irq) | |
121 | { | |
122 | printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); | |
123 | irq_err_count++; | |
124 | } | |
125 | ||
126 | int arch_show_interrupts(struct seq_file *p, int prec) | |
127 | { | |
128 | seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); | |
129 | return 0; | |
130 | } | |
131 | ||
ec500af3 AJ |
132 | irq_hw_number_t irqd_to_hwirq(struct irq_data *d) |
133 | { | |
0bd761e1 | 134 | return d->hwirq; |
ec500af3 AJ |
135 | } |
136 | EXPORT_SYMBOL_GPL(irqd_to_hwirq); | |
137 | ||
138 | irq_hw_number_t virq_to_hw(unsigned int virq) | |
139 | { | |
0bd761e1 MS |
140 | struct irq_data *irq_data = irq_get_irq_data(virq); |
141 | return WARN_ON(!irq_data) ? 0 : irq_data->hwirq; | |
ec500af3 AJ |
142 | } |
143 | EXPORT_SYMBOL_GPL(virq_to_hw); |