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