[PATCH v4 1/5(7)] OMAP1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing

Janusz Krzysztofik jkrzyszt at tis.icnet.pl
Tue Apr 27 21:01:29 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 words, pushing them into a buffer, then requests a higher level interrupt
after one or more words 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.

IRQ12 line, not used by OMAP1510 hardware (described as reserved), has been 
choosen as a higher level interrupt source.

Created and tested against linux-omap master, 
commit 104a77440f05430f29f9d3f4ecb88c1536819585 dated 2010-04-27.

Compiles on top of PATCH v4 0.1/5(7), "OMAP: add missing FIQ_START definition 
required for arch/arm/kernel/fiq.c compilation".

Compile tested with a bunch of OMAP15XX/OMAP16XX boards selected 
simultaneously.

Signed-off-by: Janusz Krzysztofik <jkrzyszt at tis.icnet.pl>
---
v2 changes:
- no functional changes,
- refresh against linux-2.6.34-rc2.
v3 changes:
- assembler code optimizations suggested by Ralph Corderoy,
- (re)use existing header file provided macros where applicable instead of 
  defining new (from scratch); remove a lot of unnecessary defines,
- follow default OMAP GPIO interrupt processing path more closely,
- prepare for choosing arbitrary IRQ for deferred_fiq handler; use IRQ12 
  (reserved on OMAP1510) instead of Timer 32K dedicated IRQ,
- more optimizations for smaller code.
v4 changes:
- correct a few occurrences of 2nd argumet missing in 3-argument assembly 
  instruction, thanks to Ralph Corderoy for pointing them out,
- remove commented out code for interrupt active edge toggling, but keep the 
  updated comment that justifies the removal.

 arch/arm/mach-omap1/Kconfig                      |   10
 arch/arm/mach-omap1/Makefile                     |    1
 arch/arm/mach-omap1/ams-delta-fiq-handler.S      |  278 +++++++++++++++++++++++
 arch/arm/mach-omap1/include/mach/ams-delta-fiq.h |   72 +++++
 4 files changed, 361 insertions(+)

diff -uprN git.orig/arch/arm/mach-omap1/Kconfig git/arch/arm/mach-omap1/Kconfig
--- git.orig/arch/arm/mach-omap1/Kconfig	2010-04-27 21:40:22.000000000 +0200
+++ git/arch/arm/mach-omap1/Kconfig	2010-04-27 22:23:41.000000000 +0200
@@ -152,6 +152,16 @@ 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 allows for fast handling of interrupts generated
+	  by the clock line of the E3 mailboard (or a PS/2 keyboard)
+	  connected to the GPIO based external keyboard port.
+
 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-04-27 21:40:22.000000000 +0200
