* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
-*/
-
-/* We have a problem that the INTOFFSET register does not always
- * show one interrupt. Occasionally we get two interrupts through
- * the prioritiser, and this causes the INTOFFSET register to show
- * what looks like the logical-or of the two interrupt numbers.
- *
- * Thanks to Klaus, Shannon, et al for helping to debug this problem
-*/
-
-#define INTPND (0x10)
-#define INTOFFSET (0x14)
+ * Modifications:
+ * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
+ */
#include <asm/hardware.h>
#include <asm/arch/irqs.h>
+
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- mov \base, #S3C24XX_VA_IRQ
+ mov \tmp, #S3C24XX_VA_IRQ
+ ldr \irqnr, [ \tmp, #0x14 ] @ get irq no
+30000:
+ teq \irqnr, #4
+ teqne \irqnr, #5
+ beq 1002f @ external irq reg
- @@ try the interrupt offset register, since it is there
+ @ debug check to see if interrupt reported is the same
+ @ as the offset....
- ldr \irqstat, [ \base, #INTPND ]
- teq \irqstat, #0
- beq 1002f
- ldr \irqnr, [ \base, #INTOFFSET ]
- mov \tmp, #1
- tst \irqstat, \tmp, lsl \irqnr
- bne 1001f
-
- @@ the number specified is not a valid irq, so try
- @@ and work it out for ourselves
-
- mov \irqnr, #0 @@ start here
-
- @@ work out which irq (if any) we got
-
- movs \tmp, \irqstat, lsl#16
- addeq \irqnr, \irqnr, #16
- moveq \irqstat, \irqstat, lsr#16
- tst \irqstat, #0xff
- addeq \irqnr, \irqnr, #8
- moveq \irqstat, \irqstat, lsr#8
- tst \irqstat, #0xf
- addeq \irqnr, \irqnr, #4
- moveq \irqstat, \irqstat, lsr#4
- tst \irqstat, #0x3
- addeq \irqnr, \irqnr, #2
- moveq \irqstat, \irqstat, lsr#2
- tst \irqstat, #0x1
- addeq \irqnr, \irqnr, #1
-
- @@ we have the value
-1001:
+ teq \irqnr, #0
+ beq 20002f
+ ldr \irqstat, [ \tmp, #0x10 ] @ INTPND
+ mov \irqstat, \irqstat, lsr \irqnr
+ tst \irqstat, #1
+ bne 20002f
+
+ /* debug/warning if we get an invalud response from the
+ * INTOFFSET register */
+#if 1
+ stmfd r13!, { r0 - r4 , r8-r12, r14 }
+ ldr r1, [ \tmp, #0x14 ] @ INTOFFSET
+ ldr r2, [ \tmp, #0x10 ] @ INTPND
+ ldr r3, [ \tmp, #0x00 ] @ SRCPND
+ adr r0, 20003f
+ bl printk
+ b 20004f
+
+20003:
+ .ascii "<7>irq: err - bad offset %d, intpnd=%08x, srcpnd=%08x\n"
+ .byte 0
+ .align 4
+20004:
+ mov r1, #1
+ mov \tmp, #S3C24XX_VA_IRQ
+ ldmfd r13!, { r0 - r4 , r8-r12, r14 }
+#endif
+
+ @ try working out interrupt number for ourselves
+ mov \irqnr, #0
+ ldr \irqstat, [ \tmp, #0x10 ] @ INTPND
+10021:
+ movs \irqstat, \irqstat, lsr#1
+ bcs 30000b @ try and re-start the proccess
+ add \irqnr, \irqnr, #1
+ cmp \irqnr, #32
+ ble 10021b
+
+ @ found no interrupt, set Z flag and leave
+ movs \irqnr, #0
+ b 1001f
+
+20005:
+20002: @ exit
+ @ we base the s3c2410x interrupts at 16 and above to allow
+ @ isa peripherals to have their standard interrupts, also
+ @ ensure that Z flag is un-set on exit
+
+ @ note, we cannot be sure if we get IRQ_EINT0 (0) that
+ @ there is simply no interrupt pending, so in all other
+ @ cases we jump to say we have found something, otherwise
+ @ we check to see if the interrupt really is assrted
adds \irqnr, \irqnr, #IRQ_EINT0
+ teq \irqnr, #IRQ_EINT0
+ bne 1001f @ exit
+ ldr \irqstat, [ \tmp, #0x10 ] @ INTPND
+ teq \irqstat, #0
+ moveq \irqnr, #0
+ b 1001f
+
+ @ we get here from no main or external interrupts pending
1002:
- @@ exit here, Z flag unset if IRQ
+ add \tmp, \tmp, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ
+ ldr \irqstat, [ \tmp, # 0xa8 ] @ EXTINTPEND
+ ldr \irqnr, [ \tmp, # 0xa4 ] @ EXTINTMASK
+
+ bic \irqstat, \irqstat, \irqnr @ clear masked irqs
+
+ mov \irqnr, #IRQ_EINT4 @ start extint nos
+ mov \irqstat, \irqstat, lsr#4 @ ignore bottom 4 bits
+10021:
+ movs \irqstat, \irqstat, lsr#1
+ bcs 1004f
+ add \irqnr, \irqnr, #1
+ cmp \irqnr, #IRQ_EINT23
+ ble 10021b
+
+ @ found no interrupt, set Z flag and leave
+ movs \irqnr, #0
+
+1004: @ ensure Z flag clear in case our MOVS shifted out the last bit
+ teq \irqnr, #0
+1001:
+ @ exit irq routine
+ .endm
- .endm
/* currently don't need an disable_fiq macro */
.macro disable_fiq
.endm
+
+