plicsw.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2019 Andes Technology Corporation
  5. *
  6. * Authors:
  7. * Zong Li <zong@andestech.com>
  8. * Nylon Chen <nylon7@andestech.com>
  9. */
  10. #include <sbi/riscv_asm.h>
  11. #include <sbi/riscv_io.h>
  12. #include <sbi/sbi_types.h>
  13. #include "plicsw.h"
  14. #include "platform.h"
  15. static u32 plicsw_ipi_hart_count;
  16. static struct plicsw plicsw_dev[AE350_HART_COUNT];
  17. static inline void plicsw_claim(void)
  18. {
  19. u32 source_hart = current_hartid();
  20. plicsw_dev[source_hart].source_id =
  21. readl(plicsw_dev[source_hart].plicsw_claim);
  22. }
  23. static inline void plicsw_complete(void)
  24. {
  25. u32 source_hart = current_hartid();
  26. u32 source = plicsw_dev[source_hart].source_id;
  27. writel(source, plicsw_dev[source_hart].plicsw_claim);
  28. }
  29. static inline void plic_sw_pending(u32 target_hart)
  30. {
  31. /*
  32. * The pending array registers are w1s type.
  33. * IPI pending array mapping as following:
  34. *
  35. * Pending array start address: base + 0x1000
  36. * -------------------------------------
  37. * | hart 3 | hart 2 | hart 1 | hart 0 |
  38. * -------------------------------------
  39. * Each hart X can send IPI to another hart by setting the
  40. * corresponding bit in hart X own region(see the below).
  41. *
  42. * In each hart region:
  43. * -----------------------------------------------
  44. * | bit 7 | bit 6 | bit 5 | bit 4 | ... | bit 0 |
  45. * -----------------------------------------------
  46. * The bit 7 is used to send IPI to hart 0
  47. * The bit 6 is used to send IPI to hart 1
  48. * The bit 5 is used to send IPI to hart 2
  49. * The bit 4 is used to send IPI to hart 3
  50. */
  51. u32 source_hart = current_hartid();
  52. u32 target_offset = (PLICSW_PENDING_PER_HART - 1) - target_hart;
  53. u32 per_hart_offset = PLICSW_PENDING_PER_HART * source_hart;
  54. u32 val = 1 << target_offset << per_hart_offset;
  55. writel(val, plicsw_dev[source_hart].plicsw_pending);
  56. }
  57. void plicsw_ipi_send(u32 target_hart)
  58. {
  59. if (plicsw_ipi_hart_count <= target_hart)
  60. return;
  61. /* Set PLICSW IPI */
  62. plic_sw_pending(target_hart);
  63. }
  64. void plicsw_ipi_clear(u32 target_hart)
  65. {
  66. if (plicsw_ipi_hart_count <= target_hart)
  67. return;
  68. /* Clear PLICSW IPI */
  69. plicsw_claim();
  70. plicsw_complete();
  71. }
  72. int plicsw_warm_ipi_init(void)
  73. {
  74. u32 hartid = current_hartid();
  75. if (!plicsw_dev[hartid].plicsw_pending
  76. && !plicsw_dev[hartid].plicsw_enable
  77. && !plicsw_dev[hartid].plicsw_claim)
  78. return -1;
  79. /* Clear PLICSW IPI */
  80. plicsw_ipi_clear(hartid);
  81. return 0;
  82. }
  83. int plicsw_cold_ipi_init(unsigned long base, u32 hart_count)
  84. {
  85. /* Setup source priority */
  86. uint32_t *priority = (void *)base + PLICSW_PRIORITY_BASE;
  87. for (int i = 0; i < AE350_HART_COUNT * PLICSW_PENDING_PER_HART; i++)
  88. writel(1, &priority[i]);
  89. /* Setup target enable */
  90. uint32_t enable_mask = PLICSW_HART_MASK;
  91. for (int i = 0; i < AE350_HART_COUNT; i++) {
  92. uint32_t *enable = (void *)base + PLICSW_ENABLE_BASE
  93. + PLICSW_ENABLE_PER_HART * i;
  94. writel(enable_mask, &enable[0]);
  95. enable_mask >>= 1;
  96. }
  97. /* Figure-out PLICSW IPI register address */
  98. plicsw_ipi_hart_count = hart_count;
  99. for (u32 hartid = 0; hartid < AE350_HART_COUNT; hartid++) {
  100. plicsw_dev[hartid].source_id = 0;
  101. plicsw_dev[hartid].plicsw_pending =
  102. (void *)base
  103. + PLICSW_PENDING_BASE
  104. + ((hartid / 4) * 4);
  105. plicsw_dev[hartid].plicsw_enable =
  106. (void *)base
  107. + PLICSW_ENABLE_BASE
  108. + PLICSW_ENABLE_PER_HART * hartid;
  109. plicsw_dev[hartid].plicsw_claim =
  110. (void *)base
  111. + PLICSW_CONTEXT_BASE
  112. + PLICSW_CONTEXT_CLAIM
  113. + PLICSW_CONTEXT_PER_HART * hartid;
  114. }
  115. return 0;
  116. }