plic.c 5.2 KB

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