plic.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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-05-20 bigmagic first version
  9. */
  10. #include <rtthread.h>
  11. #include <stdint.h>
  12. #include "plic.h"
  13. #include <riscv_io.h>
  14. #include "encoding.h"
  15. /*
  16. * Each PLIC interrupt source can be assigned a priority by writing
  17. * to its 32-bit memory-mapped priority register.
  18. * The QEMU-virt (the same as FU540-C000) supports 7 levels of priority.
  19. * A priority value of 0 is reserved to mean "never interrupt" and
  20. * effectively disables the interrupt.
  21. * Priority 1 is the lowest active priority, and priority 7 is the highest.
  22. * Ties between global interrupts of the same priority are broken by
  23. * the Interrupt ID; interrupts with the lowest ID have the highest
  24. * effective priority.
  25. */
  26. void plic_set_priority(int irq, int priority)
  27. {
  28. *(uint32_t*)PLIC_PRIORITY(irq) = priority;
  29. }
  30. /*
  31. * Each global interrupt can be enabled by setting the corresponding
  32. * bit in the enables registers.
  33. */
  34. void plic_irq_enable(int irq)
  35. {
  36. int hart = __raw_hartid();
  37. *(uint32_t*)PLIC_ENABLE(hart) = ((*(uint32_t*)PLIC_ENABLE(hart)) | (1 << irq));
  38. #ifdef RISCV_S_MODE
  39. set_csr(sie, read_csr(sie) | MIP_SEIP);
  40. #else
  41. set_csr(mie, read_csr(mie) | MIP_MEIP);
  42. #endif
  43. }
  44. void plic_irq_disable(int irq)
  45. {
  46. int hart = __raw_hartid();
  47. *(uint32_t*)PLIC_ENABLE(hart) = (((*(uint32_t*)PLIC_ENABLE(hart)) & (~(1 << irq))));
  48. }
  49. /*
  50. * PLIC will mask all interrupts of a priority less than or equal to threshold.
  51. * Maximum threshold is 7.
  52. * For example, a threshold value of zero permits all interrupts with
  53. * non-zero priority, whereas a value of 7 masks all interrupts.
  54. * Notice, the threshold is global for PLIC, not for each interrupt source.
  55. */
  56. void plic_set_threshold(int threshold)
  57. {
  58. int hart = __raw_hartid();
  59. *(uint32_t*)PLIC_THRESHOLD(hart) = threshold;
  60. }
  61. /*
  62. * DESCRIPTION:
  63. * Query the PLIC what interrupt we should serve.
  64. * Perform an interrupt claim by reading the claim register, which
  65. * returns the ID of the highest-priority pending interrupt or zero if there
  66. * is no pending interrupt.
  67. * A successful claim also atomically clears the corresponding pending bit
  68. * on the interrupt source.
  69. * RETURN VALUE:
  70. * the ID of the highest-priority pending interrupt or zero if there
  71. * is no pending interrupt.
  72. */
  73. int plic_claim(void)
  74. {
  75. int hart = __raw_hartid();
  76. int irq = *(uint32_t*)PLIC_CLAIM(hart);
  77. return irq;
  78. }
  79. /*
  80. * DESCRIPTION:
  81. * Writing the interrupt ID it received from the claim (irq) to the
  82. * complete register would signal the PLIC we've served this IRQ.
  83. * The PLIC does not check whether the completion ID is the same as the
  84. * last claim ID for that target. If the completion ID does not match an
  85. * interrupt source that is currently enabled for the target, the completion
  86. * is silently ignored.
  87. * RETURN VALUE: none
  88. */
  89. void plic_complete(int irq)
  90. {
  91. int hart = __raw_hartid();
  92. *(uint32_t*)PLIC_COMPLETE(hart) = irq;
  93. }