From patchwork Mon Mar 29 14:26:16 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janusz Krzysztofik X-Patchwork-Id: 88971 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2TEQdXR020801 for ; Mon, 29 Mar 2010 14:26:39 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752183Ab0C2O0i (ORCPT ); Mon, 29 Mar 2010 10:26:38 -0400 Received: from d1.icnet.pl ([212.160.220.21]:44400 "EHLO d1.icnet.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750925Ab0C2O0i (ORCPT ); Mon, 29 Mar 2010 10:26:38 -0400 Received: from 87-205-12-81.ip.netia.com.pl ([87.205.12.81] helo=vclass.intranet) by d1.icnet.pl with asmtp (TLS-1.0:DHE_RSA_AES_128_CBC_SHA:16) (Exim 4.34) id 1NwFvJ-00074c-28; Mon, 29 Mar 2010 16:26:37 +0200 From: Janusz Krzysztofik Organization: Tele-Info-System, Poznan, PL To: linux-omap@vger.kernel.org Subject: [RFC][PATCH v2 2/5] omap1: Amstrad Delta: add a handler for processing interrupts generated by the FIQ routine Date: Mon, 29 Mar 2010 16:26:16 +0200 User-Agent: KMail/1.9.10 Cc: Tony Lindgren , Dmitry Torokhov , linux-input@vger.kernel.org, linux-arm-kernel@lists.infradead.org, e3-hacking@earth.li References: <201003291619.25878.jkrzyszt@tis.icnet.pl> In-Reply-To: <201003291619.25878.jkrzyszt@tis.icnet.pl> MIME-Version: 1.0 Content-Disposition: inline Message-Id: <201003291626.18147.jkrzyszt@tis.icnet.pl> X-SA-Exim-Scanned: No (on d1.icnet); SAEximRunCond expanded to false Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 29 Mar 2010 14:26:40 +0000 (UTC) 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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);