112438b45SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause 212438b45SMarouene Boubakri /* 312438b45SMarouene Boubakri * Copyright 2022-2023 NXP 412438b45SMarouene Boubakri */ 512438b45SMarouene Boubakri 612438b45SMarouene Boubakri #include <assert.h> 712438b45SMarouene Boubakri #include <config.h> 812438b45SMarouene Boubakri #include <drivers/plic.h> 912438b45SMarouene Boubakri #include <io.h> 1012438b45SMarouene Boubakri #include <kernel/dt.h> 1112438b45SMarouene Boubakri #include <kernel/interrupt.h> 1212438b45SMarouene Boubakri #include <kernel/panic.h> 1312438b45SMarouene Boubakri #include <mm/core_memprot.h> 1412438b45SMarouene Boubakri #include <mm/core_mmu.h> 1512438b45SMarouene Boubakri #include <trace.h> 1612438b45SMarouene Boubakri 1712438b45SMarouene Boubakri #define PLIC_PRIORITY_OFFSET 0 1812438b45SMarouene Boubakri #define PLIC_PENDING_OFFSET 0x1000 1912438b45SMarouene Boubakri #define PLIC_ENABLE_OFFSET 0x2000 2012438b45SMarouene Boubakri #define PLIC_THRESHOLD_OFFSET 0x200000 2112438b45SMarouene Boubakri #define PLIC_CLAIM_OFFSET 0x200004 2212438b45SMarouene Boubakri 2312438b45SMarouene Boubakri #define PLIC_PRIORITY_SHIFT_PER_SOURCE U(2) 2412438b45SMarouene Boubakri #define PLIC_PENDING_SHIFT_PER_SOURCE U(0) 2512438b45SMarouene Boubakri 2612438b45SMarouene Boubakri #define PLIC_ENABLE_SHIFT_PER_TARGET U(7) 2712438b45SMarouene Boubakri #define PLIC_THRESHOLD_SHIFT_PER_TARGET U(12) 2812438b45SMarouene Boubakri #define PLIC_CLAIM_SHIFT_PER_TARGET U(12) 2912438b45SMarouene Boubakri 3012438b45SMarouene Boubakri #define PLIC_PRIORITY(base, source) \ 3112438b45SMarouene Boubakri ((base) + PLIC_PRIORITY_OFFSET + \ 3212438b45SMarouene Boubakri SHIFT_U32(source, PLIC_PRIORITY_SHIFT_PER_SOURCE) \ 3312438b45SMarouene Boubakri ) 3412438b45SMarouene Boubakri #define PLIC_PENDING(base, source) \ 3512438b45SMarouene Boubakri ((base) + PLIC_PENDING_OFFSET + \ 3612438b45SMarouene Boubakri (4 * ((source) / 32)) \ 3712438b45SMarouene Boubakri ) 38*65a1d74fSAlvin Chang #define PLIC_ENABLE(base, source, context) \ 3912438b45SMarouene Boubakri ((base) + PLIC_ENABLE_OFFSET + \ 40*65a1d74fSAlvin Chang SHIFT_U32(context, PLIC_ENABLE_SHIFT_PER_TARGET) +\ 4112438b45SMarouene Boubakri (4 * ((source) / 32)) \ 4212438b45SMarouene Boubakri ) 43*65a1d74fSAlvin Chang #define PLIC_THRESHOLD(base, context) \ 4412438b45SMarouene Boubakri ((base) + PLIC_THRESHOLD_OFFSET + \ 45*65a1d74fSAlvin Chang SHIFT_U32(context, PLIC_THRESHOLD_SHIFT_PER_TARGET) \ 4612438b45SMarouene Boubakri ) 47*65a1d74fSAlvin Chang #define PLIC_COMPLETE(base, context) \ 4812438b45SMarouene Boubakri ((base) + PLIC_CLAIM_OFFSET + \ 49*65a1d74fSAlvin Chang SHIFT_U32(context, PLIC_CLAIM_SHIFT_PER_TARGET) \ 5012438b45SMarouene Boubakri ) 51*65a1d74fSAlvin Chang #define PLIC_CLAIM(base, context) PLIC_COMPLETE(base, context) 5212438b45SMarouene Boubakri 5312438b45SMarouene Boubakri register_phys_mem_pgdir(MEM_AREA_IO_SEC, PLIC_BASE, PLIC_REG_SIZE); 5412438b45SMarouene Boubakri 55*65a1d74fSAlvin Chang /* 56*65a1d74fSAlvin Chang * We assume that each hart has M-mode and S-mode, so the contexts look like: 57*65a1d74fSAlvin Chang * PLIC context 0 is hart 0 M-mode 58*65a1d74fSAlvin Chang * PLIC context 1 is hart 0 S-mode 59*65a1d74fSAlvin Chang * PLIC context 2 is hart 1 M-mode 60*65a1d74fSAlvin Chang * PLIC context 3 is hart 1 S-mode 61*65a1d74fSAlvin Chang * ... 62*65a1d74fSAlvin Chang */ 63*65a1d74fSAlvin Chang static uint32_t plic_get_context(void) 64*65a1d74fSAlvin Chang { 65*65a1d74fSAlvin Chang size_t hartid = get_core_pos(); 66*65a1d74fSAlvin Chang bool smode = IS_ENABLED(CFG_RISCV_S_MODE) ? true : false; 67*65a1d74fSAlvin Chang 68*65a1d74fSAlvin Chang return hartid * 2 + smode; 69*65a1d74fSAlvin Chang } 70*65a1d74fSAlvin Chang 7112438b45SMarouene Boubakri static bool __maybe_unused 7212438b45SMarouene Boubakri plic_is_pending(struct plic_data *pd, uint32_t source) 7312438b45SMarouene Boubakri { 7412438b45SMarouene Boubakri return io_read32(PLIC_PENDING(pd->plic_base, source)) & 7512438b45SMarouene Boubakri BIT(source % 32); 7612438b45SMarouene Boubakri } 7712438b45SMarouene Boubakri 7812438b45SMarouene Boubakri static void plic_set_pending(struct plic_data *pd, uint32_t source) 7912438b45SMarouene Boubakri { 8012438b45SMarouene Boubakri io_setbits32(PLIC_PENDING(pd->plic_base, source), BIT(source % 32)); 8112438b45SMarouene Boubakri } 8212438b45SMarouene Boubakri 8312438b45SMarouene Boubakri static void plic_enable_interrupt(struct plic_data *pd, uint32_t source) 8412438b45SMarouene Boubakri { 85*65a1d74fSAlvin Chang uint32_t context = plic_get_context(); 86*65a1d74fSAlvin Chang 87*65a1d74fSAlvin Chang io_setbits32(PLIC_ENABLE(pd->plic_base, source, context), 8812438b45SMarouene Boubakri BIT(source & 0x1f)); 8912438b45SMarouene Boubakri } 9012438b45SMarouene Boubakri 9112438b45SMarouene Boubakri static uint32_t __maybe_unused 9212438b45SMarouene Boubakri plic_get_interrupt_enable(struct plic_data *pd, uint32_t source) 9312438b45SMarouene Boubakri { 94*65a1d74fSAlvin Chang uint32_t context = plic_get_context(); 95*65a1d74fSAlvin Chang 96*65a1d74fSAlvin Chang return io_read32(PLIC_ENABLE(pd->plic_base, source, context)) & 9712438b45SMarouene Boubakri BIT(source & 0x1f); 9812438b45SMarouene Boubakri } 9912438b45SMarouene Boubakri 10012438b45SMarouene Boubakri static void plic_disable_interrupt(struct plic_data *pd, uint32_t source) 10112438b45SMarouene Boubakri { 102*65a1d74fSAlvin Chang uint32_t context = plic_get_context(); 103*65a1d74fSAlvin Chang 104*65a1d74fSAlvin Chang io_clrbits32(PLIC_ENABLE(pd->plic_base, source, context), 10512438b45SMarouene Boubakri BIT(source & 0x1f)); 10612438b45SMarouene Boubakri } 10712438b45SMarouene Boubakri 10812438b45SMarouene Boubakri static uint32_t __maybe_unused plic_get_threshold(struct plic_data *pd) 10912438b45SMarouene Boubakri { 110*65a1d74fSAlvin Chang uint32_t context = plic_get_context(); 111*65a1d74fSAlvin Chang 112*65a1d74fSAlvin Chang return io_read32(PLIC_THRESHOLD(pd->plic_base, context)); 11312438b45SMarouene Boubakri } 11412438b45SMarouene Boubakri 11512438b45SMarouene Boubakri static void plic_set_threshold(struct plic_data *pd, uint32_t threshold) 11612438b45SMarouene Boubakri { 117*65a1d74fSAlvin Chang uint32_t context = plic_get_context(); 118*65a1d74fSAlvin Chang 119*65a1d74fSAlvin Chang io_write32(PLIC_THRESHOLD(pd->plic_base, context), threshold); 12012438b45SMarouene Boubakri } 12112438b45SMarouene Boubakri 12212438b45SMarouene Boubakri static uint32_t __maybe_unused 12312438b45SMarouene Boubakri plic_get_priority(struct plic_data *pd, uint32_t source) 12412438b45SMarouene Boubakri { 12512438b45SMarouene Boubakri return io_read32(PLIC_PRIORITY(pd->plic_base, source)); 12612438b45SMarouene Boubakri } 12712438b45SMarouene Boubakri 12812438b45SMarouene Boubakri static void plic_set_priority(struct plic_data *pd, uint32_t source, 12912438b45SMarouene Boubakri uint32_t priority) 13012438b45SMarouene Boubakri { 13112438b45SMarouene Boubakri io_write32(PLIC_PRIORITY(pd->plic_base, source), priority); 13212438b45SMarouene Boubakri } 13312438b45SMarouene Boubakri 13412438b45SMarouene Boubakri static uint32_t plic_claim_interrupt(struct plic_data *pd) 13512438b45SMarouene Boubakri { 136*65a1d74fSAlvin Chang uint32_t context = plic_get_context(); 137*65a1d74fSAlvin Chang 138*65a1d74fSAlvin Chang return io_read32(PLIC_CLAIM(pd->plic_base, context)); 13912438b45SMarouene Boubakri } 14012438b45SMarouene Boubakri 14112438b45SMarouene Boubakri static void plic_complete_interrupt(struct plic_data *pd, uint32_t source) 14212438b45SMarouene Boubakri { 143*65a1d74fSAlvin Chang uint32_t context = plic_get_context(); 144*65a1d74fSAlvin Chang 145*65a1d74fSAlvin Chang io_write32(PLIC_CLAIM(pd->plic_base, context), source); 14612438b45SMarouene Boubakri } 14712438b45SMarouene Boubakri 14812438b45SMarouene Boubakri static void plic_op_add(struct itr_chip *chip, size_t it, 14912438b45SMarouene Boubakri uint32_t type __unused, 15012438b45SMarouene Boubakri uint32_t prio) 15112438b45SMarouene Boubakri { 15212438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 15312438b45SMarouene Boubakri 15412438b45SMarouene Boubakri if (it > pd->max_it) 15512438b45SMarouene Boubakri panic(); 15612438b45SMarouene Boubakri 15712438b45SMarouene Boubakri plic_disable_interrupt(pd, it); 15812438b45SMarouene Boubakri plic_set_priority(pd, it, prio); 15912438b45SMarouene Boubakri } 16012438b45SMarouene Boubakri 16112438b45SMarouene Boubakri static void plic_op_enable(struct itr_chip *chip, size_t it) 16212438b45SMarouene Boubakri { 16312438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 16412438b45SMarouene Boubakri 16512438b45SMarouene Boubakri if (it > pd->max_it) 16612438b45SMarouene Boubakri panic(); 16712438b45SMarouene Boubakri 16812438b45SMarouene Boubakri plic_enable_interrupt(pd, it); 16912438b45SMarouene Boubakri } 17012438b45SMarouene Boubakri 17112438b45SMarouene Boubakri static void plic_op_disable(struct itr_chip *chip, size_t it) 17212438b45SMarouene Boubakri { 17312438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 17412438b45SMarouene Boubakri 17512438b45SMarouene Boubakri if (it > pd->max_it) 17612438b45SMarouene Boubakri panic(); 17712438b45SMarouene Boubakri 17812438b45SMarouene Boubakri plic_disable_interrupt(pd, it); 17912438b45SMarouene Boubakri } 18012438b45SMarouene Boubakri 18112438b45SMarouene Boubakri static void plic_op_raise_pi(struct itr_chip *chip, size_t it) 18212438b45SMarouene Boubakri { 18312438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 18412438b45SMarouene Boubakri 18512438b45SMarouene Boubakri if (it > pd->max_it) 18612438b45SMarouene Boubakri panic(); 18712438b45SMarouene Boubakri 18812438b45SMarouene Boubakri plic_set_pending(pd, it); 18912438b45SMarouene Boubakri } 19012438b45SMarouene Boubakri 19112438b45SMarouene Boubakri static void plic_op_raise_sgi(struct itr_chip *chip __unused, 19212438b45SMarouene Boubakri size_t it __unused, uint8_t cpu_mask __unused) 19312438b45SMarouene Boubakri { 19412438b45SMarouene Boubakri } 19512438b45SMarouene Boubakri 19612438b45SMarouene Boubakri static void plic_op_set_affinity(struct itr_chip *chip __unused, 19712438b45SMarouene Boubakri size_t it __unused, uint8_t cpu_mask __unused) 19812438b45SMarouene Boubakri { 19912438b45SMarouene Boubakri } 20012438b45SMarouene Boubakri 20112438b45SMarouene Boubakri static int plic_dt_get_irq(const uint32_t *properties __unused, 20212438b45SMarouene Boubakri int count __unused, uint32_t *type __unused, 20312438b45SMarouene Boubakri uint32_t *prio __unused) 20412438b45SMarouene Boubakri { 20512438b45SMarouene Boubakri return DT_INFO_INVALID_INTERRUPT; 20612438b45SMarouene Boubakri } 20712438b45SMarouene Boubakri 20812438b45SMarouene Boubakri static size_t probe_max_it(vaddr_t plic_base __unused) 20912438b45SMarouene Boubakri { 21012438b45SMarouene Boubakri return PLIC_NUM_SOURCES; 21112438b45SMarouene Boubakri } 21212438b45SMarouene Boubakri 21312438b45SMarouene Boubakri static const struct itr_ops plic_ops = { 21412438b45SMarouene Boubakri .add = plic_op_add, 21512438b45SMarouene Boubakri .enable = plic_op_enable, 21612438b45SMarouene Boubakri .disable = plic_op_disable, 21712438b45SMarouene Boubakri .raise_pi = plic_op_raise_pi, 21812438b45SMarouene Boubakri .raise_sgi = plic_op_raise_sgi, 21912438b45SMarouene Boubakri .set_affinity = plic_op_set_affinity, 22012438b45SMarouene Boubakri }; 22112438b45SMarouene Boubakri 22212438b45SMarouene Boubakri void plic_init_base_addr(struct plic_data *pd, paddr_t plic_base_pa) 22312438b45SMarouene Boubakri { 22412438b45SMarouene Boubakri vaddr_t plic_base = 0; 22512438b45SMarouene Boubakri 22612438b45SMarouene Boubakri assert(cpu_mmu_enabled()); 22712438b45SMarouene Boubakri 22812438b45SMarouene Boubakri plic_base = core_mmu_get_va(plic_base_pa, MEM_AREA_IO_SEC, 22912438b45SMarouene Boubakri PLIC_REG_SIZE); 23012438b45SMarouene Boubakri if (!plic_base) 23112438b45SMarouene Boubakri panic(); 23212438b45SMarouene Boubakri 23312438b45SMarouene Boubakri pd->plic_base = plic_base; 23412438b45SMarouene Boubakri pd->max_it = probe_max_it(plic_base); 23512438b45SMarouene Boubakri pd->chip.ops = &plic_ops; 23612438b45SMarouene Boubakri 23712438b45SMarouene Boubakri if (IS_ENABLED(CFG_DT)) 23812438b45SMarouene Boubakri pd->chip.dt_get_irq = plic_dt_get_irq; 23912438b45SMarouene Boubakri } 24012438b45SMarouene Boubakri 24112438b45SMarouene Boubakri void plic_hart_init(struct plic_data *pd __unused) 24212438b45SMarouene Boubakri { 24312438b45SMarouene Boubakri /* TODO: To be called by secondary harts */ 24412438b45SMarouene Boubakri } 24512438b45SMarouene Boubakri 24612438b45SMarouene Boubakri void plic_init(struct plic_data *pd, paddr_t plic_base_pa) 24712438b45SMarouene Boubakri { 24812438b45SMarouene Boubakri size_t n = 0; 24912438b45SMarouene Boubakri 25012438b45SMarouene Boubakri plic_init_base_addr(pd, plic_base_pa); 25112438b45SMarouene Boubakri 25212438b45SMarouene Boubakri for (n = 0; n <= pd->max_it; n++) { 25312438b45SMarouene Boubakri plic_disable_interrupt(pd, n); 25412438b45SMarouene Boubakri plic_set_priority(pd, n, 1); 25512438b45SMarouene Boubakri } 25612438b45SMarouene Boubakri 25712438b45SMarouene Boubakri plic_set_threshold(pd, 0); 25812438b45SMarouene Boubakri } 25912438b45SMarouene Boubakri 26012438b45SMarouene Boubakri void plic_it_handle(struct plic_data *pd) 26112438b45SMarouene Boubakri { 26212438b45SMarouene Boubakri uint32_t id = plic_claim_interrupt(pd); 26312438b45SMarouene Boubakri 26412438b45SMarouene Boubakri if (id <= pd->max_it) 26512438b45SMarouene Boubakri itr_handle(id); 26612438b45SMarouene Boubakri else 26712438b45SMarouene Boubakri DMSG("ignoring interrupt %" PRIu32, id); 26812438b45SMarouene Boubakri 26912438b45SMarouene Boubakri plic_complete_interrupt(pd, id); 27012438b45SMarouene Boubakri } 271