aplic.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2021 Western Digital Corporation or its affiliates.
  5. * Copyright (c) 2022 Ventana Micro Systems Inc.
  6. *
  7. * Authors:
  8. * Anup Patel <anup.patel@wdc.com>
  9. */
  10. #include <sbi/riscv_io.h>
  11. #include <sbi/sbi_console.h>
  12. #include <sbi/sbi_domain.h>
  13. #include <sbi/sbi_error.h>
  14. #include <sbi_utils/irqchip/aplic.h>
  15. #define APLIC_MAX_IDC (1UL << 14)
  16. #define APLIC_MAX_SOURCE 1024
  17. #define APLIC_DOMAINCFG 0x0000
  18. #define APLIC_DOMAINCFG_IE (1 << 8)
  19. #define APLIC_DOMAINCFG_DM (1 << 2)
  20. #define APLIC_DOMAINCFG_BE (1 << 0)
  21. #define APLIC_SOURCECFG_BASE 0x0004
  22. #define APLIC_SOURCECFG_D (1 << 10)
  23. #define APLIC_SOURCECFG_CHILDIDX_MASK 0x000003ff
  24. #define APLIC_SOURCECFG_SM_MASK 0x00000007
  25. #define APLIC_SOURCECFG_SM_INACTIVE 0x0
  26. #define APLIC_SOURCECFG_SM_DETACH 0x1
  27. #define APLIC_SOURCECFG_SM_EDGE_RISE 0x4
  28. #define APLIC_SOURCECFG_SM_EDGE_FALL 0x5
  29. #define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6
  30. #define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7
  31. #define APLIC_MMSICFGADDR 0x1bc0
  32. #define APLIC_MMSICFGADDRH 0x1bc4
  33. #define APLIC_SMSICFGADDR 0x1bc8
  34. #define APLIC_SMSICFGADDRH 0x1bcc
  35. #define APLIC_xMSICFGADDRH_L (1UL << 31)
  36. #define APLIC_xMSICFGADDRH_HHXS_MASK 0x1f
  37. #define APLIC_xMSICFGADDRH_HHXS_SHIFT 24
  38. #define APLIC_xMSICFGADDRH_LHXS_MASK 0x7
  39. #define APLIC_xMSICFGADDRH_LHXS_SHIFT 20
  40. #define APLIC_xMSICFGADDRH_HHXW_MASK 0x7
  41. #define APLIC_xMSICFGADDRH_HHXW_SHIFT 16
  42. #define APLIC_xMSICFGADDRH_LHXW_MASK 0xf
  43. #define APLIC_xMSICFGADDRH_LHXW_SHIFT 12
  44. #define APLIC_xMSICFGADDRH_BAPPN_MASK 0xfff
  45. #define APLIC_xMSICFGADDR_PPN_SHIFT 12
  46. #define APLIC_xMSICFGADDR_PPN_HART(__lhxs) \
  47. ((1UL << (__lhxs)) - 1)
  48. #define APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) \
  49. ((1UL << (__lhxw)) - 1)
  50. #define APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs) \
  51. ((__lhxs))
  52. #define APLIC_xMSICFGADDR_PPN_LHX(__lhxw, __lhxs) \
  53. (APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) << \
  54. APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs))
  55. #define APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) \
  56. ((1UL << (__hhxw)) - 1)
  57. #define APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs) \
  58. ((__hhxs) + APLIC_xMSICFGADDR_PPN_SHIFT)
  59. #define APLIC_xMSICFGADDR_PPN_HHX(__hhxw, __hhxs) \
  60. (APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) << \
  61. APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs))
  62. #define APLIC_SETIP_BASE 0x1c00
  63. #define APLIC_SETIPNUM 0x1cdc
  64. #define APLIC_CLRIP_BASE 0x1d00
  65. #define APLIC_CLRIPNUM 0x1ddc
  66. #define APLIC_SETIE_BASE 0x1e00
  67. #define APLIC_SETIENUM 0x1edc
  68. #define APLIC_CLRIE_BASE 0x1f00
  69. #define APLIC_CLRIENUM 0x1fdc
  70. #define APLIC_SETIPNUM_LE 0x2000
  71. #define APLIC_SETIPNUM_BE 0x2004
  72. #define APLIC_TARGET_BASE 0x3004
  73. #define APLIC_TARGET_HART_IDX_SHIFT 18
  74. #define APLIC_TARGET_HART_IDX_MASK 0x3fff
  75. #define APLIC_TARGET_GUEST_IDX_SHIFT 12
  76. #define APLIC_TARGET_GUEST_IDX_MASK 0x3f
  77. #define APLIC_TARGET_IPRIO_MASK 0xff
  78. #define APLIC_TARGET_EIID_MASK 0x7ff
  79. #define APLIC_IDC_BASE 0x4000
  80. #define APLIC_IDC_SIZE 32
  81. #define APLIC_IDC_IDELIVERY 0x00
  82. #define APLIC_IDC_IFORCE 0x04
  83. #define APLIC_IDC_ITHRESHOLD 0x08
  84. #define APLIC_IDC_TOPI 0x18
  85. #define APLIC_IDC_TOPI_ID_SHIFT 16
  86. #define APLIC_IDC_TOPI_ID_MASK 0x3ff
  87. #define APLIC_IDC_TOPI_PRIO_MASK 0xff
  88. #define APLIC_IDC_CLAIMI 0x1c
  89. #define APLIC_DEFAULT_PRIORITY 1
  90. #define APLIC_DISABLE_IDELIVERY 0
  91. #define APLIC_ENABLE_IDELIVERY 1
  92. #define APLIC_DISABLE_ITHRESHOLD 1
  93. #define APLIC_ENABLE_ITHRESHOLD 0
  94. static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
  95. void *msicfgaddr, void *msicfgaddrH)
  96. {
  97. u32 val;
  98. unsigned long base_ppn;
  99. /* Check if MSI config is already locked */
  100. if (readl(msicfgaddrH) & APLIC_xMSICFGADDRH_L)
  101. return;
  102. /* Compute the MSI base PPN */
  103. base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
  104. base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
  105. base_ppn &= ~APLIC_xMSICFGADDR_PPN_LHX(msicfg->lhxw, msicfg->lhxs);
  106. base_ppn &= ~APLIC_xMSICFGADDR_PPN_HHX(msicfg->hhxw, msicfg->hhxs);
  107. /* Write the lower MSI config register */
  108. writel((u32)base_ppn, msicfgaddr);
  109. /* Write the upper MSI config register */
  110. val = (((u64)base_ppn) >> 32) &
  111. APLIC_xMSICFGADDRH_BAPPN_MASK;
  112. val |= (msicfg->lhxw & APLIC_xMSICFGADDRH_LHXW_MASK)
  113. << APLIC_xMSICFGADDRH_LHXW_SHIFT;
  114. val |= (msicfg->hhxw & APLIC_xMSICFGADDRH_HHXW_MASK)
  115. << APLIC_xMSICFGADDRH_HHXW_SHIFT;
  116. val |= (msicfg->lhxs & APLIC_xMSICFGADDRH_LHXS_MASK)
  117. << APLIC_xMSICFGADDRH_LHXS_SHIFT;
  118. val |= (msicfg->hhxs & APLIC_xMSICFGADDRH_HHXS_MASK)
  119. << APLIC_xMSICFGADDRH_HHXS_SHIFT;
  120. writel(val, msicfgaddrH);
  121. }
  122. static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
  123. {
  124. if (APLIC_xMSICFGADDRH_LHXS_MASK < msicfg->lhxs)
  125. return SBI_EINVAL;
  126. if (APLIC_xMSICFGADDRH_LHXW_MASK < msicfg->lhxw)
  127. return SBI_EINVAL;
  128. if (APLIC_xMSICFGADDRH_HHXS_MASK < msicfg->hhxs)
  129. return SBI_EINVAL;
  130. if (APLIC_xMSICFGADDRH_HHXW_MASK < msicfg->hhxw)
  131. return SBI_EINVAL;
  132. return 0;
  133. }
  134. int aplic_cold_irqchip_init(struct aplic_data *aplic)
  135. {
  136. int rc;
  137. u32 i, j, tmp;
  138. struct sbi_domain_memregion reg;
  139. struct aplic_delegate_data *deleg;
  140. u32 first_deleg_irq, last_deleg_irq;
  141. /* Sanity checks */
  142. if (!aplic ||
  143. !aplic->num_source || APLIC_MAX_SOURCE <= aplic->num_source ||
  144. APLIC_MAX_IDC <= aplic->num_idc)
  145. return SBI_EINVAL;
  146. if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
  147. rc = aplic_check_msicfg(&aplic->msicfg_mmode);
  148. if (rc)
  149. return rc;
  150. }
  151. if (aplic->targets_mmode && aplic->has_msicfg_smode) {
  152. rc = aplic_check_msicfg(&aplic->msicfg_smode);
  153. if (rc)
  154. return rc;
  155. }
  156. /* Set domain configuration to 0 */
  157. writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
  158. /* Disable all interrupts */
  159. for (i = 0; i <= aplic->num_source; i++)
  160. writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
  161. (i / 32) * sizeof(u32)));
  162. /* Set interrupt type and priority for all interrupts */
  163. for (i = 1; i <= aplic->num_source; i++) {
  164. /* Set IRQ source configuration to 0 */
  165. writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
  166. (i - 1) * sizeof(u32)));
  167. /* Set IRQ target hart index and priority to 1 */
  168. writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
  169. APLIC_TARGET_BASE +
  170. (i - 1) * sizeof(u32)));
  171. }
  172. /* Configure IRQ delegation */
  173. first_deleg_irq = -1U;
  174. last_deleg_irq = 0;
  175. for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
  176. deleg = &aplic->delegate[i];
  177. if (!deleg->first_irq || !deleg->last_irq)
  178. continue;
  179. if (aplic->num_source < deleg->first_irq ||
  180. aplic->num_source < deleg->last_irq)
  181. continue;
  182. if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
  183. continue;
  184. if (deleg->first_irq > deleg->last_irq) {
  185. tmp = deleg->first_irq;
  186. deleg->first_irq = deleg->last_irq;
  187. deleg->last_irq = tmp;
  188. }
  189. if (deleg->first_irq < first_deleg_irq)
  190. first_deleg_irq = deleg->first_irq;
  191. if (last_deleg_irq < deleg->last_irq)
  192. last_deleg_irq = deleg->last_irq;
  193. for (j = deleg->first_irq; j <= deleg->last_irq; j++)
  194. writel(APLIC_SOURCECFG_D | deleg->child_index,
  195. (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
  196. (j - 1) * sizeof(u32)));
  197. }
  198. /* Default initialization of IDC structures */
  199. for (i = 0; i < aplic->num_idc; i++) {
  200. writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
  201. i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
  202. writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
  203. i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
  204. writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
  205. APLIC_IDC_BASE +
  206. (i * APLIC_IDC_SIZE) +
  207. APLIC_IDC_ITHRESHOLD));
  208. }
  209. /* MSI configuration */
  210. if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
  211. aplic_writel_msicfg(&aplic->msicfg_mmode,
  212. (void *)(aplic->addr + APLIC_MMSICFGADDR),
  213. (void *)(aplic->addr + APLIC_MMSICFGADDRH));
  214. }
  215. if (aplic->targets_mmode && aplic->has_msicfg_smode) {
  216. aplic_writel_msicfg(&aplic->msicfg_smode,
  217. (void *)(aplic->addr + APLIC_SMSICFGADDR),
  218. (void *)(aplic->addr + APLIC_SMSICFGADDRH));
  219. }
  220. /*
  221. * Add APLIC region to the root domain if:
  222. * 1) It targets M-mode of any HART directly or via MSIs
  223. * 2) All interrupts are delegated to some child APLIC
  224. */
  225. if (aplic->targets_mmode ||
  226. ((first_deleg_irq < last_deleg_irq) &&
  227. (last_deleg_irq == aplic->num_source) &&
  228. (first_deleg_irq == 1))) {
  229. sbi_domain_memregion_init(aplic->addr, aplic->size,
  230. (SBI_DOMAIN_MEMREGION_MMIO |
  231. SBI_DOMAIN_MEMREGION_M_READABLE |
  232. SBI_DOMAIN_MEMREGION_M_WRITABLE),
  233. &reg);
  234. rc = sbi_domain_root_add_memregion(&reg);
  235. if (rc)
  236. return rc;
  237. }
  238. return 0;
  239. }