plic.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-10-19 JasonHu first version
  9. * 2021-11-12 JasonHu fix bug that not intr on f133
  10. * 2023-04-22 flyingcys add plic register ioremap
  11. */
  12. #include <rtthread.h>
  13. #include <rtdbg.h>
  14. #include "plic.h"
  15. #include "rt_interrupt.h"
  16. #include "io.h"
  17. #include "encoding.h"
  18. static void *c906_plic_regs = RT_NULL;
  19. extern struct rt_irq_desc isr_table[];
  20. struct plic_handler
  21. {
  22. rt_bool_t present;
  23. void *hart_base;
  24. void *enable_base;
  25. };
  26. rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable);
  27. struct plic_handler c906_plic_handlers[C906_NR_CPUS];
  28. static void *c906_irq_priority[INTERRUPTS_MAX] = {RT_NULL};
  29. rt_inline void plic_irq_toggle(int hwirq, int enable)
  30. {
  31. int cpu = 0;
  32. void *priority_addr;
  33. /* set priority of interrupt, interrupt 0 is zero. */
  34. priority_addr = (void *)((rt_size_t)c906_plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
  35. #ifdef RT_USING_SMART
  36. if (c906_irq_priority[hwirq] == RT_NULL)
  37. {
  38. c906_irq_priority[hwirq] = rt_ioremap(priority_addr, 0x1000);
  39. }
  40. priority_addr = c906_irq_priority[hwirq];
  41. #endif
  42. writel(enable, priority_addr);
  43. struct plic_handler *handler = &c906_plic_handlers[cpu];
  44. if (handler->present)
  45. {
  46. plic_toggle(handler, hwirq, enable);
  47. }
  48. }
  49. static void generic_handle_irq(int irq)
  50. {
  51. rt_isr_handler_t isr;
  52. void *param;
  53. if (irq < 0 || irq >= IRQ_MAX_NR)
  54. {
  55. LOG_E("bad irq number %d!\n", irq);
  56. return;
  57. }
  58. if (!irq) // irq = 0 => no irq
  59. {
  60. LOG_W("no irq!\n");
  61. return;
  62. }
  63. isr = isr_table[IRQ_OFFSET + irq].handler;
  64. param = isr_table[IRQ_OFFSET + irq].param;
  65. if (isr != RT_NULL)
  66. {
  67. isr(irq, param);
  68. }
  69. /* complete irq. */
  70. plic_complete(irq);
  71. }
  72. void plic_complete(int irqno)
  73. {
  74. int cpu = 0;
  75. struct plic_handler *handler = &c906_plic_handlers[cpu];
  76. writel(irqno, (void *)((rt_size_t)handler->hart_base + CONTEXT_CLAIM));
  77. }
  78. void plic_disable_irq(int irqno)
  79. {
  80. plic_irq_toggle(irqno, 0);
  81. }
  82. void plic_enable_irq(int irqno)
  83. {
  84. plic_irq_toggle(irqno, 1);
  85. }
  86. /*
  87. * Handling an interrupt is a two-step process: first you claim the interrupt
  88. * by reading the claim register, then you complete the interrupt by writing
  89. * that source ID back to the same claim register. This automatically enables
  90. * and disables the interrupt, so there's nothing else to do.
  91. */
  92. void plic_handle_irq(void)
  93. {
  94. int cpu = 0;
  95. unsigned int irq;
  96. struct plic_handler *handler = &c906_plic_handlers[cpu];
  97. void *claim = (void *)((rt_size_t)handler->hart_base + CONTEXT_CLAIM);
  98. if (c906_plic_regs == RT_NULL || !handler->present)
  99. {
  100. LOG_E("plic state not initialized.");
  101. return;
  102. }
  103. clear_csr(sie, SIE_SEIE);
  104. while ((irq = readl(claim)))
  105. {
  106. /* ID0 is diabled permantually from spec. */
  107. if (irq == 0)
  108. {
  109. LOG_E("irq no is zero.");
  110. }
  111. else
  112. {
  113. generic_handle_irq(irq);
  114. }
  115. }
  116. set_csr(sie, SIE_SEIE);
  117. }
  118. rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
  119. {
  120. uint32_t *reg = (uint32_t *)((rt_size_t)handler->enable_base + (hwirq / 32) * sizeof(uint32_t));
  121. uint32_t hwirq_mask = 1 << (hwirq % 32);
  122. if (enable)
  123. {
  124. writel(readl(reg) | hwirq_mask, reg);
  125. }
  126. else
  127. {
  128. writel(readl(reg) & ~hwirq_mask, reg);
  129. }
  130. }
  131. void plic_init(void)
  132. {
  133. int nr_irqs;
  134. int nr_context;
  135. int i;
  136. unsigned long hwirq;
  137. int cpu = 0;
  138. if (c906_plic_regs)
  139. {
  140. LOG_E("plic already initialized!");
  141. return;
  142. }
  143. nr_context = C906_NR_CONTEXT;
  144. c906_plic_regs = (void *)C906_PLIC_PHY_ADDR;
  145. if (!c906_plic_regs)
  146. {
  147. LOG_E("fatal error, plic is reg space is null.");
  148. return;
  149. }
  150. nr_irqs = C906_PLIC_NR_EXT_IRQS;
  151. for (i = 0; i < nr_context; i ++)
  152. {
  153. struct plic_handler *handler;
  154. uint32_t threshold = 0;
  155. cpu = 0;
  156. /* skip contexts other than supervisor external interrupt */
  157. if (i == 0)
  158. {
  159. continue;
  160. }
  161. // we always use CPU0 M-mode target register.
  162. handler = &c906_plic_handlers[cpu];
  163. if (handler->present)
  164. {
  165. threshold = 0xffffffff;
  166. goto done;
  167. }
  168. handler->present = RT_TRUE;
  169. handler->hart_base = (void *)((rt_size_t)c906_plic_regs + CONTEXT_BASE + i * CONTEXT_PER_HART);
  170. handler->enable_base = (void *)((rt_size_t)c906_plic_regs + ENABLE_BASE + i * ENABLE_PER_HART);
  171. #ifdef RT_USING_SMART
  172. handler->hart_base = rt_ioremap(handler->hart_base, 0x1000);
  173. handler->enable_base = rt_ioremap(handler->enable_base, 0x1000);
  174. #endif
  175. done:
  176. /* priority must be > threshold to trigger an interrupt */
  177. writel(threshold, (void *)((rt_size_t)handler->hart_base + CONTEXT_THRESHOLD));
  178. for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
  179. {
  180. plic_toggle(handler, hwirq, 0);
  181. }
  182. }
  183. /* Enable supervisor external interrupts. */
  184. set_csr(sie, SIE_SEIE);
  185. }