plic.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. * 2021-10-19 JasonHu first version
  9. * 2021-11-12 JasonHu fix bug that not intr on f133
  10. */
  11. #include <rtthread.h>
  12. #include <rtdbg.h>
  13. #include "plic.h"
  14. #include "rt_interrupt.h"
  15. #include "io.h"
  16. #include "encoding.h"
  17. static void *c906_plic_regs = RT_NULL;
  18. struct plic_handler
  19. {
  20. rt_bool_t present;
  21. void *hart_base;
  22. void *enable_base;
  23. };
  24. rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable);
  25. struct plic_handler c906_plic_handlers[C906_NR_CPUS];
  26. rt_inline void plic_irq_toggle(int hwirq, int enable)
  27. {
  28. int cpu = 0;
  29. /* set priority of interrupt, interrupt 0 is zero. */
  30. writel(enable, c906_plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
  31. struct plic_handler *handler = &c906_plic_handlers[cpu];
  32. if (handler->present)
  33. {
  34. plic_toggle(handler, hwirq, enable);
  35. }
  36. }
  37. void plic_complete(int irqno)
  38. {
  39. int cpu = 0;
  40. struct plic_handler *handler = &c906_plic_handlers[cpu];
  41. writel(irqno, handler->hart_base + CONTEXT_CLAIM);
  42. }
  43. void plic_disable_irq(int irqno)
  44. {
  45. plic_irq_toggle(irqno, 0);
  46. }
  47. void plic_enable_irq(int irqno)
  48. {
  49. plic_irq_toggle(irqno, 1);
  50. }
  51. /*
  52. * Handling an interrupt is a two-step process: first you claim the interrupt
  53. * by reading the claim register, then you complete the interrupt by writing
  54. * that source ID back to the same claim register. This automatically enables
  55. * and disables the interrupt, so there's nothing else to do.
  56. */
  57. void plic_handle_irq(void)
  58. {
  59. int cpu = 0;
  60. unsigned int irq;
  61. struct plic_handler *handler = &c906_plic_handlers[cpu];
  62. void *claim = handler->hart_base + CONTEXT_CLAIM;
  63. if (c906_plic_regs == RT_NULL || !handler->present)
  64. {
  65. LOG_E("plic state not initialized.");
  66. return;
  67. }
  68. clear_csr(sie, SIE_SEIE);
  69. while ((irq = readl(claim)))
  70. {
  71. /* ID0 is diabled permantually from spec. */
  72. if (irq == 0)
  73. {
  74. LOG_E("irq no is zero.");
  75. }
  76. else
  77. {
  78. generic_handle_irq(irq);
  79. }
  80. }
  81. set_csr(sie, SIE_SEIE);
  82. }
  83. rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
  84. {
  85. uint32_t *reg = handler->enable_base + (hwirq / 32) * sizeof(uint32_t);
  86. uint32_t hwirq_mask = 1 << (hwirq % 32);
  87. if (enable)
  88. {
  89. writel(readl(reg) | hwirq_mask, reg);
  90. }
  91. else
  92. {
  93. writel(readl(reg) & ~hwirq_mask, reg);
  94. }
  95. }
  96. void plic_init(void)
  97. {
  98. int nr_irqs;
  99. int nr_context;
  100. int i;
  101. unsigned long hwirq;
  102. int cpu = 0;
  103. if (c906_plic_regs)
  104. {
  105. LOG_E("plic already initialized!");
  106. return;
  107. }
  108. nr_context = C906_NR_CONTEXT;
  109. c906_plic_regs = (void *)C906_PLIC_PHY_ADDR;
  110. if (!c906_plic_regs)
  111. {
  112. LOG_E("fatal error, plic is reg space is null.");
  113. return;
  114. }
  115. nr_irqs = C906_PLIC_NR_EXT_IRQS;
  116. for (i = 0; i < nr_context; i ++)
  117. {
  118. struct plic_handler *handler;
  119. uint32_t threshold = 0;
  120. cpu = 0;
  121. /* skip contexts other than supervisor external interrupt */
  122. if (i == 0)
  123. {
  124. continue;
  125. }
  126. // we always use CPU0 M-mode target register.
  127. handler = &c906_plic_handlers[cpu];
  128. if (handler->present)
  129. {
  130. threshold = 0xffffffff;
  131. goto done;
  132. }
  133. handler->present = RT_TRUE;
  134. handler->hart_base = c906_plic_regs + CONTEXT_BASE + i * CONTEXT_PER_HART;
  135. handler->enable_base = c906_plic_regs + ENABLE_BASE + i * ENABLE_PER_HART;
  136. done:
  137. /* priority must be > threshold to trigger an interrupt */
  138. writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
  139. for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
  140. {
  141. plic_toggle(handler, hwirq, 0);
  142. }
  143. }
  144. /* Enable supervisor external interrupts. */
  145. set_csr(sie, SIE_SEIE);
  146. }