Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / include / asm-arm / arch-s3c2410 / entry-macro.S
index b7d4d7f..894c35c 100644 (file)
  * 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.
+*/
 
- * Modifications:
- *     10-Mar-2005 LCVR  Changed S3C2410_VA to S3C24XX_VA
- */
+/* 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)
+#define EXTINTPEND     (0xa8)
+#define EXTINTMASK     (0xa4)
 
+#include <asm/hardware.h>
+#include <asm/arch/irqs.h>
 
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
-               mov     \tmp, #S3C24XX_VA_IRQ
-               ldr     \irqnr, [ \tmp, #0x14 ]         @ get irq no
-30000:
-               teq     \irqnr, #4
-               teqne   \irqnr, #5
-               beq     1002f                           @ external irq reg
-
-               @ debug check to see if interrupt reported is the same
-               @ as the offset....
-
-               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:
-               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
+               mov     \base, #S3C24XX_VA_IRQ
+
+               ldr     \irqstat, [ \base, #INTPND]
+               bics    \irqnr, \irqstat, #3<<4         @@ only an GPIO IRQ
+               beq     2000f
+
+               @@ try the interrupt offset register, since it is there
+
+               ldr     \irqnr, [ \base, #INTOFFSET ]
+               mov     \tmp, #1
+               tst     \irqstat, \tmp, lsl \irqnr
+               addne   \irqnr, \irqnr, #IRQ_EINT0
+               bne     1001f
+
+               @@ the number specified is not a valid irq, so try
+               @@ and work it out for ourselves
+
+               mov     \irqnr, #IRQ_EINT0              @@ start here
+               b       3000f
+
+2000:
+               @@ load the GPIO interrupt register, and check it
+
+               add     \tmp, \base, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ
+               ldr     \irqstat, [ \tmp, # EXTINTPEND ]
+               ldr     \irqnr,   [ \tmp, # EXTINTMASK ]
+               bics    \irqstat, \irqstat, \irqnr
+               beq     1001f
+
+               mov     \irqnr, #(IRQ_EINT4 - 4)
+
+               @@ work out which irq (if any) we got
+3000:
+               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
+               movs    \irqnr, \irqnr
+
 1001:
-               @ exit irq routine
-               .endm
+               @@ exit here, Z flag unset if IRQ
 
+       .endm
 
                /* currently don't need an disable_fiq macro */
 
                .macro  disable_fiq
                .endm
-
-