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 ) 3865a1d74fSAlvin Chang #define PLIC_ENABLE(base, source, context) \ 3912438b45SMarouene Boubakri ((base) + PLIC_ENABLE_OFFSET + \ 4065a1d74fSAlvin Chang SHIFT_U32(context, PLIC_ENABLE_SHIFT_PER_TARGET) +\ 4112438b45SMarouene Boubakri (4 * ((source) / 32)) \ 4212438b45SMarouene Boubakri ) 4365a1d74fSAlvin Chang #define PLIC_THRESHOLD(base, context) \ 4412438b45SMarouene Boubakri ((base) + PLIC_THRESHOLD_OFFSET + \ 4565a1d74fSAlvin Chang SHIFT_U32(context, PLIC_THRESHOLD_SHIFT_PER_TARGET) \ 4612438b45SMarouene Boubakri ) 4765a1d74fSAlvin Chang #define PLIC_COMPLETE(base, context) \ 4812438b45SMarouene Boubakri ((base) + PLIC_CLAIM_OFFSET + \ 4965a1d74fSAlvin Chang SHIFT_U32(context, PLIC_CLAIM_SHIFT_PER_TARGET) \ 5012438b45SMarouene Boubakri ) 5165a1d74fSAlvin 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 55f33bc3efSAlvin Chang struct plic_data { 56f33bc3efSAlvin Chang vaddr_t plic_base; 57f33bc3efSAlvin Chang size_t max_it; 58f33bc3efSAlvin Chang struct itr_chip chip; 59f33bc3efSAlvin Chang }; 60f33bc3efSAlvin Chang 61f33bc3efSAlvin Chang static struct plic_data plic_data __nex_bss; 62f33bc3efSAlvin Chang 6365a1d74fSAlvin Chang /* 6465a1d74fSAlvin Chang * We assume that each hart has M-mode and S-mode, so the contexts look like: 6565a1d74fSAlvin Chang * PLIC context 0 is hart 0 M-mode 6665a1d74fSAlvin Chang * PLIC context 1 is hart 0 S-mode 6765a1d74fSAlvin Chang * PLIC context 2 is hart 1 M-mode 6865a1d74fSAlvin Chang * PLIC context 3 is hart 1 S-mode 6965a1d74fSAlvin Chang * ... 7065a1d74fSAlvin Chang */ 7165a1d74fSAlvin Chang static uint32_t plic_get_context(void) 7265a1d74fSAlvin Chang { 7365a1d74fSAlvin Chang size_t hartid = get_core_pos(); 7465a1d74fSAlvin Chang bool smode = IS_ENABLED(CFG_RISCV_S_MODE) ? true : false; 7565a1d74fSAlvin Chang 7665a1d74fSAlvin Chang return hartid * 2 + smode; 7765a1d74fSAlvin Chang } 7865a1d74fSAlvin Chang 7912438b45SMarouene Boubakri static bool __maybe_unused 8012438b45SMarouene Boubakri plic_is_pending(struct plic_data *pd, uint32_t source) 8112438b45SMarouene Boubakri { 8212438b45SMarouene Boubakri return io_read32(PLIC_PENDING(pd->plic_base, source)) & 8312438b45SMarouene Boubakri BIT(source % 32); 8412438b45SMarouene Boubakri } 8512438b45SMarouene Boubakri 8612438b45SMarouene Boubakri static void plic_set_pending(struct plic_data *pd, uint32_t source) 8712438b45SMarouene Boubakri { 8812438b45SMarouene Boubakri io_setbits32(PLIC_PENDING(pd->plic_base, source), BIT(source % 32)); 8912438b45SMarouene Boubakri } 9012438b45SMarouene Boubakri 9112438b45SMarouene Boubakri static void plic_enable_interrupt(struct plic_data *pd, uint32_t source) 9212438b45SMarouene Boubakri { 9365a1d74fSAlvin Chang uint32_t context = plic_get_context(); 9465a1d74fSAlvin Chang 9565a1d74fSAlvin Chang io_setbits32(PLIC_ENABLE(pd->plic_base, source, context), 9612438b45SMarouene Boubakri BIT(source & 0x1f)); 9712438b45SMarouene Boubakri } 9812438b45SMarouene Boubakri 9912438b45SMarouene Boubakri static uint32_t __maybe_unused 10012438b45SMarouene Boubakri plic_get_interrupt_enable(struct plic_data *pd, uint32_t source) 10112438b45SMarouene Boubakri { 10265a1d74fSAlvin Chang uint32_t context = plic_get_context(); 10365a1d74fSAlvin Chang 10465a1d74fSAlvin Chang return io_read32(PLIC_ENABLE(pd->plic_base, source, context)) & 10512438b45SMarouene Boubakri BIT(source & 0x1f); 10612438b45SMarouene Boubakri } 10712438b45SMarouene Boubakri 10812438b45SMarouene Boubakri static void plic_disable_interrupt(struct plic_data *pd, uint32_t source) 10912438b45SMarouene Boubakri { 11065a1d74fSAlvin Chang uint32_t context = plic_get_context(); 11165a1d74fSAlvin Chang 11265a1d74fSAlvin Chang io_clrbits32(PLIC_ENABLE(pd->plic_base, source, context), 11312438b45SMarouene Boubakri BIT(source & 0x1f)); 11412438b45SMarouene Boubakri } 11512438b45SMarouene Boubakri 11612438b45SMarouene Boubakri static uint32_t __maybe_unused plic_get_threshold(struct plic_data *pd) 11712438b45SMarouene Boubakri { 11865a1d74fSAlvin Chang uint32_t context = plic_get_context(); 11965a1d74fSAlvin Chang 12065a1d74fSAlvin Chang return io_read32(PLIC_THRESHOLD(pd->plic_base, context)); 12112438b45SMarouene Boubakri } 12212438b45SMarouene Boubakri 12312438b45SMarouene Boubakri static void plic_set_threshold(struct plic_data *pd, uint32_t threshold) 12412438b45SMarouene Boubakri { 12565a1d74fSAlvin Chang uint32_t context = plic_get_context(); 12665a1d74fSAlvin Chang 12765a1d74fSAlvin Chang io_write32(PLIC_THRESHOLD(pd->plic_base, context), threshold); 12812438b45SMarouene Boubakri } 12912438b45SMarouene Boubakri 13012438b45SMarouene Boubakri static uint32_t __maybe_unused 13112438b45SMarouene Boubakri plic_get_priority(struct plic_data *pd, uint32_t source) 13212438b45SMarouene Boubakri { 13312438b45SMarouene Boubakri return io_read32(PLIC_PRIORITY(pd->plic_base, source)); 13412438b45SMarouene Boubakri } 13512438b45SMarouene Boubakri 13612438b45SMarouene Boubakri static void plic_set_priority(struct plic_data *pd, uint32_t source, 13712438b45SMarouene Boubakri uint32_t priority) 13812438b45SMarouene Boubakri { 13912438b45SMarouene Boubakri io_write32(PLIC_PRIORITY(pd->plic_base, source), priority); 14012438b45SMarouene Boubakri } 14112438b45SMarouene Boubakri 14212438b45SMarouene Boubakri static uint32_t plic_claim_interrupt(struct plic_data *pd) 14312438b45SMarouene Boubakri { 14465a1d74fSAlvin Chang uint32_t context = plic_get_context(); 14565a1d74fSAlvin Chang 14665a1d74fSAlvin Chang return io_read32(PLIC_CLAIM(pd->plic_base, context)); 14712438b45SMarouene Boubakri } 14812438b45SMarouene Boubakri 14912438b45SMarouene Boubakri static void plic_complete_interrupt(struct plic_data *pd, uint32_t source) 15012438b45SMarouene Boubakri { 15165a1d74fSAlvin Chang uint32_t context = plic_get_context(); 15265a1d74fSAlvin Chang 15365a1d74fSAlvin Chang io_write32(PLIC_CLAIM(pd->plic_base, context), source); 15412438b45SMarouene Boubakri } 15512438b45SMarouene Boubakri 15612438b45SMarouene Boubakri static void plic_op_add(struct itr_chip *chip, size_t it, 15712438b45SMarouene Boubakri uint32_t type __unused, 15812438b45SMarouene Boubakri uint32_t prio) 15912438b45SMarouene Boubakri { 16012438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 16112438b45SMarouene Boubakri 16212438b45SMarouene Boubakri if (it > pd->max_it) 16312438b45SMarouene Boubakri panic(); 16412438b45SMarouene Boubakri 16512438b45SMarouene Boubakri plic_disable_interrupt(pd, it); 16612438b45SMarouene Boubakri plic_set_priority(pd, it, prio); 16712438b45SMarouene Boubakri } 16812438b45SMarouene Boubakri 16912438b45SMarouene Boubakri static void plic_op_enable(struct itr_chip *chip, size_t it) 17012438b45SMarouene Boubakri { 17112438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 17212438b45SMarouene Boubakri 17312438b45SMarouene Boubakri if (it > pd->max_it) 17412438b45SMarouene Boubakri panic(); 17512438b45SMarouene Boubakri 17612438b45SMarouene Boubakri plic_enable_interrupt(pd, it); 17712438b45SMarouene Boubakri } 17812438b45SMarouene Boubakri 17912438b45SMarouene Boubakri static void plic_op_disable(struct itr_chip *chip, size_t it) 18012438b45SMarouene Boubakri { 18112438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 18212438b45SMarouene Boubakri 18312438b45SMarouene Boubakri if (it > pd->max_it) 18412438b45SMarouene Boubakri panic(); 18512438b45SMarouene Boubakri 18612438b45SMarouene Boubakri plic_disable_interrupt(pd, it); 18712438b45SMarouene Boubakri } 18812438b45SMarouene Boubakri 18912438b45SMarouene Boubakri static void plic_op_raise_pi(struct itr_chip *chip, size_t it) 19012438b45SMarouene Boubakri { 19112438b45SMarouene Boubakri struct plic_data *pd = container_of(chip, struct plic_data, chip); 19212438b45SMarouene Boubakri 19312438b45SMarouene Boubakri if (it > pd->max_it) 19412438b45SMarouene Boubakri panic(); 19512438b45SMarouene Boubakri 19612438b45SMarouene Boubakri plic_set_pending(pd, it); 19712438b45SMarouene Boubakri } 19812438b45SMarouene Boubakri 19912438b45SMarouene Boubakri static void plic_op_raise_sgi(struct itr_chip *chip __unused, 20012438b45SMarouene Boubakri size_t it __unused, uint8_t cpu_mask __unused) 20112438b45SMarouene Boubakri { 20212438b45SMarouene Boubakri } 20312438b45SMarouene Boubakri 20412438b45SMarouene Boubakri static void plic_op_set_affinity(struct itr_chip *chip __unused, 20512438b45SMarouene Boubakri size_t it __unused, uint8_t cpu_mask __unused) 20612438b45SMarouene Boubakri { 20712438b45SMarouene Boubakri } 20812438b45SMarouene Boubakri 20912438b45SMarouene Boubakri static int plic_dt_get_irq(const uint32_t *properties __unused, 21012438b45SMarouene Boubakri int count __unused, uint32_t *type __unused, 21112438b45SMarouene Boubakri uint32_t *prio __unused) 21212438b45SMarouene Boubakri { 21312438b45SMarouene Boubakri return DT_INFO_INVALID_INTERRUPT; 21412438b45SMarouene Boubakri } 21512438b45SMarouene Boubakri 21612438b45SMarouene Boubakri static size_t probe_max_it(vaddr_t plic_base __unused) 21712438b45SMarouene Boubakri { 21812438b45SMarouene Boubakri return PLIC_NUM_SOURCES; 21912438b45SMarouene Boubakri } 22012438b45SMarouene Boubakri 22112438b45SMarouene Boubakri static const struct itr_ops plic_ops = { 22212438b45SMarouene Boubakri .add = plic_op_add, 223*a1ee298aSAlvin Chang .mask = plic_op_disable, 224*a1ee298aSAlvin Chang .unmask = plic_op_enable, 22512438b45SMarouene Boubakri .enable = plic_op_enable, 22612438b45SMarouene Boubakri .disable = plic_op_disable, 22712438b45SMarouene Boubakri .raise_pi = plic_op_raise_pi, 22812438b45SMarouene Boubakri .raise_sgi = plic_op_raise_sgi, 22912438b45SMarouene Boubakri .set_affinity = plic_op_set_affinity, 23012438b45SMarouene Boubakri }; 23112438b45SMarouene Boubakri 232f33bc3efSAlvin Chang static void plic_init_base_addr(struct plic_data *pd, paddr_t plic_base_pa) 23312438b45SMarouene Boubakri { 23412438b45SMarouene Boubakri vaddr_t plic_base = 0; 23512438b45SMarouene Boubakri 23612438b45SMarouene Boubakri assert(cpu_mmu_enabled()); 23712438b45SMarouene Boubakri 23812438b45SMarouene Boubakri plic_base = core_mmu_get_va(plic_base_pa, MEM_AREA_IO_SEC, 23912438b45SMarouene Boubakri PLIC_REG_SIZE); 24012438b45SMarouene Boubakri if (!plic_base) 24112438b45SMarouene Boubakri panic(); 24212438b45SMarouene Boubakri 24312438b45SMarouene Boubakri pd->plic_base = plic_base; 24412438b45SMarouene Boubakri pd->max_it = probe_max_it(plic_base); 24512438b45SMarouene Boubakri pd->chip.ops = &plic_ops; 24612438b45SMarouene Boubakri 24712438b45SMarouene Boubakri if (IS_ENABLED(CFG_DT)) 24812438b45SMarouene Boubakri pd->chip.dt_get_irq = plic_dt_get_irq; 24912438b45SMarouene Boubakri } 25012438b45SMarouene Boubakri 251f33bc3efSAlvin Chang void plic_hart_init(void) 25212438b45SMarouene Boubakri { 25312438b45SMarouene Boubakri /* TODO: To be called by secondary harts */ 25412438b45SMarouene Boubakri } 25512438b45SMarouene Boubakri 256f33bc3efSAlvin Chang void plic_init(paddr_t plic_base_pa) 25712438b45SMarouene Boubakri { 258f33bc3efSAlvin Chang struct plic_data *pd = &plic_data; 25912438b45SMarouene Boubakri size_t n = 0; 26012438b45SMarouene Boubakri 26112438b45SMarouene Boubakri plic_init_base_addr(pd, plic_base_pa); 26212438b45SMarouene Boubakri 26312438b45SMarouene Boubakri for (n = 0; n <= pd->max_it; n++) { 26412438b45SMarouene Boubakri plic_disable_interrupt(pd, n); 26512438b45SMarouene Boubakri plic_set_priority(pd, n, 1); 26612438b45SMarouene Boubakri } 26712438b45SMarouene Boubakri 26812438b45SMarouene Boubakri plic_set_threshold(pd, 0); 269f33bc3efSAlvin Chang 270f33bc3efSAlvin Chang interrupt_main_init(&plic_data.chip); 27112438b45SMarouene Boubakri } 27212438b45SMarouene Boubakri 273f33bc3efSAlvin Chang void plic_it_handle(void) 27412438b45SMarouene Boubakri { 275f33bc3efSAlvin Chang struct plic_data *pd = &plic_data; 27612438b45SMarouene Boubakri uint32_t id = plic_claim_interrupt(pd); 27712438b45SMarouene Boubakri 27812438b45SMarouene Boubakri if (id <= pd->max_it) 27912438b45SMarouene Boubakri itr_handle(id); 28012438b45SMarouene Boubakri else 28112438b45SMarouene Boubakri DMSG("ignoring interrupt %" PRIu32, id); 28212438b45SMarouene Boubakri 28312438b45SMarouene Boubakri plic_complete_interrupt(pd, id); 28412438b45SMarouene Boubakri } 285