sa150xIntrCtl.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:30k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* sa150xIntrCtl.c - interrupt controller driver for ARM 1500/1501 */
  2. /* Copyright 1998, Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01a,21sep98,cdp  created from 01a of ambaIntrCtl.c
  7. */
  8. /*
  9. This module implements the interrupt controller driver for the
  10. Strong-ARM 1500/1501 interrupt controllers.
  11. The interrupt controllers contained within the SA-1500 and SA-1501
  12. chips are edge-triggered, flexible controllers for multiple interrupt
  13. sources.  They have registers to configure the priority of interrupts
  14. (IRQ or FIQ), an enable/disable register, a register to configure
  15. polarity (inversion of the input signal before edge-capture), status,
  16. request and latch set/clear registers.  This library provides the
  17. routines to manage interrupts multiplexed by a variable number of these
  18. controllers.
  19. The following registers are defined in the header file for this library
  20. (sa150xIntrCtl.h).
  21. SA150X_INT_DESTINATION (read/write): this is the SA-1500 IPRI or the
  22. SA-1501 INTDEST register.  When this register is written, each bit
  23. determines whether the corresponding interrupt will be directed to the
  24. IRQ or FIQ interrupt.  On the versions of these chips available at the
  25. time of writing, the sense of the bits is different between the two
  26. chips (0 configures IRQ on SA-1500 but FIQ on SA-1501).  To handle this
  27. in a flexible way, the symbol "SA150X_INT_HANDLE_1501_DESTINATION" can
  28. be #defined before including this source file (see below).
  29. SA150X_INT_SPECIAL (read/write): this is the SA-1500 IDIR register
  30. which is a test register on the SA-1501.  This is used during
  31. configuration.  For details, see the BIU section of the SA-1500
  32. documentation.
  33. SA150X_INT_ENABLE (read/write): this is the SA-1500 IENAB or the
  34. SA-1501 INTENABLE register.  When this register is written, each data
  35. bit that is set (1) causes the corresponding interrupt to be enabled.
  36. Each bit that is that is clear (0) causes the corresponding interrupt
  37. to be disabled.  This register controls enabling of FIQs as well as
  38. IRQs (the actual destination of the interrupt is controlled by
  39. SA150X_INT_DESTINATION).
  40. SA150X_INT_POLARITY (read/write): this is the SA-1500 IPOL or SA-1501
  41. INTPOL register.  When this register is written, each data bit that is
  42. set (1) causes the corresponding raw interrupt source to be inverted
  43. before it is clocked by the edge-capture logic.  Each bit that is clear
  44. (0) leaves the raw interrupt source unaltered before capture.  This
  45. effectively controls whether rising or falling edges of the interrupt
  46. source cause interrupts.  The values read from the status registers
  47. (below) take into account what has been written to this register.
  48. SA150X_INT_IRQ_REQUEST (read): this is the SA-1500 IRQ or SA-1501
  49. INTRIRQ register.  When this register is read, each data bit that is
  50. set (1) indicates an IRQ interrupt source that is both active and
  51. enabled i.e. can interrupt the CPU.
  52. SA150X_INT_FIQ_REQUEST (read): this is the SA-1500 FIQ or SA-1501
  53. INTRFIQ register.  When this register is read, each data bit that is
  54. set (1) indicates a FIQ interrupt source that is both active and
  55. enabled i.e. can interrupt the CPU.  This register is not used by
  56. VxWorks.
  57. SA150X_INT_STATUS (read): this is the SA-1500 ISTAT or SA-1501
  58. INTSTATCLR register.  When this register is read, each data bit that is
  59. set (1) indicates that an interrupt for the corresponding source is
  60. pending.  Each data bit that is clear (0) indicates that no such
  61. interrupt is pending.  This is the same register as SA150X_INT_CLEAR.
  62. SA150X_INT_CLEAR (write): this is the SA-1500 ICLR or SA-1501
  63. INTSTATCLR register.  When this register is written, each data bit that
  64. is set (1) clears the corresponding pending interrupt.  Each data bit
  65. that is clear (0) has no effect.  This is the same register as
  66. SA150X_INT_STATUS.
  67. SA150X_INT_SOURCE (read): this is the SA-1500 ISRC or SA-1501 INTSRCSET
  68. register.  When this register is read, each data bit that is set (1)
  69. indicates that the corresponding interrupt is active.  Each bit that is
  70. clear (0) indicates that the raw interrupt source is inactive.  The
  71. values read are after the polarity configuration but before the
  72. edge-capture logic i.e. they indicate the states of the raw sources.
  73. This is the same register as SA150X_INT_SET.
  74. SA150X_INT_SET (write): this is the SA-1500 ISET or SA-1501 INTSRCSET
  75. register.  When this register is written, each data bit that is set (1)
  76. sets the corresponding interrupt to be active.  Each bit that is clear
  77. (0) has no effect.  This is the same register as SA150X_INT_SOURCE.
  78. This driver uses an array of "sa150xIntrCtlDetails" to describe the
  79. multiple controllers to be handled.  At its simplest, each element
  80. gives the base address of the controller.  If various features are
  81. enabled, other details are required (see below and sa150xIntrCtl.h).
  82. The number of devices supported by this driver i.e. the number of
  83. register blocks is specified by SA150X_INT_NUM_CONTROLLERS.  There must
  84. be this number of entries in the sa150xIntrCtlDetails array.
  85. The number of interrupts supported is specified by
  86. SA150X_INT_NUM_LEVELS.  Thirty-two bits per device are assumed so
  87.     SA150X_INT_NUM_LEVELS = 32 * SA150X_INT_NUM_CONTROLLERS.
  88. This driver assumes that the chip is memory-mapped and does direct
  89. memory accesses to the registers which are assumed to be 32 bits wide.
  90. If a different access method is needed, the BSP can redefine the macros
  91. SA150X_INT_REG_READ(addr,result) and SA150X_INT_REG_WRITE(addr,data).
  92. This driver assumes that interrupt vector numbers are calculated and
  93. not the result of a special cycle on the bus.  Vector numbers are
  94. generated by adding the current interrupt bit number (bit number +
  95. controller_number * 32) to SA150X_INT_VEC_BASE to generate a vector
  96. number which the architecture level will use to invoke the proper
  97. handling routine.  If a different mapping scheme, or a special hardware
  98. routine is needed, then the BSP should redefine the macro
  99. SA150X_INT_LVL_VEC_MAP(level,vector) to override the version defined in
  100. the header file for this driver.
  101. This driver was designed to support multiple devices.  For the SA-1500,
  102. it expects one entry in the sa150xIntrCtlDetails array; for the SA-1501
  103. (which has two sets of registers), it expects two entries.
  104. Priorities
  105. ==========
  106. The order of interrupt level priority is undefined at the architecture
  107. level.  In this driver, level 0 is highest and and indicates that all
  108. levels are disabled; level <SA150X_INT_NUM_LEVELS> is the lowest and
  109. indicates that all levels are enabled.
  110. This driver implements a BSP-configurable interrupt priority scheme.
  111. The BSP should define an array of int called sa150xIntLvlPriMap, each
  112. element of which is a bit number to be polled, where 0 is bit 0 in the
  113. 0th controller, 31 is bit 31 in the 0th controller, 32 is bit 0 in the
  114. 1st controller etc..  The list should be terminated with an entry
  115. containing -1.  This list is used in the interrupt handler to check
  116. bits in the requested order and is also used to generate a map of
  117. interrupt source to new interrupt level such that whilst servicing an
  118. interrupt, all interrupts defined by the BSP to be of lower priority
  119. than that interrupt are disabled.  Interrupt sources not in the list
  120. are serviced after all others with the least-significant bit being
  121. highest priority.  (Note that the list is a list of ints rather than
  122. bytes because it causes the current compiler to generate faster code.)
  123. Note that in this priority system, intLevelSet(n) does not necessarily
  124. disable interrupt bit n and all lower-priority ones but uses
  125. sa150xIntLvlPriMap to determine which interrupts should be masked e.g.
  126. if sa150xIntLvlPriMap[] contains { 9, 4, 8, 5, -1 }, intLevelSet(0)
  127. disables all interrupt bits; intLevelSet(1) enables interrupt bit 9 but
  128. disables interrupts 4, 8, 5 and all others not listed; intLevelSet(3)
  129. enables interrupt bits 9, 4 and 8 but disables all others.  This
  130. enabling of interrupts only occurs if the interrupt has been explicitly
  131. enabled via a call to sa150xIntLvlEnable().
  132. If the list is empty (contains just a terminator) or sa150xIntLvlPriMap
  133. is declared as an int pointer of value 0 (this is more efficient),
  134. interrupts are handled as least-significant bit is highest priority.
  135. FIQs
  136. ====
  137. Because the SA150X_INT_ENABLE register controls the enabling of FIQ as
  138. well as IRQ (see above), individual FIQs *must* be enabled/disabled by
  139. calling the routines in this file (sa150xIntFiqEnable and
  140. sa150xIntFiqDisable) rather than by direct accesses to the register.
  141. Otherwise, each IRQ will cause FIQs previously enabled to be disabled.
  142. In other respects, this driver (and VxWorks) do not support FIQ (see
  143. the ARM Architecture Supplement).
  144. Special features
  145. ================
  146. This driver can be compiled with certain features enabled by predefining
  147. certain symbols (e.g. in bsp.h or config.h).  Some have been described above
  148. but here is the complete list.
  149. #define SA150X_INT_INITIALISE_SOURCES
  150. Configures the driver so that the sa150xIntDevInit() call sets all interrupt
  151. sources to IRQ, disables and clears them all and sets their polarity.
  152. #define SA150X_INT_HANDLE_1501_DESTINATION
  153. Configures the driver to handle the different meaning of bits within
  154. the DESTINATION register on different SA-150X chips.  If this symbol is
  155. defined, each element of the sa150xIntrCtlDetails array must have an
  156. extra field to modify the value written to the DESTINATION register
  157. (the value specified in the structure is exclusive ORred with the value
  158. to be written to the register).
  159. #define SA150X_INT_RETRY_READS
  160. Configures the driver to retry reads from the controller, where safe,
  161. to attempt to cope with corruption of values read.
  162. #define SA150X_INT_RETRY_WRITES
  163. Configures the driver to retry writes to the controller, where safe, to
  164. attempt to cope with corruption of values written.
  165. #define SA150X_INT_CACHE_IRQ_REQUEST
  166. Configures the driver to cache the interrupt request registers i.e. for
  167. each interrupt request, the IRQ_REQUEST registers will only be read
  168. once.  Depending on the speed of RAM versus I/O, it is possible that
  169. this might improve performance but it was originally added to improve
  170. reliability on some systems.
  171. The BSP will initialize this driver in sysHwInit2(), after initializing
  172. the main interrupt library, usually intLibInit().  The initialization
  173. routine, sa150xIntDevInit() will setup the interrupt controller device,
  174. it will mask off all individual interrupt sources and then set the
  175. interrupt level to enable all interrupts.  See sa150xIntDevInit for
  176. more information.
  177. All of the functions in this library are global.  This allows them to
  178. be used by the BSP if it is necessary to create wrapper routines or to
  179. incorporate several drivers together as one.
  180. */
  181. #include "vxWorks.h"
  182. #include "config.h"
  183. #include "intLib.h"
  184. #include "drv/intrCtl/sa150xIntrCtl.h"
  185. /* imports */
  186. IMPORT int ffsLsb(UINT32);
  187. /* Defines from config.h, or <bsp>.h */
  188. #if !defined(SA150X_INT_NUM_LEVELS) || !defined(SA150X_INT_NUM_CONTROLLERS)
  189. #error missing definitions for sa150xIntrCtl.c
  190. #endif
  191. #if (SA150X_INT_NUM_LEVELS != (SA150X_INT_NUM_CONTROLLERS * 32))
  192. #error number of sa150x interrupt levels/controllers incompatible
  193. #endif
  194. #define SA150X_INT_VEC_BASE (0x0)
  195. /* driver constants */
  196. #define SA150X_INT_ALL_ENABLED (SA150X_INT_NUM_LEVELS)
  197. #define SA150X_INT_ALL_DISABLED 0
  198. /* Local data */
  199. /* Current interrupt level setting (sa150xIntLvlChg). */
  200. LOCAL UINT32 sa150xIntLvlCurrent = SA150X_INT_ALL_DISABLED;
  201. /*
  202.  * Controller masks: for each interrupt level, this provides a mask for
  203.  * each controller (see IntLvlChg).
  204.  * Mask is 32 bits/controller * (levels + 1)
  205.  */
  206. LOCAL UINT32 sa150xIntLvlMask[SA150X_INT_NUM_CONTROLLERS *
  207.       (1 + SA150X_INT_NUM_LEVELS) *
  208.       sizeof(UINT32)];
  209. /*
  210.  * Map of interrupt bit number to level: if bit n is set,
  211.  * sa150xIntLvlMap[n] is the interrupt level to change to such that
  212.  * interrupt n and all lower priority ones are disabled.
  213.  */
  214. LOCAL int sa150xIntLvlMap[SA150X_INT_NUM_LEVELS * sizeof(int)];
  215. /* forward declarations */
  216. STATUS sa150xIntLvlVecChk (int*, int*);
  217. STATUS  sa150xIntLvlVecAck (int, int);
  218. int sa150xIntLvlChg (int);
  219. STATUS sa150xIntLvlEnable (int);
  220. STATUS sa150xIntLvlDisable (int);
  221. /*******************************************************************************
  222. *
  223. * sa150xIntDevInit - initialize the interrupt controller
  224. *
  225. * This routine will initialize the interrupt controller device,
  226. * disabling all interrupt sources.  It will also connect the device
  227. * driver specific routines into the architecture level hooks.  If the BSP
  228. * needs to create a wrapper routine around any of the architecture level
  229. * routines, it should install the pointer to the wrapper routine after
  230. * calling this routine.
  231. *
  232. * Before this routine is called, sa150xIntLvlPriMap should be initialised
  233. * as a list of interrupt bits to poll in order of decreasing priority and
  234. * terminated by <-1>.  If sa150xIntLvlPriMap is a null pointer or an
  235. * empty list, the priority scheme used will be least-significant bit
  236. * first.
  237. *
  238. * The return value ERROR indicates that the contents of
  239. * sa150xIntLvlPriMap were invalid.
  240. *
  241. * RETURNS: OK or ERROR if sa150xIntLvlPriMap invalid.
  242. */
  243. int sa150xIntDevInit (void)
  244.     {
  245.     int i, j;
  246.     int level, ctl;
  247.     UINT32 bit;
  248.     UINT32 val;
  249.     sa150xIntrCtlDetails *p;
  250.     /* if priorities are supplied, validate the supplied list */
  251.     if (sa150xIntLvlPriMap != 0)
  252. {
  253. /* first check the list is terminated (VecChk requires this) */
  254. for (i = 0; i < SA150X_INT_NUM_LEVELS; ++i)
  255.     if (sa150xIntLvlPriMap[i] == -1)
  256. break;
  257. if (!(i < SA150X_INT_NUM_LEVELS))
  258.     return ERROR; /* no terminator */
  259. /* now check that all are in range and that there are no duplicates */
  260. for (i = 0; sa150xIntLvlPriMap[i] != -1; ++i)
  261.     if (sa150xIntLvlPriMap[i] < 0 ||
  262. sa150xIntLvlPriMap[i] >= SA150X_INT_NUM_LEVELS)
  263. {
  264. return ERROR; /* out of range */
  265. }
  266.     else
  267. for (j = i + 1; sa150xIntLvlPriMap[j] != -1; ++j)
  268.     if (sa150xIntLvlPriMap[j] == sa150xIntLvlPriMap[i])
  269. {
  270. return ERROR; /* duplicate */
  271. }
  272. }
  273.     /*
  274.      * Now initialise the mask array.
  275.      * For each level (in ascending order), the mask is the mask of the
  276.      * previous level with the bit for the current level set to enable it.
  277.      */
  278.     for (ctl = 0; ctl < SA150X_INT_NUM_CONTROLLERS; ++ctl)
  279. sa150xIntLvlMask[ctl] = 0; /* mask for level 0 = all disabled */
  280.     /* do the levels for which priority has been specified */
  281.     level = 1;
  282.     if (sa150xIntLvlPriMap != 0)
  283. {
  284. for ( ; level <= SA150X_INT_NUM_LEVELS &&
  285. (i = sa150xIntLvlPriMap[level - 1], i >= 0); ++level)
  286.     {
  287.     /* copy previous level's mask to this one's */
  288.     for (ctl = 0; ctl < SA150X_INT_NUM_CONTROLLERS; ++ctl)
  289. sa150xIntLvlMask[
  290.     level * SA150X_INT_NUM_CONTROLLERS + ctl] =
  291. sa150xIntLvlMask[
  292.     (level - 1) * SA150X_INT_NUM_CONTROLLERS + ctl];
  293.     /* OR in the bit indicated by the next entry in PriMap[] */
  294.     ctl = i / 32;
  295.     bit = 1 << (i % 32);
  296.     sa150xIntLvlMask[level * SA150X_INT_NUM_CONTROLLERS + ctl] |= bit;
  297.     /*
  298.      * set index in level map: to disable this interrupt and all
  299.      * lower-priority ones, select the level one less than this
  300.      */
  301.     sa150xIntLvlMap[i] = level - 1;
  302.     }
  303. }
  304.     /* do the rest of the levels */
  305.     i = 0; /* lowest-numbered interrupt bit */
  306.     for ( ; level <= SA150X_INT_NUM_LEVELS; ++level)
  307. {
  308. /* copy previous level's mask to this one's */
  309. for (ctl = 0; ctl < SA150X_INT_NUM_CONTROLLERS; ++ctl)
  310.     sa150xIntLvlMask[
  311. level * SA150X_INT_NUM_CONTROLLERS + ctl] =
  312.     sa150xIntLvlMask[
  313. (level - 1) * SA150X_INT_NUM_CONTROLLERS + ctl];
  314. /* try to find a bit that has not yet been set */
  315. for ( ; ; ++i)
  316.     {
  317.     ctl = i / 32;
  318.     bit = 1 << (i % 32);
  319.     if ((sa150xIntLvlMask[level * SA150X_INT_NUM_CONTROLLERS + ctl] &
  320.  bit) == 0)
  321. {
  322. /* this bit not set so put it in the mask */
  323. sa150xIntLvlMask[level * SA150X_INT_NUM_CONTROLLERS + ctl] |=
  324.     bit;
  325. /*
  326.  * set index in level map: to disable this interrupt and all
  327.  * lower-priority ones, select the level one less than this
  328.  */
  329. sa150xIntLvlMap[i] = level - 1;
  330. break;
  331. }
  332.     }
  333. }
  334.     /* install the driver routines in the architecture hooks */
  335.     sysIntLvlVecChkRtn = sa150xIntLvlVecChk;
  336.     sysIntLvlVecAckRtn = sa150xIntLvlVecAck;
  337.     sysIntLvlChgRtn = sa150xIntLvlChg;
  338.     sysIntLvlEnableRtn = sa150xIntLvlEnable;
  339.     sysIntLvlDisableRtn = sa150xIntLvlDisable;
  340.     /* set up the controllers */
  341.     for (i = 0; i < SA150X_INT_NUM_CONTROLLERS; ++i)
  342. {
  343. p = &sa150xIntrCtl[i];
  344. #ifdef SA150X_INT_INITIALISE_SOURCES
  345. /* disable all sources */
  346. #ifdef SA150X_INT_RETRY_WRITES
  347. SA150X_INT_REG_WRITE_RETRY (SA150X_INT_ENABLE (p->base), 0);
  348. #else
  349. SA150X_INT_REG_WRITE (SA150X_INT_ENABLE (p->base), 0);
  350. #endif
  351. /* set all sources to IRQ - note: must not retry write (locks up) */
  352. val = 0;
  353. #ifdef SA150X_INT_HANDLE_1501_DESTINATION
  354. val ^= p->destModifier;
  355. #endif
  356. SA150X_INT_REG_WRITE (SA150X_INT_DESTINATION (p->base), val);
  357. /* set polarity of edge-triggered interrupt to positive */
  358. #ifdef SA150X_INT_RETRY_WRITES
  359. SA150X_INT_REG_WRITE_RETRY (SA150X_INT_POLARITY (p->base), 0);
  360. #else
  361. SA150X_INT_REG_WRITE (SA150X_INT_POLARITY (p->base), 0);
  362. #endif
  363. /* clear all latches */
  364. SA150X_INT_REG_WRITE (SA150X_INT_CLEAR (p->base), ~0);
  365. #endif /* SA150X_INT_INITIALISE_SOURCES */
  366. p->enabledIrqs = 0; /* all sources disabled */
  367. }
  368.     sa150xIntLvlChg (SA150X_INT_ALL_ENABLED); /* enable all levels */
  369.     return OK;
  370.     }
  371. /*******************************************************************************
  372. *
  373. * sa150xIntLvlConfigure - configure polarity and type of interrupt
  374. *
  375. * This routine configures the polarity and type (edge or level) or an
  376. * interrupt.  It should be called after initialisation of the driver and
  377. * before enabling the level.
  378. *
  379. * The return value ERROR indicates that the parameters were invalid.
  380. *
  381. * RETURNS: OK or ERROR if parameters invalid.
  382. */
  383. STATUS sa150xIntLvlConfigure
  384.     (
  385.     int level, /* level to configure */
  386.     int features /* edge/level/positive/negative */
  387.     )
  388.     {
  389.     int key;
  390.     int bit;
  391.     UINT32 val;
  392.     sa150xIntrCtlDetails *p;
  393.     if (level < 0 ||
  394. level >= SA150X_INT_NUM_LEVELS)
  395. return ERROR;
  396.     bit = 1 << (level % 32);
  397.     p = &sa150xIntrCtl[level / 32];
  398.     key = intIFLock (); /* disable IRQ and FIQ */
  399.     /* configure destination - note: must not retry write (locks up) */
  400.     SA150X_INT_REG_READ (SA150X_INT_DESTINATION (p->base), val);
  401.     val &= ~bit; /* clear bit for this interrupt */
  402. #ifdef SA150X_INT_HANDLE_1501_DESTINATION
  403.     if (features & SA150X_INT_DESTINATION_FIQ)
  404. val |= bit & (bit ^ p->destModifier);
  405.     else
  406. val |= bit & (0 ^ p->destModifier);
  407. #else
  408.     if (features & SA150X_INT_DESTINATION_FIQ)
  409. val |= bit;
  410. #endif
  411.     SA150X_INT_REG_WRITE (SA150X_INT_DESTINATION (p->base), val);
  412.     /* configure polarity */
  413.     SA150X_INT_REG_READ (SA150X_INT_POLARITY (p->base), val);
  414.     if (features & SA150X_INT_POLARITY_POSITIVE)
  415. val &= ~bit;
  416.     else
  417. val |= bit;
  418. #ifdef SA150X_INT_RETRY_WRITES
  419.     SA150X_INT_REG_WRITE_RETRY (SA150X_INT_POLARITY (p->base), val);
  420. #else
  421.     SA150X_INT_REG_WRITE (SA150X_INT_POLARITY (p->base), val);
  422. #endif
  423.     intIFUnlock (key); /* restore IRQ and FIQ */
  424.     /* clear any pending interrupt */
  425.     SA150X_INT_REG_WRITE (SA150X_INT_CLEAR (p->base), bit);
  426.     /*
  427.      * if level interrupt, and source register (which takes account of
  428.      * polarity) indicates that interrupt is still active, set request
  429.      */
  430.     if (features & SA150X_INT_TYPE_LEVEL)
  431. {
  432. SA150X_INT_REG_READ (SA150X_INT_SOURCE (p->base), val);
  433. if (val & bit)
  434.     SA150X_INT_REG_WRITE (SA150X_INT_SET (p->base), bit);
  435. }
  436.     return OK;
  437.     }
  438. /*******************************************************************************
  439. *
  440. * sa150xIntLvlVecChk - check for and return any pending interrupts
  441. *
  442. * This routine interrogates the hardware to determine the highest priority
  443. * interrupt pending.  It returns the vector associated with that interrupt, and
  444. * also the interrupt priority level prior to the interrupt (not the
  445. * level of the interrupt).  The current interrupt priority level is then
  446. * raised to the level of the current interrupt so that only higher priority
  447. * interrupts will be accepted until this interrupt is finished.
  448. *
  449. * This routine must be called with CPU interrupts disabled.
  450. *
  451. * The return value ERROR indicates that no pending interrupt was found and
  452. * that the level and vector values were not returned.
  453. *
  454. * RETURNS: OK or ERROR if no interrupt is pending.
  455. */
  456. STATUS  sa150xIntLvlVecChk
  457.     (
  458.     int* pLevel,  /* ptr to receive old interrupt level */
  459.     int* pVector  /* ptr to receive current interrupt vector */
  460.     )
  461.     {
  462.     int newLevel;
  463.     sa150xIntrCtlDetails *p;
  464.     UINT32 isr, bit;
  465.     UINT32 *priPtr;
  466.     int ctl;
  467.     int bitNum;
  468. #ifdef SA150X_INT_RETRY_READS
  469.     int ok;
  470. #define TRIES 2
  471. #endif
  472.     /* initialise vars to stop compiler warnings */
  473.     p = 0;
  474.     bit = 0;
  475.     SA150X_INT_DEBUG(0x00, 0);
  476. #ifdef SA150X_INT_CACHE_IRQ_REQUEST
  477.     /* mark all cached requests as invalid */
  478.     for (ctl = 0; ctl < SA150X_INT_NUM_CONTROLLERS; ++ctl)
  479. sa150xIntrCtl[ctl].requestsValid = FALSE;
  480. #endif
  481.     if (priPtr = sa150xIntLvlPriMap, priPtr == 0)
  482. bitNum = -1;
  483.     else
  484. {
  485. /* service interrupts according to priority specified in map */
  486. while (bitNum = *priPtr++, bitNum != -1)
  487.     {
  488.     /*
  489.      * bitNum = interrupt bit from priority map - convert it to
  490.      * a bit position in a specific controller
  491.      * Note: UINT32 cast of bitNum is an optimisation(!)
  492.      */
  493.     ctl = (UINT32)bitNum / 32;
  494.     bit = 1 << ((UINT32)bitNum % 32);
  495.     p = &sa150xIntrCtl[ctl];
  496. #ifdef SA150X_INT_CACHE_IRQ_REQUEST
  497.     if (p->requestsValid)
  498. {
  499. isr = p->irqRequests;
  500. SA150X_INT_DEBUG(0x81, ctl);
  501. }
  502.     else
  503. {
  504. #endif
  505. /* read pending interrupt register for this controller */
  506. SA150X_INT_DEBUG(0x80, ctl);
  507. SA150X_INT_REQ_REG_READ (SA150X_INT_IRQ_REQUEST (p->base), isr,
  508.  ~p->enabledIrqs, TRIES, ok);
  509. #ifdef SA150X_INT_RETRY_READS
  510. if (ok)
  511. #endif
  512. #ifdef SA150X_INT_CACHE_IRQ_REQUEST
  513.     {
  514.     p->requestsValid = TRUE;
  515.     p->irqRequests = isr;
  516.     }
  517. #ifdef SA150X_INT_RETRY_READS
  518. else
  519.     {
  520.     isr = 0;
  521.     SA150X_INT_DEBUG(0x83, bitNum);
  522.     }
  523. #endif
  524. }
  525. #endif /* SA150X_INT_CACHE_IRQ_REQUEST */
  526.     if (isr & bit)
  527. {
  528. SA150X_INT_DEBUG(0x82, bitNum);
  529. break;
  530. }
  531.     }
  532. }
  533.     /*
  534.      * If priority scan didn't find anything, look for any bit set in any
  535.      * controller, starting with the lowest-numbered bit
  536.      */
  537.     if (bitNum == -1)
  538. for (ctl = 0; ctl < SA150X_INT_NUM_CONTROLLERS; ++ctl)
  539.     {
  540.     p = &sa150xIntrCtl[ctl];
  541. #ifdef SA150X_INT_CACHE_IRQ_REQUEST
  542.     if (p->requestsValid)
  543. {
  544. isr = p->irqRequests;
  545. SA150X_INT_DEBUG(0x91, ctl);
  546. }
  547.     else
  548. {
  549. #endif
  550. /* read pending interrupt register for this controller */
  551. SA150X_INT_DEBUG(0x90, ctl);
  552. SA150X_INT_REQ_REG_READ (SA150X_INT_IRQ_REQUEST (p->base), isr,
  553.  ~p->enabledIrqs, TRIES, ok);
  554. #ifdef SA150X_INT_RETRY_READS
  555. if (ok)
  556. #endif
  557. #ifdef SA150X_INT_CACHE_IRQ_REQUEST
  558.     {
  559.     p->requestsValid = TRUE;
  560.     p->irqRequests = isr;
  561.     }
  562. #ifdef SA150X_INT_RETRY_READS
  563. else
  564.     {
  565.     isr = 0;
  566.     SA150X_INT_DEBUG(0x93, ctl);
  567.     }
  568. #endif
  569. }
  570. #endif /* SA150X_INT_CACHE_IRQ_REQUEST */
  571.     /* find lowest bit set */
  572.     bitNum = ffsLsb (isr) - 1; /* ffsLsb returns 1..n, not 0..n-1 */
  573.     if (bitNum != -1)
  574. {
  575. bit = 1 << bitNum;
  576. bitNum += ctl * 32;
  577. SA150X_INT_DEBUG(0x92, bitNum);
  578. break;
  579. }
  580.     }
  581.     /* If no interrupt is pending, return ERROR */
  582.     if (bitNum == -1)
  583. {
  584. SA150X_INT_DEBUG(0xEE, 0xEE);
  585. return ERROR;
  586. }
  587.     /*
  588.      * bitNum is the bit that is interrupting (0..SA150X_INT_NUM_LEVELS-1)
  589.      * ctl is the controller number (0..SA150X_INT_NUM_CONTROLLERS-1)
  590.      * bit is the bit within that controller
  591.      * p-> sa150xIntrCtl structure for this controller
  592.      *
  593.      * clear the interrupt
  594.      */
  595.     SA150X_INT_REG_WRITE (SA150X_INT_CLEAR (p->base), bit);
  596.     /* map the interrupting device to an interrupt level number */
  597.     newLevel = sa150xIntLvlMap[bitNum];
  598.     /* change to new interrupt level, returning previous level to caller */
  599.     *pLevel = sa150xIntLvlChg (newLevel);
  600.     /* fetch, or compute the interrupt vector number */
  601.     SA150X_INT_LVL_VEC_MAP (bitNum, *pVector);
  602.     SA150X_INT_DEBUG(0xEE, 0x00);
  603.     return OK;
  604.     }
  605. /*******************************************************************************
  606. *
  607. * sa150xIntLvlVecAck - acknowledge the current interrupt
  608. *
  609. * Acknowledge the current interrupt cycle.  The level and vector values are
  610. * those generated during the sa150xIntLvlVecChk() routine for this interrupt
  611. * cycle.  The basic action is to return the interrupt level to its previous
  612. * setting.  Note that the SA150X interrupt controller does not need an
  613. * acknowledge cycle and that the interrupt has already been cleared in
  614. * sa150xIntLvlVecChk().
  615. *
  616. * RETURNS: OK or ERROR if a hardware fault is detected.
  617. * ARGSUSED
  618. */
  619. STATUS  sa150xIntLvlVecAck
  620.     (
  621.     int level, /* old interrupt level to be restored */
  622.     int vector /* current interrupt vector, if needed */
  623.     )
  624.     {
  625.     SA150X_INT_DEBUG(0xFF, vector);
  626.     /* restore the previous interrupt level */
  627.     sa150xIntLvlChg (level);
  628.     return OK;
  629.     }
  630. /*******************************************************************************
  631. *
  632. * sa150xIntLvlChg - change the interrupt level value
  633. *
  634. * This routine implements the overall interrupt setting.  All levels
  635. * up to and including the specified level are disabled.  All levels above
  636. * the specified level will be enabled, but only if they were specifically
  637. * enabled by the sa150xIntLvlEnable() routine.
  638. *
  639. * The specific priority level SA150X_INT_NUM_LEVELS is valid and represents
  640. * all levels enabled.
  641. *
  642. * RETURNS: Previous interrupt level.
  643. */
  644. int  sa150xIntLvlChg
  645.     (
  646.     int level /* new interrupt level */
  647.     )
  648.     {
  649.     int oldLevel;
  650.     int i, m;
  651.     sa150xIntrCtlDetails *p;
  652.     int key;
  653.     oldLevel = sa150xIntLvlCurrent;
  654.     if (level >= 0 &&
  655.         level <= SA150X_INT_NUM_LEVELS)
  656. {
  657. /* change current interrupt level */
  658. sa150xIntLvlCurrent = level;
  659. }
  660.     /* Activate the enabled interrupts */
  661.     m = sa150xIntLvlCurrent * SA150X_INT_NUM_CONTROLLERS;
  662.     for (i = 0; i < SA150X_INT_NUM_CONTROLLERS; ++i)
  663. {
  664. p = &sa150xIntrCtl[i];
  665. key = intIFLock (); /* disable IRQ and FIQ */
  666. #ifdef SA150X_INT_RETRY_WRITES
  667. SA150X_INT_REG_WRITE_RETRY (SA150X_INT_ENABLE (p->base),
  668.     (sa150xIntLvlMask[m + i] & p->enabledIrqs) |
  669.     p->enabledFiqs);
  670. #else
  671. SA150X_INT_REG_WRITE (SA150X_INT_ENABLE (p->base),
  672.       (sa150xIntLvlMask[m + i] & p->enabledIrqs) |
  673.       p->enabledFiqs);
  674. #endif
  675. intIFUnlock (key);
  676. }
  677.     return oldLevel;
  678.     }
  679. /*******************************************************************************
  680. *
  681. * sa150xIntLvlEnable - enable a single interrupt level
  682. *
  683. * Enable a specific interrupt level.  The enabled level will be allowed
  684. * to generate an interrupt when the overall interrupt level is set to
  685. * enable interrupts of this priority (as configured by
  686. * sa150xIntLvlPriMap).  Without being enabled, the interrupt is blocked
  687. * regardless of the overall interrupt level setting.
  688. *
  689. * RETURNS: OK or ERROR if the specified level cannot be enabled.
  690. */
  691. STATUS  sa150xIntLvlEnable
  692.     (
  693.     int level  /* level to be enabled */
  694.     )
  695.     {
  696.     int key;
  697.     if (level < 0 ||
  698. level >= SA150X_INT_NUM_LEVELS)
  699. return ERROR;
  700.     /* set bit in enable mask */
  701.     key = intIFLock (); /* disable IRQ and FIQ */
  702.     sa150xIntrCtl[level / 32].enabledIrqs |= (1 << (level % 32));
  703.     intIFUnlock (key);
  704.     sa150xIntLvlChg (-1); /* reset current mask */
  705.     return OK;
  706.     }
  707. /*******************************************************************************
  708. *
  709. * sa150xIntLvlDisable - disable a single interrupt level
  710. *
  711. * Disable a specific interrupt level.  The disabled level is prevented
  712. * from generating an interrupt even if the overall interrupt level is set
  713. * to enable interrupts of this priority (as configured by
  714. * sa150xIntLvlPriMap).
  715. *
  716. * RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
  717. */
  718. STATUS  sa150xIntLvlDisable
  719.     (
  720.     int level  /* level to be disabled */
  721.     )
  722.     {
  723.     int key;
  724.     if (level < 0 ||
  725. level >= SA150X_INT_NUM_LEVELS)
  726. return ERROR;
  727.     /* clear bit in enable mask */
  728.     key = intIFLock (); /* disable IRQ and FIQ */
  729.     sa150xIntrCtl[level / 32].enabledIrqs &= ~(1 << (level % 32));
  730.     intIFUnlock (key);
  731.     sa150xIntLvlChg (-1); /* reset current mask */
  732.     return OK;
  733.     }
  734. /*******************************************************************************
  735. *
  736. * sa150xIntFiqEnable - enable a single FIQ interrupt
  737. *
  738. * Enable a specific FIQ interrupt. Unlike an enable IRQ interrupt, an
  739. * enabled FIQ interrupt will be always be allowed to interrupt,
  740. * irrespective of the overall interrupt level.
  741. *
  742. * RETURNS: OK or ERROR if the specified level cannot be enabled.
  743. */
  744. STATUS  sa150xIntFiqEnable
  745.     (
  746.     int level  /* level to be enabled */
  747.     )
  748.     {
  749.     int key;
  750.     if (level < 0 ||
  751. level >= SA150X_INT_NUM_LEVELS)
  752. return ERROR;
  753.     /* set bit in enable mask */
  754.     key = intIFLock (); /* disable IRQ and FIQ */
  755.     sa150xIntrCtl[level / 32].enabledFiqs |= (1 << (level % 32));
  756.     intIFUnlock (key);
  757.     sa150xIntLvlChg (-1); /* reset current mask */
  758.     return OK;
  759.     }
  760. /*******************************************************************************
  761. *
  762. * sa150xIntFiqDisable - disable a single FIQ interrupt
  763. *
  764. * Disable a specific FIQ interrupt.  The disabled level is prevented
  765. * from generating an interrupt.
  766. *
  767. * RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
  768. */
  769. STATUS  sa150xIntFiqDisable
  770.     (
  771.     int level  /* level to be disabled */
  772.     )
  773.     {
  774.     int key;
  775.     if (level < 0 ||
  776. level >= SA150X_INT_NUM_LEVELS)
  777. return ERROR;
  778.     /* clear bit in enable mask */
  779.     key = intIFLock (); /* disable IRQ and FIQ */
  780.     sa150xIntrCtl[level / 32].enabledFiqs &= ~(1 << (level % 32));
  781.     intIFUnlock (key);
  782.     sa150xIntLvlChg (-1); /* reset current mask */
  783.     return OK;
  784.     }