omapintr.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. omapintr.c
  5. Abstract:
  6. This module implements MPU interrupt controller support for the TI OMAP3
  7. SoCs.
  8. Author:
  9. Evan Green 3-Sep-2012
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. //
  17. // Include kernel.h, but be cautious about which APIs are used. Most of the
  18. // system depends on the hardware modules. Limit use to HL, RTL and AR routines.
  19. //
  20. #include <minoca/kernel/kernel.h>
  21. #include "omap3.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // This bit is set if the interrupt routes to the FIQ interrupt.
  27. //
  28. #define MPU_INTERRUPT_ROUTE_TO_FIQ 0x00000001
  29. //
  30. // Define the shift amount for the priority component of an interrupt line
  31. // configuration.
  32. //
  33. #define MPU_INTERRUPT_PRIORITY_SHIFT 2
  34. //
  35. // If any of these bits are set, then the interrupt is spurious.
  36. //
  37. #define MPU_SPURIOUS_INTERRUPT_MASK 0xFFFFFF80
  38. //
  39. // Set this bit to allow new IRQ interrupts to come in.
  40. //
  41. #define MPU_CONTROL_NEW_IRQ_AGREEMENT 0x00000001
  42. //
  43. // --------------------------------------------------------------------- Macros
  44. //
  45. //
  46. // This macro reads from the OMAP3 interrupt controller. The parameter
  47. // should be MPU_REGISTER value.
  48. //
  49. #define READ_INTERRUPT_REGISTER(_Register) \
  50. HlReadRegister32((PULONG)HlOmap3InterruptController + (_Register))
  51. //
  52. // This macro writes to the OMAP3 interrupt controller. _Register
  53. // should be MPU_REGISTER value, and _Value should be a ULONG.
  54. //
  55. #define WRITE_INTERRUPT_REGISTER(_Register, _Value) \
  56. HlWriteRegister32((PULONG)HlOmap3InterruptController + (_Register), \
  57. (_Value))
  58. //
  59. // ----------------------------------------------- Internal Function Prototypes
  60. //
  61. KSTATUS
  62. HlpOmap3InterruptInitializeIoUnit (
  63. PVOID Context
  64. );
  65. INTERRUPT_CAUSE
  66. HlpOmap3InterruptBegin (
  67. PVOID Context,
  68. PINTERRUPT_LINE FiringLine,
  69. PULONG MagicCandy
  70. );
  71. VOID
  72. HlpOmap3InterruptEndOfInterrupt (
  73. PVOID Context,
  74. ULONG MagicCandy
  75. );
  76. KSTATUS
  77. HlpOmap3InterruptRequestInterrupt (
  78. PVOID Context,
  79. PINTERRUPT_LINE Line,
  80. ULONG Vector,
  81. PINTERRUPT_HARDWARE_TARGET Target
  82. );
  83. KSTATUS
  84. HlpOmap3InterruptSetLineState (
  85. PVOID Context,
  86. PINTERRUPT_LINE Line,
  87. PINTERRUPT_LINE_STATE State,
  88. PVOID ResourceData,
  89. UINTN ResourceDataSize
  90. );
  91. VOID
  92. HlpOmap3InterruptMaskLine (
  93. PVOID Context,
  94. PINTERRUPT_LINE Line,
  95. BOOL Enable
  96. );
  97. KSTATUS
  98. HlpOmap3InterruptDescribeLines (
  99. VOID
  100. );
  101. //
  102. // ------------------------------------------------------ Data Type Definitions
  103. //
  104. typedef enum _MPU_REGISTERS {
  105. MpuSystemConfiguration = 0x4, // SYSCONFIG
  106. MpuSystemStatus = 0x5, // SYSSTATUS
  107. MpuActiveIrq = 0x10, // SIR_IRQ
  108. MpuActiveFiq = 0x11, // SIR_FIQ
  109. MpuControl = 0x12, // CONTROL
  110. MpuProtection = 0x13, // PROTECTION
  111. MpuIdle = 0x14, // IDLE
  112. MpuIrqPriority = 0x18, // IRQ_PRIORITY
  113. MpuFiqPriority = 0x19, // FIQ_PRIORITY
  114. MpuCurrentPriority = 0x1A, // THRESHOLD
  115. MpuRawInterruptStatus = 0x20, // ITR (+0x20 * n)
  116. MpuMask = 0x21, // MIR (+0x20 * n)
  117. MpuMaskClear = 0x22, // MIR_CLEAR (+0x20 * n)
  118. MpuMaskSet = 0x23, // MIR_SET (+0x20 * n)
  119. MpuSoftwareInterruptSet = 0x24, // ISR_SET (+0x20 * n)
  120. MpuSoftwareInterruptClear = 0x25, // ISR_CLEAR (+0x20 * n)
  121. MpuIrqStatus = 0x26, // PENDING_IRQ (+0x20 * n)
  122. MpuFiqStatus = 0x27, // PENDING_FIQ (+0x20 * n)
  123. MpuInterrupt = 0x40 // ILR[96]
  124. } MPU_REGISTERS, *PMPU_REGISTERS;
  125. //
  126. // -------------------------------------------------------------------- Globals
  127. //
  128. //
  129. // Store a pointer to the virtual address of the interrupt controller.
  130. //
  131. PVOID HlOmap3InterruptController = NULL;
  132. INTERRUPT_FUNCTION_TABLE HlOmap3InterruptFunctionTable = {
  133. HlpOmap3InterruptInitializeIoUnit,
  134. HlpOmap3InterruptSetLineState,
  135. HlpOmap3InterruptMaskLine,
  136. HlpOmap3InterruptBegin,
  137. NULL,
  138. HlpOmap3InterruptEndOfInterrupt,
  139. HlpOmap3InterruptRequestInterrupt,
  140. NULL,
  141. NULL,
  142. NULL,
  143. NULL,
  144. NULL
  145. };
  146. //
  147. // ------------------------------------------------------------------ Functions
  148. //
  149. VOID
  150. HlpOmap3InterruptModuleEntry (
  151. VOID
  152. )
  153. /*++
  154. Routine Description:
  155. This routine is the entry point for the OMAP3 Interrupt hardware
  156. module. Its role is to detect and report the prescense of an Integrator/CP
  157. interrupt controller.
  158. Arguments:
  159. None.
  160. Return Value:
  161. None.
  162. --*/
  163. {
  164. INTERRUPT_CONTROLLER_DESCRIPTION NewController;
  165. KSTATUS Status;
  166. //
  167. // Attempt to find the OMAP3 ACPI table.
  168. //
  169. HlOmap3Table = HlGetAcpiTable(OMAP3_SIGNATURE, NULL);
  170. if (HlOmap3Table == NULL) {
  171. goto Omap3InterruptModuleEntryEnd;
  172. }
  173. //
  174. // Zero out the controller description.
  175. //
  176. RtlZeroMemory(&NewController, sizeof(INTERRUPT_CONTROLLER_DESCRIPTION));
  177. if (HlOmap3Table->InterruptControllerPhysicalAddress != 0) {
  178. //
  179. // Initialize the new controller structure.
  180. //
  181. NewController.TableVersion = INTERRUPT_CONTROLLER_DESCRIPTION_VERSION;
  182. RtlCopyMemory(&(NewController.FunctionTable),
  183. &HlOmap3InterruptFunctionTable,
  184. sizeof(INTERRUPT_FUNCTION_TABLE));
  185. NewController.Context = NULL;
  186. NewController.Identifier = 0;
  187. NewController.ProcessorCount = 0;
  188. NewController.PriorityCount = OMAP3_INTERRUPT_PRIORITY_COUNT;
  189. //
  190. // Register the controller with the system.
  191. //
  192. Status = HlRegisterHardware(HardwareModuleInterruptController,
  193. &NewController);
  194. if (!KSUCCESS(Status)) {
  195. goto Omap3InterruptModuleEntryEnd;
  196. }
  197. }
  198. Omap3InterruptModuleEntryEnd:
  199. return;
  200. }
  201. //
  202. // --------------------------------------------------------- Internal Functions
  203. //
  204. KSTATUS
  205. HlpOmap3InterruptInitializeIoUnit (
  206. PVOID Context
  207. )
  208. /*++
  209. Routine Description:
  210. This routine initializes an interrupt controller. It's responsible for
  211. masking all interrupt lines on the controller and setting the current
  212. priority to the lowest (allow all interrupts). Once completed successfully,
  213. it is expected that interrupts can be enabled at the processor core with
  214. no interrupts occurring.
  215. Arguments:
  216. Context - Supplies the pointer to the controller's context, provided by the
  217. hardware module upon initialization.
  218. Return Value:
  219. STATUS_SUCCESS on success.
  220. Other status codes on failure.
  221. --*/
  222. {
  223. KSTATUS Status;
  224. if (HlOmap3InterruptController == NULL) {
  225. HlOmap3InterruptController = HlMapPhysicalAddress(
  226. HlOmap3Table->InterruptControllerPhysicalAddress,
  227. OMAP3_INTERRUPT_CONTROLLER_SIZE,
  228. TRUE);
  229. if (HlOmap3InterruptController == NULL) {
  230. Status = STATUS_INSUFFICIENT_RESOURCES;
  231. goto CpInterruptInitializeIoUnitEnd;
  232. }
  233. //
  234. // Describe the interrupt lines on this controller.
  235. //
  236. Status = HlpOmap3InterruptDescribeLines();
  237. if (!KSUCCESS(Status)) {
  238. goto CpInterruptInitializeIoUnitEnd;
  239. }
  240. }
  241. //
  242. // Disable all interrupts on the controller.
  243. //
  244. WRITE_INTERRUPT_REGISTER(MpuMaskSet + (0 * 8), 0xFFFFFFFF);
  245. WRITE_INTERRUPT_REGISTER(MpuMaskSet + (1 * 8), 0xFFFFFFFF);
  246. WRITE_INTERRUPT_REGISTER(MpuMaskSet + (2 * 8), 0xFFFFFFFF);
  247. WRITE_INTERRUPT_REGISTER(MpuCurrentPriority,
  248. OMAP3_INTERRUPT_PRIORITY_COUNT);
  249. //
  250. // Reset both interrupt lines and set the new agreement.
  251. //
  252. WRITE_INTERRUPT_REGISTER(MpuControl, 3);
  253. Status = STATUS_SUCCESS;
  254. CpInterruptInitializeIoUnitEnd:
  255. return Status;
  256. }
  257. INTERRUPT_CAUSE
  258. HlpOmap3InterruptBegin (
  259. PVOID Context,
  260. PINTERRUPT_LINE FiringLine,
  261. PULONG MagicCandy
  262. )
  263. /*++
  264. Routine Description:
  265. This routine is called when an interrupt fires. Its role is to determine
  266. if an interrupt has fired on the given controller, accept it, and determine
  267. which line fired if any. This routine will always be called with interrupts
  268. disabled at the processor core.
  269. Arguments:
  270. Context - Supplies the pointer to the controller's context, provided by the
  271. hardware module upon initialization.
  272. FiringLine - Supplies a pointer where the interrupt hardware module will
  273. fill in which line fired, if applicable.
  274. MagicCandy - Supplies a pointer where the interrupt hardware module can
  275. store 32 bits of private information regarding this interrupt. This
  276. information will be returned to it when the End Of Interrupt routine
  277. is called.
  278. Return Value:
  279. Returns an interrupt cause indicating whether or not an interrupt line,
  280. spurious interrupt, or no interrupt fired on this controller.
  281. --*/
  282. {
  283. ULONG ActiveIrq;
  284. ULONG ActiveIrqPriority;
  285. //
  286. // Get the currently asserting line. If it's a spurious interrupt, return
  287. // immediately.
  288. //
  289. ActiveIrq = READ_INTERRUPT_REGISTER(MpuActiveIrq);
  290. if ((ActiveIrq & MPU_SPURIOUS_INTERRUPT_MASK) != 0) {
  291. return InterruptCauseSpuriousInterrupt;
  292. }
  293. FiringLine->Type = InterruptLineControllerSpecified;
  294. FiringLine->U.Local.Controller = 0;
  295. FiringLine->U.Local.Line = ActiveIrq;
  296. //
  297. // Save the old priority into the magic candy, and then set the priority
  298. // to the priority of the interrupting source.
  299. //
  300. *MagicCandy = READ_INTERRUPT_REGISTER(MpuCurrentPriority);
  301. ActiveIrqPriority = READ_INTERRUPT_REGISTER(MpuIrqPriority);
  302. WRITE_INTERRUPT_REGISTER(MpuCurrentPriority, ActiveIrqPriority);
  303. //
  304. // Write the New IRQ Agreement bit so that additional interrupts of higher
  305. // priority can come in.
  306. //
  307. WRITE_INTERRUPT_REGISTER(MpuControl, MPU_CONTROL_NEW_IRQ_AGREEMENT);
  308. return InterruptCauseLineFired;
  309. }
  310. VOID
  311. HlpOmap3InterruptEndOfInterrupt (
  312. PVOID Context,
  313. ULONG MagicCandy
  314. )
  315. /*++
  316. Routine Description:
  317. This routine is called after an interrupt has fired and been serviced. Its
  318. role is to tell the interrupt controller that processing has completed.
  319. This routine will always be called with interrupts disabled at the
  320. processor core.
  321. Arguments:
  322. Context - Supplies the pointer to the controller's context, provided by the
  323. hardware module upon initialization.
  324. MagicCandy - Supplies the magic candy that that the interrupt hardware
  325. module stored when the interrupt began.
  326. Return Value:
  327. None.
  328. --*/
  329. {
  330. //
  331. // The magic candy value contained the priority register when this interrupt
  332. // began. Restore that value.
  333. //
  334. WRITE_INTERRUPT_REGISTER(MpuCurrentPriority, MagicCandy);
  335. return;
  336. }
  337. KSTATUS
  338. HlpOmap3InterruptRequestInterrupt (
  339. PVOID Context,
  340. PINTERRUPT_LINE Line,
  341. ULONG Vector,
  342. PINTERRUPT_HARDWARE_TARGET Target
  343. )
  344. /*++
  345. Routine Description:
  346. This routine requests a hardware interrupt on the given line.
  347. Arguments:
  348. Context - Supplies the pointer to the controller's context, provided by the
  349. hardware module upon initialization.
  350. Line - Supplies a pointer to the interrupt line to spark.
  351. Vector - Supplies the vector to generate the interrupt on (for vectored
  352. architectures only).
  353. Target - Supplies a pointer to the set of processors to target.
  354. Return Value:
  355. STATUS_SUCCESS on success.
  356. Error code on failure.
  357. --*/
  358. {
  359. //
  360. // This feature will be implemented when it is required (probably by
  361. // power management).
  362. //
  363. return STATUS_NOT_IMPLEMENTED;
  364. }
  365. KSTATUS
  366. HlpOmap3InterruptSetLineState (
  367. PVOID Context,
  368. PINTERRUPT_LINE Line,
  369. PINTERRUPT_LINE_STATE State,
  370. PVOID ResourceData,
  371. UINTN ResourceDataSize
  372. )
  373. /*++
  374. Routine Description:
  375. This routine enables or disables and configures an interrupt line.
  376. Arguments:
  377. Context - Supplies the pointer to the controller's context, provided by the
  378. hardware module upon initialization.
  379. Line - Supplies a pointer to the line to set up. This will always be a
  380. controller specified line.
  381. State - Supplies a pointer to the new configuration of the line.
  382. ResourceData - Supplies an optional pointer to the device specific resource
  383. data for the interrupt line.
  384. ResourceDataSize - Supplies the size of the resource data, in bytes.
  385. Return Value:
  386. Status code.
  387. --*/
  388. {
  389. ULONG InterruptIndex;
  390. ULONG InterruptOffset;
  391. KSTATUS Status;
  392. ULONG Value;
  393. if ((Line->Type != InterruptLineControllerSpecified) ||
  394. (Line->U.Local.Controller != 0) ||
  395. (Line->U.Local.Line >= OMAP3_INTERRUPT_LINE_COUNT)) {
  396. Status = STATUS_INVALID_PARAMETER;
  397. goto Omap3InterruptSetLineStateEnd;
  398. }
  399. if ((State->Output.Type != InterruptLineControllerSpecified) ||
  400. (State->Output.U.Local.Controller != INTERRUPT_CPU_IDENTIFIER) ||
  401. (State->Output.U.Local.Line != INTERRUPT_CPU_IRQ_PIN)) {
  402. Status = STATUS_INVALID_PARAMETER;
  403. goto Omap3InterruptSetLineStateEnd;
  404. }
  405. InterruptOffset = Line->U.Local.Line / 32;
  406. InterruptIndex = Line->U.Local.Line - (InterruptOffset * 32);
  407. //
  408. // To disable, set the interrupt mask and clean the interrupt line.
  409. //
  410. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) == 0) {
  411. WRITE_INTERRUPT_REGISTER(MpuMaskSet + (8 * InterruptOffset),
  412. 1 << InterruptIndex);
  413. WRITE_INTERRUPT_REGISTER(MpuInterrupt + Line->U.Local.Line, 0);
  414. //
  415. // To enable, write the interrupt configuration and routing into the
  416. // controller.
  417. //
  418. } else {
  419. Value = (OMAP3_INTERRUPT_PRIORITY_COUNT - State->HardwarePriority) + 1;
  420. Value = Value << MPU_INTERRUPT_PRIORITY_SHIFT;
  421. WRITE_INTERRUPT_REGISTER(MpuInterrupt + Line->U.Local.Line, Value);
  422. WRITE_INTERRUPT_REGISTER(MpuMaskClear + (8 * InterruptOffset),
  423. 1 << InterruptIndex);
  424. }
  425. Status = STATUS_SUCCESS;
  426. Omap3InterruptSetLineStateEnd:
  427. return Status;
  428. }
  429. VOID
  430. HlpOmap3InterruptMaskLine (
  431. PVOID Context,
  432. PINTERRUPT_LINE Line,
  433. BOOL Enable
  434. )
  435. /*++
  436. Routine Description:
  437. This routine masks or unmasks an interrupt line, leaving the rest of the
  438. line state intact.
  439. Arguments:
  440. Context - Supplies the pointer to the controller's context, provided by the
  441. hardware module upon initialization.
  442. Line - Supplies a pointer to the line to maek or unmask. This will always
  443. be a controller specified line.
  444. Enable - Supplies a boolean indicating whether to mask the interrupt,
  445. preventing interrupts from coming through (FALSE), or enable the line
  446. and allow interrupts to come through (TRUE).
  447. Return Value:
  448. None.
  449. --*/
  450. {
  451. ULONG InterruptIndex;
  452. ULONG InterruptOffset;
  453. MPU_REGISTERS Register;
  454. InterruptOffset = Line->U.Local.Line / 32;
  455. InterruptIndex = Line->U.Local.Line - (InterruptOffset * 32);
  456. //
  457. // To disable, set the interrupt mask and clean the interrupt line.
  458. //
  459. if (Enable == FALSE) {
  460. Register = MpuMaskSet;
  461. } else {
  462. Register = MpuMaskClear;
  463. }
  464. WRITE_INTERRUPT_REGISTER(Register + (8 * InterruptOffset),
  465. 1 << InterruptIndex);
  466. return;
  467. }
  468. KSTATUS
  469. HlpOmap3InterruptDescribeLines (
  470. VOID
  471. )
  472. /*++
  473. Routine Description:
  474. This routine describes all interrupt lines to the system.
  475. Arguments:
  476. None.
  477. Return Value:
  478. Status code.
  479. --*/
  480. {
  481. INTERRUPT_LINES_DESCRIPTION Lines;
  482. KSTATUS Status;
  483. RtlZeroMemory(&Lines, sizeof(INTERRUPT_LINES_DESCRIPTION));
  484. Lines.Version = INTERRUPT_LINES_DESCRIPTION_VERSION;
  485. //
  486. // Describe the normal lines on the OMAP3.
  487. //
  488. Lines.Type = InterruptLinesStandardPin;
  489. Lines.Controller = 0;
  490. Lines.LineStart = 0;
  491. Lines.LineEnd = OMAP3_INTERRUPT_LINE_COUNT;
  492. Lines.Gsi = HlOmap3Table->InterruptControllerGsiBase;
  493. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  494. if (!KSUCCESS(Status)) {
  495. goto Omap3InterruptDescribeLinesEnd;
  496. }
  497. //
  498. // Register the output lines.
  499. //
  500. Lines.Type = InterruptLinesOutput;
  501. Lines.OutputControllerIdentifier = INTERRUPT_CPU_IDENTIFIER;
  502. Lines.LineStart = INTERRUPT_ARM_MIN_CPU_LINE;
  503. Lines.LineEnd = INTERRUPT_ARM_MAX_CPU_LINE;
  504. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  505. if (!KSUCCESS(Status)) {
  506. goto Omap3InterruptDescribeLinesEnd;
  507. }
  508. Omap3InterruptDescribeLinesEnd:
  509. return Status;
  510. }