FreeCalypso > hg > freecalypso-sw
changeset 114:17b0511b243c
nuc-fw: continuing lowest-level BSP integration
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Thu, 24 Oct 2013 02:47:14 +0000 |
parents | 3b2e941043d8 |
children | 1e41550feec5 |
files | nuc-fw/bsp/Makefile nuc-fw/bsp/timer.c nuc-fw/bsp/timer1.c nuc-fw/bsp/timer2.c nuc-fw/sysglue/Makefile nuc-fw/sysglue/irqfiq.S |
diffstat | 6 files changed, 705 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/nuc-fw/bsp/Makefile Sun Oct 20 21:12:41 2013 +0000 +++ b/nuc-fw/bsp/Makefile Thu Oct 24 02:47:14 2013 +0000 @@ -4,9 +4,9 @@ AR= arm-elf-ar RANLIB= arm-elf-ranlib -IOBJS= armio.o inth.o niq32.o +IOBJS= niq32.o -XTOBJS= clkm.o niq.o +XTOBJS= armio.o clkm.o inth.o niq.o timer.o timer1.o timer2.o XOBJS= ${XTOBJS} AOBJS= ${IOBJS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/bsp/timer.c Thu Oct 24 02:47:14 2013 +0000 @@ -0,0 +1,267 @@ +/******************************************************************************* + TEXAS INSTRUMENTS INCORPORATED PROPRIETARY INFORMATION + + Property of Texas Instruments -- For Unrestricted Internal Use Only + Unauthorized reproduction and/or distribution is strictly prohibited. This + product is protected under copyright law and trade secret law as an + unpublished work. Created 1987, (C) Copyright 1997 Texas Instruments. All + rights reserved. + + + Filename : timer.c + + Description : timer.c + + Project : drivers + + Author : pmonteil@tif.ti.com Patrice Monteil. + + Version number : 1.3 + + Date and time : 07/23/98 16:25:32 + Previous delta : 07/23/98 16:25:32 + + SCCS file : /db/gsm_asp/db_ht96/dsp_0/gsw/rel_0/mcu_l1/release1.5/mod/emu/EMU_MCMP/eva3_drivers/source/SCCS/s.timer.c + + Sccs Id (SID) : '@(#) timer.c 1.3 07/23/98 16:25:32 ' + + +*****************************************************************************/ + +#include "../include/sys_types.h" + +#include "mem.h" +#include "iq.h" +#include "timer.h" + + +/*-------------------------------------------------------------- + * TIMER_Read() + *-------------------------------------------------------------- + * Parameters : num of the register to be read + * Return :value of the timer register read + * Functionality : read one of the TIMER register + *--------------------------------------------------------------*/ +SYS_UWORD16 TIMER_Read (unsigned short regNum) +{ + SYS_UWORD16 timerReg; + + switch (regNum) { + case 0: + timerReg = ( * (volatile SYS_UWORD16 *) TIMER_CNTL_REG) & TIMER_CNTL_MASK; + break; + case 1: + timerReg = *(volatile SYS_UWORD16 *) TIMER_READ_REG; + break; + case 2: + timerReg = ( * (volatile SYS_UWORD16 *) TIMER_MODE_REG) & TIMER_MODE_MASK; + break; + default: + break; + } + return(timerReg); +} +/*-------------------------------------------------------------- + * TM_ResetTimer() + *-------------------------------------------------------------- + * Parameters : timer number (1 or 2) + * timer value, reload yes or not, scale + * Return : none + * Functionality : Give the timewr state + *--------------------------------------------------------------*/ +void TM_ResetTimer (SYS_UWORD16 timerNum, SYS_UWORD16 countValue, + SYS_UWORD16 autoReload, SYS_UWORD16 clockScale) +{ + volatile SYS_UWORD16 *cntl; + + if (timerNum == 1) + { + cntl = (volatile SYS_UWORD16 *) TIMER1_CNTL; + + *cntl &= ~(START_STOP | PTV); /* stop and reset values */ + + (autoReload) ? (*cntl |= AR) : (*cntl &= ~AR); + + *cntl |= (clockScale << 2 ); + + /*load the value */ + *(volatile SYS_UWORD16 *) TIMER1_LOAD_TIM = countValue; + + *cntl |= START_STOP; + } + else + { + cntl = (volatile SYS_UWORD16 *) TIMER2_CNTL; + + *cntl &= ~(START_STOP | PTV); /* stop and reset values */ + + (autoReload) ? (*cntl |= AR) : (*cntl &= ~AR); + + *cntl |= (clockScale << 2 ); + + /*load the value */ + *(volatile SYS_UWORD16 *) TIMER2_LOAD_TIM = countValue; + + *cntl |= START_STOP; + } +} + +/* + * TM_StopTimer + * + * Parameters : timer number (1 or 2) + */ +void TM_StopTimer (int timerNum) +{ + volatile SYS_UWORD16 *cntl; + + if (timerNum == 1) + { + cntl = (volatile SYS_UWORD16 *) TIMER1_CNTL; + } + else + { + cntl = (volatile SYS_UWORD16 *) TIMER2_CNTL; + } + *cntl &= ~START_STOP; +} + +/* + * TM_ReadTimer + * + * Returns current timer value + * + * Parameters : timer number (1 or 2) + * + */ +SYS_UWORD16 TM_ReadTimer (int timerNum) +{ + if (timerNum == 1) + { + return (* (SYS_UWORD16 *) TIMER1_READ_TIM); + } + else + { + return (* (SYS_UWORD16 *) TIMER2_READ_TIM); + } +} + + +/* + * TM_StartTimer + * + * Parameters : timer number (1 or 2) + * + */ +void TM_StartTimer (int timerNum) +{ + volatile SYS_UWORD16 *cntl; + + if (timerNum == 1) + { + cntl = (volatile SYS_UWORD16 *) TIMER1_CNTL; + } + else + { + cntl = (volatile SYS_UWORD16 *) TIMER2_CNTL; + } + *cntl |= START_STOP; +} + +void TM_DisableWatchdog (void) +{ + /* volatile variable needed due C to optimization */ + volatile SYS_UWORD16 *reg = (volatile SYS_UWORD16 *) TIMER_MODE_REG; + + *reg = 0xf5; + *reg = 0xa0; +} + + + /* + * TM_EnableWatchdog + * + */ +void TM_EnableWatchdog(void) +{ + * ((volatile SYS_UWORD16 *) TIMER_MODE_REG) = TIMER_WDOG; +} + +/* + * TM_ResetWatchdog + * + * Parameter : Tick count + * Use a different value each time, otherwise watchdog bites + */ +void TM_ResetWatchdog(SYS_UWORD16 count) +{ + * ((volatile SYS_UWORD16 *) TIMER_LOAD_REG) = count; +} + +/* +* TM_EnableTimer (int TimerNum) +* +* Parameter : TimerNum : timer to enable (timer1 or timer2) +* +*/ +void TM_EnableTimer (int TimerNum) +{ + volatile SYS_UWORD16 *cntl; + + if (TimerNum == 1) + { + cntl = (volatile SYS_UWORD16 *) TIMER1_CNTL; + } + else + { + cntl = (volatile SYS_UWORD16 *) TIMER2_CNTL; + } + *cntl |= TIMER_CLK_EN; +} + +/* +* TM_DisableTimer (int TimerNum) +* +* Parameter : TimerNum : timer to enable (timer1 or timer2) +* +*/ +void TM_DisableTimer (int TimerNum) +{ + volatile SYS_UWORD16 *cntl; + + if (TimerNum == 1) + { + cntl = (volatile SYS_UWORD16 *) TIMER1_CNTL; + } + else + { + cntl = (volatile SYS_UWORD16 *) TIMER2_CNTL; + } + *cntl &= ~TIMER_CLK_EN; +} + +/*-------------------------------------------------------------- + * TIMER_ReadValue() + *-------------------------------------------------------------- + * Parameters : none + * Return : none + * Functionality : Read timer value + *--------------------------------------------------------------*/ + +unsigned short TIMER_ReadValue (void) +{ + return(* (SYS_UWORD16 *) TIMER_READ_REG); +} + +/*-------------------------------------------------------------- + * TIMER_WriteValue() + *-------------------------------------------------------------- + * Parameters : none + * Return : none + * Functionality : Write timer value + *--------------------------------------------------------------*/ + +void TIMER_WriteValue (SYS_UWORD16 value) +{ + * (SYS_UWORD16 *) TIMER_LOAD_REG = value; /*load the value */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/bsp/timer1.c Thu Oct 24 02:47:14 2013 +0000 @@ -0,0 +1,180 @@ +/****************************************************************************** + TEXAS INSTRUMENTS INCORPORATED PROPRIETARY INFORMATION + + Property of Texas Instruments -- For Unrestricted Internal Use Only + Unauthorized reproduction and/or distribution is strictly prohibited. This + product is protected under copyright law and trade secret law as an + unpublished work. Created 1987, (C) Copyright 1997 Texas Instruments. All + rights reserved. + + + Filename : timer1.c + + Description : Set of useful functions for TIMER module test cases + + Project : drivers + + Author : pmonteil@tif.ti.com Patrice Monteil. + + Version number : 1.4 + + Date and time : 08/18/00 14:42:35 + + Previous delta : 06/30/00 11:40:43 + + SCCS file : /db/gsm_asp/db_ht96/dsp_0/gsw/rel_0/mcu_l1/release_gprs/RELEASE_GPRS/drivers1/common/SCCS/s.timer1.c + + Sccs Id (SID) : '@(#) timer1.c 1.4 08/18/00 14:42:35 ' + + +*****************************************************************************/ + +#include "../include/sys_types.h" + +#include "mem.h" +#include "timer1.h" + +/*--------------------------------------------------------------*/ +/* Dtimer1_Get_cntlreg() */ +/*--------------------------------------------------------------*/ +/* Parameters : none */ +/* Return : none */ +/* Functionality : read one of the TIMER register */ +/*--------------------------------------------------------------*/ + +SYS_UWORD16 Dtimer1_Get_cntlreg(void) +{ + SYS_UWORD16 timerReg; + + timerReg = (( * (volatile SYS_UWORD16 *) D_TIMER_CNTL) & D_TIMER_CNTL_MASK); + return(timerReg); +} + + +/*--------------------------------------------------------------*/ +/* Dtimer_Init_cntl() */ +/*--------------------------------------------------------------*/ +/* Parameters :start/stop,reload yes/no,pre scale,ext clk on/off*/ +/* Return : none */ +/* Functionality : initialize the timer start, autoreload, Ptv */ +/* and clock enable */ +/*--------------------------------------------------------------*/ + +void Dtimer1_Init_cntl (SYS_UWORD16 St, SYS_UWORD16 Reload, SYS_UWORD16 clockScale, SYS_UWORD16 clkon) +{ + SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + + cntl &= ~(D_TIMER_ST | D_TIMER_PTV); /* stop and reset values */ + + (Reload) ? (cntl |= D_TIMER_AR) : (cntl &= ~D_TIMER_AR); + + cntl |= (clockScale << 2 ); + + cntl |= ( clkon << 5 ); + + + * (volatile SYS_UWORD16 *) D_TIMER_LOAD = St; + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; + } + +/*--------------------------------------------------------------*/ +/* Dtimer1_AR() */ +/*--------------------------------------------------------------*/ +/* Parameters :start/stop,reload yes/no,pre scale,ext clk on/off*/ +/* Return : none */ +/* Functionality : set the AR bit Ar = 0 | 1 */ +/*--------------------------------------------------------------*/ + +void Dtimer1_AR(SYS_UWORD16 Ar) +{ +SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + cntl &= ~(D_TIMER_ST); /* stop the timer */ + + cntl &= ~(D_TIMER_AR); + + cntl |= ( Ar << 1 ); + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; +} + +/*--------------------------------------------------------------*/ +/* Dtimer1_PTV() */ +/*--------------------------------------------------------------*/ +/* Parameters : pre scale */ +/* Return : none */ +/* Functionality : set the Ptv bits Ptv = 0 => 7 */ +/*--------------------------------------------------------------*/ + +void Dtimer1_PTV(SYS_UWORD16 Ptv) +{ +SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + cntl &= ~(D_TIMER_ST); /* stop the timer */ + + cntl &= ~(D_TIMER_PTV); /* Ptv[4:0] set to 0 */ + + cntl |= ( Ptv << 2 ); + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; +} + +/*--------------------------------------------------------------*/ +/* Dtimer1_Clken() */ +/*--------------------------------------------------------------*/ +/* Parameters : ext clk on/off */ +/* Return : none */ +/* Functionality : set the clock_enable bit En = 0 | 1 */ +/*--------------------------------------------------------------*/ + +void Dtimer1_Clken(SYS_UWORD16 En) +{ +SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + cntl &= ( ~D_TIMER_CLK_EN); + + cntl |= ( En << 5 ); + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; +} + + + +/*--------------------------------------------------------------*/ +/* Dtimer_Start() */ +/*--------------------------------------------------------------*/ +/* Parameters : on/off */ +/* Return : none */ +/* Functionality : Start or stop the timer */ +/*--------------------------------------------------------------*/ + +void Dtimer1_Start (SYS_UWORD16 startStop) +{ + (startStop == D_TIMER_ST) ? + ((* (SYS_UWORD16 *) D_TIMER_CNTL) |= D_TIMER_ST) : /* condition vrai */ + ((* (SYS_UWORD16 *) D_TIMER_CNTL) &= ~D_TIMER_ST); /* condition fausse */ +} + +/*--------------------------------------------------------------*/ +/* Dtimer_ReadValue() */ +/*--------------------------------------------------------------*/ +/* Parameters : on/off */ +/* Return : none */ +/* Functionality : Read timer value */ +/*--------------------------------------------------------------*/ +SYS_UWORD16 Dtimer1_ReadValue (void) +{ + return(* (SYS_UWORD16 *) D_TIMER_READ); +} + +/*--------------------------------------------------------------*/ +/* Parameters : on/off */ +/* Return : none */ +/* Functionality : Write timer value */ +/*--------------------------------------------------------------*/ +void Dtimer1_WriteValue (SYS_UWORD16 value) +{ + (* (SYS_UWORD16 *) D_TIMER_LOAD) = value; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/bsp/timer2.c Thu Oct 24 02:47:14 2013 +0000 @@ -0,0 +1,182 @@ +/****************************************************************************** + TEXAS INSTRUMENTS INCORPORATED PROPRIETARY INFORMATION + + Property of Texas Instruments -- For Unrestricted Internal Use Only + Unauthorized reproduction and/or distribution is strictly prohibited. This + product is protected under copyright law and trade secret law as an + unpublished work. Created 1987, (C) Copyright 1997 Texas Instruments. All + rights reserved. + + + Filename : timer2.c + + Description : Set of useful functions for TIMER module test cases + + Project : drivers + + Author : pmonteil@tif.ti.com Patrice Monteil. + Version number : 1.3 + + Date and time : 08/18/00 14:42:39 + + Previous delta : 07/10/00 16:15:18 + + SCCS file : /db/gsm_asp/db_ht96/dsp_0/gsw/rel_0/mcu_l1/release_gprs/RELEASE_GPRS/drivers1/common/SCCS/s.timer2.c + + Sccs Id (SID) : '@(#) timer2.c 1.3 08/18/00 14:42:39 ' + + + +*****************************************************************************/ + +#include "../include/sys_types.h" + +#include "mem.h" +#include "timer2.h" + +/*--------------------------------------------------------------*/ +/* Dtimer2_Get_cntlreg() */ +/*--------------------------------------------------------------*/ +/* Parameters : none */ +/* Return : none */ +/* Functionality : read one of the TIMER register */ +/*--------------------------------------------------------------*/ + +SYS_UWORD16 Dtimer2_Get_cntlreg(void) +{ + SYS_UWORD16 timerReg; + + timerReg = (( * (volatile SYS_UWORD16 *) D_TIMER_CNTL) & D_TIMER_CNTL_MASK); + return(timerReg); +} + + +/*--------------------------------------------------------------*/ +/* Dtimer2_Init_cntl() */ +/*--------------------------------------------------------------*/ +/* Parameters :start/stop,reload yes/no,pre scale,ext clk on/off*/ +/* Return : none */ +/* Functionality : initialize the timer start, autoreload, Ptv */ +/* and clock enable */ +/*--------------------------------------------------------------*/ + +void Dtimer2_Init_cntl (SYS_UWORD16 St, SYS_UWORD16 Reload, SYS_UWORD16 clockScale, SYS_UWORD16 clkon) +{ + SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + + cntl &= ~(D_TIMER_ST | D_TIMER_PTV); /* stop and reset values */ + + (Reload) ? (cntl |= D_TIMER_AR) : (cntl &= ~D_TIMER_AR); + + cntl |= (clockScale << 2 ); + + cntl |= ( clkon << 5 ); + + + * (volatile SYS_UWORD16 *) D_TIMER_LOAD = St; + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; + } + +/*--------------------------------------------------------------*/ +/* Dtimer2_AR() */ +/*--------------------------------------------------------------*/ +/* Parameters :start/stop,reload yes/no,pre scale,ext clk on/off*/ +/* Return : none */ +/* Functionality : set the AR bit Ar = 0 | 1 */ +/*--------------------------------------------------------------*/ + +void Dtimer2_AR(SYS_UWORD16 Ar) +{ +SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + cntl &= ~(D_TIMER_ST); /* stop the timer */ + + cntl &= ~(D_TIMER_AR); + + cntl |= ( Ar << 1 ); + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; +} + +/*--------------------------------------------------------------*/ +/* Dtimer2_PTV() */ +/*--------------------------------------------------------------*/ +/* Parameters : pre scale */ +/* Return : none */ +/* Functionality : set the Ptv bits Ptv = 0 => 7 */ +/*--------------------------------------------------------------*/ + +void Dtimer2_PTV(SYS_UWORD16 Ptv) +{ +SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + cntl &= ~(D_TIMER_ST); /* stop the timer */ + + cntl &= ~(D_TIMER_PTV); /* Ptv[4:0] set to 0 */ + + cntl |= ( Ptv << 2 ); + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; +} + +/*--------------------------------------------------------------*/ +/* Dtimer1_Clken() */ +/*--------------------------------------------------------------*/ +/* Parameters : ext clk on/off */ +/* Return : none */ +/* Functionality : set the clock_enable bit En = 0 | 1 */ +/*--------------------------------------------------------------*/ + +void Dtimer2_Clken(SYS_UWORD16 En) +{ +SYS_UWORD16 cntl = * (volatile SYS_UWORD16 *) D_TIMER_CNTL; + + cntl &= ( ~D_TIMER_CLK_EN); + + cntl |= ( En << 5 ); + + * (volatile SYS_UWORD16 *) D_TIMER_CNTL = cntl; +} + + + +/*--------------------------------------------------------------*/ +/* Dtimer2_Start() */ +/*--------------------------------------------------------------*/ +/* Parameters : on/off */ +/* Return : none */ +/* Functionality : Start or stop the timer */ +/*--------------------------------------------------------------*/ + +void Dtimer2_Start (SYS_UWORD16 startStop) +{ + (startStop == D_TIMER_ST) ? + ((* (SYS_UWORD16 *) D_TIMER_CNTL) |= D_TIMER_ST) : /* condition vrai */ + ((* (SYS_UWORD16 *) D_TIMER_CNTL) &= ~D_TIMER_ST); /* condition fausse */ +} + +/*--------------------------------------------------------------*/ +/* Dtimer2_ReadValue() */ +/*--------------------------------------------------------------*/ +/* Parameters : on/off */ +/* Return : none */ +/* Functionality : Read timer value */ +/*--------------------------------------------------------------*/ + +SYS_UWORD16 Dtimer2_ReadValue (void) +{ + return(* (SYS_UWORD16 *) D_TIMER_READ); +} + +/*--------------------------------------------------------------*/ +/* Parameters : on/off */ +/* Return : none */ +/* Functionality : Write timer value */ +/*--------------------------------------------------------------*/ + +void Dtimer2_WriteValue (SYS_UWORD16 value) +{ + (* (SYS_UWORD16 *) D_TIMER_LOAD) = value; +}
--- a/nuc-fw/sysglue/Makefile Sun Oct 20 21:12:41 2013 +0000 +++ b/nuc-fw/sysglue/Makefile Thu Oct 24 02:47:14 2013 +0000 @@ -1,7 +1,7 @@ CC= arm-elf-gcc ASFLAGS=-mthumb-interwork -OBJS= sysinit.o +OBJS= irqfiq.o sysinit.o all: ${OBJS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/sysglue/irqfiq.S Thu Oct 24 02:47:14 2013 +0000 @@ -0,0 +1,73 @@ +/* + * This module contains the assembly shells for IRQ and FIQ, separated + * from the architectured vectors only by some simple unconditional + * branch instructions. + * + * Note that TI's way of handling interrupts sacrifices Nucleus' ability + * to nest interrupts and minimize the IRQ-disabled window: if my (Falcon's) + * understanding is correct, TI's code leaves all further IRQs disabled + * for the full execution duration of an IRQ handler. (IRQ handlers are + * really LISRs, but TI's GSM fw does not use Nucleus' LISR framework.) + */ + + .section iram.text,"ax",%progbits + .code 32 + + .globl _INT_IRQ +_INT_IRQ: + STMDB sp!,{a1-a4} @ Save a1-a4 on temporary IRQ stack + +/* + * Thanks to TI for discovering and documenting this apparent ARM7TDMI bug: + +BUG correction 1st part ------------------- +It looks like there is an issue with ARM7 IRQ masking in the CPSR register +which leads to crashes in Nucleus+ scheduler. +Basically the code below (correct as LOCKOUT = 0xC0) is used in many places by N+ but do not +prevent from having an interrupt after the execution of the third line (I mean execution, not +fetch). + MRS a1,CPSR ; Pickup current CPSR + ORR a1,a1,#LOCKOUT ; Build interrupt lockout value + MSR CPSR,a1 ; Lockout interrupts + * IRQ INTERRUPT ! * + Next instructions... + +SW workaround: +When a task is interrupted at this point an interrupted context is stored on its task and will +be resumed later on at the next instruction but to make a long story short it leads to some +problem as the OS does not expect to be interrupted there. +Further testing tends to show that the CPSR *seems* to be loaded with the proper masking value +but that the IRQ is still triggered (has been hardwarewise requested during the instruction +exectution by the ARM7 core?) +*/ + + MRS a1,spsr @ check for the IRQ bug: + TST a1,#0x80 @ if the I - flag is set, + BNE IRQBUG @ then postpone execution of this IRQ +/* Bug correction 1st part end --------------- */ + + SUB a4,lr,#4 @ Save IRQ's lr (return address) + BL TCT_Interrupt_Context_Save @ Call context save routine + + BL IQ_IRQ_isr @ Call int. service routine + + /* IRQ interrupt processing is complete. Restore context- Never + returns! */ + B TCT_Interrupt_Context_Restore + +/* BUG correction 2nd part ------------------ */ +IRQBUG: LDMFD sp!,{a1-a4} @ return from interrupt + SUBS pc,r14,#4 +/* BUG correction 2nd part end -------------- */ + + .globl _INT_FIQ +_INT_FIQ: + STMDB sp!,{a1-a4} @ Save a1-a4 on temporary FIQ stack + SUB a4,lr,#4 @ Save FIQ's lr (return address) + BL TCT_Interrupt_Context_Save @ Call context save routine + + BL IQ_FIQ_isr @ Call the FIQ ISR + + /* FIQ interrupt processing is complete. Restore context- Never + returns! */ + B TCT_Interrupt_Context_Restore