From mboxrd@z Thu Jan 1 00:00:00 1970 From: Janusz Krzysztofik Subject: [RFC][PATCH v2 1/5] omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing Date: Mon, 29 Mar 2010 16:24:08 +0200 Message-ID: <201003291624.10034.jkrzyszt@tis.icnet.pl> References: <201003291619.25878.jkrzyszt@tis.icnet.pl> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Return-path: Received: from d1.icnet.pl ([212.160.220.21]:44027 "EHLO d1.icnet.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751178Ab0C2OY3 (ORCPT ); Mon, 29 Mar 2010 10:24:29 -0400 In-Reply-To: <201003291619.25878.jkrzyszt@tis.icnet.pl> Content-Disposition: inline Sender: linux-omap-owner@vger.kernel.org List-Id: linux-omap@vger.kernel.org To: linux-omap@vger.kernel.org Cc: Tony Lindgren , linux-arm-kernel@lists.infradead.org, e3-hacking@earth.li 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 --- 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 +#include +#include +#include + +#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 +#ifdef CONFIG_FIQ +#define FIQ_START 1024 +#endif + #endif From mboxrd@z Thu Jan 1 00:00:00 1970 From: jkrzyszt@tis.icnet.pl (Janusz Krzysztofik) Date: Mon, 29 Mar 2010 16:24:08 +0200 Subject: [RFC][PATCH v2 1/5] omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing In-Reply-To: <201003291619.25878.jkrzyszt@tis.icnet.pl> References: <201003291619.25878.jkrzyszt@tis.icnet.pl> Message-ID: <201003291624.10034.jkrzyszt@tis.icnet.pl> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org 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 --- 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 +#include +#include +#include + +#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 +#ifdef CONFIG_FIQ +#define FIQ_START 1024 +#endif + #endif