aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorHeiko Stuebner <heiko@sntech.de>2013-03-06 22:38:25 -0500
committerKukjin Kim <kgene.kim@samsung.com>2013-03-06 22:38:25 -0500
commit17453dd2e7df20612770ebbf1ab5d506a432210c (patch)
tree818a77eccd79e7e265a5d9ca5f6ef579f67697b2 /arch/arm
parent3d3eb5a476a55e9ef1aeaa6a3c2b00587ed32521 (diff)
ARM: S3C24XX: add handle_irq function
This removes the dependency on static irq mappings for basic irq handling and makes the s3c24xx entry-macro.S obsolete. Also the interrupts of the second full interrupt controller on the s3c2416 are really handled now, which was forgotten when adding them. The handling itself does the same as the previous assembler-code in that it tries to get the interrupt offset from the offset register first and if that produces wrong results manually searches for the interrupt bit in the pending register value. It also saves the historic comment which explains the reason behind this. Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/entry-macro.S70
-rw-r--r--arch/arm/mach-s3c24xx/irq.c58
3 files changed, 59 insertions, 70 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 46fcfa8805f8..6820ffde359f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -778,6 +778,7 @@ config ARCH_S3C24XX
778 select HAVE_S3C2410_I2C if I2C 778 select HAVE_S3C2410_I2C if I2C
779 select HAVE_S3C2410_WATCHDOG if WATCHDOG 779 select HAVE_S3C2410_WATCHDOG if WATCHDOG
780 select HAVE_S3C_RTC if RTC_CLASS 780 select HAVE_S3C_RTC if RTC_CLASS
781 select MULTI_IRQ_HANDLER
781 select NEED_MACH_GPIO_H 782 select NEED_MACH_GPIO_H
782 select NEED_MACH_IO_H 783 select NEED_MACH_IO_H
783 help 784 help
diff --git a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
deleted file mode 100644
index 6a21beeba1da..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,70 +0,0 @@
1/*
2 * arch/arm/mach-s3c2410/include/mach/entry-macro.S
3 *
4 * Low-level IRQ helper macros for S3C2410-based platforms
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9*/
10
11/* We have a problem that the INTOFFSET register does not always
12 * show one interrupt. Occasionally we get two interrupts through
13 * the prioritiser, and this causes the INTOFFSET register to show
14 * what looks like the logical-or of the two interrupt numbers.
15 *
16 * Thanks to Klaus, Shannon, et al for helping to debug this problem
17*/
18
19#define INTPND (0x10)
20#define INTOFFSET (0x14)
21
22#include <mach/hardware.h>
23#include <asm/irq.h>
24
25 .macro get_irqnr_preamble, base, tmp
26 .endm
27
28 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
29
30 mov \base, #S3C24XX_VA_IRQ
31
32 @@ try the interrupt offset register, since it is there
33
34 ldr \irqstat, [\base, #INTPND ]
35 teq \irqstat, #0
36 beq 1002f
37 ldr \irqnr, [\base, #INTOFFSET ]
38 mov \tmp, #1
39 tst \irqstat, \tmp, lsl \irqnr
40 bne 1001f
41
42 @@ the number specified is not a valid irq, so try
43 @@ and work it out for ourselves
44
45 mov \irqnr, #0 @@ start here
46
47 @@ work out which irq (if any) we got
48
49 movs \tmp, \irqstat, lsl#16
50 addeq \irqnr, \irqnr, #16
51 moveq \irqstat, \irqstat, lsr#16
52 tst \irqstat, #0xff
53 addeq \irqnr, \irqnr, #8
54 moveq \irqstat, \irqstat, lsr#8
55 tst \irqstat, #0xf
56 addeq \irqnr, \irqnr, #4
57 moveq \irqstat, \irqstat, lsr#4
58 tst \irqstat, #0x3
59 addeq \irqnr, \irqnr, #2
60 moveq \irqstat, \irqstat, lsr#2
61 tst \irqstat, #0x1
62 addeq \irqnr, \irqnr, #1
63
64 @@ we have the value
651001:
66 adds \irqnr, \irqnr, #IRQ_EINT0
671002:
68 @@ exit here, Z flag unset if IRQ
69
70 .endm
diff --git a/arch/arm/mach-s3c24xx/irq.c b/arch/arm/mach-s3c24xx/irq.c
index 8bc29313c341..5c9f8b7a1fd6 100644
--- a/arch/arm/mach-s3c24xx/irq.c
+++ b/arch/arm/mach-s3c24xx/irq.c
@@ -26,6 +26,7 @@
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/irqdomain.h> 27#include <linux/irqdomain.h>
28 28
29#include <asm/exception.h>
29#include <asm/mach/irq.h> 30#include <asm/mach/irq.h>
30 31
31#include <mach/regs-irq.h> 32#include <mach/regs-irq.h>
@@ -282,6 +283,56 @@ static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
282 chained_irq_exit(chip, desc); 283 chained_irq_exit(chip, desc);
283} 284}
284 285
286static struct s3c_irq_intc *main_intc;
287static struct s3c_irq_intc *main_intc2;
288
289static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
290 struct pt_regs *regs)
291{
292 int pnd;
293 int offset;
294 int irq;
295
296 pnd = __raw_readl(intc->reg_intpnd);
297 if (!pnd)
298 return false;
299
300 /* We have a problem that the INTOFFSET register does not always
301 * show one interrupt. Occasionally we get two interrupts through
302 * the prioritiser, and this causes the INTOFFSET register to show
303 * what looks like the logical-or of the two interrupt numbers.
304 *
305 * Thanks to Klaus, Shannon, et al for helping to debug this problem
306 */
307 offset = __raw_readl(intc->reg_intpnd + 4);
308
309 /* Find the bit manually, when the offset is wrong.
310 * The pending register only ever contains the one bit of the next
311 * interrupt to handle.
312 */
313 if (!(pnd & (1 << offset)))
314 offset = __ffs(pnd);
315
316 irq = irq_find_mapping(intc->domain, offset);
317 handle_IRQ(irq, regs);
318 return true;
319}
320
321asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs)
322{
323 do {
324 if (likely(main_intc))
325 if (s3c24xx_handle_intc(main_intc, regs))
326 continue;
327
328 if (main_intc2)
329 if (s3c24xx_handle_intc(main_intc2, regs))
330 continue;
331
332 break;
333 } while (1);
334}
335
285#ifdef CONFIG_FIQ 336#ifdef CONFIG_FIQ
286/** 337/**
287 * s3c24xx_set_fiq - set the FIQ routing 338 * s3c24xx_set_fiq - set the FIQ routing
@@ -502,6 +553,13 @@ static struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np,
502 goto err; 553 goto err;
503 } 554 }
504 555
556 if (address == 0x4a000000)
557 main_intc = intc;
558 else if (address == 0x4a000040)
559 main_intc2 = intc;
560
561 set_handle_irq(s3c24xx_handle_irq);
562
505 return intc; 563 return intc;
506 564
507err: 565err: