18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-omap1/ams-delta-fiq-handler.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on linux/arch/arm/lib/floppydma.S 68c2ecf20Sopenharmony_ci * Renamed and modified to work with 2.6 kernel by Matt Callow 78c2ecf20Sopenharmony_ci * Copyright (C) 1995, 1996 Russell King 88c2ecf20Sopenharmony_ci * Copyright (C) 2004 Pete Trapps 98c2ecf20Sopenharmony_ci * Copyright (C) 2006 Matt Callow 108c2ecf20Sopenharmony_ci * Copyright (C) 2010 Janusz Krzysztofik 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/linkage.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_data/ams-delta-fiq.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_data/gpio-omap.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/assembler.h> 188c2ecf20Sopenharmony_ci#include <asm/irq.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "ams-delta-fiq.h" 218c2ecf20Sopenharmony_ci#include "board-ams-delta.h" 228c2ecf20Sopenharmony_ci#include "iomap.h" 238c2ecf20Sopenharmony_ci#include "soc.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * OMAP1510 GPIO related symbol copied from arch/arm/mach-omap1/gpio15xx.c. 278c2ecf20Sopenharmony_ci * Unfortunately, it was not placed in a separate header file. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci#define OMAP1510_GPIO_BASE 0xFFFCE000 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* GPIO register bitmasks */ 328c2ecf20Sopenharmony_ci#define KEYBRD_DATA_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_DATA) 338c2ecf20Sopenharmony_ci#define KEYBRD_CLK_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_CLK) 348c2ecf20Sopenharmony_ci#define MODEM_IRQ_MASK (0x1 << AMS_DELTA_GPIO_PIN_MODEM_IRQ) 358c2ecf20Sopenharmony_ci#define HOOK_SWITCH_MASK (0x1 << AMS_DELTA_GPIO_PIN_HOOK_SWITCH) 368c2ecf20Sopenharmony_ci#define OTHERS_MASK (MODEM_IRQ_MASK | HOOK_SWITCH_MASK) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* IRQ handler register bitmasks */ 398c2ecf20Sopenharmony_ci#define DEFERRED_FIQ_MASK OMAP_IRQ_BIT(INT_DEFERRED_FIQ) 408c2ecf20Sopenharmony_ci#define GPIO_BANK1_MASK OMAP_IRQ_BIT(INT_GPIO_BANK1) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Driver buffer byte offsets */ 438c2ecf20Sopenharmony_ci#define BUF_MASK (FIQ_MASK * 4) 448c2ecf20Sopenharmony_ci#define BUF_STATE (FIQ_STATE * 4) 458c2ecf20Sopenharmony_ci#define BUF_KEYS_CNT (FIQ_KEYS_CNT * 4) 468c2ecf20Sopenharmony_ci#define BUF_TAIL_OFFSET (FIQ_TAIL_OFFSET * 4) 478c2ecf20Sopenharmony_ci#define BUF_HEAD_OFFSET (FIQ_HEAD_OFFSET * 4) 488c2ecf20Sopenharmony_ci#define BUF_BUF_LEN (FIQ_BUF_LEN * 4) 498c2ecf20Sopenharmony_ci#define BUF_KEY (FIQ_KEY * 4) 508c2ecf20Sopenharmony_ci#define BUF_MISSED_KEYS (FIQ_MISSED_KEYS * 4) 518c2ecf20Sopenharmony_ci#define BUF_BUFFER_START (FIQ_BUFFER_START * 4) 528c2ecf20Sopenharmony_ci#define BUF_GPIO_INT_MASK (FIQ_GPIO_INT_MASK * 4) 538c2ecf20Sopenharmony_ci#define BUF_KEYS_HICNT (FIQ_KEYS_HICNT * 4) 548c2ecf20Sopenharmony_ci#define BUF_IRQ_PEND (FIQ_IRQ_PEND * 4) 558c2ecf20Sopenharmony_ci#define BUF_SIR_CODE_L1 (FIQ_SIR_CODE_L1 * 4) 568c2ecf20Sopenharmony_ci#define BUF_SIR_CODE_L2 (IRQ_SIR_CODE_L2 * 4) 578c2ecf20Sopenharmony_ci#define BUF_CNT_INT_00 (FIQ_CNT_INT_00 * 4) 588c2ecf20Sopenharmony_ci#define BUF_CNT_INT_KEY (FIQ_CNT_INT_KEY * 4) 598c2ecf20Sopenharmony_ci#define BUF_CNT_INT_MDM (FIQ_CNT_INT_MDM * 4) 608c2ecf20Sopenharmony_ci#define BUF_CNT_INT_03 (FIQ_CNT_INT_03 * 4) 618c2ecf20Sopenharmony_ci#define BUF_CNT_INT_HSW (FIQ_CNT_INT_HSW * 4) 628c2ecf20Sopenharmony_ci#define BUF_CNT_INT_05 (FIQ_CNT_INT_05 * 4) 638c2ecf20Sopenharmony_ci#define BUF_CNT_INT_06 (FIQ_CNT_INT_06 * 4) 648c2ecf20Sopenharmony_ci#define BUF_CNT_INT_07 (FIQ_CNT_INT_07 * 4) 658c2ecf20Sopenharmony_ci#define BUF_CNT_INT_08 (FIQ_CNT_INT_08 * 4) 668c2ecf20Sopenharmony_ci#define BUF_CNT_INT_09 (FIQ_CNT_INT_09 * 4) 678c2ecf20Sopenharmony_ci#define BUF_CNT_INT_10 (FIQ_CNT_INT_10 * 4) 688c2ecf20Sopenharmony_ci#define BUF_CNT_INT_11 (FIQ_CNT_INT_11 * 4) 698c2ecf20Sopenharmony_ci#define BUF_CNT_INT_12 (FIQ_CNT_INT_12 * 4) 708c2ecf20Sopenharmony_ci#define BUF_CNT_INT_13 (FIQ_CNT_INT_13 * 4) 718c2ecf20Sopenharmony_ci#define BUF_CNT_INT_14 (FIQ_CNT_INT_14 * 4) 728c2ecf20Sopenharmony_ci#define BUF_CNT_INT_15 (FIQ_CNT_INT_15 * 4) 738c2ecf20Sopenharmony_ci#define BUF_CIRC_BUFF (FIQ_CIRC_BUFF * 4) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * Register usage 788c2ecf20Sopenharmony_ci * r8 - temporary 798c2ecf20Sopenharmony_ci * r9 - the driver buffer 808c2ecf20Sopenharmony_ci * r10 - temporary 818c2ecf20Sopenharmony_ci * r11 - interrupts mask 828c2ecf20Sopenharmony_ci * r12 - base pointers 838c2ecf20Sopenharmony_ci * r13 - interrupts status 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci .text 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci .global qwerty_fiqin_end 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ciENTRY(qwerty_fiqin_start) 918c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 928c2ecf20Sopenharmony_ci @ FIQ intrrupt handler 938c2ecf20Sopenharmony_ci ldr r12, omap_ih1_base @ set pointer to level1 handler 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci ldr r11, [r12, #IRQ_MIR_REG_OFFSET] @ fetch interrupts mask 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ldr r13, [r12, #IRQ_ITR_REG_OFFSET] @ fetch interrupts status 988c2ecf20Sopenharmony_ci bics r13, r13, r11 @ clear masked - any left? 998c2ecf20Sopenharmony_ci beq exit @ none - spurious FIQ? exit 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET] @ get requested interrupt number 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci mov r8, #2 @ reset FIQ agreement 1048c2ecf20Sopenharmony_ci str r8, [r12, #IRQ_CONTROL_REG_OFFSET] 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci cmp r10, #(INT_GPIO_BANK1 - NR_IRQS_LEGACY) @ is it GPIO interrupt? 1078c2ecf20Sopenharmony_ci beq gpio @ yes - process it 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci mov r8, #1 1108c2ecf20Sopenharmony_ci orr r8, r11, r8, lsl r10 @ mask spurious interrupt 1118c2ecf20Sopenharmony_ci str r8, [r12, #IRQ_MIR_REG_OFFSET] 1128c2ecf20Sopenharmony_ciexit: 1138c2ecf20Sopenharmony_ci subs pc, lr, #4 @ return from FIQ 1148c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@ 1188c2ecf20Sopenharmony_cigpio: @ GPIO bank interrupt handler 1198c2ecf20Sopenharmony_ci ldr r12, omap1510_gpio_base @ set base pointer to GPIO bank 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ldr r11, [r12, #OMAP1510_GPIO_INT_MASK] @ fetch GPIO interrupts mask 1228c2ecf20Sopenharmony_cirestart: 1238c2ecf20Sopenharmony_ci ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ fetch status bits 1248c2ecf20Sopenharmony_ci bics r13, r13, r11 @ clear masked - any left? 1258c2ecf20Sopenharmony_ci beq exit @ no - spurious interrupt? exit 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci orr r11, r11, r13 @ mask all requested interrupts 1288c2ecf20Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci ands r10, r13, #KEYBRD_CLK_MASK @ extract keyboard status - set? 1338c2ecf20Sopenharmony_ci beq hksw @ no - try next source 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@ 1378c2ecf20Sopenharmony_ci @ Keyboard clock FIQ mode interrupt handler 1388c2ecf20Sopenharmony_ci @ r10 now contains KEYBRD_CLK_MASK, use it 1398c2ecf20Sopenharmony_ci bic r11, r11, r10 @ unmask it 1408c2ecf20Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci @ Process keyboard data 1438c2ecf20Sopenharmony_ci ldr r8, [r12, #OMAP1510_GPIO_DATA_INPUT] @ fetch GPIO input 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci ldr r10, [r9, #BUF_STATE] @ fetch kbd interface state 1468c2ecf20Sopenharmony_ci cmp r10, #0 @ are we expecting start bit? 1478c2ecf20Sopenharmony_ci bne data @ no - go to data processing 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ands r8, r8, #KEYBRD_DATA_MASK @ check start bit - detected? 1508c2ecf20Sopenharmony_ci beq hksw @ no - try next source 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci @ r8 contains KEYBRD_DATA_MASK, use it 1538c2ecf20Sopenharmony_ci str r8, [r9, #BUF_STATE] @ enter data processing state 1548c2ecf20Sopenharmony_ci @ r10 already contains 0, reuse it 1558c2ecf20Sopenharmony_ci str r10, [r9, #BUF_KEY] @ clear keycode 1568c2ecf20Sopenharmony_ci mov r10, #2 @ reset input bit mask 1578c2ecf20Sopenharmony_ci str r10, [r9, #BUF_MASK] 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci @ Mask other GPIO line interrupts till key done 1608c2ecf20Sopenharmony_ci str r11, [r9, #BUF_GPIO_INT_MASK] @ save mask for later restore 1618c2ecf20Sopenharmony_ci mvn r11, #KEYBRD_CLK_MASK @ prepare all except kbd mask 1628c2ecf20Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ store into the mask register 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci b restart @ restart 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cidata: ldr r10, [r9, #BUF_MASK] @ fetch current input bit mask 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci @ r8 still contains GPIO input bits 1698c2ecf20Sopenharmony_ci ands r8, r8, #KEYBRD_DATA_MASK @ is keyboard data line low? 1708c2ecf20Sopenharmony_ci ldreq r8, [r9, #BUF_KEY] @ yes - fetch collected so far, 1718c2ecf20Sopenharmony_ci orreq r8, r8, r10 @ set 1 at current mask position 1728c2ecf20Sopenharmony_ci streq r8, [r9, #BUF_KEY] @ and save back 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci mov r10, r10, lsl #1 @ shift mask left 1758c2ecf20Sopenharmony_ci bics r10, r10, #0x800 @ have we got all the bits? 1768c2ecf20Sopenharmony_ci strne r10, [r9, #BUF_MASK] @ not yet - store the mask 1778c2ecf20Sopenharmony_ci bne restart @ and restart 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci @ r10 already contains 0, reuse it 1808c2ecf20Sopenharmony_ci str r10, [r9, #BUF_STATE] @ reset state to start 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci @ Key done - restore interrupt mask 1838c2ecf20Sopenharmony_ci ldr r10, [r9, #BUF_GPIO_INT_MASK] @ fetch saved mask 1848c2ecf20Sopenharmony_ci and r11, r11, r10 @ unmask all saved as unmasked 1858c2ecf20Sopenharmony_ci str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ restore into the mask register 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci @ Try appending the keycode to the circular buffer 1888c2ecf20Sopenharmony_ci ldr r10, [r9, #BUF_KEYS_CNT] @ get saved keystrokes count 1898c2ecf20Sopenharmony_ci ldr r8, [r9, #BUF_BUF_LEN] @ get buffer size 1908c2ecf20Sopenharmony_ci cmp r10, r8 @ is buffer full? 1918c2ecf20Sopenharmony_ci beq hksw @ yes - key lost, next source 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci add r10, r10, #1 @ incremet keystrokes counter 1948c2ecf20Sopenharmony_ci str r10, [r9, #BUF_KEYS_CNT] 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ldr r10, [r9, #BUF_TAIL_OFFSET] @ get buffer tail offset 1978c2ecf20Sopenharmony_ci @ r8 already contains buffer size 1988c2ecf20Sopenharmony_ci cmp r10, r8 @ end of buffer? 1998c2ecf20Sopenharmony_ci moveq r10, #0 @ yes - rewind to buffer start 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ldr r12, [r9, #BUF_BUFFER_START] @ get buffer start address 2028c2ecf20Sopenharmony_ci add r12, r12, r10, LSL #2 @ calculate buffer tail address 2038c2ecf20Sopenharmony_ci ldr r8, [r9, #BUF_KEY] @ get last keycode 2048c2ecf20Sopenharmony_ci str r8, [r12] @ append it to the buffer tail 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci add r10, r10, #1 @ increment buffer tail offset 2078c2ecf20Sopenharmony_ci str r10, [r9, #BUF_TAIL_OFFSET] 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ldr r10, [r9, #BUF_CNT_INT_KEY] @ increment interrupts counter 2108c2ecf20Sopenharmony_ci add r10, r10, #1 2118c2ecf20Sopenharmony_ci str r10, [r9, #BUF_CNT_INT_KEY] 2128c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cihksw: @Is hook switch interrupt requested? 2168c2ecf20Sopenharmony_ci tst r13, #HOOK_SWITCH_MASK @ is hook switch status bit set? 2178c2ecf20Sopenharmony_ci beq mdm @ no - try next source 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 2218c2ecf20Sopenharmony_ci @ Hook switch interrupt FIQ mode simple handler 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci @ Don't toggle active edge, the switch always bounces 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci @ Increment hook switch interrupt counter 2268c2ecf20Sopenharmony_ci ldr r10, [r9, #BUF_CNT_INT_HSW] 2278c2ecf20Sopenharmony_ci add r10, r10, #1 2288c2ecf20Sopenharmony_ci str r10, [r9, #BUF_CNT_INT_HSW] 2298c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cimdm: @Is it a modem interrupt? 2338c2ecf20Sopenharmony_ci tst r13, #MODEM_IRQ_MASK @ is modem status bit set? 2348c2ecf20Sopenharmony_ci beq irq @ no - check for next interrupt 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 2388c2ecf20Sopenharmony_ci @ Modem FIQ mode interrupt handler stub 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci @ Increment modem interrupt counter 2418c2ecf20Sopenharmony_ci ldr r10, [r9, #BUF_CNT_INT_MDM] 2428c2ecf20Sopenharmony_ci add r10, r10, #1 2438c2ecf20Sopenharmony_ci str r10, [r9, #BUF_CNT_INT_MDM] 2448c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciirq: @ Place deferred_fiq interrupt request 2488c2ecf20Sopenharmony_ci ldr r12, deferred_fiq_ih_base @ set pointer to IRQ handler 2498c2ecf20Sopenharmony_ci mov r10, #DEFERRED_FIQ_MASK @ set deferred_fiq bit 2508c2ecf20Sopenharmony_ci str r10, [r12, #IRQ_ISR_REG_OFFSET] @ place it in the ISR register 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ldr r12, omap1510_gpio_base @ set pointer back to GPIO bank 2538c2ecf20Sopenharmony_ci b restart @ check for next GPIO interrupt 2548c2ecf20Sopenharmony_ci @@@@@@@@@@@@@@@@@@@@@@@@@@@ 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* 2588c2ecf20Sopenharmony_ci * Virtual addresses for IO 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ciomap_ih1_base: 2618c2ecf20Sopenharmony_ci .word OMAP1_IO_ADDRESS(OMAP_IH1_BASE) 2628c2ecf20Sopenharmony_cideferred_fiq_ih_base: 2638c2ecf20Sopenharmony_ci .word OMAP1_IO_ADDRESS(DEFERRED_FIQ_IH_BASE) 2648c2ecf20Sopenharmony_ciomap1510_gpio_base: 2658c2ecf20Sopenharmony_ci .word OMAP1_IO_ADDRESS(OMAP1510_GPIO_BASE) 2668c2ecf20Sopenharmony_ciqwerty_fiqin_end: 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* 2698c2ecf20Sopenharmony_ci * Check the size of the FIQ, 2708c2ecf20Sopenharmony_ci * it cannot go beyond 0xffff0200, and is copied to 0xffff001c 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci.if (qwerty_fiqin_end - qwerty_fiqin_start) > (0x200 - 0x1c) 2738c2ecf20Sopenharmony_ci .err 2748c2ecf20Sopenharmony_ci.endif 275