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

VxWorks

开发平台:

C/C++

  1. /* sa1100IntrCtl.c - Digital Semiconductor SA-1100 interrupt controller driver */
  2. /* Copyright 1984-1998, Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01b,21sep98,cdp  fixed intEnable/Disable(0) (TSR#115062);
  7.  corrected range check in sa1100IntLvlEnable/Disable.
  8. 01a,09dec97,cdp  created from 01e of ambaIntrCtl.c.
  9. */
  10. /*
  11. This module implements the Digital Semiconductor SA-1100 interrupt controller
  12. driver.
  13. The SA-1100 interrupt controller is a simple interrupt controller
  14. described in full in the Digital StrongARM SA-1100 Data Sheet.  The
  15. interrupt controller has request registers, a mask register, a level
  16. register and supports level and edge-triggered interrupts.  This
  17. library provides the routines to manage interrupts multiplexed by the
  18. SA-1100 interrupt controller.
  19. The SA-1100 interrupt controller has a number of registers.  Those used by
  20. this driver are described below under the symbolic names used herein.
  21. SA1100_INT_CSR_ICMR (read/write): this is the "Interrupt Controller Mask
  22. Register" (ICMR) described in the SA-1100 Data Sheet.  When this register is
  23. written, each data bit that is set (1) causes the corresponding
  24. interrupt to be enabled; each data bit that is clear (0) causes the
  25. corresponding interrupt to be disabled.  When this register is read, each data
  26. bit that is set (1) indicates an interrupt source that is enabled.
  27. SA1100_INT_CSR_ICIP (read): this is the "Interrupt Controller IRQ
  28. Pending Register" (ICIP) described in the SA-1100 Data Sheet.  When
  29. this register is read, each data bit that is set (1) indicates an
  30. interrupt source that is both active and enabled (not masked) i.e. can
  31. interrupt the processor.  This driver provides a means by which bits in
  32. this register can be permanently masked e.g. if the particular
  33. implementation of SA-1100 returns bits in an undefined state.  Setting
  34. SA1100_INT_ICIP_MASK to be a bitwise OR of all the valid bits
  35. achieves the required effect.  The driver also provides a simple
  36. optimisation in the interrupt checking routine sa1100IntLvlVecChk(): if
  37. SA1100_INT_ICIP_FIRST_BIT is set to the lowest numbered bit of the
  38. interrupt controller that is used by the BSP, lower-numbered bits than
  39. this will not be checked.  The driver uses an external array
  40. sa1100IntLvlMask[] to determine what should be written to
  41. SA1100_INT_CSR_ICMR to change interrupt levels.  This should be defined
  42. by the BSP such that sa1100IntLvlMask[n] has a bit set (1) for each
  43. interrupt source that should be enabled for interrupt level <n>. For
  44. example, sa1100IntLvlMask[0] should be 0 so that all interrupts are
  45. disabled when interrupt level 0 is selected.
  46. SA1100_INT_CSR_ICLR (read/write): this is the "Interrupt Controller
  47. Level Register" (ICLR) described in the SA-1100 Data Sheet.  When this
  48. register is written, each data bit that is set (1) directs the
  49. interrupt associated with that bit position to the processor's FIQ
  50. input; Each data bit that is clear (0) directs the interrupt associated
  51. with that bit position to the processor's IRQ input.  When this
  52. register is read, each data bit that is set (1) indicates that the
  53. interrupt associated with that bit position is directed to the
  54. processor's FIQ input; each data bit that is clear (0) indicates that
  55. the interrupt associated with that bit position is directed to the
  56. processor's IRQ input.
  57. SA1100_INT_CSR_ICCR (read/write): this is the "Interrupt Controller
  58. Control Register" (ICCR) described in the SA-1100 Data Sheet.  When
  59. this register is written, if data bit zero is set (1), the contents of
  60. the ICMR control which interrupts can bring the SA-1100 out of idle
  61. mode; if data bit zero is clear (0), any interrupt can bring the
  62. SA-1100 out of idle mode, even if it is masked in the ICMR.
  63. The number of interrupts supported by the device i.e. the number of
  64. bits in the SA1100_INT_CSR_ICIP register, is specified by
  65. SA1100_INT_NUM_LEVELS.
  66. We assume that config.h or <bsp>.h has defined the addresses of the
  67. controller chips registers: SA1100_INT_CSR_ICMR, SA1100_INT_CSR_ICIP,
  68. SA1100_INT_CSR_ICLR, SA1100_INT_CSR_ICCR and also the driver
  69. constants SA1100_INT_ICIP_MASK, SA1100_INT_NUM_LEVELS.
  70. This driver assumes that the chip is memory-mapped and does direct
  71. memory accesses to the registers which are assumed to be 32 bits wide.
  72. If a different access method is needed, the BSP can redefine the macros
  73. SA1100_INT_REG_READ(addr,result) and SA1100_INT_REG_WRITE(addr,data).
  74. This driver assumes that interrupt vector numbers are calculated and
  75. not the result of a special cycle on the bus.  Vector numbers are
  76. generated by adding the current interrupt level number to
  77. SA1100_INT_VEC_BASE to generate a vector number which the architecture
  78. level will use to invoke the proper handling routine.  If a different
  79. mapping scheme, or a special hardware routine is needed, then the BSP
  80. should redefine the macro SA1100_INT_LVL_VEC_MAP(level,vector) to
  81. override the version defined in this file.
  82. The order of interrupt level priority is undefined at the architecture
  83. level.  In this driver, level 0 is highest and and indicates that all
  84. levels are disabled; level <SA1100_INT_NUM_LEVELS> is the lowest and
  85. indicates that all levels are enabled.
  86. This driver was designed to support a single instance of a real
  87. device.  At some point it should be upgraded to operate on an object
  88. model and to support any number of real devices.
  89. The BSP will initialize this driver in sysHwInit2(), after initializing
  90. the main interrupt library, usually intLibInit().  The initialization
  91. routine, sa1100IntDevInit() will setup the interrupt controller device,
  92. it will mask off all individual interrupt sources and then set the
  93. interrupt level to enable all interrupts.  See sa1100IntDevInit for more
  94. information.
  95. All of the functions in this library are global.  This allows them to
  96. be used by the BSP if it is necessary to create wrapper routines or to
  97. incorporate several drivers together as one.
  98. */
  99. #include "vxWorks.h"
  100. #include "config.h"
  101. #include "intLib.h"
  102. /* Defines from config.h, or <bsp>.h */
  103. #if !defined(SA1100_INT_CSR_ICMR) || !defined(SA1100_INT_CSR_ICIP) || 
  104.     !defined(SA1100_INT_CSR_ICLR) || !defined(SA1100_INT_CSR_ICCR) || 
  105.     !defined(SA1100_INT_ICIP_MASK) || !defined(SA1100_INT_NUM_LEVELS)
  106. #   error missing SA-1100 interrupt definitions
  107. #endif
  108. #ifndef SA1100_INT_ICIP_FIRST_BIT
  109. #define SA1100_INT_ICIP_FIRST_BIT 0
  110. #endif
  111. #define SA1100_INT_VEC_BASE (0x0)
  112. /* hardware access methods */
  113. #ifndef SA1100_INT_REG_READ
  114. #define SA1100_INT_REG_READ(reg,result) 
  115. ((result) = *(volatile UINT32 *)(reg))
  116. #endif /* SA1100_INT_REG_READ */
  117. #ifndef SA1100_INT_REG_WRITE
  118. #define SA1100_INT_REG_WRITE(reg,data) 
  119. (*((volatile UINT32 *)(reg)) = (data))
  120. #endif /* SA1100_INT_REG_WRITE */
  121. /* Convert level number to vector number */
  122. #ifndef SA1100_INT_LVL_VEC_MAP
  123. #define SA1100_INT_LVL_VEC_MAP(level, vector) 
  124. ((vector) = ((level) + SA1100_INT_VEC_BASE))
  125. #endif /* SA1100_INT_LVL_VEC_MAP */
  126. /* Convert pending register value, to a level number */
  127. #ifndef SA1100_INT_PEND_LVL_MAP
  128. #define SA1100_INT_PEND_LVL_MAP(pendReg, level) 
  129. ((level) = (pendReg))
  130. #endif /* SA1100_INT_PEND_LVL_MAP */
  131. /* driver constants */
  132. #define SA1100_INT_ALL_ENABLED (SA1100_INT_NUM_LEVELS)
  133. #define SA1100_INT_ALL_DISABLED 0
  134. /* Local data */
  135. /* Current interrupt level setting (sa1100IntLvlChg). */
  136. LOCAL UINT32 sa1100IntLvlCurrent = SA1100_INT_ALL_DISABLED; /* all disabled */
  137. /*
  138.  * A mask word.  Bits are set in this word when a specific level
  139.  * is enabled. It is used to mask off individual levels that have
  140.  * not been explicitly enabled.
  141.  */
  142. LOCAL UINT32 sa1100IntLvlEnabled;
  143. /* forward declarations */
  144. STATUS sa1100IntLvlVecChk (int*, int*);
  145. STATUS  sa1100IntLvlVecAck (int, int);
  146. int sa1100IntLvlChg (int);
  147. STATUS sa1100IntLvlEnable (int);
  148. STATUS sa1100IntLvlDisable (int);
  149. /*******************************************************************************
  150. *
  151. * sa1100IntDevInit - initialize the interrupt controller
  152. *
  153. * This routine will initialize the interrupt controller device,
  154. * disabling all interrupt sources.  It will also connect the device
  155. * driver specific routines into the architecture level hooks.  If the BSP
  156. * needs to create a wrapper routine around any of the arhitecture level
  157. * routines, it should install the pointer to the wrapper routine after
  158. * calling this routine.  On the SA-1100, this configures the chip so
  159. * that only unmasked interrupts can bring the CPU out of Idle Mode but
  160. * does not write the ICLR to configure whether interrupt sources cause
  161. * IRQ or FIQ because that is done in sysALib.s.
  162. * RETURNS: N/A
  163. */
  164. void sa1100IntDevInit (void)
  165.     {
  166.     /* install the driver routines in the architecture hooks */
  167.     sysIntLvlVecChkRtn = sa1100IntLvlVecChk;
  168.     sysIntLvlVecAckRtn = sa1100IntLvlVecAck;
  169.     sysIntLvlChgRtn = sa1100IntLvlChg;
  170.     sysIntLvlEnableRtn = sa1100IntLvlEnable;
  171.     sysIntLvlDisableRtn = sa1100IntLvlDisable;
  172.     /* set DIM so that only unmasked interrupts can cause Idle Mode exit */
  173.     SA1100_INT_REG_WRITE (SA1100_INT_CSR_ICCR, 1);
  174.     sa1100IntLvlEnabled = 0;  /* all sources disabled */
  175.     sa1100IntLvlChg (SA1100_INT_ALL_ENABLED); /* enable all levels */
  176.     }
  177. /*******************************************************************************
  178. *
  179. * sa1100IntLvlVecChk - check for and return any pending interrupts
  180. *
  181. * This routine interrogates the hardware to determine the highest priority
  182. * interrupt pending.  It returns the vector associated with that interrupt, and
  183. * also the interrupt priority level prior to the interrupt (not the
  184. * level of the interrupt).  The current interrupt priority level is then
  185. * raised to the level of the current interrupt so that only higher priority
  186. * interrupts will be accepted until this interrupt is finished.
  187. *
  188. * The return value ERROR indicates that no pending interrupt was found and
  189. * that the level and vector values were not returned.
  190. *
  191. * RETURNS: OK or ERROR if no interrupt is pending.
  192. */
  193. STATUS  sa1100IntLvlVecChk
  194.     (
  195.     int* pLevel,  /* ptr to receive old interrupt level */
  196.     int* pVector  /* ptr to receive current interrupt vector */
  197.     )
  198.     {
  199.     int newLevel;
  200.     UINT32 isr;
  201.     /* Read pending interrupt register and mask undefined bits */
  202.     SA1100_INT_REG_READ (SA1100_INT_CSR_ICIP, isr);
  203.     isr &= SA1100_INT_ICIP_MASK;
  204.     /* If no interrupt is pending, return ERROR */
  205.     if (isr == 0)
  206. return ERROR;
  207.     newLevel = SA1100_INT_ICIP_FIRST_BIT; /* don't check unused low bits */
  208.     /*
  209.      * Step through the bits looking for a 1. This *will* terminate.
  210.      * We could use ffsLsb() for this if we don't mind the function call
  211.      * overhead
  212.      */
  213.     for ( ; (isr & (1 << newLevel)) == 0; ++newLevel)
  214. /* do nothing */ ;
  215.     /* map the interrupting device to an interrupt level number */
  216.     SA1100_INT_PEND_LVL_MAP (newLevel, newLevel);
  217.     /* change to new interrupt level, returning previous level to caller */
  218.     *pLevel = sa1100IntLvlChg (newLevel);
  219.     /* fetch, or compute the interrupt vector number */
  220.     SA1100_INT_LVL_VEC_MAP (newLevel, *pVector);
  221.     return OK;
  222.     }
  223. /*******************************************************************************
  224. *
  225. * sa1100IntLvlVecAck - acknowledge the current interrupt
  226. *
  227. * Acknowledge the current interrupt cycle.  The level and vector values are
  228. * those generated during the sa1100IntLvlVecChk() routine for this interrupt
  229. * cycle.  The basic action is to reset the current interrupt and return
  230. * the interrupt level to its previous setting.  Note that the SA_1100 interrupt
  231. * controller does not need an acknowledge cycle.
  232. *
  233. * RETURNS: OK or ERROR if a hardware fault is detected.
  234. * ARGSUSED
  235. */
  236. STATUS  sa1100IntLvlVecAck
  237.     (
  238.     int level, /* old interrupt level to be restored */
  239.     int vector /* current interrupt vector, if needed */
  240.     )
  241.     {
  242.     /* restore the previous interrupt level */
  243.     sa1100IntLvlChg (level);
  244.     return OK;
  245.     }
  246. /*******************************************************************************
  247. *
  248. * sa1100IntLvlChg - change the interrupt level value
  249. *
  250. * This routine implements the overall interrupt setting.  All levels
  251. * up to and including the specifed level are disabled.  All levels above
  252. * the specified level will be enabled, but only if they were specifically
  253. * enabled by the sa1100IntLvlEnable() routine.
  254. *
  255. * The specific priority level SA1100_INT_NUM_LEVELS is valid and represents
  256. * all levels enabled.
  257. *
  258. * RETURNS: Previous interrupt level.
  259. */
  260. int  sa1100IntLvlChg
  261.     (
  262.     int level /* new interrupt level */
  263.     )
  264.     {
  265.     int oldLevel;
  266.     
  267.     oldLevel = sa1100IntLvlCurrent;
  268.     if (level >= 0 &&
  269.         level <= SA1100_INT_NUM_LEVELS)
  270. {
  271. /* change current interrupt level */
  272. sa1100IntLvlCurrent = level;
  273. }
  274.     /* Activate the enabled interrupts */
  275.     SA1100_INT_REG_WRITE (SA1100_INT_CSR_ICMR, 
  276. (sa1100IntLvlMask[sa1100IntLvlCurrent] & sa1100IntLvlEnabled));
  277.     return oldLevel;
  278.     }
  279. /*******************************************************************************
  280. *
  281. * sa1100IntLvlEnable - enable a single interrupt level
  282. *
  283. * Enable a specific interrupt level.  The enabled level will be allowed to
  284. * generate an interrupt, when the overall interrupt level is set below the
  285. * specified level.  Without being enabled, the interrupt is blocked regardless
  286. * of the overall interrupt level setting.
  287. *
  288. * RETURNS: OK or ERROR if the specified level cannot be enabled.
  289. */
  290. STATUS  sa1100IntLvlEnable
  291.     (
  292.     int level  /* level to be enabled */
  293.     )
  294.     {
  295.     int key;
  296.     if (level < 0 ||
  297. level >= SA1100_INT_NUM_LEVELS)
  298. return ERROR;
  299.     /* set bit in enable mask */
  300.     key = intLock ();
  301.     sa1100IntLvlEnabled |= (1 << level);
  302.     intUnlock (key);
  303.     sa1100IntLvlChg (-1); /* reset current mask */
  304.     return OK;
  305.     }
  306. /*******************************************************************************
  307. *
  308. * sa1100IntLvlDisable - disable a single interrupt level
  309. *
  310. * Disable a specific interrupt level.  The disabled level is prevented
  311. * from generating an interrupt even if the overall interrupt level is set
  312. * below the specified level.
  313. *
  314. * RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
  315. */
  316. STATUS  sa1100IntLvlDisable
  317.     (
  318.     int level  /* level to be disabled */
  319.     )
  320.     {
  321.     int key;
  322.     if (level < 0 ||
  323. level >= SA1100_INT_NUM_LEVELS)
  324. return ERROR;
  325.     /* clear bit in enable mask */
  326.     key = intLock ();
  327.     sa1100IntLvlEnabled &= ~(1 << level);
  328.     intUnlock (key);
  329.     sa1100IntLvlChg (-1); /* reset current mask */
  330.     return OK;
  331.     }