[RFC][PATCH 1/5] omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing
Janusz Krzysztofik
jkrzyszt at tis.icnet.pl
Fri Dec 11 09:52:33 EST 2009
(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 <jkrzyszt at tis.icnet.pl>
To: linux-omap at 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 <jkrzyszt at 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
-------------------------------------------------------
More information about the linux-arm-kernel
mailing list