diff mbox

[RFC,2/5] omap1: Amstrad Delta: add a handler for processing interrupts generated by the FIQ routine

Message ID 200912102105.49875.jkrzyszt@tis.icnet.pl (mailing list archive)
State RFC, archived
Delegated to: Tony Lindgren
Headers show

Commit Message

Janusz Krzysztofik Dec. 10, 2009, 8:05 p.m. UTC
None
diff mbox

Patch

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,7 +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_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	2009-12-10 03:34:03.000000000 +0100
@@ -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	2009-12-10 03:36:45.000000000 +0100
@@ -0,0 +1,56 @@ 
+/*
+ * 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 char qwerty_fiqin_start, qwerty_fiqin_end;
+
+extern void __init ams_delta_init_fiq(void);