[RFC][PATCH v2 2/5] omap1: Amstrad Delta: add a handler for processing interrupts generated by the FIQ routine
Janusz Krzysztofik
jkrzyszt at tis.icnet.pl
Mon Mar 29 10:26:16 EDT 2010
This patch introduces an IRQ handler used for processing interrupts generated
by the FIQ handler when it decides there are data ready for processing.
The handler further invokes device specific interrupt routines based on an
interrupt source as passed from the FIQ handler.
It can be registered by the board as a handler for the otherwise unused 32k
timer interrupt.
Applies on top of patch 1/5 from this series:
omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing
Created and tested against linux-2.6.34-rc2.
Signed-off-by: Janusz Krzysztofik <jkrzyszt at tis.icnet.pl>
---
v2 changes:
- add fiq_buffer[] declaration missing from the header file,
- refresh against 2.6.34-rc2.
arch/arm/mach-omap1/Makefile | 2
arch/arm/mach-omap1/ams-delta-fiq.c | 175 +++++++++++++++++++++++
arch/arm/mach-omap1/include/mach/ams-delta-fiq.h | 57 +++++++
3 files changed, 233 insertions(+), 1 deletion(-)
diff -uprN git.orig/arch/arm/mach-omap1/Makefile git/arch/arm/mach-omap1/Makefile
--- git.orig/arch/arm/mach-omap1/Makefile 2010-03-28 23:35:25.000000000 +0200
+++ git/arch/arm/mach-omap1/Makefile 2010-03-28 23:34:38.000000000 +0200
@@ -37,7 +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_AMS_DELTA_FIQ) += ams-delta-fiq.o 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.c git/arch/arm/mach-omap1/ams-delta-fiq.c
--- git.orig/arch/arm/mach-omap1/ams-delta-fiq.c 1970-01-01 01:00:00.000000000 +0100
+++ git/arch/arm/mach-omap1/ams-delta-fiq.c 2010-03-28 23:34:38.000000000 +0200
@@ -0,0 +1,175 @@
+/*
+ * Amstrad E3 FIQ handling
+ *
+ * Copyright (C) 2009 Janusz Krzysztofik
+ * Copyright (c) 2006 Matt Callow
+ * Copyright (c) 2004 Amstrad Plc
+ * Copyright (C) 2001 RidgeRun, Inc.
+ *
+ * Parts of this code are taken from linux/arch/arm/mach-omap/irq.c
+ * in the MontaVista 2.4 kernel (and the Amstrad changes therein)
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/gpio.h>
+#include <asm/fiq.h>
+#include <mach/ams-delta-fiq.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <plat/board-ams-delta.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+
+static struct fiq_handler fh = {
+ .name = "ams-delta-fiq"
+};
+
+/*
+ * This buffer is shared between FIQ and IRQ contexts.
+ * The FIQ and IRQ isrs can both read and write it.
+ * It is structured as a header section several 32bit slots,
+ * followed by the circular buffer where the FIQ isr stores
+ * characters received from the qwerty keyboard.
+ * See ams-delta-fiq.h for details of offsets.
+ */
+unsigned int fiq_buffer[1024];
+EXPORT_SYMBOL(fiq_buffer);
+
+static unsigned int fiq_buffer_irq[FIQ_CIRC_BUFF];
+
+static irqreturn_t deferred_fiq(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ int list_index, buffer_offset;
+ int irq_num;
+ const unsigned int cpu = smp_processor_id();
+
+ /*
+ * Call the interrupt handler for each GPIO interrupt
+ * where the FIQ interrupt counter > the IRQ counter
+ */
+ for (buffer_offset = FIQ_CNT_INT_04;
+ buffer_offset >= FIQ_CNT_INT_CHAR; buffer_offset--) {
+ while (fiq_buffer[buffer_offset] >
+ fiq_buffer_irq[buffer_offset]) {
+
+ list_index = buffer_offset - FIQ_CNT_INT_00;
+ irq_num = list_index + IH_GPIO_BASE;
+
+ if (irq_desc[irq_num].action->handler != NULL) {
+ irq_desc[irq_num].action->handler(irq_num,
+ irq_desc[irq_num].action->dev_id);
+ /* keep /proc/interrupts up to date */
+ kstat_cpu(cpu).softirqs[irq_num]++;
+
+ /*
+ * Increment the IRQ count to ensure one IRQ
+ * call per FIQ. There is a corresponding
+ * increment in the FIQ handler having and
+ * IRQ & FIQ level counters avoids any races.
+ * There is a possibility that two calls to this
+ * handler occur when keyboard and modem
+ * interrupts are close together. Although both
+ * interrupts will be serviced during the first
+ * one. This should have no serious effect apart
+ * from an unecessary call through here on
+ * occasion, but that's better than missing one.
+ */
+ fiq_buffer_irq[buffer_offset]++;
+ } else {
+ printk(KERN_WARNING
+ "!!! NULL HANDLER for[%d]!!!\n",
+ irq_num);
+ fiq_buffer_irq[buffer_offset]++;
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+void __init ams_delta_init_fiq(void)
+{
+ int retval;
+ void *fiqhandler_start;
+ unsigned int fiqhandler_length;
+ struct pt_regs FIQ_regs;
+ unsigned long val, offset;
+ int i;
+
+ fiqhandler_start = &qwerty_fiqin_start;
+ fiqhandler_length = &qwerty_fiqin_end - &qwerty_fiqin_start;
+ printk(KERN_INFO "Installing fiq handler from %p, length 0x%x\r\n",
+ fiqhandler_start, fiqhandler_length);
+
+ retval = claim_fiq(&fh);
+ if (retval) {
+ printk(KERN_ERR "ams_delta_init_fiq(): couldn't claim FIQ."
+ " ret = %d\n\r", retval);
+ return;
+ }
+
+ if (request_irq(INT_OS_TIMER, deferred_fiq, 0, "deferred_fiq", 0) < 0) {
+ printk(KERN_ERR "Failed to get OS_TIMER\r\n");
+ release_fiq(&fh);
+ return;
+ }
+
+ set_fiq_handler(fiqhandler_start, fiqhandler_length);
+
+ /*
+ * Initialise the buffer which is shared
+ * between FIQ mode and IRQ mode
+ */
+ fiq_buffer[FIQ_GPIO_INT_MASK] = 0;
+ fiq_buffer[FIQ_MASK] = 0;
+ fiq_buffer[FIQ_STATE] = 0;
+ fiq_buffer[FIQ_CHAR] = 0;
+ fiq_buffer[FIQ_CHAR_CNT] = 0;
+ fiq_buffer[FIQ_CHAR_HICNT] = 0;
+ fiq_buffer[FIQ_FRNT_OFFSET] = 0;
+ fiq_buffer[FIQ_BACK_OFFSET] = 0;
+ fiq_buffer[FIQ_BUF_LEN] = 256;
+ fiq_buffer[FIQ_MISSED_CHARS] = 0;
+ fiq_buffer[FIQ_BUFFER_START] =
+ (unsigned int) &fiq_buffer[FIQ_CIRC_BUFF];
+
+ for (i = FIQ_CNT_INT_00; i <= FIQ_CNT_INT_15; i++) {
+ fiq_buffer[i] = 0;
+ fiq_buffer_irq[i] = 0;
+ }
+
+ /*
+ * FIQ mode r9 always points to the fiq_buffer, becauses the FIQ isr
+ * will run in an unpredictable context. The fiq_buffer is the FIQ isr's
+ * only means of communication with the IRQ level and other kernel
+ * context code.
+ */
+ FIQ_regs.ARM_r9 = (unsigned int)fiq_buffer;
+ FIQ_regs.ARM_r10 = 0;
+ FIQ_regs.ARM_sp = 0;
+
+ set_fiq_regs(&FIQ_regs);
+
+ printk(KERN_INFO "request_fiq(): fiq_buffer = %p\n", fiq_buffer);
+
+ /*
+ * Set FIQ, priority 0, tigger rising on the GPIO INT
+ * It would be nice to use omap_irq_set_cfg() here, but it's static
+ */
+ val = 1 | ((IRQ_TYPE_EDGE_RISING & 0x1) << 1);
+ offset = IRQ_ILR0_REG_OFFSET + INT_GPIO_BANK1 * 0x4;
+ omap_writel(val, OMAP_IH1_BASE + offset);
+}
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-03-28 23:34:38.000000000 +0200
@@ -0,0 +1,57 @@
+/*
+ * 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
+ *
+ * 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.
+ */
+
+/*
+ * These are the offsets from the begining of the fiq_buffer. They are here
+ * as the buffer and header need to be accessed by drivers servicing devices
+ * which generate GPIO interrupts - e.g. qwerty, modem, smartcard
+ */
+
+#define FIQ_MASK 0
+#define FIQ_STATE 1
+#define FIQ_CHAR_CNT 2
+#define FIQ_FRNT_OFFSET 3
+#define FIQ_BACK_OFFSET 4
+#define FIQ_BUF_LEN 5
+#define FIQ_CHAR 6
+#define FIQ_MISSED_CHARS 7
+#define FIQ_BUFFER_START 8
+#define FIQ_GPIO_INT_MASK 9
+#define FIQ_CHAR_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_CHAR 15
+#define FIQ_CNT_INT_MDM 16
+#define FIQ_CNT_INT_FIQ 17
+#define FIQ_CNT_INT_04 18
+#define FIQ_CNT_INT_05 19
+#define FIQ_CNT_INT_KBD 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 */
+
+extern unsigned int fiq_buffer[];
+extern unsigned char qwerty_fiqin_start, qwerty_fiqin_end;
+
+extern void __init ams_delta_init_fiq(void);
More information about the linux-arm-kernel
mailing list