📄 lh7a400_int_driver.c
字号:
/**********************************************************************
* $Workfile: LH7A400_int_driver.c $
* $Revision: 1.13 $
* $Author: BarnettH $
* $Date: Jun 19 2002 18:06:52 $
*
* Project: LH7A400
*
* Description:
* This file contains driver support for the LH7A400
* interrupt driver. This module contains the following
* user functions:
* int_init_irq_handler()--init basic interrupt driver irq handling
* int_init_fiq_handler()--init basic interrupt driver fiq handling
* int_install_irq_handler()--install a handler with a priority
* for a particular IRQ source
* int_install_fiq_handler()--install a handler with a priority
* for a particular FIQ source
* int_remove_irq_handler()--remove the handler for a given priority
* and unhook the IRQ source for that priority
* int_remove_fiq_handler()--remove the handler for a given priority
* and unhook the FIQ source for that priority
* int_enable_interrupt()--enable an interrupt source
* int_disable_interrupt()--disable an interrupt source
* int_enabled()--return true if a source is enabled
* int_pending()--return true if a source is pending
* int_priority()--return the priority assigned to the source
* int_handler()--return a pointer to the hander for the source
*
* The interrupt controller in the LH7A400 divides interrupt
* sources into two categories: IRQ and FIQ. Beyond that
* the interrupt controller does not prioritize interrupt
* sources. It also does not provide a facility for vectoring
* interrupts. This driver provides prioritization and
* vectoring for all interrupt sources with minimum latency.
* To do this, a function called an IRQ dispatcher is
* installed at the IRQ exception vector, and an FIQ
* dispatcher is installed at the FIQ exception vector.
*
* The user should assign a priority to each IRQ interrupt
* source and each FIQ interrupt source. A priority is a
* number from 0 (the highest priority) to the number of
* sources in the category (FIQ or IRQ) minus 1. Therefore,
* for IRQ sources, priorties are 0 (highest priority) to 23
* (lowest priority). For FIQ sources, priorities are 0
* (highest priority) to 3 (lowest priority).
*
* Priorities resolve the simultaneous interrupt conflict. If
* many interrupt sources are simultaneously active, then the
* dispatcher will service the source with the highest
* priority first.
*
* Each source also has a handler function associated with it.
* The handler is a function that takes no arguments and
* returns nothing. It is the responsibility of the handler to
* clear the interrupt source or else the interrupt handler
* will be called in an infinite loop.
*
* The dispatcher calls the handler for each active interrupt
* until all sources are cleared.
*
* For maximum system performance, the FIQ handler functions
* should be coded in assembly language. If they are coded
* in C, care should be taken to preseve registers r0-r7
* if the C program modifies them.
*
* See priority_driver.c for a description of how this collection
* of modules works.
*
* Original Author: KovitzP
*
* References:
* Internal documentation
*
* Dependencies:
* This module uses the functionality contained in
* priority_driver.c to implement the priority encoding scheme.
* The default IRQ dispatcher function uses a macro in
* priority_driver.h to make the handler.
*
* This module requires LH7A400_int_vec.s. It contains the FIQ
* dispatcher and assembly language branch instruction that get
* installed at the FIQ and IRQ exception vector locations.
*
* The int_install_fiq_dispatcher() and int_install_irq_dispatcher()
* functions require the two words in volatile memory that
* immediately follow the FIQ exception vector location. If either
* of these 2 locations get modified after a call to either of
* these functions, IRQ and FIQ exception processing will be
* unreliable.
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/CHIPS/archives/LH7A400/Interrupts/Drivers/LH7A400_int_driver.c-arc $
*
* Rev 1.13 Jun 19 2002 18:06:52 BarnettH
* Changed register names to agree with LH7A400_intc.h
*
* Rev 1.12 Jun 13 2002 11:17:24 MaysR
* Fixed error in unhandled IRQ handler.
* Changed all functions back to accept UNS_32 parameters,
* and added range checking within each function.
*
* Rev 1.11 Jun 05 2002 19:54:46 MaysR
* Corrected all function parameters to accept proper sized arguments
* to be compatible with priority driver.
* Added two new functions for getting next available IRQ & FIQ.
*
* Rev 1.10 10 Apr 2002 16:48:22 suryang
* Uses new SMA_priority_driver.
*
* Rev 1.9 10 Apr 2002 16:07:34 suryang
* Changed register names to lowercase.
*
* Rev 1.8 09 Apr 2002 11:51:06 suryang
* Added initialized flag.
*
* Rev 1.7 Jan 07 2002 11:11:52 KovitzP
* Integrated with LH7A400_cp15_driver
*
* Rev 1.6 Jan 04 2002 16:43:18 KovitzP
* Added hooks to allow for installation of an external IRQ handler.
*
* Rev 1.5 Jan 03 2002 16:13:58 KovitzP
* Integrated with priority_driver.c functions
*
* Rev 1.4 Nov 20 2001 07:57:28 KovitzP
* Updated comments. Made interrupt dispatcher handle exactly
* one interrupt at a time. Added null pointer checking for handler
* install functions.
*
* Rev 1.3 Nov 16 2001 18:13:56 KovitzP
* Corrected bugs that were causing FIQ priority_encode and function
* vectors to be stored in the wrong places
*
* Rev 1.2 Nov 16 2001 16:33:26 KovitzP
* Corrected bug in int_install_fiq_dispatcher() that was causing the
* dispatcher to be installed in the wrong place.
*
* Rev 1.1 Nov 15 2001 17:29:16 KovitzP
* Added FIQ support. Changed default handler operation to properly
* handle uninstalled interrupts. Added functions to uninstall
* interrupts. Will not work with cache enabled; install handler
* routines do not drain D cache or invalidate I-cache.
*
* Rev 1.0a Nov 13 2001 17:43:14 SuryanG
* Created new archive with new name. Updated with comments and added
* a few new function definitions.
*
* Rev 1.0 Nov 12 2001 12:43:44 SuryanG
* Initial revision.
*
* COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
* CAMAS, WA
*********************************************************************/
#include "LH7A400_int_driver.h"
#include "LH7A400_cp15_driver.h"
#include "SMA_priority_driver.h"
static UNS_32 initialized = 0; /* should be initialized to zero */
static UNS_32 irq_status;
static INT_8 irq_priority_encode0[INTC_N_COMBINATIONS];
static INT_8 irq_priority_encode1[INTC_N_COMBINATIONS];
static INT_8 irq_priority_encode2[INTC_N_COMBINATIONS];
static INT_8 irq_priorities[INTC_N_IRQ_HANDLERS + 1]; /* extra element
for sentinel
search */
static void (* irq_handlers[INTC_N_IRQ_HANDLERS + 1])(void);
static PRIORITY_DATA irq_data =
{
INTC_N_IRQ_HANDLERS,
irq_priorities,
irq_priority_encode0,
irq_priority_encode1,
irq_priority_encode2,
0,
irq_handlers
};
extern volatile UNS_32 irq_dispatcher_addr, irq_vec;
extern volatile UNS_32 fiq_dispatcher_addr, fiq_vec;
extern volatile UNS_32 LH7A400_FIQ_dispatcher;
extern volatile UNS_32 LH7A400_FIQ_disp_end;
/*
note: fiq_handlers_0 and fiq_priority_encode_0
are global so that the FIQ dispatcher can be coded
in an assembly language module
*/
static INT_8 fiq_priorities[INTC_N_FIQ_HANDLERS + 1]; /* extra element
for sentinel
search */
typedef void (* * vfpp)(void);
typedef void (* vfp)(void);
extern volatile UNS_32 (* * fiq_handlers_0)(void);
extern volatile UNS_32 fiq_priority_encode_0;
extern volatile UNS_32 LH7A400_unhandled_fiq_handler;
static PRIORITY_DATA fiq_data;
/**********************************************************************
*
* Function: LH7A400_unhandled_handler
*
* Purpose:
* This function is called when the interrupt
* controller signals an interrupt for an unhandled source.
*
* Processing:
* Disable the source that triggered the unhandled interrupt
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
static void LH7A400_unhandled_handler(void)
{
INTC->enableclear = irq_status & ~_BITMASK(INTC_N_FIQ_HANDLERS);
}
/**********************************************************************
*
* Function: LH7A400_IRQ_dispatcher
*
* Purpose:
* This function calls the handler previously installed using
* int_install_irq_handler. It preserves status.
*
* Processing:
* Preserve the machine state if it was built with INTC_IRQ defined.
* Read the interrupt status. Isolate the interrupt status register
* IRQ status bits. Divide the interrupt status bits into three
* bytes. Each byte is an index into an array of priorities.
* The highest of the three priorites is used as an index into
* an array of pointers handler functions. Call the indexed function.
* Restore the machine state if it was built with INTC_IRQ defined.
* If the highest priority was ILLEGAL_PRIORITY, disable the source
* that caused the interrupt (because there is not handler installed
* to handle the interrupt).
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
* INTC_IRQ must be defined if it is desired to use this default
* interrupt dispatcher as the IRQ vector handler. The ARM Compiler
* handle the saving and restoring of context when an interrupt
* occurs. Most operating systems require a more detailed context
* save and restore than the default provided by the ARM compiler.
* It is recommended that the appropriate OS-specific manuals be
* consulted to determine whether this should be defined or not.
*
**********************************************************************/
#if defined(INTC_IRQ)
__irq
#endif
void LH7A400_IRQ_dispatcher(void)
MAKE_DISPATCHER24(((irq_status = INTC->status) >> INTC_N_FIQ_HANDLERS),
irq_handlers,
irq_priority_encode)
/**********************************************************************
*
* Function: int_install_irq_dispatcher
*
* Purpose:
* write to the exception vector locations so that an IRQ interrupt
* will call LH7A400_IRQ_dispatcher() no matter where the linker
* has decided to locate LH7A400_IRQ_dispatcher().
*
* Processing:
* int_install_irq_dispatcher() writes an assembly language
* instruction at memory word 0x18 that causes a branch to the
* 32-bit address stored at address 0x14.
*
* The entry at location 0x14 in the ARM processor is "reserved"
* and usually populated with a NOP instruction. Here, we make
* use of this location to store the address of the IRQ handler
* (in our case, irq_dispatcher). The next location, 0x18, is
* the address that the ARM processor jumps to when it encounters
* an IRQ interrupt. Here, we place an instruction loading the
* program counter with the address in location 0x14, which
* happens to be the IRQ handler address.
*
* The reason 0x14 is required is that the instruction that causes
* the branch, LDR pc,branch_address, will only work if
* branch_address is within 4095 of the current pc address. Using
* 0x14 makes sure that the address is in range independent of the
* linker.
*
* The simple branch instruction, B <addr> won't work here either
* if the memory space is large than 32 Meg and the handler happens to
* be located more than 32 Meg away from the exception vector address.
*
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
* This function requires that the words at memory
* locations 0x18 (the IRQ exception vector location) and 0x14
* (the reserved exception vector word) are in volatile memory.
*
* This cannot be used with the 26-bit architecture versions
* of ARM, where this vector was used for address exceptions; Caveat
* code porters.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -