[RFC][PATCH v2 1/5] omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing

Janusz Krzysztofik jkrzyszt at tis.icnet.pl
Mon Mar 29 10:24:08 EDT 2010


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-2.6.34-rc2.

Signed-off-by: Janusz Krzysztofik <jkrzyszt at tis.icnet.pl>
---
v2 changes:
- no functional changes,
- refresh against linux-2.6.34-rc2.

 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	2010-03-25 15:52:17.000000000 +0100
+++ git/arch/arm/mach-omap1/Kconfig	2010-03-28 23:28:44.000000000 +0200
@@ -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	2010-03-25 15:52:17.000000000 +0100
+++ git/arch/arm/mach-omap1/Makefile	2010-03-28 23:28:44.000000000 +0200
@@ -37,6 +37,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	2010-03-28 23:28:44.000000000 +0200
@@ -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	2010-03-25 15:52:38.000000000 +0100
+++ git/arch/arm/plat-omap/include/plat/irqs.h	2010-03-28 23:28:44.000000000 +0200
@@ -430,4 +430,8 @@ void omap3_intc_resume_idle(void);
 
 #include <mach/hardware.h>
 
+#ifdef CONFIG_FIQ
+#define FIQ_START		1024
+#endif
+
 #endif



More information about the linux-arm-kernel mailing list