gic.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. gic.c
  5. Abstract:
  6. This module implements support for the ARM Generic Interrupt Controller.
  7. Author:
  8. Evan Green 3-Mar-2014
  9. Environment:
  10. Firmware
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <uefifw.h>
  16. #include "dev/gic.h"
  17. //
  18. // --------------------------------------------------------------------- Macros
  19. //
  20. //
  21. // Define register access macros to the distributor and CPU interface.
  22. //
  23. #define READ_GIC_DISTRIBUTOR(_Context, _Register) \
  24. EfiReadRegister32((UINT32 *)((_Context)->DistributorBase + (_Register)))
  25. #define WRITE_GIC_DISTRIBUTOR(_Context, _Register, _Value) \
  26. EfiWriteRegister32((UINT32 *)((_Context)->DistributorBase + (_Register)), \
  27. (_Value))
  28. #define READ_GIC_DISTRIBUTOR_BYTE(_Context, _Register) \
  29. EfiReadRegister8((UINT8 *)((_Context)->DistributorBase + (_Register))
  30. #define WRITE_GIC_DISTRIBUTOR_BYTE(_Context, _Register, _Value) \
  31. EfiWriteRegister8((UINT8 *)((_Context)->DistributorBase + (_Register)), \
  32. (_Value))
  33. #define READ_GIC_CPU_INTERFACE(_Context, _Register) \
  34. EfiReadRegister32((UINT8 *)((_Context)->CpuInterfaceBase + (_Register)))
  35. #define WRITE_GIC_CPU_INTERFACE(_Context, _Register, _Value) \
  36. EfiWriteRegister32((UINT8 *)((_Context)->CpuInterfaceBase + (_Register)), \
  37. (_Value))
  38. #define READ_GIC_CPU_INTERFACE_BYTE(_Context, _Register) \
  39. EfiReadRegister8((UINT8 *)((_Context)->CpuInterfaceBase + (_Register)))
  40. #define WRITE_GIC_CPU_INTERFACE_BYTE(_Context, _Register, _Value) \
  41. EfiWriteRegister8((UINT8 *)((_Context)->CpuInterfaceBase + (_Register)), \
  42. (_Value))
  43. //
  44. // ---------------------------------------------------------------- Definitions
  45. //
  46. //
  47. // Define the number of software interrupt (SGI) lines.
  48. //
  49. #define GIC_SOFTWARE_INTERRUPT_LINE_COUNT 16
  50. //
  51. // Define the maximum number of lines a GIC can have.
  52. //
  53. #define GIC_MAX_LINES 1024
  54. //
  55. // Define the spurious line.
  56. //
  57. #define GIC_SPURIOUS_LINE 1023
  58. //
  59. // GIC Distributor register definitions.
  60. //
  61. //
  62. // Define distributor Control register bits.
  63. //
  64. #define GIC_DISTRIBUTOR_CONTROL_ENABLE 0x1
  65. //
  66. // Define register bits of the distributor type register.
  67. //
  68. #define GIC_DISTRIBUTOR_TYPE_LINE_COUNT_MASK 0x1F
  69. //
  70. // Define register bits of the software interrupt register.
  71. //
  72. #define GIC_DISTRIBUTOR_SOFTWARE_INTERRUPT_ALL_BUT_SELF_SHORTHAND 0x01000000
  73. #define GIC_DISTRIBUTOR_SOFTWARE_INTERRUPT_SELF_SHORTHAND 0x02000000
  74. #define GIC_DISTRIBUTOR_SOFTWARE_INTERRUPT_TARGET_SHIFT 16
  75. //
  76. // Define register bits of the interrupt configuration register.
  77. //
  78. #define GIC_DISTRIBUTOR_INTERRUPT_CONFIGURATION_EDGE_TRIGGERED 0x2
  79. #define GIC_DISTRIBUTOR_INTERRUPT_CONFIGURATION_N_TO_N 0x0
  80. #define GIC_DISTRIBUTOR_INTERRUPT_CONFIGURATION_1_TO_N 0x1
  81. #define GIC_DISTRIBUTOR_INTERRUPT_CONFIGURATION_MASK 0x3
  82. //
  83. // GIC CPU Interface register definitions.
  84. //
  85. //
  86. // Define the control register bit definitions.
  87. //
  88. #define GIC_CPU_INTERFACE_CONTROL_ENABLE 0x1
  89. //
  90. // Define register definitions for the CPU interface binary point register.
  91. // All GICs must support a binary point of at least 3, meaning there are 4 bits
  92. // for the priority group, and therefore 16 unique priority levels.
  93. //
  94. #define GIC_CPU_INTERFACE_BINARY_POINT_MINIMUM 3
  95. //
  96. // Define register definitions for the interrupt acknowledge register.
  97. //
  98. #define GIC_CPU_INTERFACE_ACKNOWLEDGE_LINE_MASK 0x3FF
  99. //
  100. // Define the priority assigned to all enabled interrupts.
  101. //
  102. #define EFI_GIC_INTERRUPT_PRIORITY 0x80
  103. #define EFI_GIC_LOW_PRIORITY 0xF0
  104. //
  105. // ------------------------------------------------------ Data Type Definitions
  106. //
  107. //
  108. // Define the GIC Distributor register offsets, in bytes.
  109. //
  110. typedef enum _GIC_DISTRIBUTOR_REGISTER {
  111. GicDistributorControl = 0x000, // GICD_CTLR
  112. GicDistributorType = 0x004, // GICD_TYPER
  113. GicDistributorImplementor = 0x008, // GICD_IIDR
  114. GicDistributorGroup = 0x080, // GICD_IGROUPRn
  115. GicDistributorEnableSet = 0x100, // GICD_ISENABLERn
  116. GicDistributorEnableClear = 0x180, // GICD_ICENABLERn
  117. GicDistributorPendingSet = 0x200, // GICD_ISPENDRn
  118. GicDistributorPendingClear = 0x280, // GICD_ICPENDRn
  119. GicDistributorActiveSet = 0x300, // GICD_ISACTIVERn
  120. GicDistributorActiveClear = 0x380, // GICD_ICACTIVERn
  121. GicDistributorPriority = 0x400, // GICD_IPRIORITYRn
  122. GicDistributorInterruptTarget = 0x800, // GICD_ITARGETSRn
  123. GicDistributorInterruptConfiguration = 0xC00, // GICD_ICFGRn
  124. GicDistributorNonSecureAccessControl = 0xE00, // GICD_NSACRn
  125. GicDistributorSoftwareInterrupt = 0xF00, // GICD_SGIR
  126. GicDistributorSoftwareInterruptPendingClear = 0xF10, // GICD_CPENDSGIRn
  127. GicDistributorSoftwareInterruptPendingSet = 0xF20, // GICD_SPENDSSGIRn
  128. } GIC_DISTRIBUTOR_REGISTER, *PGIC_DISTRIBUTOR_REGISTER;
  129. //
  130. // Define the GIC CPU Interface register offsets, in bytes.
  131. //
  132. typedef enum _GIC_CPU_INTERFACE_REGISTER {
  133. GicCpuInterfaceControl = 0x00, // GICC_CTLR
  134. GicCpuInterfacePriorityMask = 0x04, // GICC_PMR
  135. GicCpuInterfaceBinaryPoint = 0x08, // GICC_BPR
  136. GicCpuInterfaceInterruptAcknowledge = 0x0C, // GICC_IAR
  137. GicCpuInterfaceEndOfInterrupt = 0x10, // GICC_EOIR
  138. GicCpuInterfaceRunningPriority = 0x14, // GICC_RPR
  139. GicCpuInterfaceHighestPendingPriority = 0x18, // GICC_HPPIR
  140. GicCpuInterfaceAliasedBinaryPoint = 0x1C, // GICC_ABPR,
  141. GicCpuInterfaceAliasedInterruptAcknowledge = 0x20, // GICC_AIAR
  142. GicCpuInterfaceAliasedEndOfInterrupt = 0x24, // GICC_AEOIR
  143. GicCpuInterfaceAliasedHighestPendingPriority = 0x28, // GICC_AHPPIR
  144. GicCpuInterfaceActivePriority = 0xD0, // GICC_APRn
  145. GicCpuInterfaceNonSecureActivePriority = 0xE0, // GICC_NSAPRn
  146. GicCpuInterfaceIdentification = 0xFC, // GICC_IIDR
  147. GicCpuInterfaceDeactivateInterrupt = 0x1000 // GICC_DIR
  148. } GIC_CPU_INTERFACE_REGISTER, *PGIC_CPU_INTERFACE_REGISTER;
  149. //
  150. // ----------------------------------------------- Internal Function Prototypes
  151. //
  152. //
  153. // -------------------------------------------------------------------- Globals
  154. //
  155. //
  156. // ------------------------------------------------------------------ Functions
  157. //
  158. EFI_STATUS
  159. EfipGicInitialize (
  160. PGIC_CONTEXT Context
  161. )
  162. /*++
  163. Routine Description:
  164. This routine initializes a Generic Interrupt Controller. It enables the
  165. controller and masks all interrupt lines.
  166. Arguments:
  167. Context - Supplies the pointer to the controller's context. The base must
  168. be filled in by the caller, and the rest must be zeroed out by the
  169. caller.
  170. Return Value:
  171. EFI Status code.
  172. --*/
  173. {
  174. UINT32 BlockIndex;
  175. UINT32 LineCountField;
  176. EFI_STATUS Status;
  177. if ((Context->DistributorBase == NULL) ||
  178. (Context->CpuInterfaceBase == NULL)) {
  179. Status = EFI_INVALID_PARAMETER;
  180. goto GicInitializeEnd;
  181. }
  182. //
  183. // Determine the maximum number of lines that this controller may have.
  184. //
  185. LineCountField = READ_GIC_DISTRIBUTOR(Context, GicDistributorType) &
  186. GIC_DISTRIBUTOR_TYPE_LINE_COUNT_MASK;
  187. Context->MaxLines = 32 * (LineCountField + 1);
  188. //
  189. // Mask every interrupt in the distributor.
  190. //
  191. for (BlockIndex = 0;
  192. BlockIndex < Context->MaxLines / 32;
  193. BlockIndex += 1) {
  194. WRITE_GIC_DISTRIBUTOR(Context,
  195. GicDistributorEnableClear + (4 * BlockIndex),
  196. 0xFFFFFFFF);
  197. }
  198. //
  199. // Enable all the software generated interrupts (lines 0-16).
  200. //
  201. WRITE_GIC_DISTRIBUTOR(Context, GicDistributorEnableSet, 0x0000FFFF);
  202. //
  203. // Enable the GIC distributor.
  204. //
  205. WRITE_GIC_DISTRIBUTOR(Context,
  206. GicDistributorControl,
  207. GIC_DISTRIBUTOR_CONTROL_ENABLE);
  208. //
  209. // Set the binary point register to define where the priority group ends
  210. // and the subgroup begins. Initialize it to the most conservative value
  211. // that all implementations must support.
  212. //
  213. WRITE_GIC_CPU_INTERFACE(Context,
  214. GicCpuInterfaceBinaryPoint,
  215. GIC_CPU_INTERFACE_BINARY_POINT_MINIMUM);
  216. //
  217. // Set the running priority to its lowest value.
  218. //
  219. WRITE_GIC_CPU_INTERFACE(Context,
  220. GicCpuInterfacePriorityMask,
  221. EFI_GIC_LOW_PRIORITY);
  222. //
  223. // Enable this CPU interface.
  224. //
  225. WRITE_GIC_CPU_INTERFACE(Context,
  226. GicCpuInterfaceControl,
  227. GIC_CPU_INTERFACE_CONTROL_ENABLE);
  228. Status = EFI_SUCCESS;
  229. GicInitializeEnd:
  230. return Status;
  231. }
  232. VOID
  233. EfipGicBeginInterrupt (
  234. PGIC_CONTEXT Context,
  235. UINT32 *InterruptNumber,
  236. VOID **InterruptContext
  237. )
  238. /*++
  239. Routine Description:
  240. This routine is called when an interrupts comes in. This routine determines
  241. the interrupt source.
  242. Arguments:
  243. Context - Supplies a pointer to the interrupt controller context.
  244. InterruptNumber - Supplies a pointer where interrupt line number will be
  245. returned.
  246. InterruptContext - Supplies a pointer where the platform can store a
  247. pointer's worth of context that will be passed back when ending the
  248. interrupt.
  249. Return Value:
  250. None.
  251. --*/
  252. {
  253. UINT32 AcknowledgeRegister;
  254. //
  255. // Read the interrupt acknowledge register, which accepts the highest
  256. // priority interrupt (marking it from pending to active). save this in the
  257. // context area to know what to EOI.
  258. //
  259. AcknowledgeRegister =
  260. READ_GIC_CPU_INTERFACE(Context,
  261. GicCpuInterfaceInterruptAcknowledge);
  262. *InterruptNumber =
  263. AcknowledgeRegister & GIC_CPU_INTERFACE_ACKNOWLEDGE_LINE_MASK;
  264. *InterruptContext = (VOID *)(UINTN)AcknowledgeRegister;
  265. return;
  266. }
  267. VOID
  268. EfipGicEndInterrupt (
  269. PGIC_CONTEXT Context,
  270. UINT32 InterruptNumber,
  271. VOID *InterruptContext
  272. )
  273. /*++
  274. Routine Description:
  275. This routine is called to finish handling of a platform interrupt. This is
  276. where the End-Of-Interrupt would get sent to the interrupt controller.
  277. Arguments:
  278. Context - Supplies a pointer to the interrupt controller context.
  279. InterruptNumber - Supplies the interrupt number that occurred.
  280. InterruptContext - Supplies the context returned by the interrupt
  281. controller when the interrupt began.
  282. Return Value:
  283. None.
  284. --*/
  285. {
  286. //
  287. // Write the value put into the opaque token into the EOI register.
  288. //
  289. if (InterruptNumber != GIC_SPURIOUS_LINE) {
  290. WRITE_GIC_CPU_INTERFACE(Context,
  291. GicCpuInterfaceEndOfInterrupt,
  292. (UINT32)(UINTN)InterruptContext);
  293. }
  294. return;
  295. }
  296. EFI_STATUS
  297. EfipGicSetLineState (
  298. PGIC_CONTEXT Context,
  299. UINT32 LineNumber,
  300. BOOLEAN Enabled,
  301. BOOLEAN EdgeTriggered
  302. )
  303. /*++
  304. Routine Description:
  305. This routine enables or disables an interrupt line.
  306. Arguments:
  307. Context - Supplies the pointer to the controller's context.
  308. LineNumber - Supplies the line number to enable or disable.
  309. Enabled - Supplies a boolean indicating if the line should be enabled or
  310. disabled.
  311. EdgeTriggered - Supplies a boolean indicating if the interrupt is edge
  312. triggered (TRUE) or level triggered (FALSE).
  313. Return Value:
  314. EFI Status code.
  315. --*/
  316. {
  317. UINT32 Configuration;
  318. UINT32 ConfigurationBlock;
  319. UINT32 ConfigurationShift;
  320. UINT32 LineBit;
  321. UINT32 LineBlock;
  322. EFI_STATUS Status;
  323. UINT8 Target;
  324. LineBlock = (LineNumber / 32) * 4;
  325. LineBit = LineNumber % 32;
  326. Status = EFI_SUCCESS;
  327. //
  328. // Fail if the system is trying to set a really wacky interrupt line number.
  329. //
  330. if (LineNumber >= GIC_MAX_LINES) {
  331. Status = EFI_INVALID_PARAMETER;
  332. goto GicSetLineStateEnd;
  333. }
  334. //
  335. // Simply clear out the line if it is being disabled.
  336. //
  337. if (Enabled == FALSE) {
  338. WRITE_GIC_DISTRIBUTOR(Context,
  339. GicDistributorEnableClear + LineBlock,
  340. 1 << LineBit);
  341. Status = EFI_SUCCESS;
  342. goto GicSetLineStateEnd;
  343. }
  344. //
  345. // Set the priority of the requested line.
  346. //
  347. WRITE_GIC_DISTRIBUTOR_BYTE(Context,
  348. GicDistributorPriority + LineNumber,
  349. EFI_GIC_INTERRUPT_PRIORITY);
  350. //
  351. // The interrupt always targets the first processor.
  352. //
  353. Target = 0x01;
  354. WRITE_GIC_DISTRIBUTOR_BYTE(Context,
  355. GicDistributorInterruptTarget + LineNumber,
  356. Target);
  357. //
  358. // Set the configuration register.
  359. //
  360. ConfigurationBlock = 4 * (LineNumber / 16);
  361. ConfigurationShift = 2 * (LineNumber % 16);
  362. Configuration = READ_GIC_DISTRIBUTOR(
  363. Context,
  364. GicDistributorInterruptConfiguration + ConfigurationBlock);
  365. //
  366. // Mask out all the bits being set, then set the appropriate ones.
  367. //
  368. Configuration &= ~(GIC_DISTRIBUTOR_INTERRUPT_CONFIGURATION_MASK <<
  369. ConfigurationShift);
  370. if (EdgeTriggered != FALSE) {
  371. Configuration |=
  372. GIC_DISTRIBUTOR_INTERRUPT_CONFIGURATION_EDGE_TRIGGERED <<
  373. ConfigurationShift;
  374. }
  375. WRITE_GIC_DISTRIBUTOR(
  376. Context,
  377. GicDistributorInterruptConfiguration + ConfigurationBlock,
  378. Configuration);
  379. //
  380. // Enable the line.
  381. //
  382. WRITE_GIC_DISTRIBUTOR(Context,
  383. GicDistributorEnableSet + LineBlock,
  384. 1 << LineBit);
  385. GicSetLineStateEnd:
  386. return Status;
  387. }
  388. //
  389. // --------------------------------------------------------- Internal Functions
  390. //