(resending with LAKML added to CC: after Tony's suggestion)
(dropping linux-input - Dmitry, please request me to readd if desired)

----------  Original message  ----------

Subject: [RFC][PATCH 1/5] omap1: Amstrad Delta: add FIQ handler for serial
        keyboard port interrupt processing
Date: Thursday 10 December 2009
From: Janusz Krzysztofik <jkrzy...@tis.icnet.pl>
To: linux-omap@vger.kernel.org

This patch introduces a Fast Interrupt Request (FIQ) handler for Amstrad Delta
(E3) videophone. The handler's purpose is to process interrupts generated by a
GPIO line that a serial keyboard clock hangs off. It collects consecutive bits
into bytes, pushing them into a buffer, then requests a higher level interrupt
after one or more characters are ready for further processing by a keyboard
port driver.

The handler also processes interrupts generated by two other GPIO lines, used
by other on-board supported devices, by simply requesting a higher level
interrupt, that in turn should invoke those device's specific irq handlers.

32k timer IRQ line, not used for any purpose by the on-board hardware, has
been choosen as a higher level interrupt source.

Created and tested against linux-omap for-next,
commit 82f1d8f22f2c65e70206e40a6f17688bf64a892c dated 2009-12-02.

Signed-off-by: Janusz Krzysztofik <jkrzy...@tis.icnet.pl>

---

 arch/arm/mach-omap1/Kconfig                 |    8
 arch/arm/mach-omap1/Makefile                |    1
 arch/arm/mach-omap1/ams-delta-fiq-handler.S |  342 ++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/irqs.h      |    4
 4 files changed, 355 insertions(+)

diff -uprN git.orig/arch/arm/mach-omap1/Kconfig git/arch/arm/mach-omap1/Kconfig
--- git.orig/arch/arm/mach-omap1/Kconfig        2009-12-02 15:48:37.000000000 
+0100
+++ git/arch/arm/mach-omap1/Kconfig     2009-12-10 02:14:37.000000000 +0100
@@ -152,6 +152,14 @@ config MACH_AMS_DELTA
          Support for the Amstrad E3 (codename Delta) videophone. Say Y here
          if you have such a device.
 
+config AMS_DELTA_FIQ
+       bool "Fast Interrupt Request (FIQ) support for the E3"
+       depends on MACH_AMS_DELTA
+       select FIQ
+       help
+         Provide a FIQ handler for the E3. This redirects the gpio IRQ to FIQ
+         And is required to use the E3 mailboard
+
 config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
        depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
diff -uprN git.orig/arch/arm/mach-omap1/Makefile 
git/arch/arm/mach-omap1/Makefile
--- git.orig/arch/arm/mach-omap1/Makefile       2009-12-10 01:36:56.000000000 
+0100
+++ git/arch/arm/mach-omap1/Makefile    2009-12-10 02:14:37.000000000 +0100
@@ -33,6 +33,7 @@ obj-$(CONFIG_MACH_OMAP_PALMZ71)               += boar
 obj-$(CONFIG_MACH_OMAP_PALMTT)         += board-palmtt.o
 obj-$(CONFIG_MACH_NOKIA770)            += board-nokia770.o
 obj-$(CONFIG_MACH_AMS_DELTA)           += board-ams-delta.o
+obj-$(CONFIG_AMS_DELTA_FIQ)            += ams-delta-fiq-handler.o
 obj-$(CONFIG_MACH_SX1)                 += board-sx1.o board-sx1-mmc.o
 obj-$(CONFIG_MACH_HERALD)              += board-htcherald.o
 
diff -uprN git.orig/arch/arm/mach-omap1/ams-delta-fiq-handler.S 
git/arch/arm/mach-omap1/ams-delta-fiq-handler.S
--- git.orig/arch/arm/mach-omap1/ams-delta-fiq-handler.S        1970-01-01 
01:00:00.000000000 +0100
+++ git/arch/arm/mach-omap1/ams-delta-fiq-handler.S     2009-12-10 
03:27:14.000000000 +0100
@@ -0,0 +1,342 @@
+/*
+ *  linux/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+ *
+ *  Based on  linux/arch/arm/lib/floppydma.S
+ *  Renamed and modified to work with 2.6 kernel by Matt Callow
+ *  Copyright (C) 1995, 1996 Russell King
+ *  Copyright (C) 2004 Pete Trapps
+ *  Copyright (C) 2006 Matt Callow
+ *  Copyright (C) 2009 Janusz Krzysztofik
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <plat/io.h>
+
+#define OMAP1510_TIMER1_BASE   0xfffec500
+#define OMAP1510_TIMER2_BASE   0xfffec600
+#define OMAP1510_TIMER3_BASE   0xfffec700
+#define OMAP1510_WATCHDOG_BASE 0xfffec800
+
+#define MAX_INTER_BIT_GAP      (6 * 200)       /* 6 ticks/uSec => 200uSec */
+
+/* MPU Timer Register Offsets */
+#define CNTL_TIMER             0
+#define LOAD_TIM               4
+#define READ_TIM               8
+
+#define MPU_L1_INTERRUPT_BASE  OMAP1_IO_ADDRESS(0xFFFECB00)
+#define MPU_L2_INTERRUPT_BASE  OMAP1_IO_ADDRESS(0xFFFE0000)
+
+#define ITR                    0x00
+#define MIR                    0x04
+#define SIR_IRQ_CODE           0x10
+#define SIR_FIQ_CODE           0x14
+#define CONTROL_REG            0x18
+#define ILR14                  0x54
+#define ILR30                  0x94
+#define ISR                    0x9C
+
+#define T_BIT                  0x20
+#define F_BIT                  0x40
+#define I_BIT                  0x80
+#define CC_V_BIT               (1 << 28)
+#define CC_C_BIT               (1 << 29)
+#define CC_Z_BIT               (1 << 30)
+#define CC_N_BIT               (1 << 31)
+#define PCMASK                 0
+
+#define GPIO_BASE              OMAP1_IO_ADDRESS(0xFFFCE000)
+#define GPIO_DATA_INPUT        0x00
+#define GPIO_DATA_OUTPUT       0x04
+#define GPIO_DIRECTION_CONTROL 0x08
+#define GPIO_INTERRUPT_CONTROL 0x0C
+#define GPIO_INTERRUPT_MASK    0x10
+#define GPIO_INTERRUPT_STATUS  0x14
+#define GPIO_PIN_CONTROL       0x18
+
+/*
+ * GPIO_DATA_INPUT bit 0 is MBRD_DI_PROC
+ * GPIO_DATA_INPUT bit 1 is MBRD_CLK
+ */
+#define MBRD_DI_PROC_MASK      0x01
+#define MBRD_CLK_MASK          0x02
+#define MDM_MASK               0x04
+#define HKSW_MASK              0x10
+#define OTHERS_MASK            0x14
+
+#define INT_GPIO0               0
+#define INT_GPIO1               1
+#define INT_GPIO2               2
+#define INT_GPIO3               3
+#define INT_GPIO4               4
+#define INT_GPIO5               5
+#define INT_GPIO6               6
+#define INT_GPIO7               7
+#define INT_GPIO8               8
+#define INT_GPIO9               9
+#define INT_GPIO10             10
+#define INT_GPIO11             11
+#define INT_GPIO12             12
+#define INT_GPIO13             13
+#define INT_GPIO14             14
+#define INT_GPIO15             15
+
+#define GPIO6_HDW_IP_SCARD_0_MASK 0x40
+
+/* Driver buffer offsets */
+#define FIQ_MASK                0
+#define FIQ_STATE               4
+#define FIQ_CHAR_CNT            8
+#define FIQ_FRNT_OFFSET                12
+#define FIQ_BACK_OFFSET                16
+#define FIQ_BUF_LEN            20
+#define FIQ_CHAR               24
+#define FIQ_MISSED_CHARS       28
+#define FIQ_BUFFER_START       32
+#define FIQ_GPIO_INT_MASK      36
+#define FIQ_CHAR_HICNT         40
+#define FIQ_IRQ_PEND           44
+#define FIQ_SIR_CODE_L1                48
+#define IRQ_SIR_CODE_L2                52
+#define FIQ_CNT_INT_00         56
+#define FIQ_CNT_INT_CHAR       60
+#define FIQ_CNT_INT_MDM                64
+#define FIQ_CNT_INT_FIQ                68
+#define FIQ_CNT_INT_04         72
+#define FIQ_CNT_INT_05         76
+#define FIQ_CNT_INT_KBD                80
+#define FIQ_CNT_INT_07         84
+#define FIQ_CNT_INT_08         88
+#define FIQ_CNT_INT_09         92
+#define FIQ_CNT_INT_10         96
+#define FIQ_CNT_INT_11         100
+#define FIQ_CNT_INT_12         104
+#define FIQ_CNT_INT_13         108
+#define FIQ_CNT_INT_14         112
+#define FIQ_CNT_INT_15         116
+#define FIQ_CIRC_BUFF          120     /*Start of circular buffer */
+
+#define TIMER_32k_MASK         0x400000
+#define GPIO_INT_MASK                  0x4000
+
+/*
+ * Register useage
+ * r8 -
+ * r9 - the driver buffer
+ * r10 -
+ * r11 -
+ * r12 -base pointers
+ * r13 -
+ */
+
+       .text
+
+       .global qwerty_fiqin_end
+
+ENTRY(qwerty_fiqin_start)
+       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+       @setup base pointer = MPU_L1_INTERRUPT_BASE 0xFFFECB00
+       ldr r12, mpu_l1_interrupt_base
+       ldr r11, [r12, #SIR_FIQ_CODE]           @read SIR to clear FIQ
+
+       @@@@@@@@@@@@@@@@@@@@@@@@@@@
+       @setup base pointer = GPIO_BASE 0xFFFCE000
+       ldr r12, gpio_base
+
+key:   @Is it a keyboard interrupt?
+       ldr r11, [r12,#GPIO_INTERRUPT_STATUS]   @ get GPIO interrupt status
+       and r10, r11, #MBRD_CLK_MASK            @ reveal keyboard bit
+       cmp r10, #MBRD_CLK_MASK                 @ is keyboard bit low?
+       bne mdm                                 @ no - spurious - try mdm
+       mov r10, #MBRD_CLK_MASK
+       str r10, [r12,#GPIO_INTERRUPT_STATUS]   @ Set the bit to clear interrupt
+
+       ldr r10, [r9, #FIQ_CNT_INT_KBD]         @ get int count for IRQ handlers
+       add r10, r10, #1                        @ increment it
+       str r10, [r9, #FIQ_CNT_INT_KBD]         @ save status for IRQ handlers
+
+       @@@@@@@@@@@@@@@@@@@@@@
+       @ start processing keyboard bitstream
+state:
+       ldr r10, [r9,#FIQ_STATE]
+       cmp r10, #0                             @ are we expecting start bit?
+       bne data                                @ no - in data processing state
+
+start:
+       ldr r11, [r12, #GPIO_DATA_INPUT]        @ get input
+       and r11, r11, #MBRD_DI_PROC_MASK        @ mask out other bits
+       cmp r11, #MBRD_DI_PROC_MASK             @ is kbd data in bit set?
+       bne exit                                @ no - exit, wait for next irq
+       mov r10, #1                             @ good start bit, change state
+                                               @ to data processing
+       str r10, [r9,#FIQ_STATE]
+       mov r10, #0x02                          @ set mask to 0x02
+       str r10, [r9, #FIQ_MASK]
+       mov r10, #0                             @ clear character byte
+       str r10, [r9, #FIQ_CHAR]
+
+       @@@@@@@@@ MASK OTHERS TILL KEY DONE @@@@@@@@@@@@@@
+       mov r10, #OTHERS_MASK
+       ldr r11, [r12, #GPIO_INTERRUPT_MASK]    @ get mask reg
+       str r11, [r9, #FIQ_GPIO_INT_MASK]       @ save it for later restore
+       orr r11, r11, r10                       @ mask modem int
+       str r11, [r12, #GPIO_INTERRUPT_MASK]    @ write mask reg
+       @@@@@@@@@@ END @@@@@@@@@@@@@@@@@
+       b exit                                  @ exit, wait for first data bit
+
+data:  ldr r11, [r12, #GPIO_DATA_INPUT]        @ get input
+       and r11, r11, #MBRD_DI_PROC_MASK        @ mask out other bits
+       cmp r11, #0                             @ is kbd data in clear?
+       bne shift
+       ldr r10, [r9, #FIQ_CHAR]
+       ldr r11, [r9, #FIQ_MASK]
+       orr r10, r11, r10                       @ or mask and character byte
+       str r10, [r9, #FIQ_CHAR]
+
+shift: ldr r10, [r9, #FIQ_MASK]
+       mov r10, r10, lsl #1                    @ shift mask left
+       str r10, [r9, #FIQ_MASK]
+       cmp r10, #0x800                         @ have we got all the bits?
+       bne exit                                @ not yet - get more
+       mov r10, #0                             @ yes set state to start
+       str r10, [r9, #FIQ_STATE]
+
+       @@@@@@@@@ KEY DONE - RESTORE INTERRUPT MASK @@@
+       ldr r11, [r9,#FIQ_GPIO_INT_MASK]
+       str r11, [r12, #GPIO_INTERRUPT_MASK]    @ write mask reg
+       @@@@@@@@@@ END @@@@@@@@@@@@@@@@@
+
+       @Add char to circular buffer
+       ldr r10, [r9, #FIQ_CHAR_CNT]            @ get char count
+       ldr r8, [r9, #FIQ_BUF_LEN]              @ get buffer size
+       cmp r10, r8                             @ is buffer full?
+       bne not_full
+       ldr r10, [r9, #FIQ_MISSED_CHARS]        @ get missed char count
+       add r10, r10, #1                        @ inc missed char count
+       str r10, [r9, #FIQ_MISSED_CHARS]        @ save missed char count
+       b int                                   @ force IRQ
+
+not_full:
+       ldr r10, [r9, #FIQ_FRNT_OFFSET]         @ get current front offset
+       ldr r11, [r9, #FIQ_BUF_LEN]             @ get buff size
+       cmp r10,        r11                     @ offset == buffer size?
+       bne store                               @ no - so branch to front
+       mov r10, #0                             @ set front offset = 0
+
+store: ldr r12, [r9, #FIQ_BUFFER_START]        @ get start addr of circ buffer
+       add r12, r12, r10, LSL #2               @ add front offset to buff base
+       ldr r8, [r9, #FIQ_CHAR]                 @ get latest character
+       str r8, [r12]                           @ ####01 store in circ buffer
+       add r10, r10, #1                        @ inc front offset
+       str r10, [r9, #FIQ_FRNT_OFFSET]         @ ####04 store front offset
+       ldr r8, [r9, #FIQ_CHAR_CNT]             @ get char count
+       add r8, r8, #1                          @ inc count of chars in buffer
+       str r8, [r9, #FIQ_CHAR_CNT]             @ ####02 store char count
+
+       ldr r10, [r9, #FIQ_CHAR_HICNT]          @ get char count hi watermark
+       cmp r10, r8
+       bgt setstat                             @ hi count bigger - don't change
+       str r8, [r9, #FIQ_CHAR_HICNT]           @ store char cnt in hi watermark
+setstat:
+       ldr r10, [r9, #FIQ_CNT_INT_CHAR]        @ get char cnt for IRQ handlers
+       add r10, r10, #1                        @ increment it
+       str r10, [r9, #FIQ_CNT_INT_CHAR]        @ save status for IRQ handlers
+
+       @@@@@@@@@@@@@@@@@@@@@@@@
+       @ Force a INT_OS_32kHz_TIMER interrupt
+       @setup base pointer = MPU_L2_INTERRUPT_BASE     0xFFFE0000
+int:   ldr r12, mpu_l2_interrupt_base
+       mov r10, #TIMER_32k_MASK                @ set 32kHz_TIMER bit
+       str r10, [r12, #ISR]                    @ write ISR
+
+
+       @@@@@@@@@@@@@@@@@@@@@@@@@@@
+       @setup base pointer = GPIO_BASE 0xFFFCE000
+       ldr r12, gpio_base
+
+mdm:   @Is it a modem interrupt?
+       ldr r11, [r12,#GPIO_INTERRUPT_MASK]     @ get GPIO interrupt mask
+       and r10, r11, #MDM_MASK                 @ reveal modem bit
+       cmp r10, #MDM_MASK                      @ is mask bit set?
+       beq hksw                                @ yes, next source
+
+       ldr r11, [r12,#GPIO_DATA_INPUT]         @ get GPIO data line status
+       and r10, r11, #MDM_MASK                 @ reveal modem bit
+       cmp r10, #MDM_MASK                      @ is modem bit set?
+       bne hksw                                @ no, so skip mdm - next source
+
+       mov r10, #MDM_MASK                      @ its a mdm interrupt
+       str r10, [r12,#GPIO_INTERRUPT_STATUS]   @ clear the modem interrupt
+
+       ldr r10, [r9, #FIQ_CNT_INT_MDM]         @ get modem interrupt count
+       add r10, r10, #1                        @ increment it
+       str r10, [r9, #FIQ_CNT_INT_MDM]         @ save count for IRQ handlers
+
+       @@@@@@@@@@@@@@@@@@@@@@@@
+       @ Force a INT_OS_32kHz_TIMER interrupt
+       @setup base pointer = MPU_L2_INTERRUPT_BASE 0xFFFE0000
+       ldr r12, mpu_l2_interrupt_base
+       mov r10, #TIMER_32k_MASK                @ set 32kHz_TIMER bit
+       str r10, [r12, #ISR]                    @ write ISR
+
+       @@@@@@@@@@@@@@@@@@@@@@@@@@@
+       @setup base pointer = GPIO_BASE 0xFFFCE000
+       ldr r12, gpio_base
+
+hksw:  @Is it a hook switch interrupt?
+       ldr r11, [r12,#GPIO_INTERRUPT_MASK]     @ get GPIO interrupt mask
+       and r10, r11, #HKSW_MASK                @ reveal hook switch bit
+       cmp r10, #HKSW_MASK                     @ is mask bit set?
+       beq exit                                @ yes, exit
+
+       ldr r11, [r12,#GPIO_INTERRUPT_STATUS]   @ get GPIO interrupts status
+       and r10, r11, #HKSW_MASK                @ reveal hook switch bit
+       cmp r10, #HKSW_MASK                     @ is hook switch bit set?
+       bne exit                                @ no, so skip hksw - exit
+
+       mov r10, #HKSW_MASK                     @ it's a hooksw interrupt
+       str r10, [r12,#GPIO_INTERRUPT_STATUS]   @ clear hook switch interrupt
+
+       ldr r10, [r9, #FIQ_CNT_INT_04]          @ get hooksw inerrupt count
+       add r10, r10, #1                        @ increment it
+       str r10, [r9, #FIQ_CNT_INT_04]          @ save count for IRQ handlers
+
+       @@@@@@@@@@@@@@@@@@@@@@@@
+       @ Force a INT_OS_32kHz_TIMER interrupt
+       @setup base pointer = MPU_L2_INTERRUPT_BASE 0xFFFE0000
+       ldr r12, mpu_l2_interrupt_base
+       mov r10, #TIMER_32k_MASK                @ set 32kHz_TIMER bit
+       str r10, [r12, #ISR]                    @ write ISR
+
+       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+       @setup base pointer = MPU_L1_INTERRUPT_BASE 0xFFFECB00
+exit:  ldr r12, mpu_l1_interrupt_base
+       mov r10, # 0x2
+       str r10, [r12, #CONTROL_REG]            @ reset FIQ Agreement
+
+       subs    pc, lr, #4                      @ return from FIQ
+
+/*
+ * Virtual addresses for IO
+ */
+mpu_l1_interrupt_base:
+       .word MPU_L1_INTERRUPT_BASE
+mpu_l2_interrupt_base:
+       .word MPU_L2_INTERRUPT_BASE
+gpio_base:
+       .word GPIO_BASE
+qwerty_fiqin_end:
+
+/*
+ * Check the size of the FIQ,
+ * it cannot go beyond 0xffff0200, and is copied to 0xffff001c
+ */
+.if (qwerty_fiqin_end - qwerty_fiqin_start) > (0x200 - 0x1c)
+       .err
+.endif
diff -uprN git.orig/arch/arm/plat-omap/include/plat/irqs.h 
git/arch/arm/plat-omap/include/plat/irqs.h
--- git.orig/arch/arm/plat-omap/include/plat/irqs.h     2009-12-02 
15:48:51.000000000 +0100
+++ git/arch/arm/plat-omap/include/plat/irqs.h  2009-12-10 03:38:02.000000000 
+0100
@@ -489,4 +489,8 @@ void omap_intc_restore_context(void);
 
 #include <mach/hardware.h>
 
+#ifdef CONFIG_FIQ
+#define FIQ_START              1024
+#endif
+
 #endif

-------------------------------------------------------
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to