162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/mach-omap1/ams-delta-fiq-handler.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on linux/arch/arm/lib/floppydma.S 662306a36Sopenharmony_ci * Renamed and modified to work with 2.6 kernel by Matt Callow 762306a36Sopenharmony_ci * Copyright (C) 1995, 1996 Russell King 862306a36Sopenharmony_ci * Copyright (C) 2004 Pete Trapps 962306a36Sopenharmony_ci * Copyright (C) 2006 Matt Callow 1062306a36Sopenharmony_ci * Copyright (C) 2010 Janusz Krzysztofik 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/linkage.h> 1462306a36Sopenharmony_ci#include <linux/platform_data/ams-delta-fiq.h> 1562306a36Sopenharmony_ci#include <linux/platform_data/gpio-omap.h> 1662306a36Sopenharmony_ci#include <linux/soc/ti/omap1-io.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <asm/assembler.h> 1962306a36Sopenharmony_ci#include <asm/irq.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "hardware.h" 2262306a36Sopenharmony_ci#include "ams-delta-fiq.h" 2362306a36Sopenharmony_ci#include "board-ams-delta.h" 2462306a36Sopenharmony_ci#include "iomap.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * OMAP1510 GPIO related symbol copied from arch/arm/mach-omap1/gpio15xx.c. 2862306a36Sopenharmony_ci * Unfortunately, it was not placed in a separate header file. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#define OMAP1510_GPIO_BASE 0xFFFCE000 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* GPIO register bitmasks */ 3362306a36Sopenharmony_ci#define KEYBRD_DATA_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_DATA) 3462306a36Sopenharmony_ci#define KEYBRD_CLK_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_CLK) 3562306a36Sopenharmony_ci#define MODEM_IRQ_MASK (0x1 << AMS_DELTA_GPIO_PIN_MODEM_IRQ) 3662306a36Sopenharmony_ci#define HOOK_SWITCH_MASK (0x1 << AMS_DELTA_GPIO_PIN_HOOK_SWITCH) 3762306a36Sopenharmony_ci#define OTHERS_MASK (MODEM_IRQ_MASK | HOOK_SWITCH_MASK) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* IRQ handler register bitmasks */ 4062306a36Sopenharmony_ci#define DEFERRED_FIQ_MASK OMAP_IRQ_BIT(INT_DEFERRED_FIQ) 4162306a36Sopenharmony_ci#define GPIO_BANK1_MASK OMAP_IRQ_BIT(INT_GPIO_BANK1) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Driver buffer byte offsets */ 4462306a36Sopenharmony_ci#define BUF_MASK (FIQ_MASK * 4) 4562306a36Sopenharmony_ci#define BUF_STATE (FIQ_STATE * 4) 4662306a36Sopenharmony_ci#define BUF_KEYS_CNT (FIQ_KEYS_CNT * 4) 4762306a36Sopenharmony_ci#define BUF_TAIL_OFFSET (FIQ_TAIL_OFFSET * 4) 4862306a36Sopenharmony_ci#define BUF_HEAD_OFFSET (FIQ_HEAD_OFFSET * 4) 4962306a36Sopenharmony_ci#define BUF_BUF_LEN (FIQ_BUF_LEN * 4) 5062306a36Sopenharmony_ci#define BUF_KEY (FIQ_KEY * 4) 5162306a36Sopenharmony_ci#define BUF_MISSED_KEYS (FIQ_MISSED_KEYS * 4) 5262306a36Sopenharmony_ci#define BUF_BUFFER_START (FIQ_BUFFER_START * 4) 5362306a36Sopenharmony_ci#define BUF_GPIO_INT_MASK (FIQ_GPIO_INT_MASK * 4) 5462306a36Sopenharmony_ci#define BUF_KEYS_HICNT (FIQ_KEYS_HICNT * 4) 5562306a36Sopenharmony_ci#define BUF_IRQ_PEND (FIQ_IRQ_PEND * 4) 5662306a36Sopenharmony_ci#define BUF_SIR_CODE_L1 (FIQ_SIR_CODE_L1 * 4) 5762306a36Sopenharmony_ci#define BUF_SIR_CODE_L2 (IRQ_SIR_CODE_L2 * 4) 5862306a36Sopenharmony_ci#define BUF_CNT_INT_00 (FIQ_CNT_INT_00 * 4) 5962306a36Sopenharmony_ci#define BUF_CNT_INT_KEY (FIQ_CNT_INT_KEY * 4) 6062306a36Sopenharmony_ci#define BUF_CNT_INT_MDM (FIQ_CNT_INT_MDM * 4) 6162306a36Sopenharmony_ci#define BUF_CNT_INT_03 (FIQ_CNT_INT_03 * 4) 6262306a36Sopenharmony_ci#define BUF_CNT_INT_HSW (FIQ_CNT_INT_HSW * 4) 6362306a36Sopenharmony_ci#define BUF_CNT_INT_05 (FIQ_CNT_INT_05 * 4) 6462306a36Sopenharmony_ci#define BUF_CNT_INT_06 (FIQ_CNT_INT_06 * 4) 6562306a36Sopenharmony_ci#define BUF_CNT_INT_07 (FIQ_CNT_INT_07 * 4) 6662306a36Sopenharmony_ci#define BUF_CNT_INT_08 (FIQ_CNT_INT_08 * 4) 6762306a36Sopenharmony_ci#define BUF_CNT_INT_09 (FIQ_CNT_INT_09 * 4) 6862306a36Sopenharmony_ci#define BUF_CNT_INT_10 (FIQ_CNT_INT_10 * 4) 6962306a36Sopenharmony_ci#define BUF_CNT_INT_11 (FIQ_CNT_INT_11 * 4) 7062306a36Sopenharmony_ci#define BUF_CNT_INT_12 (FIQ_CNT_INT_12 * 4) 7162306a36Sopenharmony_ci#define BUF_CNT_INT_13 (FIQ_CNT_INT_13 * 4) 7262306a36Sopenharmony_ci#define BUF_CNT_INT_14 (FIQ_CNT_INT_14 * 4) 7362306a36Sopenharmony_ci#define BUF_CNT_INT_15 (FIQ_CNT_INT_15 * 4) 7462306a36Sopenharmony_ci#define BUF_CIRC_BUFF (FIQ_CIRC_BUFF * 4) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * Register usage 7962306a36Sopenharmony_ci * r8 - temporary 8062306a36Sopenharmony_ci * r9 - the driver buffer 8162306a36Sopenharmony_ci * r10 - temporary 8262306a36Sopenharmony_ci * r11 - interrupts mask 8362306a36Sopenharmony_ci * r12 - base pointers 8462306a36Sopenharmony_ci * r13 - interrupts status 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci .text 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci .global qwerty_fiqin_end 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciENTRY(qwerty_fiqin_start) 9262306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9362306a36Sopenharmony_ci @ FIQ intrrupt handler 9462306a36Sopenharmony_ci ldr r12, omap_ih1_base @ set pointer to level1 handler 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci ldr r11, [r12, #IRQ_MIR_REG_OFFSET] @ fetch interrupts mask 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ldr r13, [r12, #IRQ_ITR_REG_OFFSET] @ fetch interrupts status 9962306a36Sopenharmony_ci bics r13, r13, r11 @ clear masked - any left? 10062306a36Sopenharmony_ci beq exit @ none - spurious FIQ? exit 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET] @ get requested interrupt number 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci mov r8, #2 @ reset FIQ agreement 10562306a36Sopenharmony_ci str r8, [r12, #IRQ_CONTROL_REG_OFFSET] 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci cmp r10, #(INT_GPIO_BANK1 - NR_IRQS_LEGACY) @ is it GPIO interrupt? 10862306a36Sopenharmony_ci beq gpio @ yes - process it 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci mov r8, #1 11162306a36Sopenharmony_ci orr r8, r11, r8, lsl r10 @ mask spurious interrupt 11262306a36Sopenharmony_ci str r8, [r12, #IRQ_MIR_REG_OFFSET] 11362306a36Sopenharmony_ciexit: 11462306a36Sopenharmony_ci subs pc, lr, #4 @ return from FIQ 11562306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@ 11962306a36Sopenharmony_cigpio: @ GPIO bank interrupt handler 12062306a36Sopenharmony_ci ldr r12, omap1510_gpio_base @ set base pointer to GPIO bank 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ldr r11, [r12, #OMAP1510_GPIO_INT_MASK] @ fetch GPIO interrupts mask 12362306a36Sopenharmony_cirestart: 12462306a36Sopenharmony_ci ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ fetch status bits 12562306a36Sopenharmony_ci bics r13, r13, r11 @ clear masked - any left? 12662306a36Sopenharmony_ci beq exit @ no - spurious interrupt? exit 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci orr r11, r11, r13 @ mask all requested interrupts 12962306a36Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ands r10, r13, #KEYBRD_CLK_MASK @ extract keyboard status - set? 13462306a36Sopenharmony_ci beq hksw @ no - try next source 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@ 13862306a36Sopenharmony_ci @ Keyboard clock FIQ mode interrupt handler 13962306a36Sopenharmony_ci @ r10 now contains KEYBRD_CLK_MASK, use it 14062306a36Sopenharmony_ci bic r11, r11, r10 @ unmask it 14162306a36Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci @ Process keyboard data 14462306a36Sopenharmony_ci ldr r8, [r12, #OMAP1510_GPIO_DATA_INPUT] @ fetch GPIO input 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ldr r10, [r9, #BUF_STATE] @ fetch kbd interface state 14762306a36Sopenharmony_ci cmp r10, #0 @ are we expecting start bit? 14862306a36Sopenharmony_ci bne data @ no - go to data processing 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ands r8, r8, #KEYBRD_DATA_MASK @ check start bit - detected? 15162306a36Sopenharmony_ci beq hksw @ no - try next source 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci @ r8 contains KEYBRD_DATA_MASK, use it 15462306a36Sopenharmony_ci str r8, [r9, #BUF_STATE] @ enter data processing state 15562306a36Sopenharmony_ci @ r10 already contains 0, reuse it 15662306a36Sopenharmony_ci str r10, [r9, #BUF_KEY] @ clear keycode 15762306a36Sopenharmony_ci mov r10, #2 @ reset input bit mask 15862306a36Sopenharmony_ci str r10, [r9, #BUF_MASK] 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci @ Mask other GPIO line interrupts till key done 16162306a36Sopenharmony_ci str r11, [r9, #BUF_GPIO_INT_MASK] @ save mask for later restore 16262306a36Sopenharmony_ci mvn r11, #KEYBRD_CLK_MASK @ prepare all except kbd mask 16362306a36Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ store into the mask register 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci b restart @ restart 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cidata: ldr r10, [r9, #BUF_MASK] @ fetch current input bit mask 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci @ r8 still contains GPIO input bits 17062306a36Sopenharmony_ci ands r8, r8, #KEYBRD_DATA_MASK @ is keyboard data line low? 17162306a36Sopenharmony_ci ldreq r8, [r9, #BUF_KEY] @ yes - fetch collected so far, 17262306a36Sopenharmony_ci orreq r8, r8, r10 @ set 1 at current mask position 17362306a36Sopenharmony_ci streq r8, [r9, #BUF_KEY] @ and save back 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci mov r10, r10, lsl #1 @ shift mask left 17662306a36Sopenharmony_ci bics r10, r10, #0x800 @ have we got all the bits? 17762306a36Sopenharmony_ci strne r10, [r9, #BUF_MASK] @ not yet - store the mask 17862306a36Sopenharmony_ci bne restart @ and restart 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci @ r10 already contains 0, reuse it 18162306a36Sopenharmony_ci str r10, [r9, #BUF_STATE] @ reset state to start 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci @ Key done - restore interrupt mask 18462306a36Sopenharmony_ci ldr r10, [r9, #BUF_GPIO_INT_MASK] @ fetch saved mask 18562306a36Sopenharmony_ci and r11, r11, r10 @ unmask all saved as unmasked 18662306a36Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ restore into the mask register 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci @ Try appending the keycode to the circular buffer 18962306a36Sopenharmony_ci ldr r10, [r9, #BUF_KEYS_CNT] @ get saved keystrokes count 19062306a36Sopenharmony_ci ldr r8, [r9, #BUF_BUF_LEN] @ get buffer size 19162306a36Sopenharmony_ci cmp r10, r8 @ is buffer full? 19262306a36Sopenharmony_ci beq hksw @ yes - key lost, next source 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci add r10, r10, #1 @ incremet keystrokes counter 19562306a36Sopenharmony_ci str r10, [r9, #BUF_KEYS_CNT] 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ldr r10, [r9, #BUF_TAIL_OFFSET] @ get buffer tail offset 19862306a36Sopenharmony_ci @ r8 already contains buffer size 19962306a36Sopenharmony_ci cmp r10, r8 @ end of buffer? 20062306a36Sopenharmony_ci moveq r10, #0 @ yes - rewind to buffer start 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci ldr r12, [r9, #BUF_BUFFER_START] @ get buffer start address 20362306a36Sopenharmony_ci add r12, r12, r10, LSL #2 @ calculate buffer tail address 20462306a36Sopenharmony_ci ldr r8, [r9, #BUF_KEY] @ get last keycode 20562306a36Sopenharmony_ci str r8, [r12] @ append it to the buffer tail 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci add r10, r10, #1 @ increment buffer tail offset 20862306a36Sopenharmony_ci str r10, [r9, #BUF_TAIL_OFFSET] 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci ldr r10, [r9, #BUF_CNT_INT_KEY] @ increment interrupts counter 21162306a36Sopenharmony_ci add r10, r10, #1 21262306a36Sopenharmony_ci str r10, [r9, #BUF_CNT_INT_KEY] 21362306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cihksw: @Is hook switch interrupt requested? 21762306a36Sopenharmony_ci tst r13, #HOOK_SWITCH_MASK @ is hook switch status bit set? 21862306a36Sopenharmony_ci beq mdm @ no - try next source 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 22262306a36Sopenharmony_ci @ Hook switch interrupt FIQ mode simple handler 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci @ Don't toggle active edge, the switch always bounces 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci @ Increment hook switch interrupt counter 22762306a36Sopenharmony_ci ldr r10, [r9, #BUF_CNT_INT_HSW] 22862306a36Sopenharmony_ci add r10, r10, #1 22962306a36Sopenharmony_ci str r10, [r9, #BUF_CNT_INT_HSW] 23062306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cimdm: @Is it a modem interrupt? 23462306a36Sopenharmony_ci tst r13, #MODEM_IRQ_MASK @ is modem status bit set? 23562306a36Sopenharmony_ci beq irq @ no - check for next interrupt 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 23962306a36Sopenharmony_ci @ Modem FIQ mode interrupt handler stub 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci @ Increment modem interrupt counter 24262306a36Sopenharmony_ci ldr r10, [r9, #BUF_CNT_INT_MDM] 24362306a36Sopenharmony_ci add r10, r10, #1 24462306a36Sopenharmony_ci str r10, [r9, #BUF_CNT_INT_MDM] 24562306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ciirq: @ Place deferred_fiq interrupt request 24962306a36Sopenharmony_ci ldr r12, deferred_fiq_ih_base @ set pointer to IRQ handler 25062306a36Sopenharmony_ci mov r10, #DEFERRED_FIQ_MASK @ set deferred_fiq bit 25162306a36Sopenharmony_ci str r10, [r12, #IRQ_ISR_REG_OFFSET] @ place it in the ISR register 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci ldr r12, omap1510_gpio_base @ set pointer back to GPIO bank 25462306a36Sopenharmony_ci b restart @ check for next GPIO interrupt 25562306a36Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* 25962306a36Sopenharmony_ci * Virtual addresses for IO 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ciomap_ih1_base: 26262306a36Sopenharmony_ci .word OMAP1_IO_ADDRESS(OMAP_IH1_BASE) 26362306a36Sopenharmony_cideferred_fiq_ih_base: 26462306a36Sopenharmony_ci .word OMAP1_IO_ADDRESS(DEFERRED_FIQ_IH_BASE) 26562306a36Sopenharmony_ciomap1510_gpio_base: 26662306a36Sopenharmony_ci .word OMAP1_IO_ADDRESS(OMAP1510_GPIO_BASE) 26762306a36Sopenharmony_ciqwerty_fiqin_end: 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* 27062306a36Sopenharmony_ci * Check the size of the FIQ, 27162306a36Sopenharmony_ci * it cannot go beyond 0xffff0200, and is copied to 0xffff001c 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci.if (qwerty_fiqin_end - qwerty_fiqin_start) > (0x200 - 0x1c) 27462306a36Sopenharmony_ci .err 27562306a36Sopenharmony_ci.endif 276