+++ git/arch/arm/mach-omap1/Makefile	2010-04-27 22:23:41.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-04-27 22:23:41.000000000 +0200
@@ -0,0 +1,278 @@
+/*
+ *  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) 2010 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 <plat/io.h>
+#include <plat/board-ams-delta.h>
+
+#include <mach/ams-delta-fiq.h>
+
+/*
+ * GPIO related definitions, copied from arch/arm/plat-omap/gpio.c.
+ * Unfortunately, those were not placed in a separate header file.
+ */
+#define OMAP1510_GPIO_BASE		0xFFFCE000
+#define OMAP1510_GPIO_DATA_INPUT	0x00
+#define OMAP1510_GPIO_DATA_OUTPUT	0x04
+#define OMAP1510_GPIO_DIR_CONTROL	0x08
+#define OMAP1510_GPIO_INT_CONTROL	0x0c
+#define OMAP1510_GPIO_INT_MASK		0x10
+#define OMAP1510_GPIO_INT_STATUS	0x14
+#define OMAP1510_GPIO_PIN_CONTROL	0x18
+
+/* GPIO register bitmasks */
+#define KEYBRD_DATA_MASK		(0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_DATA)
+#define KEYBRD_CLK_MASK			(0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_CLK)
+#define MODEM_IRQ_MASK			(0x1 << AMS_DELTA_GPIO_PIN_MODEM_IRQ)
+#define HOOK_SWITCH_MASK		(0x1 << AMS_DELTA_GPIO_PIN_HOOK_SWITCH)
+#define OTHERS_MASK			(MODEM_IRQ_MASK | HOOK_SWITCH_MASK)
+
+/* IRQ handler register bitmasks */
+#define DEFERRED_FIQ_MASK		(0x1 << (INT_DEFERRED_FIQ % IH2_BASE))
+#define GPIO_BANK1_MASK  		(0x1 << INT_GPIO_BANK1)
+
+/* Driver buffer byte offsets */
+#define BUF_MASK			(FIQ_MASK * 4)
+#define BUF_STATE			(FIQ_STATE * 4)
+#define BUF_KEYS_CNT			(FIQ_KEYS_CNT * 4)
+#define BUF_TAIL_OFFSET			(FIQ_TAIL_OFFSET * 4)
+#define BUF_HEAD_OFFSET			(FIQ_HEAD_OFFSET * 4)
+#define BUF_BUF_LEN			(FIQ_BUF_LEN * 4)
+#define BUF_KEY				(FIQ_KEY * 4)
+#define BUF_MISSED_KEYS			(FIQ_MISSED_KEYS * 4)
+#define BUF_BUFFER_START		(FIQ_BUFFER_START * 4)
+#define BUF_GPIO_INT_MASK		(FIQ_GPIO_INT_MASK * 4)
+#define BUF_KEYS_HICNT			(FIQ_KEYS_HICNT * 4)
+#define BUF_IRQ_PEND			(FIQ_IRQ_PEND * 4)
+#define BUF_SIR_CODE_L1			(FIQ_SIR_CODE_L1 * 4)
+#define BUF_SIR_CODE_L2			(IRQ_SIR_CODE_L2 * 4)
+#define BUF_CNT_INT_00			(FIQ_CNT_INT_00 * 4)
+#define BUF_CNT_INT_KEY			(FIQ_CNT_INT_KEY * 4)
+#define BUF_CNT_INT_MDM			(FIQ_CNT_INT_MDM * 4)
+#define BUF_CNT_INT_03			(FIQ_CNT_INT_03 * 4)
+#define BUF_CNT_INT_HSW			(FIQ_CNT_INT_HSW * 4)
+#define BUF_CNT_INT_05			(FIQ_CNT_INT_05 * 4)
+#define BUF_CNT_INT_06			(FIQ_CNT_INT_06 * 4)
+#define BUF_CNT_INT_07			(FIQ_CNT_INT_07 * 4)
+#define BUF_CNT_INT_08			(FIQ_CNT_INT_08 * 4)
+#define BUF_CNT_INT_09			(FIQ_CNT_INT_09 * 4)
+#define BUF_CNT_INT_10			(FIQ_CNT_INT_10 * 4)
+#define BUF_CNT_INT_11			(FIQ_CNT_INT_11 * 4)
+#define BUF_CNT_INT_12			(FIQ_CNT_INT_12 * 4)
+#define BUF_CNT_INT_13			(FIQ_CNT_INT_13 * 4)
+#define BUF_CNT_INT_14			(FIQ_CNT_INT_14 * 4)
+#define BUF_CNT_INT_15			(FIQ_CNT_INT_15 * 4)
+#define BUF_CIRC_BUFF			(FIQ_CIRC_BUFF * 4)
+
+
+/*
+ * Register useage
+ * r8  - temporary
+ * r9  - the driver buffer
+ * r10 - temporary
+ * r11 - interrupts mask
+ * r12 - base pointers
+ * r13 - interrupts status
+ */
+
+	.text
+
+	.global qwerty_fiqin_end
+
+ENTRY(qwerty_fiqin_start)
+	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+	@ FIQ intrrupt handler
+	ldr r12, omap_ih1_base			@ set pointer to level1 handler
+
+	ldr r11, [r12, #IRQ_MIR_REG_OFFSET]	@ fetch interrupts mask
+
+	ldr r13, [r12, #IRQ_ITR_REG_OFFSET]	@ fetch interrupts status
+	bics r13, r13, r11			@ clear masked - any left?
+	beq exit				@ none - spurious FIQ? exit
+
+	ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET]	@ get requested interrupt number
+
+	mov r8, #2				@ reset FIQ agreement
+	str r8, [r12, #IRQ_CONTROL_REG_OFFSET]
+
+	cmp r10, #INT_GPIO_BANK1		@ is it GPIO bank interrupt?
+	beq gpio				@ yes - process it
+
+	mov r8, #1
+	orr r8, r11, r8, lsl r10		@ mask spurious interrupt
+	str r8, [r12, #IRQ_MIR_REG_OFFSET]
+exit:
+	subs	pc, lr, #4			@ return from FIQ
+	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+
+	@@@@@@@@@@@@@@@@@@@@@@@@@@@
+gpio:	@ GPIO bank interrupt handler
+	ldr r12, omap1510_gpio_base		@ set base pointer to GPIO bank
+
+	ldr r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ fetch GPIO interrupts mask
+restart:
+	ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS]	@ fetch status bits
+	bics r13, r13, r11			@ clear masked - any left?
+	beq exit				@ no - spurious interrupt? exit
+
+	orr r11, r11, r13			@ mask all requested interrupts
+	str r11, [r12, #OMAP1510_GPIO_INT_MASK]
+
+	ands r10, r13, #KEYBRD_CLK_MASK		@ extract keyboard status - set?
+	beq hksw				@ no - try next source
+
+
+	@@@@@@@@@@@@@@@@@@@@@@
+	@ Keyboard clock FIQ mode interrupt handler
+	@ r10 now contains KEYBRD_CLK_MASK, use it
+	str r10, [r12, #OMAP1510_GPIO_INT_STATUS]	@ ack the interrupt
+	bic r11, r11, r10				@ unmask it
+	str r11, [r12, #OMAP1510_GPIO_INT_MASK]
+
+	@ Process keyboard data
+	ldr r8, [r12, #OMAP1510_GPIO_DATA_INPUT]	@ fetch GPIO input
+
+	ldr r10, [r9, #BUF_STATE]		@ fetch kbd interface state
+	cmp r10, #0				@ are we expecting start bit?
+	bne data				@ no - go to data processing
+
+	ands r8, r8, #KEYBRD_DATA_MASK		@ check start bit - detected?
+	beq hksw				@ no - try next source
+
+	@ r8 contains KEYBRD_DATA_MASK, use it
+	str r8, [r9, #BUF_STATE]		@ enter data processing state
+	@ r10 already contains 0, reuse it
+	str r10, [r9, #BUF_KEY]			@ clear keycode
+	mov r10, #2				@ reset input bit mask
+	str r10, [r9, #BUF_MASK]
+
+	@ Mask other GPIO line interrupts till key done
+	str r11, [r9, #BUF_GPIO_INT_MASK]	@ save mask for later restore
+	mvn r11, #KEYBRD_CLK_MASK		@ prepare all except kbd mask
+	str r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ store into the mask register
+
+	b restart				@ restart
+
+data:	ldr r10, [r9, #BUF_MASK]		@ fetch current input bit mask
+
+	@ r8 still contains GPIO input bits
+	ands r8, r8, #KEYBRD_DATA_MASK		@ is keyboard data line low?
+	ldreq r8, [r9, #BUF_KEY]		@ yes - fetch collected so far,
+	orreq r8, r8, r10			@ set 1 at current mask position
+	streq r8, [r9, #BUF_KEY]		@ and save back
+
+	mov r10, r10, lsl #1			@ shift mask left
+	bics r10, r10, #0x800			@ have we got all the bits?
+	strne r10, [r9, #BUF_MASK]		@ not yet - store the mask
+	bne restart				@ and restart
+
+	@ r10 already contains 0, reuse it
+	str r10, [r9, #BUF_STATE]		@ reset state to start
+
+	@ Key done - restore interrupt mask
+	ldr r10, [r9, #BUF_GPIO_INT_MASK]	@ fetch saved mask
+	and r11, r11, r10			@ unmask all saved as unmasked
+	str r11, [r12, #OMAP1510_GPIO_INT_MASK]	@ restore into the mask register
+
+	@ Try appending the keycode to the circular buffer
+	ldr r10, [r9, #BUF_KEYS_CNT]		@ get saved keystrokes count
+	ldr r8, [r9, #BUF_BUF_LEN]		@ get buffer size
+	cmp r10, r8				@ is buffer full?
+	beq hksw				@ yes - key lost, next source
+
+	add r10, r10, #1			@ incremet keystrokes counter
+	str r10, [r9, #BUF_KEYS_CNT]
+
+	ldr r10, [r9, #BUF_TAIL_OFFSET]		@ get buffer tail offset
+	@ r8 already contains buffer size
+	cmp r10, r8				@ end of buffer?
+	moveq r10, #0				@ yes - rewind to buffer start
+
+	ldr r12, [r9, #BUF_BUFFER_START]	@ get buffer start address
+	add r12, r12, r10, LSL #2		@ calculate buffer tail address
+	ldr r8, [r9, #BUF_KEY]			@ get last keycode
+	str r8, [r12]				@ append it to the buffer tail
+
+	add r10, r10, #1			@ increment buffer tail offset
+	str r10, [r9, #BUF_TAIL_OFFSET]
+
+	ldr r10, [r9, #BUF_CNT_INT_KEY]		@ increment interrupts counter
+	add r10, r10, #1
+	str r10, [r9, #BUF_CNT_INT_KEY]
+	@@@@@@@@@@@@@@@@@@@@@@@@
+
+
+hksw:	@Is hook switch interrupt requested?
+	tst r13, #HOOK_SWITCH_MASK 		@ is hook switch status bit set?
+	beq mdm					@ no - try next source
+
+
+	@@@@@@@@@@@@@@@@@@@@@@@@
+	@ Hook switch interrupt FIQ mode simple handler
+
+	@ Don't toggle active edge, the switch always bounces
+
+	@ Increment hook switch interrupt counter
+	ldr r10, [r9, #BUF_CNT_INT_HSW]
+	add r10, r10, #1
+	str r10, [r9, #BUF_CNT_INT_HSW]
+	@@@@@@@@@@@@@@@@@@@@@@@@
+
+
+mdm:	@Is it a modem interrupt?
+	tst r13, #MODEM_IRQ_MASK 		@ is modem status bit set?
+	beq irq					@ no - check for next interrupt
+
+
+	@@@@@@@@@@@@@@@@@@@@@@@@
+	@ Modem FIQ mode interrupt handler stub
+
+	@ Increment modem interrupt counter
+	ldr r10, [r9, #BUF_CNT_INT_MDM]
+	add r10, r10, #1
+	str r10, [r9, #BUF_CNT_INT_MDM]
+	@@@@@@@@@@@@@@@@@@@@@@@@
+
+
+irq:	@ Place deferred_fiq interrupt request
+	ldr r12, deferred_fiq_ih_base		@ set pointer to IRQ handler
+	mov r10, #DEFERRED_FIQ_MASK		@ set deferred_fiq bit
+	str r10, [r12, #IRQ_ISR_REG_OFFSET] 	@ place it in the ISR register
+
+	ldr r12, omap1510_gpio_base		@ set pointer back to GPIO bank
+	b restart				@ check for next GPIO interrupt
+	@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+
+/*
+ * Virtual addresses for IO
+ */
+omap_ih1_base:
+	.word OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
+deferred_fiq_ih_base:
+	.word OMAP1_IO_ADDRESS(DEFERRED_FIQ_IH_BASE)
+omap1510_gpio_base:
+	.word OMAP1_IO_ADDRESS(OMAP1510_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/mach-omap1/include/mach/ams-delta-fiq.h git/arch/arm/mach-omap1/include/mach/ams-delta-fiq.h
--- git.orig/arch/arm/mach-omap1/include/mach/ams-delta-fiq.h	1970-01-01 01:00:00.000000000 +0100
+++ git/arch/arm/mach-omap1/include/mach/ams-delta-fiq.h	2010-04-27 22:23:41.000000000 +0200
@@ -0,0 +1,72 @@
+/*
+ * arch/arm/mach-omap1/include/ams-delta-fiq.h
+ *
+ * Taken from the original Amstrad modifications to fiq.h
+ *
+ * Copyright (c) 2004 Amstrad Plc
+ * Copyright (c) 2006 Matt Callow
+ * Copyright (c) 2010 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.
+ */
+#ifndef __AMS_DELTA_FIQ_H
+#define __AMS_DELTA_FIQ_H
+
+#include <plat/irqs.h>
+
+/*
+ * Interrupt number used for passing control from FIQ to IRQ.
+ * IRQ12, described as reserved, has been selected.
+ */
+#define INT_DEFERRED_FIQ	INT_1510_RES12
+/*
+ * Base address of an interrupt handler that the INT_DEFERRED_FIQ belongs to.
+ */
+#if (INT_DEFERRED_FIQ < IH2_BASE)
+#define DEFERRED_FIQ_IH_BASE	OMAP_IH1_BASE
+#else
+#define DEFERRED_FIQ_IH_BASE	OMAP_IH2_BASE
+#endif
+
+/*
+ * These are the offsets from the begining of the fiq_buffer. They are put here
+ * since the buffer and header need to be accessed by drivers servicing devices
+ * which generate GPIO interrupts - e.g. keyboard, modem, hook switch.
+ */
+#define FIQ_MASK		 0
+#define FIQ_STATE		 1
+#define FIQ_KEYS_CNT		 2
+#define FIQ_TAIL_OFFSET		 3
+#define FIQ_HEAD_OFFSET		 4
+#define FIQ_BUF_LEN		 5
+#define FIQ_KEY			 6
+#define FIQ_MISSED_KEYS		 7
+#define FIQ_BUFFER_START	 8
+#define FIQ_GPIO_INT_MASK	 9
+#define FIQ_KEYS_HICNT		10
+#define FIQ_IRQ_PEND		11
+#define FIQ_SIR_CODE_L1		12
+#define IRQ_SIR_CODE_L2		13
+
+#define FIQ_CNT_INT_00		14
+#define FIQ_CNT_INT_KEY		15
+#define FIQ_CNT_INT_MDM		16
+#define FIQ_CNT_INT_03		17
+#define FIQ_CNT_INT_HSW		18
+#define FIQ_CNT_INT_05		19
+#define FIQ_CNT_INT_06		20
+#define FIQ_CNT_INT_07		21
+#define FIQ_CNT_INT_08		22
+#define FIQ_CNT_INT_09		23
+#define FIQ_CNT_INT_10		24
+#define FIQ_CNT_INT_11		25
+#define FIQ_CNT_INT_12		26
+#define FIQ_CNT_INT_13		27
+#define FIQ_CNT_INT_14		28
+#define FIQ_CNT_INT_15		29
+
+#define FIQ_CIRC_BUFF		30      /*Start of circular buffer */
+
+#endif



More information about the linux-arm-kernel mailing list