1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * linux/arch/arm/mach-omap1/ams-delta-fiq-handler.S 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Based on linux/arch/arm/lib/floppydma.S 6*4882a593Smuzhiyun * Renamed and modified to work with 2.6 kernel by Matt Callow 7*4882a593Smuzhiyun * Copyright (C) 1995, 1996 Russell King 8*4882a593Smuzhiyun * Copyright (C) 2004 Pete Trapps 9*4882a593Smuzhiyun * Copyright (C) 2006 Matt Callow 10*4882a593Smuzhiyun * Copyright (C) 2010 Janusz Krzysztofik 11*4882a593Smuzhiyun */ 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun#include <linux/linkage.h> 14*4882a593Smuzhiyun#include <linux/platform_data/ams-delta-fiq.h> 15*4882a593Smuzhiyun#include <linux/platform_data/gpio-omap.h> 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun#include <asm/assembler.h> 18*4882a593Smuzhiyun#include <asm/irq.h> 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun#include "ams-delta-fiq.h" 21*4882a593Smuzhiyun#include "board-ams-delta.h" 22*4882a593Smuzhiyun#include "iomap.h" 23*4882a593Smuzhiyun#include "soc.h" 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun/* 26*4882a593Smuzhiyun * OMAP1510 GPIO related symbol copied from arch/arm/mach-omap1/gpio15xx.c. 27*4882a593Smuzhiyun * Unfortunately, it was not placed in a separate header file. 28*4882a593Smuzhiyun */ 29*4882a593Smuzhiyun#define OMAP1510_GPIO_BASE 0xFFFCE000 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun/* GPIO register bitmasks */ 32*4882a593Smuzhiyun#define KEYBRD_DATA_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_DATA) 33*4882a593Smuzhiyun#define KEYBRD_CLK_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_CLK) 34*4882a593Smuzhiyun#define MODEM_IRQ_MASK (0x1 << AMS_DELTA_GPIO_PIN_MODEM_IRQ) 35*4882a593Smuzhiyun#define HOOK_SWITCH_MASK (0x1 << AMS_DELTA_GPIO_PIN_HOOK_SWITCH) 36*4882a593Smuzhiyun#define OTHERS_MASK (MODEM_IRQ_MASK | HOOK_SWITCH_MASK) 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun/* IRQ handler register bitmasks */ 39*4882a593Smuzhiyun#define DEFERRED_FIQ_MASK OMAP_IRQ_BIT(INT_DEFERRED_FIQ) 40*4882a593Smuzhiyun#define GPIO_BANK1_MASK OMAP_IRQ_BIT(INT_GPIO_BANK1) 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun/* Driver buffer byte offsets */ 43*4882a593Smuzhiyun#define BUF_MASK (FIQ_MASK * 4) 44*4882a593Smuzhiyun#define BUF_STATE (FIQ_STATE * 4) 45*4882a593Smuzhiyun#define BUF_KEYS_CNT (FIQ_KEYS_CNT * 4) 46*4882a593Smuzhiyun#define BUF_TAIL_OFFSET (FIQ_TAIL_OFFSET * 4) 47*4882a593Smuzhiyun#define BUF_HEAD_OFFSET (FIQ_HEAD_OFFSET * 4) 48*4882a593Smuzhiyun#define BUF_BUF_LEN (FIQ_BUF_LEN * 4) 49*4882a593Smuzhiyun#define BUF_KEY (FIQ_KEY * 4) 50*4882a593Smuzhiyun#define BUF_MISSED_KEYS (FIQ_MISSED_KEYS * 4) 51*4882a593Smuzhiyun#define BUF_BUFFER_START (FIQ_BUFFER_START * 4) 52*4882a593Smuzhiyun#define BUF_GPIO_INT_MASK (FIQ_GPIO_INT_MASK * 4) 53*4882a593Smuzhiyun#define BUF_KEYS_HICNT (FIQ_KEYS_HICNT * 4) 54*4882a593Smuzhiyun#define BUF_IRQ_PEND (FIQ_IRQ_PEND * 4) 55*4882a593Smuzhiyun#define BUF_SIR_CODE_L1 (FIQ_SIR_CODE_L1 * 4) 56*4882a593Smuzhiyun#define BUF_SIR_CODE_L2 (IRQ_SIR_CODE_L2 * 4) 57*4882a593Smuzhiyun#define BUF_CNT_INT_00 (FIQ_CNT_INT_00 * 4) 58*4882a593Smuzhiyun#define BUF_CNT_INT_KEY (FIQ_CNT_INT_KEY * 4) 59*4882a593Smuzhiyun#define BUF_CNT_INT_MDM (FIQ_CNT_INT_MDM * 4) 60*4882a593Smuzhiyun#define BUF_CNT_INT_03 (FIQ_CNT_INT_03 * 4) 61*4882a593Smuzhiyun#define BUF_CNT_INT_HSW (FIQ_CNT_INT_HSW * 4) 62*4882a593Smuzhiyun#define BUF_CNT_INT_05 (FIQ_CNT_INT_05 * 4) 63*4882a593Smuzhiyun#define BUF_CNT_INT_06 (FIQ_CNT_INT_06 * 4) 64*4882a593Smuzhiyun#define BUF_CNT_INT_07 (FIQ_CNT_INT_07 * 4) 65*4882a593Smuzhiyun#define BUF_CNT_INT_08 (FIQ_CNT_INT_08 * 4) 66*4882a593Smuzhiyun#define BUF_CNT_INT_09 (FIQ_CNT_INT_09 * 4) 67*4882a593Smuzhiyun#define BUF_CNT_INT_10 (FIQ_CNT_INT_10 * 4) 68*4882a593Smuzhiyun#define BUF_CNT_INT_11 (FIQ_CNT_INT_11 * 4) 69*4882a593Smuzhiyun#define BUF_CNT_INT_12 (FIQ_CNT_INT_12 * 4) 70*4882a593Smuzhiyun#define BUF_CNT_INT_13 (FIQ_CNT_INT_13 * 4) 71*4882a593Smuzhiyun#define BUF_CNT_INT_14 (FIQ_CNT_INT_14 * 4) 72*4882a593Smuzhiyun#define BUF_CNT_INT_15 (FIQ_CNT_INT_15 * 4) 73*4882a593Smuzhiyun#define BUF_CIRC_BUFF (FIQ_CIRC_BUFF * 4) 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun/* 77*4882a593Smuzhiyun * Register usage 78*4882a593Smuzhiyun * r8 - temporary 79*4882a593Smuzhiyun * r9 - the driver buffer 80*4882a593Smuzhiyun * r10 - temporary 81*4882a593Smuzhiyun * r11 - interrupts mask 82*4882a593Smuzhiyun * r12 - base pointers 83*4882a593Smuzhiyun * r13 - interrupts status 84*4882a593Smuzhiyun */ 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun .text 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun .global qwerty_fiqin_end 89*4882a593Smuzhiyun 90*4882a593SmuzhiyunENTRY(qwerty_fiqin_start) 91*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 92*4882a593Smuzhiyun @ FIQ intrrupt handler 93*4882a593Smuzhiyun ldr r12, omap_ih1_base @ set pointer to level1 handler 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun ldr r11, [r12, #IRQ_MIR_REG_OFFSET] @ fetch interrupts mask 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun ldr r13, [r12, #IRQ_ITR_REG_OFFSET] @ fetch interrupts status 98*4882a593Smuzhiyun bics r13, r13, r11 @ clear masked - any left? 99*4882a593Smuzhiyun beq exit @ none - spurious FIQ? exit 100*4882a593Smuzhiyun 101*4882a593Smuzhiyun ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET] @ get requested interrupt number 102*4882a593Smuzhiyun 103*4882a593Smuzhiyun mov r8, #2 @ reset FIQ agreement 104*4882a593Smuzhiyun str r8, [r12, #IRQ_CONTROL_REG_OFFSET] 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun cmp r10, #(INT_GPIO_BANK1 - NR_IRQS_LEGACY) @ is it GPIO interrupt? 107*4882a593Smuzhiyun beq gpio @ yes - process it 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun mov r8, #1 110*4882a593Smuzhiyun orr r8, r11, r8, lsl r10 @ mask spurious interrupt 111*4882a593Smuzhiyun str r8, [r12, #IRQ_MIR_REG_OFFSET] 112*4882a593Smuzhiyunexit: 113*4882a593Smuzhiyun subs pc, lr, #4 @ return from FIQ 114*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun 117*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@@@@ 118*4882a593Smuzhiyungpio: @ GPIO bank interrupt handler 119*4882a593Smuzhiyun ldr r12, omap1510_gpio_base @ set base pointer to GPIO bank 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun ldr r11, [r12, #OMAP1510_GPIO_INT_MASK] @ fetch GPIO interrupts mask 122*4882a593Smuzhiyunrestart: 123*4882a593Smuzhiyun ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ fetch status bits 124*4882a593Smuzhiyun bics r13, r13, r11 @ clear masked - any left? 125*4882a593Smuzhiyun beq exit @ no - spurious interrupt? exit 126*4882a593Smuzhiyun 127*4882a593Smuzhiyun orr r11, r11, r13 @ mask all requested interrupts 128*4882a593Smuzhiyun str r11, [r12, #OMAP1510_GPIO_INT_MASK] 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun ands r10, r13, #KEYBRD_CLK_MASK @ extract keyboard status - set? 133*4882a593Smuzhiyun beq hksw @ no - try next source 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@ 137*4882a593Smuzhiyun @ Keyboard clock FIQ mode interrupt handler 138*4882a593Smuzhiyun @ r10 now contains KEYBRD_CLK_MASK, use it 139*4882a593Smuzhiyun bic r11, r11, r10 @ unmask it 140*4882a593Smuzhiyun str r11, [r12, #OMAP1510_GPIO_INT_MASK] 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun @ Process keyboard data 143*4882a593Smuzhiyun ldr r8, [r12, #OMAP1510_GPIO_DATA_INPUT] @ fetch GPIO input 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun ldr r10, [r9, #BUF_STATE] @ fetch kbd interface state 146*4882a593Smuzhiyun cmp r10, #0 @ are we expecting start bit? 147*4882a593Smuzhiyun bne data @ no - go to data processing 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun ands r8, r8, #KEYBRD_DATA_MASK @ check start bit - detected? 150*4882a593Smuzhiyun beq hksw @ no - try next source 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun @ r8 contains KEYBRD_DATA_MASK, use it 153*4882a593Smuzhiyun str r8, [r9, #BUF_STATE] @ enter data processing state 154*4882a593Smuzhiyun @ r10 already contains 0, reuse it 155*4882a593Smuzhiyun str r10, [r9, #BUF_KEY] @ clear keycode 156*4882a593Smuzhiyun mov r10, #2 @ reset input bit mask 157*4882a593Smuzhiyun str r10, [r9, #BUF_MASK] 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun @ Mask other GPIO line interrupts till key done 160*4882a593Smuzhiyun str r11, [r9, #BUF_GPIO_INT_MASK] @ save mask for later restore 161*4882a593Smuzhiyun mvn r11, #KEYBRD_CLK_MASK @ prepare all except kbd mask 162*4882a593Smuzhiyun str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ store into the mask register 163*4882a593Smuzhiyun 164*4882a593Smuzhiyun b restart @ restart 165*4882a593Smuzhiyun 166*4882a593Smuzhiyundata: ldr r10, [r9, #BUF_MASK] @ fetch current input bit mask 167*4882a593Smuzhiyun 168*4882a593Smuzhiyun @ r8 still contains GPIO input bits 169*4882a593Smuzhiyun ands r8, r8, #KEYBRD_DATA_MASK @ is keyboard data line low? 170*4882a593Smuzhiyun ldreq r8, [r9, #BUF_KEY] @ yes - fetch collected so far, 171*4882a593Smuzhiyun orreq r8, r8, r10 @ set 1 at current mask position 172*4882a593Smuzhiyun streq r8, [r9, #BUF_KEY] @ and save back 173*4882a593Smuzhiyun 174*4882a593Smuzhiyun mov r10, r10, lsl #1 @ shift mask left 175*4882a593Smuzhiyun bics r10, r10, #0x800 @ have we got all the bits? 176*4882a593Smuzhiyun strne r10, [r9, #BUF_MASK] @ not yet - store the mask 177*4882a593Smuzhiyun bne restart @ and restart 178*4882a593Smuzhiyun 179*4882a593Smuzhiyun @ r10 already contains 0, reuse it 180*4882a593Smuzhiyun str r10, [r9, #BUF_STATE] @ reset state to start 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun @ Key done - restore interrupt mask 183*4882a593Smuzhiyun ldr r10, [r9, #BUF_GPIO_INT_MASK] @ fetch saved mask 184*4882a593Smuzhiyun and r11, r11, r10 @ unmask all saved as unmasked 185*4882a593Smuzhiyun str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ restore into the mask register 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun @ Try appending the keycode to the circular buffer 188*4882a593Smuzhiyun ldr r10, [r9, #BUF_KEYS_CNT] @ get saved keystrokes count 189*4882a593Smuzhiyun ldr r8, [r9, #BUF_BUF_LEN] @ get buffer size 190*4882a593Smuzhiyun cmp r10, r8 @ is buffer full? 191*4882a593Smuzhiyun beq hksw @ yes - key lost, next source 192*4882a593Smuzhiyun 193*4882a593Smuzhiyun add r10, r10, #1 @ incremet keystrokes counter 194*4882a593Smuzhiyun str r10, [r9, #BUF_KEYS_CNT] 195*4882a593Smuzhiyun 196*4882a593Smuzhiyun ldr r10, [r9, #BUF_TAIL_OFFSET] @ get buffer tail offset 197*4882a593Smuzhiyun @ r8 already contains buffer size 198*4882a593Smuzhiyun cmp r10, r8 @ end of buffer? 199*4882a593Smuzhiyun moveq r10, #0 @ yes - rewind to buffer start 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun ldr r12, [r9, #BUF_BUFFER_START] @ get buffer start address 202*4882a593Smuzhiyun add r12, r12, r10, LSL #2 @ calculate buffer tail address 203*4882a593Smuzhiyun ldr r8, [r9, #BUF_KEY] @ get last keycode 204*4882a593Smuzhiyun str r8, [r12] @ append it to the buffer tail 205*4882a593Smuzhiyun 206*4882a593Smuzhiyun add r10, r10, #1 @ increment buffer tail offset 207*4882a593Smuzhiyun str r10, [r9, #BUF_TAIL_OFFSET] 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun ldr r10, [r9, #BUF_CNT_INT_KEY] @ increment interrupts counter 210*4882a593Smuzhiyun add r10, r10, #1 211*4882a593Smuzhiyun str r10, [r9, #BUF_CNT_INT_KEY] 212*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@ 213*4882a593Smuzhiyun 214*4882a593Smuzhiyun 215*4882a593Smuzhiyunhksw: @Is hook switch interrupt requested? 216*4882a593Smuzhiyun tst r13, #HOOK_SWITCH_MASK @ is hook switch status bit set? 217*4882a593Smuzhiyun beq mdm @ no - try next source 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun 220*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@ 221*4882a593Smuzhiyun @ Hook switch interrupt FIQ mode simple handler 222*4882a593Smuzhiyun 223*4882a593Smuzhiyun @ Don't toggle active edge, the switch always bounces 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun @ Increment hook switch interrupt counter 226*4882a593Smuzhiyun ldr r10, [r9, #BUF_CNT_INT_HSW] 227*4882a593Smuzhiyun add r10, r10, #1 228*4882a593Smuzhiyun str r10, [r9, #BUF_CNT_INT_HSW] 229*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@ 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun 232*4882a593Smuzhiyunmdm: @Is it a modem interrupt? 233*4882a593Smuzhiyun tst r13, #MODEM_IRQ_MASK @ is modem status bit set? 234*4882a593Smuzhiyun beq irq @ no - check for next interrupt 235*4882a593Smuzhiyun 236*4882a593Smuzhiyun 237*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@ 238*4882a593Smuzhiyun @ Modem FIQ mode interrupt handler stub 239*4882a593Smuzhiyun 240*4882a593Smuzhiyun @ Increment modem interrupt counter 241*4882a593Smuzhiyun ldr r10, [r9, #BUF_CNT_INT_MDM] 242*4882a593Smuzhiyun add r10, r10, #1 243*4882a593Smuzhiyun str r10, [r9, #BUF_CNT_INT_MDM] 244*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@ 245*4882a593Smuzhiyun 246*4882a593Smuzhiyun 247*4882a593Smuzhiyunirq: @ Place deferred_fiq interrupt request 248*4882a593Smuzhiyun ldr r12, deferred_fiq_ih_base @ set pointer to IRQ handler 249*4882a593Smuzhiyun mov r10, #DEFERRED_FIQ_MASK @ set deferred_fiq bit 250*4882a593Smuzhiyun str r10, [r12, #IRQ_ISR_REG_OFFSET] @ place it in the ISR register 251*4882a593Smuzhiyun 252*4882a593Smuzhiyun ldr r12, omap1510_gpio_base @ set pointer back to GPIO bank 253*4882a593Smuzhiyun b restart @ check for next GPIO interrupt 254*4882a593Smuzhiyun @@@@@@@@@@@@@@@@@@@@@@@@@@@ 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun 257*4882a593Smuzhiyun/* 258*4882a593Smuzhiyun * Virtual addresses for IO 259*4882a593Smuzhiyun */ 260*4882a593Smuzhiyunomap_ih1_base: 261*4882a593Smuzhiyun .word OMAP1_IO_ADDRESS(OMAP_IH1_BASE) 262*4882a593Smuzhiyundeferred_fiq_ih_base: 263*4882a593Smuzhiyun .word OMAP1_IO_ADDRESS(DEFERRED_FIQ_IH_BASE) 264*4882a593Smuzhiyunomap1510_gpio_base: 265*4882a593Smuzhiyun .word OMAP1_IO_ADDRESS(OMAP1510_GPIO_BASE) 266*4882a593Smuzhiyunqwerty_fiqin_end: 267*4882a593Smuzhiyun 268*4882a593Smuzhiyun/* 269*4882a593Smuzhiyun * Check the size of the FIQ, 270*4882a593Smuzhiyun * it cannot go beyond 0xffff0200, and is copied to 0xffff001c 271*4882a593Smuzhiyun */ 272*4882a593Smuzhiyun.if (qwerty_fiqin_end - qwerty_fiqin_start) > (0x200 - 0x1c) 273*4882a593Smuzhiyun .err 274*4882a593Smuzhiyun.endif 275