aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-spear
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2012-11-12 12:26:03 -0500
committerViresh Kumar <viresh.kumar@linaro.org>2012-11-26 06:25:33 -0500
commitdf1590d9ae5e37e07e7cf91107e4c2c946ce8bf4 (patch)
tree7e17333920f4ab9986f3f40e881b4bc890a91724 /arch/arm/plat-spear
parente2eb69183ec4156eb814e67672e492bf902bbcd2 (diff)
ARM: SPEAr3xx: Shirq: Move shirq controller out of plat/
This patch moves shirq interrupt controllers driver and header file out of plat-spear directory. It is moved to drivers/irqchip/ directory. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Diffstat (limited to 'arch/arm/plat-spear')
-rw-r--r--arch/arm/plat-spear/Makefile2
-rw-r--r--arch/arm/plat-spear/include/plat/shirq.h66
-rw-r--r--arch/arm/plat-spear/shirq.c315
3 files changed, 1 insertions, 382 deletions
diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile
index 2607bd05c525..01e88532a5db 100644
--- a/arch/arm/plat-spear/Makefile
+++ b/arch/arm/plat-spear/Makefile
@@ -5,5 +5,5 @@
5# Common support 5# Common support
6obj-y := restart.o time.o 6obj-y := restart.o time.o
7 7
8obj-$(CONFIG_ARCH_SPEAR3XX) += pl080.o shirq.o 8obj-$(CONFIG_ARCH_SPEAR3XX) += pl080.o
9obj-$(CONFIG_ARCH_SPEAR6XX) += pl080.o 9obj-$(CONFIG_ARCH_SPEAR6XX) += pl080.o
diff --git a/arch/arm/plat-spear/include/plat/shirq.h b/arch/arm/plat-spear/include/plat/shirq.h
deleted file mode 100644
index c51b355f00de..000000000000
--- a/arch/arm/plat-spear/include/plat/shirq.h
+++ /dev/null
@@ -1,66 +0,0 @@
1/*
2 * arch/arm/plat-spear/include/plat/shirq.h
3 *
4 * SPEAr platform shared irq layer header file
5 *
6 * Copyright (C) 2009 ST Microelectronics
7 * Viresh Kumar <viresh.linux@gmail.com>
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 */
13
14#ifndef __PLAT_SHIRQ_H
15#define __PLAT_SHIRQ_H
16
17#include <linux/irq.h>
18#include <linux/types.h>
19
20/*
21 * struct shirq_regs: shared irq register configuration
22 *
23 * enb_reg: enable register offset
24 * reset_to_enb: val 1 indicates, we need to clear bit for enabling interrupt
25 * status_reg: status register offset
26 * status_reg_mask: status register valid mask
27 * clear_reg: clear register offset
28 * reset_to_clear: val 1 indicates, we need to clear bit for clearing interrupt
29 */
30struct shirq_regs {
31 u32 enb_reg;
32 u32 reset_to_enb;
33 u32 status_reg;
34 u32 clear_reg;
35 u32 reset_to_clear;
36};
37
38/*
39 * struct spear_shirq: shared irq structure
40 *
41 * irq: hardware irq number
42 * irq_base: base irq in linux domain
43 * irq_nr: no. of shared interrupts in a particular block
44 * irq_bit_off: starting bit offset in the status register
45 * invalid_irq: irq group is currently disabled
46 * base: base address of shared irq register
47 * regs: register configuration for shared irq block
48 */
49struct spear_shirq {
50 u32 irq;
51 u32 irq_base;
52 u32 irq_nr;
53 u32 irq_bit_off;
54 int invalid_irq;
55 void __iomem *base;
56 struct shirq_regs regs;
57};
58
59int __init spear300_shirq_of_init(struct device_node *np,
60 struct device_node *parent);
61int __init spear310_shirq_of_init(struct device_node *np,
62 struct device_node *parent);
63int __init spear320_shirq_of_init(struct device_node *np,
64 struct device_node *parent);
65
66#endif /* __PLAT_SHIRQ_H */
diff --git a/arch/arm/plat-spear/shirq.c b/arch/arm/plat-spear/shirq.c
deleted file mode 100644
index 955c7249a5c1..000000000000
--- a/arch/arm/plat-spear/shirq.c
+++ /dev/null
@@ -1,315 +0,0 @@
1/*
2 * arch/arm/plat-spear/shirq.c
3 *
4 * SPEAr platform shared irq layer source file
5 *
6 * Copyright (C) 2009 ST Microelectronics
7 * Viresh Kumar <viresh.linux@gmail.com>
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 */
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include <linux/err.h>
16#include <linux/export.h>
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/irq.h>
20#include <linux/irqdomain.h>
21#include <linux/of.h>
22#include <linux/of_address.h>
23#include <linux/of_irq.h>
24#include <linux/spinlock.h>
25#include <plat/shirq.h>
26
27static DEFINE_SPINLOCK(lock);
28
29/* spear300 shared irq registers offsets and masks */
30#define SPEAR300_INT_ENB_MASK_REG 0x54
31#define SPEAR300_INT_STS_MASK_REG 0x58
32
33static struct spear_shirq spear300_shirq_ras1 = {
34 .irq_nr = 9,
35 .irq_bit_off = 0,
36 .regs = {
37 .enb_reg = SPEAR300_INT_ENB_MASK_REG,
38 .status_reg = SPEAR300_INT_STS_MASK_REG,
39 .clear_reg = -1,
40 },
41};
42
43static struct spear_shirq *spear300_shirq_blocks[] = {
44 &spear300_shirq_ras1,
45};
46
47/* spear310 shared irq registers offsets and masks */
48#define SPEAR310_INT_STS_MASK_REG 0x04
49
50static struct spear_shirq spear310_shirq_ras1 = {
51 .irq_nr = 8,
52 .irq_bit_off = 0,
53 .regs = {
54 .enb_reg = -1,
55 .status_reg = SPEAR310_INT_STS_MASK_REG,
56 .clear_reg = -1,
57 },
58};
59
60static struct spear_shirq spear310_shirq_ras2 = {
61 .irq_nr = 5,
62 .irq_bit_off = 8,
63 .regs = {
64 .enb_reg = -1,
65 .status_reg = SPEAR310_INT_STS_MASK_REG,
66 .clear_reg = -1,
67 },
68};
69
70static struct spear_shirq spear310_shirq_ras3 = {
71 .irq_nr = 1,
72 .irq_bit_off = 13,
73 .regs = {
74 .enb_reg = -1,
75 .status_reg = SPEAR310_INT_STS_MASK_REG,
76 .clear_reg = -1,
77 },
78};
79
80static struct spear_shirq spear310_shirq_intrcomm_ras = {
81 .irq_nr = 3,
82 .irq_bit_off = 14,
83 .regs = {
84 .enb_reg = -1,
85 .status_reg = SPEAR310_INT_STS_MASK_REG,
86 .clear_reg = -1,
87 },
88};
89
90static struct spear_shirq *spear310_shirq_blocks[] = {
91 &spear310_shirq_ras1,
92 &spear310_shirq_ras2,
93 &spear310_shirq_ras3,
94 &spear310_shirq_intrcomm_ras,
95};
96
97/* spear320 shared irq registers offsets and masks */
98#define SPEAR320_INT_STS_MASK_REG 0x04
99#define SPEAR320_INT_CLR_MASK_REG 0x04
100#define SPEAR320_INT_ENB_MASK_REG 0x08
101
102static struct spear_shirq spear320_shirq_ras1 = {
103 .irq_nr = 3,
104 .irq_bit_off = 7,
105 .regs = {
106 .enb_reg = -1,
107 .status_reg = SPEAR320_INT_STS_MASK_REG,
108 .clear_reg = SPEAR320_INT_CLR_MASK_REG,
109 .reset_to_clear = 1,
110 },
111};
112
113static struct spear_shirq spear320_shirq_ras2 = {
114 .irq_nr = 1,
115 .irq_bit_off = 10,
116 .regs = {
117 .enb_reg = -1,
118 .status_reg = SPEAR320_INT_STS_MASK_REG,
119 .clear_reg = SPEAR320_INT_CLR_MASK_REG,
120 .reset_to_clear = 1,
121 },
122};
123
124static struct spear_shirq spear320_shirq_ras3 = {
125 .irq_nr = 3,
126 .irq_bit_off = 0,
127 .invalid_irq = 1,
128 .regs = {
129 .enb_reg = SPEAR320_INT_ENB_MASK_REG,
130 .reset_to_enb = 1,
131 .status_reg = SPEAR320_INT_STS_MASK_REG,
132 .clear_reg = SPEAR320_INT_CLR_MASK_REG,
133 .reset_to_clear = 1,
134 },
135};
136
137static struct spear_shirq spear320_shirq_intrcomm_ras = {
138 .irq_nr = 11,
139 .irq_bit_off = 11,
140 .regs = {
141 .enb_reg = -1,
142 .status_reg = SPEAR320_INT_STS_MASK_REG,
143 .clear_reg = SPEAR320_INT_CLR_MASK_REG,
144 .reset_to_clear = 1,
145 },
146};
147
148static struct spear_shirq *spear320_shirq_blocks[] = {
149 &spear320_shirq_ras3,
150 &spear320_shirq_ras1,
151 &spear320_shirq_ras2,
152 &spear320_shirq_intrcomm_ras,
153};
154
155static void shirq_irq_mask_unmask(struct irq_data *d, bool mask)
156{
157 struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
158 u32 val, offset = d->irq - shirq->irq_base;
159 unsigned long flags;
160
161 if (shirq->regs.enb_reg == -1)
162 return;
163
164 spin_lock_irqsave(&lock, flags);
165 val = readl(shirq->base + shirq->regs.enb_reg);
166
167 if (mask ^ shirq->regs.reset_to_enb)
168 val &= ~(0x1 << shirq->irq_bit_off << offset);
169 else
170 val |= 0x1 << shirq->irq_bit_off << offset;
171
172 writel(val, shirq->base + shirq->regs.enb_reg);
173 spin_unlock_irqrestore(&lock, flags);
174
175}
176
177static void shirq_irq_mask(struct irq_data *d)
178{
179 shirq_irq_mask_unmask(d, 1);
180}
181
182static void shirq_irq_unmask(struct irq_data *d)
183{
184 shirq_irq_mask_unmask(d, 0);
185}
186
187static struct irq_chip shirq_chip = {
188 .name = "spear-shirq",
189 .irq_ack = shirq_irq_mask,
190 .irq_mask = shirq_irq_mask,
191 .irq_unmask = shirq_irq_unmask,
192};
193
194static void shirq_handler(unsigned irq, struct irq_desc *desc)
195{
196 u32 i, j, val, mask, tmp;
197 struct irq_chip *chip;
198 struct spear_shirq *shirq = irq_get_handler_data(irq);
199
200 chip = irq_get_chip(irq);
201 chip->irq_ack(&desc->irq_data);
202
203 mask = ((0x1 << shirq->irq_nr) - 1) << shirq->irq_bit_off;
204 while ((val = readl(shirq->base + shirq->regs.status_reg) &
205 mask)) {
206
207 val >>= shirq->irq_bit_off;
208 for (i = 0, j = 1; i < shirq->irq_nr; i++, j <<= 1) {
209
210 if (!(j & val))
211 continue;
212
213 generic_handle_irq(shirq->irq_base + i);
214
215 /* clear interrupt */
216 if (shirq->regs.clear_reg == -1)
217 continue;
218
219 tmp = readl(shirq->base + shirq->regs.clear_reg);
220 if (shirq->regs.reset_to_clear)
221 tmp &= ~(j << shirq->irq_bit_off);
222 else
223 tmp |= (j << shirq->irq_bit_off);
224 writel(tmp, shirq->base + shirq->regs.clear_reg);
225 }
226 }
227 chip->irq_unmask(&desc->irq_data);
228}
229
230static void __init spear_shirq_register(struct spear_shirq *shirq)
231{
232 int i;
233
234 if (shirq->invalid_irq)
235 return;
236
237 irq_set_chained_handler(shirq->irq, shirq_handler);
238 for (i = 0; i < shirq->irq_nr; i++) {
239 irq_set_chip_and_handler(shirq->irq_base + i,
240 &shirq_chip, handle_simple_irq);
241 set_irq_flags(shirq->irq_base + i, IRQF_VALID);
242 irq_set_chip_data(shirq->irq_base + i, shirq);
243 }
244
245 irq_set_handler_data(shirq->irq, shirq);
246}
247
248static int __init shirq_init(struct spear_shirq **shirq_blocks, int block_nr,
249 struct device_node *np)
250{
251 int i, irq_base, hwirq = 0, irq_nr = 0;
252 static struct irq_domain *shirq_domain;
253 void __iomem *base;
254
255 base = of_iomap(np, 0);
256 if (!base) {
257 pr_err("%s: failed to map shirq registers\n", __func__);
258 return -ENXIO;
259 }
260
261 for (i = 0; i < block_nr; i++)
262 irq_nr += shirq_blocks[i]->irq_nr;
263
264 irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
265 if (IS_ERR_VALUE(irq_base)) {
266 pr_err("%s: irq desc alloc failed\n", __func__);
267 goto err_unmap;
268 }
269
270 shirq_domain = irq_domain_add_legacy(np, irq_nr, irq_base, 0,
271 &irq_domain_simple_ops, NULL);
272 if (WARN_ON(!shirq_domain)) {
273 pr_warn("%s: irq domain init failed\n", __func__);
274 goto err_free_desc;
275 }
276
277 for (i = 0; i < block_nr; i++) {
278 shirq_blocks[i]->base = base;
279 shirq_blocks[i]->irq_base = irq_find_mapping(shirq_domain,
280 hwirq);
281 shirq_blocks[i]->irq = irq_of_parse_and_map(np, i);
282
283 spear_shirq_register(shirq_blocks[i]);
284 hwirq += shirq_blocks[i]->irq_nr;
285 }
286
287 return 0;
288
289err_free_desc:
290 irq_free_descs(irq_base, irq_nr);
291err_unmap:
292 iounmap(base);
293 return -ENXIO;
294}
295
296int __init spear300_shirq_of_init(struct device_node *np,
297 struct device_node *parent)
298{
299 return shirq_init(spear300_shirq_blocks,
300 ARRAY_SIZE(spear300_shirq_blocks), np);
301}
302
303int __init spear310_shirq_of_init(struct device_node *np,
304 struct device_node *parent)
305{
306 return shirq_init(spear310_shirq_blocks,
307 ARRAY_SIZE(spear310_shirq_blocks), np);
308}
309
310int __init spear320_shirq_of_init(struct device_node *np,
311 struct device_node *parent)
312{
313 return shirq_init(spear320_shirq_blocks,
314 ARRAY_SIZE(spear320_shirq_blocks), np);
315}