/* * include/asm/arch/entry-macro.S * * Copyright (C) 2012 MStar Semiconductor. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include .macro disable_fiq .endm .macro arch_ret_to_user, tmp1, tmp2 .endm /****************** * IRQ Workflow !! ******************/ .macro get_irqnr_and_base, irqnr, level, base, tmp, tmp2 ldr \base, =IO_ADDRESS(ARM_ICTL_BASE) /* Store previous priority level in a table (in case we preempted * a running interrupt). */ ldr \level, [\base, #IRQ_PLEVEL_OFFSET] mov \tmp, #1 mov \level, \tmp, lsl \level ldr \tmp, .irqpriotable orr \tmp, \tmp, \level str \tmp, .irqpriotable 1: /* Get current interruption priority level (in order to update * final status register). */ ldr \level, [\base, #IRQ_VECTOR_OFFSET] str \level, [\base, #IRQ_PLEVEL_OFFSET] /* Save final status register to get IRQ number. */ ldr \irqnr, [\base, #IRQ_FINALSTATUS_OFFSET_L] ldr \tmp2, [\base, #IRQ_FINALSTATUS_OFFSET_H] /* Check vector offset consistency. */ ldr \tmp, [\base, #IRQ_VECTOR_OFFSET] cmp \level, \tmp bne 1b /* Mask lower and same priority interrupts. */ add \level, \level, #1 str \level, [\base, #IRQ_PLEVEL_OFFSET] /* Disable all interrupts if we are on the maximum priority level. */ cmp \level, #16 bne 2f mov \tmp, #0xFFFFFFFF str \tmp, [\base, #IRQ_INTMASK_OFFSET_L] str \tmp, [\base, #IRQ_INTMASK_OFFSET_H] 2: clz \irqnr, \irqnr @ find the upper active IRQ cmp \irqnr, #32 @ is there a pending IRQ in the first 32 sources beq 3f @ no, see the the sources 32 to 63 rsb \irqnr, \irqnr, #31 @ yes find the correct irqnr (32 - nbzero-1) b 1001f @ end function 3: clz \irqnr, \tmp2 @ find the upper active IRQ cmp \irqnr, #32 @ is there a pending it in the sources 32 to 63 moveq \irqnr, #64 @ no, return 64 to warn that that there is a problem beq 1001f @ no, end function rsb \irqnr, \irqnr, #63 @ yes find the correct irqnr (64 - nbzero-1) 1001: /* WARNING: These lines override the default behaviour, */ /* which is to loop back at the start of the macro after the handler */ /* set r1 to registers address */ movne r1, sp /* set label 2 as return address */ adrne lr, 2f .endm .macro restore_cpr_and_check_status .endm .macro restore_irq_level, level, tmp, table /* Get previous priority level (in case we preempted a running * interrupt) and update the table. */ ldr \table, .irqpriotable @ find the last irq level clz \level, \table @ stored in .irqpriotable rsb \level, \level, #31 mov \tmp, #1 mov \tmp, \tmp, lsl \level bic \table, \table, \tmp @ suppr this priority in .irqpriotable str \table, .irqpriotable /* Set the previous priority level. */ ldr \tmp, =IO_ADDRESS(ARM_ICTL_BASE) @ change to this priority str \level, [\tmp, #IRQ_PLEVEL_OFFSET] mov \table, #0 str \table, [\tmp, #IRQ_INTMASK_OFFSET_L] str \table, [\tmp, #IRQ_INTMASK_OFFSET_H] .endm /* This macro is called only for MSE500 platform because some processing * must be done after the handler and must work under RTAI */ .macro irq_prio_table .endm /* This macro is called only for SPC300 platform */ /* beacuse some processing must be done after the handler */ .macro irq_handler_spc300 reg0, reg6, reg5, reg1, reglr, reg2 get_irqnr_and_base \reg0, \reg6, \reg5, \reglr, \reg2 @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ bne asm_do_IRQ 2: restore_irq_level \reg5, \reg6, \reg0 .endm