intr.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. intr.c
  9. Abstract:
  10. This module implements support for the BCM2709 Interrupt Controller.
  11. Author:
  12. Chris Stevens 18-Mar-2015
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <uefifw.h>
  20. #include <dev/bcm2709.h>
  21. //
  22. // --------------------------------------------------------------------- Macros
  23. //
  24. //
  25. // This macro reads from the BCM2709 interrupt controller. The parameter should
  26. // be a BCM2709_INTERRUPT_REGISTER value.
  27. //
  28. #define READ_INTERRUPT_REGISTER(_Register) \
  29. EfiReadRegister32(BCM2709_INTERRUPT_BASE + (_Register))
  30. //
  31. // This macro writes to the BCM2709 interrupt controller. _Register should be a
  32. // BCM2709_INTERRUPT_REGISTER value and _Value should be a ULONG.
  33. //
  34. #define WRITE_INTERRUPT_REGISTER(_Register, _Value) \
  35. EfiWriteRegister32(BCM2709_INTERRUPT_BASE + (_Register), (_Value))
  36. //
  37. // ---------------------------------------------------------------- Definitions
  38. //
  39. //
  40. // ------------------------------------------------------ Data Type Definitions
  41. //
  42. //
  43. // ----------------------------------------------- Internal Function Prototypes
  44. //
  45. //
  46. // -------------------------------------------------------------------- Globals
  47. //
  48. //
  49. // Store a table that tracks which GPU IRQs are in the basic pending status
  50. // register.
  51. //
  52. UINT32
  53. EfiBcm2709InterruptIrqBasicGpuTable[BCM2709_INTERRUPT_IRQ_BASIC_GPU_COUNT] = {
  54. 7,
  55. 9,
  56. 10,
  57. 18,
  58. 19,
  59. 53,
  60. 54,
  61. 55,
  62. 56,
  63. 57,
  64. 62
  65. };
  66. //
  67. // ------------------------------------------------------------------ Functions
  68. //
  69. EFI_STATUS
  70. EfipBcm2709InterruptInitialize (
  71. VOID
  72. )
  73. /*++
  74. Routine Description:
  75. This routine initializes a BCM2709 Interrupt Controller.
  76. Arguments:
  77. PlatformBase - Supplies the platform's BCM2709 register base address.
  78. Return Value:
  79. EFI Status code.
  80. --*/
  81. {
  82. //
  83. // Fail if the BCM2709 device library is not initialized.
  84. //
  85. if (EfiBcm2709Initialized == FALSE) {
  86. return EFI_NOT_READY;
  87. }
  88. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisable1, 0xFFFFFFFF);
  89. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisable2, 0xFFFFFFFF);
  90. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisableBasic, 0xFFFFFFFF);
  91. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptFiqControl, 0);
  92. return EFI_SUCCESS;
  93. }
  94. VOID
  95. EfipBcm2709InterruptBeginInterrupt (
  96. UINT32 *InterruptNumber,
  97. VOID **InterruptContext
  98. )
  99. /*++
  100. Routine Description:
  101. This routine is called when an interrupts comes in. This routine is
  102. responsible for reporting the interrupt number.
  103. Arguments:
  104. InterruptNumber - Supplies a pointer where interrupt line number will be
  105. returned.
  106. InterruptContext - Supplies a pointer where the platform can store a
  107. pointer's worth of context that will be passed back when ending the
  108. interrupt.
  109. Return Value:
  110. None.
  111. --*/
  112. {
  113. UINT32 Base;
  114. UINT32 Index;
  115. UINT32 Status;
  116. //
  117. // Determine which interrupt fired based on the pending status.
  118. //
  119. Status = READ_INTERRUPT_REGISTER(Bcm2709InterruptIrqPendingBasic);
  120. if (Status == 0) {
  121. return;
  122. }
  123. //
  124. // If this is a basic interrupt, then determine which line fired based on
  125. // the bit set.
  126. //
  127. if ((Status & BCM2709_INTERRUPT_IRQ_BASIC_MASK) != 0) {
  128. Index = 0;
  129. while ((Status & 0x1) == 0) {
  130. Status = Status >> 1;
  131. Index += 1;
  132. }
  133. Index += Bcm2709InterruptArmTimer;
  134. //
  135. // If this is a GPU interrupt that gets set in the basic pending status
  136. // register, then check which bit is set. The pending 1 and 2 bits do not
  137. // get set for these interrupts.
  138. //
  139. } else if ((Status & BCM2709_INTERRUPT_IRQ_BASIC_GPU_MASK) != 0) {
  140. Status = Status >> BCM2709_INTERRUPT_IRQ_BASIC_GPU_SHIFT;
  141. Index = 0;
  142. while ((Status & 0x1) == 0) {
  143. Status = Status >> 1;
  144. Index += 1;
  145. }
  146. Index = EfiBcm2709InterruptIrqBasicGpuTable[Index];
  147. } else {
  148. if ((Status & BCM2709_INTERRUPT_IRQ_BASIC_PENDING_1) != 0) {
  149. Status = READ_INTERRUPT_REGISTER(Bcm2709InterruptIrqPending1);
  150. Base = 0;
  151. } else {
  152. Status = READ_INTERRUPT_REGISTER(Bcm2709InterruptIrqPending2);
  153. Base = 32;
  154. }
  155. Index = 0;
  156. while ((Status & 0x1) == 0) {
  157. Status = Status >> 1;
  158. Index += 1;
  159. }
  160. Index += Base;
  161. }
  162. *InterruptNumber = Index;
  163. return;
  164. }
  165. VOID
  166. EfipBcm2709InterruptEndInterrupt (
  167. UINT32 InterruptNumber,
  168. VOID *InterruptContext
  169. )
  170. /*++
  171. Routine Description:
  172. This routine is called to finish handling of a platform interrupt. This is
  173. where the End-Of-Interrupt would get sent to the interrupt controller.
  174. Arguments:
  175. InterruptNumber - Supplies the interrupt number that occurred.
  176. InterruptContext - Supplies the context returned by the interrupt
  177. controller when the interrupt began.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. return;
  183. }
  184. EFI_STATUS
  185. EfipBcm2709InterruptSetInterruptLineState (
  186. UINT32 LineNumber,
  187. BOOLEAN Enabled,
  188. BOOLEAN EdgeTriggered
  189. )
  190. /*++
  191. Routine Description:
  192. This routine enables or disables an interrupt line.
  193. Arguments:
  194. LineNumber - Supplies the line number to enable or disable.
  195. Enabled - Supplies a boolean indicating if the line should be enabled or
  196. disabled.
  197. EdgeTriggered - Supplies a boolean indicating if the interrupt is edge
  198. triggered (TRUE) or level triggered (FALSE).
  199. Return Value:
  200. EFI Status code.
  201. --*/
  202. {
  203. BCM2709_INTERRUPT_REGISTER Register;
  204. UINT32 RegisterValue;
  205. UINT32 Shift;
  206. //
  207. // If the line is a GPU line, then determine which of the two
  208. // disable/enable registers it belongs to.
  209. //
  210. if (LineNumber < BCM2709_INTERRUPT_GPU_LINE_COUNT) {
  211. Shift = LineNumber;
  212. if (Shift >= 32) {
  213. Shift -= 32;
  214. }
  215. RegisterValue = 1 << Shift;
  216. if (Enabled == FALSE) {
  217. if (LineNumber < 32) {
  218. Register = Bcm2709InterruptIrqDisable1;
  219. } else {
  220. Register = Bcm2709InterruptIrqDisable2;
  221. }
  222. } else {
  223. if (LineNumber < 32) {
  224. Register = Bcm2709InterruptIrqEnable1;
  225. } else {
  226. Register = Bcm2709InterruptIrqEnable2;
  227. }
  228. }
  229. //
  230. // Otherwise the interrupt belongs to the basic enable and disable
  231. // registers.
  232. //
  233. } else {
  234. Shift = LineNumber - BCM2709_INTERRUPT_GPU_LINE_COUNT;
  235. RegisterValue = 1 << Shift;
  236. if (Enabled == FALSE) {
  237. Register = Bcm2709InterruptIrqDisableBasic;
  238. } else {
  239. Register = Bcm2709InterruptIrqEnableBasic;
  240. }
  241. }
  242. //
  243. // Change the state of the interrupt based on the register and the value
  244. // determined above.
  245. //
  246. WRITE_INTERRUPT_REGISTER(Register, RegisterValue);
  247. return EFI_SUCCESS;
  248. }
  249. //
  250. // --------------------------------------------------------- Internal Functions
  251. //