1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2022-2023 NXP 4 */ 5 6 #include <assert.h> 7 #include <config.h> 8 #include <drivers/plic.h> 9 #include <io.h> 10 #include <kernel/dt.h> 11 #include <kernel/interrupt.h> 12 #include <kernel/panic.h> 13 #include <mm/core_memprot.h> 14 #include <mm/core_mmu.h> 15 #include <trace.h> 16 17 #define PLIC_PRIORITY_OFFSET 0 18 #define PLIC_PENDING_OFFSET 0x1000 19 #define PLIC_ENABLE_OFFSET 0x2000 20 #define PLIC_THRESHOLD_OFFSET 0x200000 21 #define PLIC_CLAIM_OFFSET 0x200004 22 23 #define PLIC_PRIORITY_SHIFT_PER_SOURCE U(2) 24 #define PLIC_PENDING_SHIFT_PER_SOURCE U(0) 25 26 #define PLIC_ENABLE_SHIFT_PER_TARGET U(7) 27 #define PLIC_THRESHOLD_SHIFT_PER_TARGET U(12) 28 #define PLIC_CLAIM_SHIFT_PER_TARGET U(12) 29 30 #define PLIC_PRIORITY(base, source) \ 31 ((base) + PLIC_PRIORITY_OFFSET + \ 32 SHIFT_U32(source, PLIC_PRIORITY_SHIFT_PER_SOURCE) \ 33 ) 34 #define PLIC_PENDING(base, source) \ 35 ((base) + PLIC_PENDING_OFFSET + \ 36 (4 * ((source) / 32)) \ 37 ) 38 #define PLIC_ENABLE(base, source, context) \ 39 ((base) + PLIC_ENABLE_OFFSET + \ 40 SHIFT_U32(context, PLIC_ENABLE_SHIFT_PER_TARGET) +\ 41 (4 * ((source) / 32)) \ 42 ) 43 #define PLIC_THRESHOLD(base, context) \ 44 ((base) + PLIC_THRESHOLD_OFFSET + \ 45 SHIFT_U32(context, PLIC_THRESHOLD_SHIFT_PER_TARGET) \ 46 ) 47 #define PLIC_COMPLETE(base, context) \ 48 ((base) + PLIC_CLAIM_OFFSET + \ 49 SHIFT_U32(context, PLIC_CLAIM_SHIFT_PER_TARGET) \ 50 ) 51 #define PLIC_CLAIM(base, context) PLIC_COMPLETE(base, context) 52 53 register_phys_mem_pgdir(MEM_AREA_IO_SEC, PLIC_BASE, PLIC_REG_SIZE); 54 55 struct plic_data { 56 vaddr_t plic_base; 57 size_t max_it; 58 struct itr_chip chip; 59 }; 60 61 static struct plic_data plic_data __nex_bss; 62 63 /* 64 * We assume that each hart has M-mode and S-mode, so the contexts look like: 65 * PLIC context 0 is hart 0 M-mode 66 * PLIC context 1 is hart 0 S-mode 67 * PLIC context 2 is hart 1 M-mode 68 * PLIC context 3 is hart 1 S-mode 69 * ... 70 */ 71 static uint32_t plic_get_context(void) 72 { 73 size_t hartid = get_core_pos(); 74 bool smode = IS_ENABLED(CFG_RISCV_S_MODE) ? true : false; 75 76 return hartid * 2 + smode; 77 } 78 79 static bool __maybe_unused 80 plic_is_pending(struct plic_data *pd, uint32_t source) 81 { 82 return io_read32(PLIC_PENDING(pd->plic_base, source)) & 83 BIT(source % 32); 84 } 85 86 static void plic_set_pending(struct plic_data *pd, uint32_t source) 87 { 88 io_setbits32(PLIC_PENDING(pd->plic_base, source), BIT(source % 32)); 89 } 90 91 static void plic_enable_interrupt(struct plic_data *pd, uint32_t source) 92 { 93 uint32_t context = plic_get_context(); 94 95 io_setbits32(PLIC_ENABLE(pd->plic_base, source, context), 96 BIT(source & 0x1f)); 97 } 98 99 static uint32_t __maybe_unused 100 plic_get_interrupt_enable(struct plic_data *pd, uint32_t source) 101 { 102 uint32_t context = plic_get_context(); 103 104 return io_read32(PLIC_ENABLE(pd->plic_base, source, context)) & 105 BIT(source & 0x1f); 106 } 107 108 static void plic_disable_interrupt(struct plic_data *pd, uint32_t source) 109 { 110 uint32_t context = plic_get_context(); 111 112 io_clrbits32(PLIC_ENABLE(pd->plic_base, source, context), 113 BIT(source & 0x1f)); 114 } 115 116 static uint32_t __maybe_unused plic_get_threshold(struct plic_data *pd) 117 { 118 uint32_t context = plic_get_context(); 119 120 return io_read32(PLIC_THRESHOLD(pd->plic_base, context)); 121 } 122 123 static void plic_set_threshold(struct plic_data *pd, uint32_t threshold) 124 { 125 uint32_t context = plic_get_context(); 126 127 io_write32(PLIC_THRESHOLD(pd->plic_base, context), threshold); 128 } 129 130 static uint32_t __maybe_unused 131 plic_get_priority(struct plic_data *pd, uint32_t source) 132 { 133 return io_read32(PLIC_PRIORITY(pd->plic_base, source)); 134 } 135 136 static void plic_set_priority(struct plic_data *pd, uint32_t source, 137 uint32_t priority) 138 { 139 io_write32(PLIC_PRIORITY(pd->plic_base, source), priority); 140 } 141 142 static uint32_t plic_claim_interrupt(struct plic_data *pd) 143 { 144 uint32_t context = plic_get_context(); 145 146 return io_read32(PLIC_CLAIM(pd->plic_base, context)); 147 } 148 149 static void plic_complete_interrupt(struct plic_data *pd, uint32_t source) 150 { 151 uint32_t context = plic_get_context(); 152 153 io_write32(PLIC_CLAIM(pd->plic_base, context), source); 154 } 155 156 static void plic_op_add(struct itr_chip *chip, size_t it, 157 uint32_t type __unused, 158 uint32_t prio) 159 { 160 struct plic_data *pd = container_of(chip, struct plic_data, chip); 161 162 if (it > pd->max_it) 163 panic(); 164 165 plic_disable_interrupt(pd, it); 166 plic_set_priority(pd, it, prio); 167 } 168 169 static void plic_op_enable(struct itr_chip *chip, size_t it) 170 { 171 struct plic_data *pd = container_of(chip, struct plic_data, chip); 172 173 if (it > pd->max_it) 174 panic(); 175 176 plic_enable_interrupt(pd, it); 177 } 178 179 static void plic_op_disable(struct itr_chip *chip, size_t it) 180 { 181 struct plic_data *pd = container_of(chip, struct plic_data, chip); 182 183 if (it > pd->max_it) 184 panic(); 185 186 plic_disable_interrupt(pd, it); 187 } 188 189 static void plic_op_raise_pi(struct itr_chip *chip, size_t it) 190 { 191 struct plic_data *pd = container_of(chip, struct plic_data, chip); 192 193 if (it > pd->max_it) 194 panic(); 195 196 plic_set_pending(pd, it); 197 } 198 199 static void plic_op_raise_sgi(struct itr_chip *chip __unused, 200 size_t it __unused, uint32_t cpu_mask __unused) 201 { 202 } 203 204 static void plic_op_set_affinity(struct itr_chip *chip __unused, 205 size_t it __unused, uint8_t cpu_mask __unused) 206 { 207 } 208 209 static int plic_dt_get_irq(const uint32_t *properties __unused, 210 int count __unused, uint32_t *type __unused, 211 uint32_t *prio __unused) 212 { 213 return DT_INFO_INVALID_INTERRUPT; 214 } 215 216 static size_t probe_max_it(vaddr_t plic_base __unused) 217 { 218 return PLIC_NUM_SOURCES; 219 } 220 221 static const struct itr_ops plic_ops = { 222 .add = plic_op_add, 223 .mask = plic_op_disable, 224 .unmask = plic_op_enable, 225 .enable = plic_op_enable, 226 .disable = plic_op_disable, 227 .raise_pi = plic_op_raise_pi, 228 .raise_sgi = plic_op_raise_sgi, 229 .set_affinity = plic_op_set_affinity, 230 }; 231 232 static void plic_init_base_addr(struct plic_data *pd, paddr_t plic_base_pa) 233 { 234 vaddr_t plic_base = 0; 235 236 assert(cpu_mmu_enabled()); 237 238 plic_base = core_mmu_get_va(plic_base_pa, MEM_AREA_IO_SEC, 239 PLIC_REG_SIZE); 240 if (!plic_base) 241 panic(); 242 243 pd->plic_base = plic_base; 244 pd->max_it = probe_max_it(plic_base); 245 pd->chip.ops = &plic_ops; 246 247 if (IS_ENABLED(CFG_DT)) 248 pd->chip.dt_get_irq = plic_dt_get_irq; 249 } 250 251 void plic_hart_init(void) 252 { 253 /* TODO: To be called by secondary harts */ 254 } 255 256 void plic_init(paddr_t plic_base_pa) 257 { 258 struct plic_data *pd = &plic_data; 259 size_t n = 0; 260 261 plic_init_base_addr(pd, plic_base_pa); 262 263 for (n = 0; n <= pd->max_it; n++) { 264 plic_disable_interrupt(pd, n); 265 plic_set_priority(pd, n, 1); 266 } 267 268 plic_set_threshold(pd, 0); 269 270 interrupt_main_init(&plic_data.chip); 271 } 272 273 void plic_it_handle(void) 274 { 275 struct plic_data *pd = &plic_data; 276 uint32_t id = plic_claim_interrupt(pd); 277 278 if (id > 0 && id <= pd->max_it) 279 interrupt_call_handlers(&pd->chip, id); 280 else 281 DMSG("ignoring interrupt %" PRIu32, id); 282 283 plic_complete_interrupt(pd, id); 284 } 285