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, hart) \ 39 ((base) + PLIC_ENABLE_OFFSET + \ 40 SHIFT_U32(hart, PLIC_ENABLE_SHIFT_PER_TARGET) +\ 41 (4 * ((source) / 32)) \ 42 ) 43 #define PLIC_THRESHOLD(base, hart) \ 44 ((base) + PLIC_THRESHOLD_OFFSET + \ 45 SHIFT_U32(hart, PLIC_THRESHOLD_SHIFT_PER_TARGET) \ 46 ) 47 #define PLIC_COMPLETE(base, hart) \ 48 ((base) + PLIC_CLAIM_OFFSET + \ 49 SHIFT_U32(hart, PLIC_CLAIM_SHIFT_PER_TARGET) \ 50 ) 51 #define PLIC_CLAIM(base, hart) PLIC_COMPLETE(base, hart) 52 53 register_phys_mem_pgdir(MEM_AREA_IO_SEC, PLIC_BASE, PLIC_REG_SIZE); 54 55 static bool __maybe_unused 56 plic_is_pending(struct plic_data *pd, uint32_t source) 57 { 58 return io_read32(PLIC_PENDING(pd->plic_base, source)) & 59 BIT(source % 32); 60 } 61 62 static void plic_set_pending(struct plic_data *pd, uint32_t source) 63 { 64 io_setbits32(PLIC_PENDING(pd->plic_base, source), BIT(source % 32)); 65 } 66 67 static void plic_enable_interrupt(struct plic_data *pd, uint32_t source) 68 { 69 io_setbits32(PLIC_ENABLE(pd->plic_base, source, get_core_pos()), 70 BIT(source & 0x1f)); 71 } 72 73 static uint32_t __maybe_unused 74 plic_get_interrupt_enable(struct plic_data *pd, uint32_t source) 75 { 76 return io_read32(PLIC_ENABLE(pd->plic_base, source, get_core_pos())) & 77 BIT(source & 0x1f); 78 } 79 80 static void plic_disable_interrupt(struct plic_data *pd, uint32_t source) 81 { 82 io_clrbits32(PLIC_ENABLE(pd->plic_base, source, get_core_pos()), 83 BIT(source & 0x1f)); 84 } 85 86 static uint32_t __maybe_unused plic_get_threshold(struct plic_data *pd) 87 { 88 return io_read32(PLIC_THRESHOLD(pd->plic_base, get_core_pos())); 89 } 90 91 static void plic_set_threshold(struct plic_data *pd, uint32_t threshold) 92 { 93 io_write32(PLIC_THRESHOLD(pd->plic_base, get_core_pos()), threshold); 94 } 95 96 static uint32_t __maybe_unused 97 plic_get_priority(struct plic_data *pd, uint32_t source) 98 { 99 return io_read32(PLIC_PRIORITY(pd->plic_base, source)); 100 } 101 102 static void plic_set_priority(struct plic_data *pd, uint32_t source, 103 uint32_t priority) 104 { 105 io_write32(PLIC_PRIORITY(pd->plic_base, source), priority); 106 } 107 108 static uint32_t plic_claim_interrupt(struct plic_data *pd) 109 { 110 return io_read32(PLIC_CLAIM(pd->plic_base, get_core_pos())); 111 } 112 113 static void plic_complete_interrupt(struct plic_data *pd, uint32_t source) 114 { 115 io_write32(PLIC_CLAIM(pd->plic_base, get_core_pos()), source); 116 } 117 118 static void plic_op_add(struct itr_chip *chip, size_t it, 119 uint32_t type __unused, 120 uint32_t prio) 121 { 122 struct plic_data *pd = container_of(chip, struct plic_data, chip); 123 124 if (it > pd->max_it) 125 panic(); 126 127 plic_disable_interrupt(pd, it); 128 plic_set_priority(pd, it, prio); 129 } 130 131 static void plic_op_enable(struct itr_chip *chip, size_t it) 132 { 133 struct plic_data *pd = container_of(chip, struct plic_data, chip); 134 135 if (it > pd->max_it) 136 panic(); 137 138 plic_enable_interrupt(pd, it); 139 } 140 141 static void plic_op_disable(struct itr_chip *chip, size_t it) 142 { 143 struct plic_data *pd = container_of(chip, struct plic_data, chip); 144 145 if (it > pd->max_it) 146 panic(); 147 148 plic_disable_interrupt(pd, it); 149 } 150 151 static void plic_op_raise_pi(struct itr_chip *chip, size_t it) 152 { 153 struct plic_data *pd = container_of(chip, struct plic_data, chip); 154 155 if (it > pd->max_it) 156 panic(); 157 158 plic_set_pending(pd, it); 159 } 160 161 static void plic_op_raise_sgi(struct itr_chip *chip __unused, 162 size_t it __unused, uint8_t cpu_mask __unused) 163 { 164 } 165 166 static void plic_op_set_affinity(struct itr_chip *chip __unused, 167 size_t it __unused, uint8_t cpu_mask __unused) 168 { 169 } 170 171 static int plic_dt_get_irq(const uint32_t *properties __unused, 172 int count __unused, uint32_t *type __unused, 173 uint32_t *prio __unused) 174 { 175 return DT_INFO_INVALID_INTERRUPT; 176 } 177 178 static size_t probe_max_it(vaddr_t plic_base __unused) 179 { 180 return PLIC_NUM_SOURCES; 181 } 182 183 static const struct itr_ops plic_ops = { 184 .add = plic_op_add, 185 .enable = plic_op_enable, 186 .disable = plic_op_disable, 187 .raise_pi = plic_op_raise_pi, 188 .raise_sgi = plic_op_raise_sgi, 189 .set_affinity = plic_op_set_affinity, 190 }; 191 192 void plic_init_base_addr(struct plic_data *pd, paddr_t plic_base_pa) 193 { 194 vaddr_t plic_base = 0; 195 196 assert(cpu_mmu_enabled()); 197 198 plic_base = core_mmu_get_va(plic_base_pa, MEM_AREA_IO_SEC, 199 PLIC_REG_SIZE); 200 if (!plic_base) 201 panic(); 202 203 pd->plic_base = plic_base; 204 pd->max_it = probe_max_it(plic_base); 205 pd->chip.ops = &plic_ops; 206 207 if (IS_ENABLED(CFG_DT)) 208 pd->chip.dt_get_irq = plic_dt_get_irq; 209 } 210 211 void plic_hart_init(struct plic_data *pd __unused) 212 { 213 /* TODO: To be called by secondary harts */ 214 } 215 216 void plic_init(struct plic_data *pd, paddr_t plic_base_pa) 217 { 218 size_t n = 0; 219 220 plic_init_base_addr(pd, plic_base_pa); 221 222 for (n = 0; n <= pd->max_it; n++) { 223 plic_disable_interrupt(pd, n); 224 plic_set_priority(pd, n, 1); 225 } 226 227 plic_set_threshold(pd, 0); 228 } 229 230 void plic_it_handle(struct plic_data *pd) 231 { 232 uint32_t id = plic_claim_interrupt(pd); 233 234 if (id <= pd->max_it) 235 itr_handle(id); 236 else 237 DMSG("ignoring interrupt %" PRIu32, id); 238 239 plic_complete_interrupt(pd, id); 240 } 241