sa1100IntrCtl.c
资源名称:ixp425BSP.rar [点击查看]
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:14k
源码类别:
VxWorks
开发平台:
C/C++
- /* sa1100IntrCtl.c - Digital Semiconductor SA-1100 interrupt controller driver */
- /* Copyright 1984-1998, Wind River Systems, Inc. */
- /*
- modification history
- --------------------
- 01b,21sep98,cdp fixed intEnable/Disable(0) (TSR#115062);
- corrected range check in sa1100IntLvlEnable/Disable.
- 01a,09dec97,cdp created from 01e of ambaIntrCtl.c.
- */
- /*
- This module implements the Digital Semiconductor SA-1100 interrupt controller
- driver.
- The SA-1100 interrupt controller is a simple interrupt controller
- described in full in the Digital StrongARM SA-1100 Data Sheet. The
- interrupt controller has request registers, a mask register, a level
- register and supports level and edge-triggered interrupts. This
- library provides the routines to manage interrupts multiplexed by the
- SA-1100 interrupt controller.
- The SA-1100 interrupt controller has a number of registers. Those used by
- this driver are described below under the symbolic names used herein.
- SA1100_INT_CSR_ICMR (read/write): this is the "Interrupt Controller Mask
- Register" (ICMR) described in the SA-1100 Data Sheet. When this register is
- written, each data bit that is set (1) causes the corresponding
- interrupt to be enabled; each data bit that is clear (0) causes the
- corresponding interrupt to be disabled. When this register is read, each data
- bit that is set (1) indicates an interrupt source that is enabled.
- SA1100_INT_CSR_ICIP (read): this is the "Interrupt Controller IRQ
- Pending Register" (ICIP) described in the SA-1100 Data Sheet. When
- this register is read, each data bit that is set (1) indicates an
- interrupt source that is both active and enabled (not masked) i.e. can
- interrupt the processor. This driver provides a means by which bits in
- this register can be permanently masked e.g. if the particular
- implementation of SA-1100 returns bits in an undefined state. Setting
- SA1100_INT_ICIP_MASK to be a bitwise OR of all the valid bits
- achieves the required effect. The driver also provides a simple
- optimisation in the interrupt checking routine sa1100IntLvlVecChk(): if
- SA1100_INT_ICIP_FIRST_BIT is set to the lowest numbered bit of the
- interrupt controller that is used by the BSP, lower-numbered bits than
- this will not be checked. The driver uses an external array
- sa1100IntLvlMask[] to determine what should be written to
- SA1100_INT_CSR_ICMR to change interrupt levels. This should be defined
- by the BSP such that sa1100IntLvlMask[n] has a bit set (1) for each
- interrupt source that should be enabled for interrupt level <n>. For
- example, sa1100IntLvlMask[0] should be 0 so that all interrupts are
- disabled when interrupt level 0 is selected.
- SA1100_INT_CSR_ICLR (read/write): this is the "Interrupt Controller
- Level Register" (ICLR) described in the SA-1100 Data Sheet. When this
- register is written, each data bit that is set (1) directs the
- interrupt associated with that bit position to the processor's FIQ
- input; Each data bit that is clear (0) directs the interrupt associated
- with that bit position to the processor's IRQ input. When this
- register is read, each data bit that is set (1) indicates that the
- interrupt associated with that bit position is directed to the
- processor's FIQ input; each data bit that is clear (0) indicates that
- the interrupt associated with that bit position is directed to the
- processor's IRQ input.
- SA1100_INT_CSR_ICCR (read/write): this is the "Interrupt Controller
- Control Register" (ICCR) described in the SA-1100 Data Sheet. When
- this register is written, if data bit zero is set (1), the contents of
- the ICMR control which interrupts can bring the SA-1100 out of idle
- mode; if data bit zero is clear (0), any interrupt can bring the
- SA-1100 out of idle mode, even if it is masked in the ICMR.
- The number of interrupts supported by the device i.e. the number of
- bits in the SA1100_INT_CSR_ICIP register, is specified by
- SA1100_INT_NUM_LEVELS.
- We assume that config.h or <bsp>.h has defined the addresses of the
- controller chips registers: SA1100_INT_CSR_ICMR, SA1100_INT_CSR_ICIP,
- SA1100_INT_CSR_ICLR, SA1100_INT_CSR_ICCR and also the driver
- constants SA1100_INT_ICIP_MASK, SA1100_INT_NUM_LEVELS.
- This driver assumes that the chip is memory-mapped and does direct
- memory accesses to the registers which are assumed to be 32 bits wide.
- If a different access method is needed, the BSP can redefine the macros
- SA1100_INT_REG_READ(addr,result) and SA1100_INT_REG_WRITE(addr,data).
- This driver assumes that interrupt vector numbers are calculated and
- not the result of a special cycle on the bus. Vector numbers are
- generated by adding the current interrupt level number to
- SA1100_INT_VEC_BASE to generate a vector number which the architecture
- level will use to invoke the proper handling routine. If a different
- mapping scheme, or a special hardware routine is needed, then the BSP
- should redefine the macro SA1100_INT_LVL_VEC_MAP(level,vector) to
- override the version defined in this file.
- The order of interrupt level priority is undefined at the architecture
- level. In this driver, level 0 is highest and and indicates that all
- levels are disabled; level <SA1100_INT_NUM_LEVELS> is the lowest and
- indicates that all levels are enabled.
- This driver was designed to support a single instance of a real
- device. At some point it should be upgraded to operate on an object
- model and to support any number of real devices.
- The BSP will initialize this driver in sysHwInit2(), after initializing
- the main interrupt library, usually intLibInit(). The initialization
- routine, sa1100IntDevInit() will setup the interrupt controller device,
- it will mask off all individual interrupt sources and then set the
- interrupt level to enable all interrupts. See sa1100IntDevInit for more
- information.
- All of the functions in this library are global. This allows them to
- be used by the BSP if it is necessary to create wrapper routines or to
- incorporate several drivers together as one.
- */
- #include "vxWorks.h"
- #include "config.h"
- #include "intLib.h"
- /* Defines from config.h, or <bsp>.h */
- #if !defined(SA1100_INT_CSR_ICMR) || !defined(SA1100_INT_CSR_ICIP) ||
- !defined(SA1100_INT_CSR_ICLR) || !defined(SA1100_INT_CSR_ICCR) ||
- !defined(SA1100_INT_ICIP_MASK) || !defined(SA1100_INT_NUM_LEVELS)
- # error missing SA-1100 interrupt definitions
- #endif
- #ifndef SA1100_INT_ICIP_FIRST_BIT
- #define SA1100_INT_ICIP_FIRST_BIT 0
- #endif
- #define SA1100_INT_VEC_BASE (0x0)
- /* hardware access methods */
- #ifndef SA1100_INT_REG_READ
- #define SA1100_INT_REG_READ(reg,result)
- ((result) = *(volatile UINT32 *)(reg))
- #endif /* SA1100_INT_REG_READ */
- #ifndef SA1100_INT_REG_WRITE
- #define SA1100_INT_REG_WRITE(reg,data)
- (*((volatile UINT32 *)(reg)) = (data))
- #endif /* SA1100_INT_REG_WRITE */
- /* Convert level number to vector number */
- #ifndef SA1100_INT_LVL_VEC_MAP
- #define SA1100_INT_LVL_VEC_MAP(level, vector)
- ((vector) = ((level) + SA1100_INT_VEC_BASE))
- #endif /* SA1100_INT_LVL_VEC_MAP */
- /* Convert pending register value, to a level number */
- #ifndef SA1100_INT_PEND_LVL_MAP
- #define SA1100_INT_PEND_LVL_MAP(pendReg, level)
- ((level) = (pendReg))
- #endif /* SA1100_INT_PEND_LVL_MAP */
- /* driver constants */
- #define SA1100_INT_ALL_ENABLED (SA1100_INT_NUM_LEVELS)
- #define SA1100_INT_ALL_DISABLED 0
- /* Local data */
- /* Current interrupt level setting (sa1100IntLvlChg). */
- LOCAL UINT32 sa1100IntLvlCurrent = SA1100_INT_ALL_DISABLED; /* all 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 sa1100IntLvlEnabled;
- /* forward declarations */
- STATUS sa1100IntLvlVecChk (int*, int*);
- STATUS sa1100IntLvlVecAck (int, int);
- int sa1100IntLvlChg (int);
- STATUS sa1100IntLvlEnable (int);
- STATUS sa1100IntLvlDisable (int);
- /*******************************************************************************
- *
- * sa1100IntDevInit - 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 arhitecture level
- * routines, it should install the pointer to the wrapper routine after
- * calling this routine. On the SA-1100, this configures the chip so
- * that only unmasked interrupts can bring the CPU out of Idle Mode but
- * does not write the ICLR to configure whether interrupt sources cause
- * IRQ or FIQ because that is done in sysALib.s.
- *
- * RETURNS: N/A
- */
- void sa1100IntDevInit (void)
- {
- /* install the driver routines in the architecture hooks */
- sysIntLvlVecChkRtn = sa1100IntLvlVecChk;
- sysIntLvlVecAckRtn = sa1100IntLvlVecAck;
- sysIntLvlChgRtn = sa1100IntLvlChg;
- sysIntLvlEnableRtn = sa1100IntLvlEnable;
- sysIntLvlDisableRtn = sa1100IntLvlDisable;
- /* set DIM so that only unmasked interrupts can cause Idle Mode exit */
- SA1100_INT_REG_WRITE (SA1100_INT_CSR_ICCR, 1);
- sa1100IntLvlEnabled = 0; /* all sources disabled */
- sa1100IntLvlChg (SA1100_INT_ALL_ENABLED); /* enable all levels */
- }
- /*******************************************************************************
- *
- * sa1100IntLvlVecChk - check for and return any pending interrupts
- *
- * This routine interrogates the hardware to determine the highest priority
- * interrupt pending. It returns the vector associated with that interrupt, and
- * also the interrupt priority level prior to the interrupt (not the
- * level of the interrupt). The current interrupt priority level is then
- * raised to the level of the current interrupt so that only higher priority
- * interrupts will be accepted until this interrupt is finished.
- *
- * The return value ERROR indicates that no pending interrupt was found and
- * that the level and vector values were not returned.
- *
- * RETURNS: OK or ERROR if no interrupt is pending.
- */
- STATUS sa1100IntLvlVecChk
- (
- int* pLevel, /* ptr to receive old interrupt level */
- int* pVector /* ptr to receive current interrupt vector */
- )
- {
- int newLevel;
- UINT32 isr;
- /* Read pending interrupt register and mask undefined bits */
- SA1100_INT_REG_READ (SA1100_INT_CSR_ICIP, isr);
- isr &= SA1100_INT_ICIP_MASK;
- /* If no interrupt is pending, return ERROR */
- if (isr == 0)
- return ERROR;
- newLevel = SA1100_INT_ICIP_FIRST_BIT; /* don't check unused low bits */
- /*
- * Step through the bits looking for a 1. This *will* terminate.
- * We could use ffsLsb() for this if we don't mind the function call
- * overhead
- */
- for ( ; (isr & (1 << newLevel)) == 0; ++newLevel)
- /* do nothing */ ;
- /* map the interrupting device to an interrupt level number */
- SA1100_INT_PEND_LVL_MAP (newLevel, newLevel);
- /* change to new interrupt level, returning previous level to caller */
- *pLevel = sa1100IntLvlChg (newLevel);
- /* fetch, or compute the interrupt vector number */
- SA1100_INT_LVL_VEC_MAP (newLevel, *pVector);
- return OK;
- }
- /*******************************************************************************
- *
- * sa1100IntLvlVecAck - acknowledge the current interrupt
- *
- * Acknowledge the current interrupt cycle. The level and vector values are
- * those generated during the sa1100IntLvlVecChk() routine for this interrupt
- * cycle. The basic action is to reset the current interrupt and return
- * the interrupt level to its previous setting. Note that the SA_1100 interrupt
- * controller does not need an acknowledge cycle.
- *
- * RETURNS: OK or ERROR if a hardware fault is detected.
- * ARGSUSED
- */
- STATUS sa1100IntLvlVecAck
- (
- int level, /* old interrupt level to be restored */
- int vector /* current interrupt vector, if needed */
- )
- {
- /* restore the previous interrupt level */
- sa1100IntLvlChg (level);
- return OK;
- }
- /*******************************************************************************
- *
- * sa1100IntLvlChg - change the interrupt level value
- *
- * This routine implements the overall interrupt setting. All levels
- * up to and including the specifed level are disabled. All levels above
- * the specified level will be enabled, but only if they were specifically
- * enabled by the sa1100IntLvlEnable() routine.
- *
- * The specific priority level SA1100_INT_NUM_LEVELS is valid and represents
- * all levels enabled.
- *
- * RETURNS: Previous interrupt level.
- */
- int sa1100IntLvlChg
- (
- int level /* new interrupt level */
- )
- {
- int oldLevel;
- oldLevel = sa1100IntLvlCurrent;
- if (level >= 0 &&
- level <= SA1100_INT_NUM_LEVELS)
- {
- /* change current interrupt level */
- sa1100IntLvlCurrent = level;
- }
- /* Activate the enabled interrupts */
- SA1100_INT_REG_WRITE (SA1100_INT_CSR_ICMR,
- (sa1100IntLvlMask[sa1100IntLvlCurrent] & sa1100IntLvlEnabled));
- return oldLevel;
- }
- /*******************************************************************************
- *
- * sa1100IntLvlEnable - enable a single interrupt level
- *
- * Enable a specific interrupt level. The enabled level will be allowed to
- * generate an interrupt, when the overall interrupt level is set below the
- * specified level. Without being enabled, the interrupt is blocked regardless
- * of the overall interrupt level setting.
- *
- * RETURNS: OK or ERROR if the specified level cannot be enabled.
- */
- STATUS sa1100IntLvlEnable
- (
- int level /* level to be enabled */
- )
- {
- int key;
- if (level < 0 ||
- level >= SA1100_INT_NUM_LEVELS)
- return ERROR;
- /* set bit in enable mask */
- key = intLock ();
- sa1100IntLvlEnabled |= (1 << level);
- intUnlock (key);
- sa1100IntLvlChg (-1); /* reset current mask */
- return OK;
- }
- /*******************************************************************************
- *
- * sa1100IntLvlDisable - disable a single interrupt level
- *
- * Disable a specific interrupt level. The disabled level is prevented
- * from generating an interrupt even if the overall interrupt level is set
- * below the specified level.
- *
- * RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
- */
- STATUS sa1100IntLvlDisable
- (
- int level /* level to be disabled */
- )
- {
- int key;
- if (level < 0 ||
- level >= SA1100_INT_NUM_LEVELS)
- return ERROR;
- /* clear bit in enable mask */
- key = intLock ();
- sa1100IntLvlEnabled &= ~(1 << level);
- intUnlock (key);
- sa1100IntLvlChg (-1); /* reset current mask */
- return OK;
- }