gic.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2013-07-20 Bernard first version
  9. * 2014-04-03 Grissiom many enhancements
  10. * 2018-11-22 Jesven add rt_hw_ipi_send()
  11. * add rt_hw_ipi_handler_install()
  12. */
  13. #include <rthw.h>
  14. #include <rtthread.h>
  15. #include "gic.h"
  16. #include "cp15.h"
  17. struct arm_gic
  18. {
  19. rt_uint32_t offset; /* the first interrupt index in the vector table */
  20. rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
  21. rt_uint32_t cpu_hw_base; /* the base addrees of the gic cpu interface */
  22. };
  23. static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
  24. /** Macro to access the Generic Interrupt Controller Interface (GICC)
  25. */
  26. #define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U) /* GICC_CTLR */
  27. #define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U) /* GICC_PMR */
  28. #define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U) /* GICC_BPR */
  29. #define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU) /* GICC_IAR */
  30. #define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U) /* GICC_EOIR */
  31. #define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U) /* GICC_RPR */
  32. #define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U) /* GICC_HPPIR */
  33. #define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU) /* GICC_IIDR */
  34. /** Macro to access the Generic Interrupt Controller Distributor (GICD)
  35. */
  36. #define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U) /* GICD_CTLR */
  37. #define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U) /* GICD_TYPER */
  38. #define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U) /* GICD_IGROUPRn */
  39. #define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U) /* GICD_ISENABLERn */
  40. #define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U) /* GICD_ICENABLERn */
  41. #define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U) /* GICD_ISPENDRn */
  42. #define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U) /* GICD_ICPENDRn */
  43. #define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U) /* GICD_ISACTIVERn */
  44. #define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U) /* GICD_ICACTIVERn */
  45. #define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U) /* GICD_IPRIORITYRn */
  46. #define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U) /* GICD_ITARGETSRn */
  47. #define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U) /* GICD_ICFGRn */
  48. #define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U) /* GICD_SGIR */
  49. #define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U) /* GICD_CPENDSGIRn */
  50. #define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U) /* GICD_SPENDSGIRn */
  51. #define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U) /* ICPIDR2 */
  52. static unsigned int _gic_max_irq;
  53. /**
  54. * @brief Get the active interrupt number
  55. *
  56. * @note Read the GICC_IAR register and add the interrupt number offset to get
  57. * the actual interrupt number.
  58. * This read acts as an acknowledge for the interrupt, changing the interrupt
  59. * state from pending to active.
  60. *
  61. * GICC_IAR register bit fields:
  62. * - GICC_IAR[31:13]: Reserved, read as 0
  63. * - GICC_IAR[12:10]: CPUID
  64. * For SGIs: This value is the CPUID that requested the interrupt.
  65. * For other interrupts: This value reads as 0 (RAZ).
  66. * - GICC_IAR[9:0]: Interrupt ID
  67. *
  68. * @param index GIC controller index
  69. *
  70. * @return The actual interrupt number (with offset added).
  71. * Note: For SGIs, the return value may include CPUID information in the upper bits.
  72. */
  73. int arm_gic_get_active_irq(rt_uint32_t index)
  74. {
  75. int irq;
  76. RT_ASSERT(index < ARM_GIC_MAX_NR);
  77. irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base);
  78. irq += _gic_table[index].offset;
  79. return irq;
  80. }
  81. /**
  82. * @brief Acknowledge and end the interrupt
  83. *
  84. * @note This function completes the interrupt handling by:
  85. * 1. Clearing the pending status of the interrupt in the Distributor (GICD_ICPENDRn).
  86. * 2. Writing the interrupt ID to the End of Interrupt Register (GICC_EOIR).
  87. * This signals the GIC that interrupt processing is complete and changes
  88. * the interrupt state from active to inactive.
  89. *
  90. * This function should be called after the interrupt handler has finished
  91. * processing the interrupt, typically at the end of the interrupt service routine.
  92. *
  93. * @param index GIC controller index
  94. * @param irq The actual interrupt number (with offset) to acknowledge
  95. */
  96. void arm_gic_ack(rt_uint32_t index, int irq)
  97. {
  98. rt_uint32_t mask = 1U << (irq % 32U);
  99. RT_ASSERT(index < ARM_GIC_MAX_NR);
  100. irq = irq - _gic_table[index].offset;
  101. RT_ASSERT(irq >= 0U);
  102. GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
  103. GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
  104. }
  105. /**
  106. * @brief Disable the forwarding of the corresponding interrupt
  107. *
  108. * @param index GIC controller index
  109. * @param irq The actual interrupt number(with offset)
  110. */
  111. void arm_gic_mask(rt_uint32_t index, int irq)
  112. {
  113. rt_uint32_t mask = 1U << (irq % 32U);
  114. RT_ASSERT(index < ARM_GIC_MAX_NR);
  115. irq = irq - _gic_table[index].offset;
  116. RT_ASSERT(irq >= 0U);
  117. GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
  118. }
  119. /**
  120. * @brief Enables the forwarding of the corresponding interrupt
  121. *
  122. * @param index GIC controller index
  123. * @param irq The actual interrupt number(with offset)
  124. */
  125. void arm_gic_umask(rt_uint32_t index, int irq)
  126. {
  127. rt_uint32_t mask = 1U << (irq % 32U);
  128. RT_ASSERT(index < ARM_GIC_MAX_NR);
  129. irq = irq - _gic_table[index].offset;
  130. RT_ASSERT(irq >= 0U);
  131. GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; /* GICD_ISENABLERn */
  132. }
  133. /**
  134. * @brief Identifies whether the interrupt is pending
  135. *
  136. * @param index GIC controller index
  137. * @param irq The actual interrupt number(with offset)
  138. *
  139. * @return 0: not pending, 1: pending
  140. */
  141. rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
  142. {
  143. rt_uint32_t pend;
  144. RT_ASSERT(index < ARM_GIC_MAX_NR);
  145. irq = irq - _gic_table[index].offset;
  146. RT_ASSERT(irq >= 0U);
  147. if (irq >= 16U)
  148. {
  149. pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL; /* GICD_ISPENDRn */
  150. }
  151. else
  152. {
  153. /* INTID 0-15 Software Generated Interrupt */
  154. pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL; /* GICD_SPENDSGIRn */
  155. /* No CPU identification offered */
  156. if (pend != 0U)
  157. {
  158. pend = 1U;
  159. }
  160. else
  161. {
  162. pend = 0U;
  163. }
  164. }
  165. return (pend);
  166. }
  167. /**
  168. * @brief Set the interrupt as pending
  169. *
  170. * @param index GIC controller index
  171. * @param irq The actual interrupt number(with offset)
  172. */
  173. void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
  174. {
  175. RT_ASSERT(index < ARM_GIC_MAX_NR);
  176. irq = irq - _gic_table[index].offset;
  177. RT_ASSERT(irq >= 0U);
  178. if (irq >= 16U)
  179. {
  180. GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
  181. }
  182. else
  183. {
  184. /* INTID 0-15 Software Generated Interrupt */
  185. /* Forward the interrupt to the CPU interface that requested it */
  186. GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
  187. }
  188. }
  189. /**
  190. * @brief clears the pending state of the interrupt
  191. *
  192. * @param index GIC controller index
  193. * @param irq The actual interrupt number(with offset)
  194. */
  195. void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
  196. {
  197. rt_uint32_t mask;
  198. RT_ASSERT(index < ARM_GIC_MAX_NR);
  199. irq = irq - _gic_table[index].offset;
  200. RT_ASSERT(irq >= 0U);
  201. if (irq >= 16U)
  202. {
  203. mask = 1U << (irq % 32U);
  204. GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
  205. }
  206. else
  207. {
  208. mask = 1U << ((irq % 4U) * 8U);
  209. GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
  210. }
  211. }
  212. /**
  213. * @brief Configure whether the corresponding interrupt is edge-triggered or level-sensitive
  214. *
  215. * @note For SGIs (interrupt IDs 0-15), the Int_config fields are read-only,
  216. * meaning that GICD_ICFGR0 is read-only. Writing to this register for SGIs
  217. * will have no effect.
  218. *
  219. * For PPIs (interrupt IDs 16-31), it is IMPLEMENTATION DEFINED whether
  220. * the most significant bit of the Int_config field is programmable.
  221. * Some implementations may make PPI configuration registers read-only.
  222. *
  223. * This function is primarily intended for configuring SPIs (interrupt IDs 32+),
  224. * which have fully programmable configuration registers.
  225. *
  226. * @param index GIC controller index
  227. * @param irq The actual interrupt number(with offset)
  228. * @param config 0: level-sensitive, 1: edge-triggered
  229. */
  230. void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
  231. {
  232. rt_uint32_t icfgr;
  233. rt_uint32_t shift;
  234. RT_ASSERT(index < ARM_GIC_MAX_NR);
  235. irq = irq - _gic_table[index].offset;
  236. RT_ASSERT(irq >= 0U);
  237. icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
  238. shift = (irq % 16U) << 1U;
  239. icfgr &= (~(3U << shift));
  240. icfgr |= (config << (shift + 1));
  241. GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
  242. }
  243. /**
  244. * @brief Identifies whether the corresponding interrupt is edge-triggered or level-sensitive
  245. *
  246. * @param index GIC controller index
  247. * @param irq The actual interrupt number(with offset)
  248. *
  249. * @return 0: level-sensitive, 1: edge-triggered
  250. */
  251. rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
  252. {
  253. RT_ASSERT(index < ARM_GIC_MAX_NR);
  254. irq = irq - _gic_table[index].offset;
  255. RT_ASSERT(irq >= 0U);
  256. return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
  257. }
  258. /**
  259. * @brief Deactivates the corresponding interrupt
  260. *
  261. * @param index GIC controller index
  262. * @param irq The actual interrupt number(with offset)
  263. */
  264. void arm_gic_clear_active(rt_uint32_t index, int irq)
  265. {
  266. rt_uint32_t mask = 1U << (irq % 32U);
  267. RT_ASSERT(index < ARM_GIC_MAX_NR);
  268. irq = irq - _gic_table[index].offset;
  269. RT_ASSERT(irq >= 0U);
  270. GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
  271. }
  272. /**
  273. * @brief Set up the cpu mask for the specific interrupt
  274. *
  275. * @param index GIC controller index
  276. * @param irq The actual interrupt number(with offset)
  277. *
  278. * @param cpumask CPU targets. Only the lower 8 bits are valid (bits [7:0]).
  279. */
  280. void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
  281. {
  282. rt_uint32_t old_tgt;
  283. RT_ASSERT(index < ARM_GIC_MAX_NR);
  284. irq = irq - _gic_table[index].offset;
  285. RT_ASSERT(irq >= 0U);
  286. old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
  287. old_tgt &= ~(0x0FFUL << ((irq % 4U)*8U));
  288. old_tgt |= cpumask << ((irq % 4U)*8U);
  289. GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
  290. }
  291. /**
  292. * @brief Get the CPU targets for the specific interrupt
  293. *
  294. * @param index GIC controller index
  295. * @param irq The actual interrupt number(with offset)
  296. *
  297. * @return CPU targets
  298. */
  299. rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
  300. {
  301. RT_ASSERT(index < ARM_GIC_MAX_NR);
  302. irq = irq - _gic_table[index].offset;
  303. RT_ASSERT(irq >= 0U);
  304. return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
  305. }
  306. /**
  307. * @brief Set the priority for the specific interrupt
  308. *
  309. * @note The lower the value, the greater the priority of the corresponding interrupt.
  310. *
  311. * @param index GIC controller index
  312. * @param irq The actual interrupt number(with offset)
  313. * @param priority The priority to set.Only the lower 8 bits are valid (bits [7:0]).
  314. */
  315. void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
  316. {
  317. rt_uint32_t mask;
  318. RT_ASSERT(index < ARM_GIC_MAX_NR);
  319. irq = irq - _gic_table[index].offset;
  320. RT_ASSERT(irq >= 0U);
  321. mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
  322. mask &= ~(0xFFUL << ((irq % 4U) * 8U));
  323. mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
  324. GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
  325. }
  326. /**
  327. * @brief Get the priority for the specific interrupt
  328. *
  329. * @param index GIC controller index
  330. * @param irq The actual interrupt number(with offset)
  331. *
  332. * @return The priority of the corresponding interrupt.Only the lower 8 bits are valid (bits [7:0]).
  333. */
  334. rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
  335. {
  336. RT_ASSERT(index < ARM_GIC_MAX_NR);
  337. irq = irq - _gic_table[index].offset;
  338. RT_ASSERT(irq >= 0U);
  339. return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
  340. }
  341. /**
  342. * @brief Set the priority mask for the specific CPU
  343. *
  344. * @note Only interrupts with higher priority than the value in this
  345. * register are signaled to the processor.
  346. *
  347. * @param index GIC controller index
  348. * @param priority The priority mask to set.Only the lower 8 bits are valid (bits [7:0]).
  349. */
  350. void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
  351. {
  352. RT_ASSERT(index < ARM_GIC_MAX_NR);
  353. /* set priority mask */
  354. GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
  355. }
  356. /**
  357. * @brief Get the priority mask for the specific CPU
  358. *
  359. * @param index GIC controller index
  360. *
  361. * @return The priority mask to return. Only the lower 8 bits are valid (bits [7:0]).
  362. */
  363. rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
  364. {
  365. RT_ASSERT(index < ARM_GIC_MAX_NR);
  366. return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
  367. }
  368. /**
  369. * @brief Set the binary point value for interrupt priority splitting
  370. *
  371. * @note This function sets the GICC_BPR (Binary Point Register) value, which is used
  372. * to split the priority field into group priority and subpriority fields.
  373. * The binary point determines how many bits are used for group priority:
  374. * - A larger value results in fewer bits for group priority,
  375. * reducing interrupt preemption capability.
  376. * - A smaller value results in more bits for group priority,
  377. * increasing interrupt preemption capability.
  378. * - Only the lower 3 bits are valid (bits [2:0], range 0-7).
  379. *
  380. * @param index GIC controller index
  381. * @param binary_point Binary point value. Only the lower 3 bits are valid (bits [2:0]).
  382. */
  383. void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
  384. {
  385. GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
  386. }
  387. /**
  388. * @brief Get the binary point value for interrupt priority splitting
  389. *
  390. * @param index GIC controller index
  391. * @return Binary point value. Only the lower 3 bits are valid (bits [2:0]).
  392. */
  393. rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
  394. {
  395. return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
  396. }
  397. /**
  398. * @brief Get the status of the specified interrupt
  399. *
  400. * @note This function reads both the active and pending status of the interrupt
  401. *
  402. * @param index GIC controller index
  403. * @param irq The actual interrupt number (with offset)
  404. *
  405. * @return Encoded interrupt status:
  406. * - Bit 0: Pending status
  407. * - Bit 1: Active status
  408. */
  409. rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
  410. {
  411. rt_uint32_t pending;
  412. rt_uint32_t active;
  413. RT_ASSERT(index < ARM_GIC_MAX_NR);
  414. irq = irq - _gic_table[index].offset;
  415. RT_ASSERT(irq >= 0U);
  416. active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
  417. pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
  418. return ((active << 1U) | pending);
  419. }
  420. /**
  421. * @brief Send a Software Generated Interrupt (SGI) to specified CPU(s)
  422. *
  423. * @note This function writes to the GICD_SGIR (Software Generated Interrupt Register)
  424. * to generate an SGI. The register value is constructed as follows:
  425. * - Bits [25:24]: TargetListFilter - determines how the SGI is forwarded
  426. * * 0b00: Forward to CPUs specified in CPUTargetList
  427. * * 0b01: Forward to all CPUs except the requesting CPU
  428. * * 0b10: Forward only to the requesting CPU
  429. * * 0b11: Reserved
  430. * - Bits [23:16]: CPUTargetList - 8-bit mask specifying target CPUs
  431. * (only used when TargetListFilter = 0b00)
  432. * * Each bit represents a CPU: bit 0 = CPU 0, bit 1 = CPU 1, etc.
  433. * - Bits [3:0]: SGIINTID - the SGI interrupt ID (0-15)
  434. *
  435. * @param index GIC controller index
  436. * @param irq The actual interrupt number (with offset).
  437. * @param target_list CPU target mask. Only the lower 8 bits are valid (bits [7:0]).
  438. * Each bit represents a CPU. Used when filter_list = 0b00.
  439. * @param filter_list Target list filter mode. Only the lower 2 bits are valid (bits [1:0]).
  440. * Determines how the SGI is forwarded to CPUs.
  441. */
  442. void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list)
  443. {
  444. RT_ASSERT(index < ARM_GIC_MAX_NR);
  445. irq = irq - _gic_table[index].offset;
  446. RT_ASSERT(irq >= 0U);
  447. GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
  448. }
  449. /**
  450. * @brief Get the highest priority pending interrupt ID without acknowledging it
  451. *
  452. * @note This function reads the GICC_HPPIR (Highest Priority Pending Interrupt Register)
  453. * to get the interrupt ID of the highest priority pending interrupt.
  454. *
  455. * Unlike reading GICC_IAR (via arm_gic_get_active_irq()), reading GICC_HPPIR
  456. * does NOT acknowledge the interrupt. This means:
  457. * - The interrupt state remains unchanged (still pending)
  458. *
  459. * @param index GIC controller index
  460. *
  461. * @return The 32-bit value read from the GICC_HPPIR register.
  462. * The caller can extract specific fields (hardware interrupt ID without offset added).
  463. */
  464. rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
  465. {
  466. RT_ASSERT(index < ARM_GIC_MAX_NR);
  467. return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
  468. }
  469. /**
  470. * @brief Get the CPU Interface Identification Register (GICC_IIDR) value
  471. *
  472. * @param index GIC controller index
  473. *
  474. * @return The 32-bit value read from the GICC_IIDR register.
  475. * The caller can extract specific fields (implementer, product ID, revision, architecture version.)
  476. */
  477. rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
  478. {
  479. RT_ASSERT(index < ARM_GIC_MAX_NR);
  480. return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
  481. }
  482. /**
  483. * @brief Set the interrupt group for the specified interrupt
  484. *
  485. * @note This function configures the interrupt group in the GICD_IGROUPRn register.
  486. * The interrupt group determines the security classification of the interrupt
  487. * when the GIC implements Security Extensions:
  488. * - Group 0 (group = 0): Secure interrupts, used for secure world
  489. * - Group 1 (group = 1): Non-secure interrupts, used for non-secure world
  490. *
  491. * @param index GIC controller index
  492. * @param irq The actual interrupt number (with offset)
  493. * @param group Interrupt group: 0 for Group 0 (secure), 1 for Group 1 (non-secure)
  494. */
  495. void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
  496. {
  497. rt_uint32_t igroupr;
  498. rt_uint32_t shift;
  499. RT_ASSERT(index < ARM_GIC_MAX_NR);
  500. RT_ASSERT(group <= 1U);
  501. irq = irq - _gic_table[index].offset;
  502. RT_ASSERT(irq >= 0U);
  503. igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
  504. shift = (irq % 32U);
  505. igroupr &= (~(1U << shift));
  506. igroupr |= ( (group & 0x1U) << shift);
  507. GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
  508. }
  509. /**
  510. * @brief Get the interrupt group for the specified interrupt
  511. *
  512. * @note This function reads the interrupt group from the GICD_IGROUPRn register.
  513. * The return value indicates which security group the interrupt belongs to:
  514. * - 0: Group 0 (Secure interrupt)
  515. * - 1: Group 1 (Non-secure interrupt)
  516. *
  517. * @param index GIC controller index
  518. * @param irq The actual interrupt number (with offset)
  519. *
  520. * @return The interrupt group: 0 for Group 0 (secure), 1 for Group 1 (non-secure)
  521. */
  522. rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
  523. {
  524. RT_ASSERT(index < ARM_GIC_MAX_NR);
  525. irq = irq - _gic_table[index].offset;
  526. RT_ASSERT(irq >= 0U);
  527. return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
  528. }
  529. /**
  530. * @brief Initialize the GIC Distributor (GICD)
  531. *
  532. * @note: The exact bit definitions and behavior may vary depending on
  533. * the GIC implementation (GICv1/GICv2) and security context.
  534. *
  535. *
  536. * @param index GIC controller index
  537. * @param dist_base Base address of the GIC Distributor (GICD)
  538. * @param irq_start The first interrupt index offset in the vector table
  539. *
  540. * @return 0
  541. */
  542. int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
  543. {
  544. unsigned int gic_type, i;
  545. rt_uint32_t cpumask = 1U << 0U;
  546. RT_ASSERT(index < ARM_GIC_MAX_NR);
  547. _gic_table[index].dist_hw_base = dist_base;
  548. _gic_table[index].offset = irq_start;
  549. /* Find out how many interrupts are supported. */
  550. gic_type = GIC_DIST_TYPE(dist_base);
  551. _gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
  552. /*
  553. * The GIC only supports up to 1020 interrupt sources.
  554. * Limit this to either the architected maximum, or the
  555. * platform maximum.
  556. */
  557. if (_gic_max_irq > 1020U)
  558. _gic_max_irq = 1020U;
  559. if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
  560. _gic_max_irq = ARM_GIC_NR_IRQS;
  561. cpumask |= cpumask << 8U;
  562. cpumask |= cpumask << 16U;
  563. cpumask |= cpumask << 24U;
  564. GIC_DIST_CTRL(dist_base) = 0x0U;
  565. /* Set all global interrupts to be level triggered, active low. */
  566. for (i = 32U; i < _gic_max_irq; i += 16U)
  567. GIC_DIST_CONFIG(dist_base, i) = 0x0U;
  568. /* Set all global interrupts to this CPU only. */
  569. for (i = 32U; i < _gic_max_irq; i += 4U)
  570. GIC_DIST_TARGET(dist_base, i) = cpumask;
  571. /* Set priority on all interrupts. */
  572. for (i = 0U; i < _gic_max_irq; i += 4U)
  573. GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
  574. /* Disable all interrupts. */
  575. for (i = 0U; i < _gic_max_irq; i += 32U)
  576. GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
  577. #if 0
  578. /* All interrupts defaults to IGROUP1(IRQ). */
  579. for (i = 0; i < _gic_max_irq; i += 32)
  580. GIC_DIST_IGROUP(dist_base, i) = 0xffffffff;
  581. #endif
  582. for (i = 0U; i < _gic_max_irq; i += 32U)
  583. GIC_DIST_IGROUP(dist_base, i) = 0U;
  584. /* Enable group0 and group1 interrupt forwarding. */
  585. GIC_DIST_CTRL(dist_base) = 0x01U;
  586. return 0;
  587. }
  588. /**
  589. * @brief Initialize the GIC CPU Interface (GICC)
  590. *
  591. * @note: The exact bit definitions and behavior may vary depending on
  592. * the GIC implementation (GICv1/GICv2) and security context..
  593. *
  594. * @param index GIC controller index
  595. * @param cpu_base Base address of the GIC CPU Interface (GICC)
  596. *
  597. * @return 0
  598. */
  599. int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
  600. {
  601. RT_ASSERT(index < ARM_GIC_MAX_NR);
  602. if (!_gic_table[index].cpu_hw_base)
  603. {
  604. _gic_table[index].cpu_hw_base = cpu_base;
  605. }
  606. cpu_base = _gic_table[index].cpu_hw_base;
  607. GIC_CPU_PRIMASK(cpu_base) = 0xf0U;
  608. GIC_CPU_BINPOINT(cpu_base) = 0x7U;
  609. /* Enable CPU interrupt */
  610. GIC_CPU_CTRL(cpu_base) = 0x01U;
  611. return 0;
  612. }
  613. /**
  614. * @brief Print the GIC infomations(version, base addr, max irq nums, security extension)
  615. *
  616. * @param index GIC controller index
  617. */
  618. void arm_gic_dump_type(rt_uint32_t index)
  619. {
  620. unsigned int gic_type;
  621. gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
  622. rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
  623. (GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
  624. _gic_table[index].dist_hw_base,
  625. _gic_max_irq,
  626. gic_type & (1U << 10U) ? "has" : "no",
  627. gic_type);
  628. }
  629. /**
  630. * @brief Print the GIC status(highest priority pending interrupt, enable status, pending status , active status)
  631. *
  632. * @param index
  633. */
  634. void arm_gic_dump(rt_uint32_t index)
  635. {
  636. unsigned int i, k;
  637. k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
  638. rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
  639. rt_kprintf("--- hw mask ---\n");
  640. for (i = 0U; i < _gic_max_irq / 32U; i++)
  641. {
  642. rt_kprintf("0x%08x, ",
  643. GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
  644. i * 32U));
  645. }
  646. rt_kprintf("\n--- hw pending ---\n");
  647. for (i = 0U; i < _gic_max_irq / 32U; i++)
  648. {
  649. rt_kprintf("0x%08x, ",
  650. GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
  651. i * 32U));
  652. }
  653. rt_kprintf("\n--- hw active ---\n");
  654. for (i = 0U; i < _gic_max_irq / 32U; i++)
  655. {
  656. rt_kprintf("0x%08x, ",
  657. GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
  658. i * 32U));
  659. }
  660. rt_kprintf("\n");
  661. }
  662. long gic_dump(void)
  663. {
  664. arm_gic_dump_type(0);
  665. arm_gic_dump(0);
  666. return 0;
  667. }
  668. MSH_CMD_EXPORT(gic_dump, show gic status);