📄 ambaintrctl.c
字号:
/* ambaIntrCtl.c - AMBA interrupt controller driver *//* Copyright 1984-1998, Wind River Systems, Inc. *//*modification history--------------------01i,03dec01,rec fix compiler warnings01h,21sep98,cdp fixed intEnable/Disable(0) (TSR#115062); corrected range check in ambaIntLvlEnable/Disable; made AMBA_INT_CSR_MASK optional; added configurable interrupt priorities.01f,10mar98,jpd layout tidying.01e,13nov97,cdp include intLib.h and remove things pulled in from it; make default I/O access 32 (not 16) bits wide; documentation.01d,15aug97,cdp rewritten for new interrupt structure (template 01d).01c,14may97,jpd added conditional use of valid interrupts mask.01b,18feb97,cdp renamed sysIntEnable/Disable and made global with result. Tidyup for mangen. intEnable/Disable now return int.01a,13dec96,cdp created from target/config/pid7t/intPid.c.*//*This module implements the AMBA interrupt controller driver.The AMBA interrupt controller is a simple, generic interrupt controllerdescribed in full in the ARM Reference Peripherals Specification. Theinterrupt controller has status and request registers, separate enableand disable registers and supports level-sensitive interrupts. Thislibrary provides the routines to manage interrupts multiplexed by theAMBA interrupt controller.The AMBA interrupt controller has a number of registers. Those used bythis driver are described below under the symbolic names used herein.AMBA_INT_CSR_ENB (write): this is the "Enable Set" register describedin the ARM Reference Peripherals Specification. When this register iswritten, each data bit that is set (1) causes the correspondinginterrupt to be enabled. Bits that are clear (0) have no effect.AMBA_INT_CSR_DIS (write): this is the "Enable Clear" register which hasthe opposite effect. When this register is written, each data bit thatis set (1) causes the corresponding interrupt to be disabled. Bitsthat are clear (0) have no effect.AMBA_INT_CSR_PEND (read): this is the "Interrupt Request" register.When this register is read, each data bit that is set (1) indicates aninterrupt source that is both active and enabled i.e. can interrupt theprocessor. This driver provides a means by which bits in this registercan be masked if the particular implementation of AMBA returns bits inan undefined state. Setting AMBA_INT_CSR_MASK to be a bitwise OR ofall the valid bits achieves the required effect. IfAMBA_INT_PRIORITY_MAP is not #defined (see below), the driver also usesan external array ambaIntLvlMask[] to determine what should be writtento AMBA_INT_CSR_ENB to change interrupt levels. This should be definedby the BSP such that ambaIntLvlMask[n] has a bit set (1) for eachinterrupt source that should be enabled for interrupt level <n>. Forexample, ambaIntLvlMask[0] should be 0 so that all interrupts aredisabled when interrupt level 0 is selected.The number of interrupts supported by the device i.e. the number ofbits in the AMBA_INT_CSR_PEND register, is specified byAMBA_INT_NUM_LEVELS.We assume that config.h or <bsp>.h has defined the addresses of thecontroller chips registers: AMBA_INT_CSR_ENB, AMBA_INT_CSR_DIS andAMBA_INT_CSR_PEND and also the driver constants AMBA_INT_CSR_MASK (ifrequired) and AMBA_INT_NUM_LEVELS.This driver assumes that the chip is memory-mapped and does directmemory accesses to the registers which are assumed to be 32 bits wide.If a different access method is needed, the BSP can redefine the macrosAMBA_INT_REG_READ(addr,result) and AMBA_INT_REG_WRITE(addr,data).This driver assumes that interrupt vector numbers are calculated andnot the result of a special cycle on the bus. Vector numbers aregenerated by adding the current interrupt level number toAMBA_INT_VEC_BASE to generate a vector number which the architecturelevel will use to invoke the proper handling routine. If a differentmapping scheme, or a special hardware routine is needed, then the BSPshould redefine the macro AMBA_INT_LVL_VEC_MAP(level,vector) tooverride the version defined in this file.This driver was designed to support a single instance of a realdevice. At some point it should be upgraded to operate on an objectmodel and to support any number of real devices.Priorities==========The order of interrupt level priority is undefined at the architecturelevel. In this driver, level 0 is highest and and indicates that alllevels are disabled; level <AMBA_INT_NUM_LEVELS> is the lowest andindicates that all levels are enabled.By default, this driver implements a least-significant bit firstinterrupt priority scheme (this is compatible with earlier versions ofthis driver) which requires a definition of ambaIntLvlMask (see above).If required, the driver can be compiled to implement a BSP-configurableinterrupt priority scheme by #defining AMBA_INT_PRIORITY_MAP. For thismodel, the BSP should define an array of int called ambaIntLvlPriMap,each element of which is a bit number to be polled. The list should beterminated with an entry containing -1. This list is used in theinterrupt handler to check bits in the requested order and is also usedto generate a map of interrupt source to new interrupt level such thatwhilst servicing an interrupt, all interrupts defined by the BSP to beof lower priority than that interrupt are disabled. Interrupt sourcesnot in the list are serviced after all others in least-significant bitfirst priority. (Note that the list is a list of ints rather thanbytes because it causes the current compiler to generate faster code.)Note that in this priority system, intLevelSet(n) does not necessarilydisable interrupt bit n and all lower-priority ones but usesambaIntLvlPriMap to determine which interrupts should be masked e.g.if ambaIntLvlPriMap[] contains { 9, 4, 8, 5, -1 }, intLevelSet(0)disables all interrupt bits; intLevelSet(1) enables interrupt bit 9 butdisables interrupts 4, 8, 5 and all others not listed; intLevelSet(3)enables interrupt bits 9, 4 and 8 but disables all others. Thisenabling of interrupts only occurs if the interrupt has been explicitlyenabled via a call to ambaIntLvlEnable().If the list is empty (contains just a terminator) or ambaIntLvlPriMapis declared as an int pointer of value 0 (this is more efficient),interrupts are handled as least-significant bit is highest priority.The BSP will initialize this driver in sysHwInit2(), after initializingthe main interrupt library, usually intLibInit(). The initializationroutine, ambaIntDevInit() will setup the interrupt controller device,it will mask off all individual interrupt sources and then set theinterrupt level to enable all interrupts. See ambaIntDevInit for moreinformation.All of the functions in this library are global. This allows them tobe used by the BSP if it is necessary to create wrapper routines or toincorporate several drivers together as one.*/#include "vxWorks.h"#include "config.h"#include "intLib.h"IMPORT int ffsLsb (UINT32);/* Defines from config.h, or <bsp>.h */#if !defined (AMBA_INT_CSR_PEND) || !defined (AMBA_INT_CSR_ENB) || \ !defined (AMBA_INT_NUM_LEVELS) || !defined (AMBA_INT_CSR_DIS)# error missing AMBA interrupt definitions#endif#define AMBA_INT_VEC_BASE (0x0)/* hardware access methods */#ifndef AMBA_INT_REG_READ#define AMBA_INT_REG_READ(reg,result) \ ((result) = *(volatile UINT32 *)(reg))#endif /*AMBA_INT_REG_READ*/#ifndef AMBA_INT_REG_WRITE#define AMBA_INT_REG_WRITE(reg,data) \ (*((volatile UINT32 *)(reg)) = (data))#endif /*AMBA_INT_REG_WRITE*//* Convert level number to vector number */#ifndef AMBA_INT_LVL_VEC_MAP#define AMBA_INT_LVL_VEC_MAP(level, vector) \ ((vector) = ((level) + AMBA_INT_VEC_BASE))#endif /* AMBA_INT_LVL_VEC_MAP */#ifndef AMBA_INT_PRIORITY_MAP/* Convert pending register value, to a level number */#ifndef AMBA_INT_PEND_LVL_MAP#define AMBA_INT_PEND_LVL_MAP(pendReg, level) \ ((level) = (pendReg))#endif /* AMBA_INT_PEND_LVL_MAP */#endif /* AMBA_INT_PRIORITY_MAP *//* driver constants */#define AMBA_INT_ALL_ENABLED (AMBA_INT_NUM_LEVELS)#define AMBA_INT_ALL_DISABLED 0/* Local data *//* Current interrupt level setting (ambaIntLvlChg). */LOCAL UINT32 ambaIntLvlCurrent = AMBA_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 ambaIntLvlEnabled;#ifdef AMBA_INT_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 ambaIntLvlMask[(1 + AMBA_INT_NUM_LEVELS) * sizeof(UINT32)];/* * Map of interrupt bit number to level: if bit n is set, ambaIntLvlMap[n] * is the interrupt level to change to such that interrupt n and all lower * priority ones are disabled. */LOCAL int ambaIntLvlMap[AMBA_INT_NUM_LEVELS * sizeof(int)];#endif /* AMBA_INT_PRIORITY_MAP *//* forward declarations */STATUS ambaIntLvlVecChk (int*, int*);STATUS ambaIntLvlVecAck (int, int);int ambaIntLvlChg (int);STATUS ambaIntLvlEnable (int);STATUS ambaIntLvlDisable (int);/********************************************************************************* ambaIntDevInit - 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.** If used with configurable priorities (#define AMBA_INT_PRIORITY_MAP),* before this routine is called, ambaIntLvlPriMap should be initialised* as a list of interrupt bits to poll in order of decreasing priority and* terminated by an entry containing -1. If ambaIntLvlPriMap is a null* pointer (or an empty list), the priority scheme used will be* least-significant bit first. This is equivalent to the scheme used if* AMBA_INT_PRIORITY_MAP is not defined but slightly less efficient.** The return value ERROR indicates that the contents of* ambaIntLvlPriMap (if used) were invalid.** RETURNS: OK or ERROR if ambaIntLvlPriMap invalid.*/int ambaIntDevInit (void) {#ifdef AMBA_INT_PRIORITY_MAP int i, j; int level; UINT32 bit; /* if priorities are supplied, validate the supplied list */ if (ambaIntLvlPriMap != 0) { /* first check the list is terminated (VecChk requires this) */ for (i = 0; i < AMBA_INT_NUM_LEVELS; ++i) if (ambaIntLvlPriMap[i] == -1) break; if (!(i < AMBA_INT_NUM_LEVELS)) return ERROR; /* no terminator */ /* now check that all are in range and that there are no duplicates */ for (i = 0; ambaIntLvlPriMap[i] != -1; ++i) if (ambaIntLvlPriMap[i] < 0 || ambaIntLvlPriMap[i] >= AMBA_INT_NUM_LEVELS) { return ERROR; /* out of range */ } else for (j = i + 1; ambaIntLvlPriMap[j] != -1; ++j) if (ambaIntLvlPriMap[j] == ambaIntLvlPriMap[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. */ ambaIntLvlMask[0] = 0; /* mask for level 0 = all disabled */ /* do the levels for which priority has been specified */ level = 1; if (ambaIntLvlPriMap != 0) { for ( ; level <= AMBA_INT_NUM_LEVELS && (i = ambaIntLvlPriMap[level - 1], i >= 0); ++level) { /* copy previous level's mask to this one's */ ambaIntLvlMask[level] = ambaIntLvlMask[level - 1]; /* OR in the bit indicated by the next entry in PriMap[] */ ambaIntLvlMask[level] |= 1 << i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -