📄 at91intrctl.c
字号:
/* at91IntrCtl.c - AT91 interrupt controller driver */
/* Copyright 1999 ARM Limited */
/*
modification history
--------------------
01b,27aug99,jpd add use of Protect Mode and Spurious Vector; doc'n updated.
01a,29jun99,jpd created.
*/
#include "vxWorks.h"
#include "config.h"
#include "intLib.h"
IMPORT int ffsLsb (UINT32);
/* Defines from config.h, or <bsp>.h */
#if !defined (AT91_INT_CSR_PEND) || !defined (AT91_INT_CSR_ENB) || \
!defined (AT91_INT_NUM_LEVELS) || !defined (AT91_INT_CSR_DIS)
# error missing AT91 interrupt definitions
#endif
#define AT91_INT_VEC_BASE (0x0)
/* hardware access methods */
#ifndef AT91_INT_REG_READ
#define AT91_INT_REG_READ(reg,result) \
((result) = *(volatile UINT32 *)(reg))
#endif /*AT91_INT_REG_READ*/
#ifndef AT91_INT_REG_WRITE
#define AT91_INT_REG_WRITE(reg,data) \
(*((volatile UINT32 *)(reg)) = (data))
#endif /*AT91_INT_REG_WRITE*/
/* Convert level number to vector number */
#ifndef AT91_INT_LVL_VEC_MAP
#define AT91_INT_LVL_VEC_MAP(level, vector) \
((vector) = ((level) + AT91_INT_VEC_BASE))
#endif /* AT91_INT_LVL_VEC_MAP */
#ifndef AT91_INT_SOFT_PRIORITY_MAP
/* Convert pending register value, to a level number */
#ifndef AT91_INT_PEND_LVL_MAP
#define AT91_INT_PEND_LVL_MAP(pendReg, level) \
((level) = (pendReg))
#endif /* AT91_INT_PEND_LVL_MAP */
#endif /* AT91_INT_SOFT_PRIORITY_MAP */
/* driver constants */
#define AT91_INT_ALL_ENABLED (AT91_INT_NUM_LEVELS)
#define AT91_INT_ALL_DISABLED 0
/* Local data */
/* Current interrupt level setting (at91IntLvlChg). */
LOCAL UINT32 at91IntLvlCurrent = AT91_INT_ALL_DISABLED; /* all levels disabled*/
/*
* A mask word. Bits are set in this word when a specific level
* is enabled. It is used to mask off individual levels that have
* not been explicitly enabled.
*/
LOCAL UINT32 at91IntLvlEnabled;
#ifdef AT91_INT_SOFT_PRIORITY_MAP
/*
* Controller masks: for each interrupt level, this provides a mask for
* the controller (see IntLvlChg).
* Mask is 32 bits * (levels + 1)
*/
LOCAL UINT32 at91IntLvlMask[(1 + AT91_INT_NUM_LEVELS) * sizeof(UINT32)];
/*
* Map of interrupt bit number to level: if bit n is set, at91IntLvlMap[n]
* is the interrupt level to change to such that interrupt n and all lower
* priority ones are disabled.
*/
LOCAL int at91IntLvlMap[AT91_INT_NUM_LEVELS * sizeof(int)];
#endif /* AT91_INT_SOFT_PRIORITY_MAP */
/* forward declarations */
STATUS at91IntLvlVecChk (int*, int*);
STATUS at91IntLvlVecAck (int, int);
int at91IntLvlChg (int);
STATUS at91IntLvlEnable (int);
STATUS at91IntLvlDisable (int);
/*******************************************************************************
*
* at91IntDevInit - initialize the interrupt controller
*
* This routine will initialize the interrupt controller device, disabling
* all interrupt sources. It will also connect the device driver specific
* routines into the architecture level hooks. If the BSP needs to create
* a wrapper routine around any of the architecture level routines, it
* should install the pointer to the wrapper routine after calling this
* routine.
*
* By default, the driver is compiled to implement a software-
* controlled, BSP-configurable interrupt priority scheme by #defining
* AT91_INT_SOFT_PRIORITY_MAP. The order of interrupt level priority is
* undefined at the architecture level: when using software priorities in
* this driver, level 0 is highest and and indicates that all levels are
* disabled; level AT91_INT_NUM_LEVELS is the lowest and indicates that
* all levels are enabled.
*
* Alternatively, if required, this driver can be configured to
* implement a least-significant bit first interrupt priority scheme by
* undefining the symbol AT91_INT_SOFT_PRIORITY_MAP (this is then
* compatible with earlier versions of the AMBA interrupt driver). The
* driver then requires a definition of at91IntLvlMask[].
*
* If compiled to implement software configurable interrupt
* priorities, the hardware priority scheme is currently unused by this
* driver. For this model, before this routine is called, the BSP
* should define an array of int called at91IntLvlPriMap[], each element of
* which is a bit number to be polled. The list should be terminated with
* an entry containing -1. This list is used in the interrupt handler to
* check bits in the requested order and is also used to generate a map of
* interrupt source to new interrupt level such that whilst servicing an
* interrupt, all interrupts defined by the BSP to be of lower priority
* than that interrupt are disabled. Interrupt sources not in the list
* are serviced after all others in least-significant bit first priority.
*
* Note that in this priority system, intLevelSet(n) does not necessarily
* disable interrupt bit n and all lower-priority ones but uses
* at91IntLvlPriMap to determine which interrupts should be masked e.g.
* if at91IntLvlPriMap[] contains { 9, 4, 8, 5, -1 }, intLevelSet(0)
* disables all interrupt bits; intLevelSet(1) enables interrupt bit 9 but
* disables interrupts 4, 8, 5 and all others not listed; intLevelSet(3)
* enables interrupt bits 9, 4 and 8 but disables all others. This
* enabling of interrupts only occurs if the interrupt has been explicitly
* enabled via a call to at91IntLvlEnable().
*
* If the list is empty (contains just a terminator) or at91IntLvlPriMap
* is declared as an int pointer of value 0 (this is more efficient),
* interrupts are handled as least-significant bit is highest priority.
*
* If the symbol AT91_INT_USE_PROTECT_MODE is defined, then the Protect
* mode feature of the AT91 is used: the appropriate bit is set in the
* Special Functions register, and the Interrupt Vector register is
* written to when appropriate, allowing the Interrupt Vector register to
* be read by a debugger.
*
* The Spurious Vector feature is utilised by this driver and spurious
* interrupts will be detected, and reported to the architecture code
* calling this driver.
*
* The BSP will call this routine to initialize this driver in
* sysHwInit2(), after initializing the main interrupt library, usually
* intLibInit(). This routine sets up the interrupt controller device by
* masking off all individual interrupt sources and then setting the
* interrupt level to enable all interrupts.
*
* The return value ERROR indicates that the contents of
* at91IntLvlPriMap (if used) were invalid.
*
* INTERNAL
* The at91IntLvlPriMap list is a list of ints rather than bytes because
* it causes the current compiler to generate faster code.
*
* RETURNS: OK or ERROR if at91IntLvlPriMap invalid.
*/
int at91IntDevInit (void)
{
#ifdef AT91_INT_SOFT_PRIORITY_MAP
int i, j;
int level;
UINT32 bit;
/* if priorities are supplied, validate the supplied list */
if (at91IntLvlPriMap != 0)
{
/* first check the list is terminated (VecChk requires this) */
for (i = 0; i < AT91_INT_NUM_LEVELS; ++i)
if (at91IntLvlPriMap[i] == -1)
break;
if (!(i < AT91_INT_NUM_LEVELS))
return ERROR; /* no terminator */
/* now check that all are in range and that there are no duplicates */
for (i = 0; at91IntLvlPriMap[i] != -1; ++i)
if (at91IntLvlPriMap[i] < 0 ||
at91IntLvlPriMap[i] >= AT91_INT_NUM_LEVELS)
{
return ERROR; /* out of range */
}
else
for (j = i + 1; at91IntLvlPriMap[j] != -1; ++j)
if (at91IntLvlPriMap[j] == at91IntLvlPriMap[i])
{
return ERROR; /* duplicate */
}
}
/*
* Now initialise the mask array.
* For each level (in ascending order), the mask is the mask of the
* previous level with the bit for the current level set to enable it.
*/
at91IntLvlMask[0] = 0; /* mask for level 0 = all disabled */
/* do the levels for which priority has been specified */
level = 1;
if (at91IntLvlPriMap != 0)
{
for ( ; level <= AT91_INT_NUM_LEVELS &&
(i = at91IntLvlPriMap[level - 1], i >= 0); ++level)
{
/* copy previous level's mask to this one's */
at91IntLvlMask[level] = at91IntLvlMask[level - 1];
/* OR in the bit indicated by the next entry in PriMap[] */
at91IntLvlMask[level] |= 1 << i;
/*
* set index in level map: to disable this interrupt and all
* lower-priority ones, select the level one less than this
*/
at91IntLvlMap[i] = level - 1;
}
}
/* do the rest of the levels */
i = 0; /* lowest-numbered interrupt bit */
for ( ; level <= AT91_INT_NUM_LEVELS; ++level)
{
/* copy previous level's mask to this one's */
at91IntLvlMask[level] = at91IntLvlMask[level - 1];
/* try to find a bit that has not yet been set */
for ( ; ; ++i)
{
bit = 1 << i;
if ((at91IntLvlMask[level] & bit) == 0)
{
/* this bit not set so put it in the mask */
at91IntLvlMask[level] |= bit;
/*
* set index in level map: to disable this interrupt and all
* lower-priority ones, select the level one less than this
*/
at91IntLvlMap[i] = level - 1;
break;
}
}
}
#endif /* AT91_INT_SOFT_PRIORITY_MAP */
/* install the driver routines in the architecture hooks */
sysIntLvlVecChkRtn = at91IntLvlVecChk;
sysIntLvlVecAckRtn = at91IntLvlVecAck;
sysIntLvlChgRtn = at91IntLvlChg;
sysIntLvlEnableRtn = at91IntLvlEnable;
sysIntLvlDisableRtn = at91IntLvlDisable;
at91IntLvlEnabled = 0; /* all sources disabled */
/*
* Inititalise all source vector registers to zero, which is the
* same value as the value we will put into the spurious vector
* register. Reading zero back from the vector register will then
* indicate either a spurious interrupt, or an interrupt that was
* never configured.
*/
for (i = 0; i < AT91_INT_NUM_LEVELS; ++i)
AT91_INT_REG_WRITE ((AT91_INT_CSR_SVEC + (level * 4)), 0);
AT91_INT_REG_WRITE (AT91_INT_CSR_SPU, 0);
#ifdef AT91_INT_USE_PROTECT_MODE
/* Enable write access and enable protect mode in Special Function Reg */
AT91_INT_REG_WRITE (AT91_SF_PMR, AT91_PMR_KEY | AT91_PMR_AIC);
#endif /* AT91_INT_USE_PROTECT_MODE */
at91IntLvlChg (AT91_INT_ALL_ENABLED); /* enable all levels */
return OK;
}
/*******************************************************************************
*
* at91IntLvlConfigure - configure polarity and type of interrupt
*
* This routine configures the polarity and type (edge or level) or an
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -