diff options
author | John Crispin <blogic@openwrt.org> | 2013-01-20 16:00:50 -0500 |
---|---|---|
committer | John Crispin <blogic@openwrt.org> | 2013-02-16 19:25:29 -0500 |
commit | 19d3814e7b325f8965fd71f329b3467a97f8d217 (patch) | |
tree | 0cf12e3b82697f1588e2d573c3b4e61b4c19bf9f /arch/mips/ralink | |
parent | 8563991026ee98bb5e477167236972a45dfea0e3 (diff) |
MIPS: ralink: adds irq code
All of the Ralink Wifi SoC currently supported by this series share the same
interrupt controller (INTC).
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/4890/
Diffstat (limited to 'arch/mips/ralink')
-rw-r--r-- | arch/mips/ralink/irq.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c new file mode 100644 index 000000000000..e62c9751e2d8 --- /dev/null +++ b/arch/mips/ralink/irq.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify it | ||
3 | * under the terms of the GNU General Public License version 2 as published | ||
4 | * by the Free Software Foundation. | ||
5 | * | ||
6 | * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> | ||
7 | * Copyright (C) 2013 John Crispin <blogic@openwrt.org> | ||
8 | */ | ||
9 | |||
10 | #include <linux/io.h> | ||
11 | #include <linux/bitops.h> | ||
12 | #include <linux/of_platform.h> | ||
13 | #include <linux/of_address.h> | ||
14 | #include <linux/of_irq.h> | ||
15 | #include <linux/irqdomain.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | |||
18 | #include <asm/irq_cpu.h> | ||
19 | #include <asm/mipsregs.h> | ||
20 | |||
21 | #include "common.h" | ||
22 | |||
23 | /* INTC register offsets */ | ||
24 | #define INTC_REG_STATUS0 0x00 | ||
25 | #define INTC_REG_STATUS1 0x04 | ||
26 | #define INTC_REG_TYPE 0x20 | ||
27 | #define INTC_REG_RAW_STATUS 0x30 | ||
28 | #define INTC_REG_ENABLE 0x34 | ||
29 | #define INTC_REG_DISABLE 0x38 | ||
30 | |||
31 | #define INTC_INT_GLOBAL BIT(31) | ||
32 | |||
33 | #define RALINK_CPU_IRQ_INTC (MIPS_CPU_IRQ_BASE + 2) | ||
34 | #define RALINK_CPU_IRQ_FE (MIPS_CPU_IRQ_BASE + 5) | ||
35 | #define RALINK_CPU_IRQ_WIFI (MIPS_CPU_IRQ_BASE + 6) | ||
36 | #define RALINK_CPU_IRQ_COUNTER (MIPS_CPU_IRQ_BASE + 7) | ||
37 | |||
38 | /* we have a cascade of 8 irqs */ | ||
39 | #define RALINK_INTC_IRQ_BASE 8 | ||
40 | |||
41 | /* we have 32 SoC irqs */ | ||
42 | #define RALINK_INTC_IRQ_COUNT 32 | ||
43 | |||
44 | #define RALINK_INTC_IRQ_PERFC (RALINK_INTC_IRQ_BASE + 9) | ||
45 | |||
46 | static void __iomem *rt_intc_membase; | ||
47 | |||
48 | static inline void rt_intc_w32(u32 val, unsigned reg) | ||
49 | { | ||
50 | __raw_writel(val, rt_intc_membase + reg); | ||
51 | } | ||
52 | |||
53 | static inline u32 rt_intc_r32(unsigned reg) | ||
54 | { | ||
55 | return __raw_readl(rt_intc_membase + reg); | ||
56 | } | ||
57 | |||
58 | static void ralink_intc_irq_unmask(struct irq_data *d) | ||
59 | { | ||
60 | rt_intc_w32(BIT(d->hwirq), INTC_REG_ENABLE); | ||
61 | } | ||
62 | |||
63 | static void ralink_intc_irq_mask(struct irq_data *d) | ||
64 | { | ||
65 | rt_intc_w32(BIT(d->hwirq), INTC_REG_DISABLE); | ||
66 | } | ||
67 | |||
68 | static struct irq_chip ralink_intc_irq_chip = { | ||
69 | .name = "INTC", | ||
70 | .irq_unmask = ralink_intc_irq_unmask, | ||
71 | .irq_mask = ralink_intc_irq_mask, | ||
72 | .irq_mask_ack = ralink_intc_irq_mask, | ||
73 | }; | ||
74 | |||
75 | unsigned int __cpuinit get_c0_compare_int(void) | ||
76 | { | ||
77 | return CP0_LEGACY_COMPARE_IRQ; | ||
78 | } | ||
79 | |||
80 | static void ralink_intc_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
81 | { | ||
82 | u32 pending = rt_intc_r32(INTC_REG_STATUS0); | ||
83 | |||
84 | if (pending) { | ||
85 | struct irq_domain *domain = irq_get_handler_data(irq); | ||
86 | generic_handle_irq(irq_find_mapping(domain, __ffs(pending))); | ||
87 | } else { | ||
88 | spurious_interrupt(); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | asmlinkage void plat_irq_dispatch(void) | ||
93 | { | ||
94 | unsigned long pending; | ||
95 | |||
96 | pending = read_c0_status() & read_c0_cause() & ST0_IM; | ||
97 | |||
98 | if (pending & STATUSF_IP7) | ||
99 | do_IRQ(RALINK_CPU_IRQ_COUNTER); | ||
100 | |||
101 | else if (pending & STATUSF_IP5) | ||
102 | do_IRQ(RALINK_CPU_IRQ_FE); | ||
103 | |||
104 | else if (pending & STATUSF_IP6) | ||
105 | do_IRQ(RALINK_CPU_IRQ_WIFI); | ||
106 | |||
107 | else if (pending & STATUSF_IP2) | ||
108 | do_IRQ(RALINK_CPU_IRQ_INTC); | ||
109 | |||
110 | else | ||
111 | spurious_interrupt(); | ||
112 | } | ||
113 | |||
114 | static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | ||
115 | { | ||
116 | irq_set_chip_and_handler(irq, &ralink_intc_irq_chip, handle_level_irq); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static const struct irq_domain_ops irq_domain_ops = { | ||
122 | .xlate = irq_domain_xlate_onecell, | ||
123 | .map = intc_map, | ||
124 | }; | ||
125 | |||
126 | static int __init intc_of_init(struct device_node *node, | ||
127 | struct device_node *parent) | ||
128 | { | ||
129 | struct resource res; | ||
130 | struct irq_domain *domain; | ||
131 | |||
132 | mips_cpu_irq_init(); | ||
133 | |||
134 | if (of_address_to_resource(node, 0, &res)) | ||
135 | panic("Failed to get intc memory range"); | ||
136 | |||
137 | if (request_mem_region(res.start, resource_size(&res), | ||
138 | res.name) < 0) | ||
139 | pr_err("Failed to request intc memory"); | ||
140 | |||
141 | rt_intc_membase = ioremap_nocache(res.start, | ||
142 | resource_size(&res)); | ||
143 | if (!rt_intc_membase) | ||
144 | panic("Failed to remap intc memory"); | ||
145 | |||
146 | /* disable all interrupts */ | ||
147 | rt_intc_w32(~0, INTC_REG_DISABLE); | ||
148 | |||
149 | /* route all INTC interrupts to MIPS HW0 interrupt */ | ||
150 | rt_intc_w32(0, INTC_REG_TYPE); | ||
151 | |||
152 | domain = irq_domain_add_legacy(node, RALINK_INTC_IRQ_COUNT, | ||
153 | RALINK_INTC_IRQ_BASE, 0, &irq_domain_ops, NULL); | ||
154 | if (!domain) | ||
155 | panic("Failed to add irqdomain"); | ||
156 | |||
157 | rt_intc_w32(INTC_INT_GLOBAL, INTC_REG_ENABLE); | ||
158 | |||
159 | irq_set_chained_handler(RALINK_CPU_IRQ_INTC, ralink_intc_irq_handler); | ||
160 | irq_set_handler_data(RALINK_CPU_IRQ_INTC, domain); | ||
161 | |||
162 | cp0_perfcount_irq = irq_create_mapping(domain, 9); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct of_device_id __initdata of_irq_ids[] = { | ||
168 | { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, | ||
169 | {}, | ||
170 | }; | ||
171 | |||
172 | void __init arch_init_irq(void) | ||
173 | { | ||
174 | of_irq_init(of_irq_ids); | ||
175 | } | ||
176 | |||