1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC) 4 */ 5 6 #include <assert.h> 7 #include <config.h> 8 #include <drivers/aplic.h> 9 #include <drivers/aplic_priv.h> 10 #include <io.h> 11 #include <kernel/interrupt.h> 12 #include <kernel/misc.h> 13 #include <kernel/panic.h> 14 #include <mm/core_memprot.h> 15 #include <mm/core_mmu.h> 16 #include <trace.h> 17 #include <types_ext.h> 18 #include <util.h> 19 20 #define APLIC_MAX_IDC BIT(14) /* 16384 */ 21 #define APLIC_IDC_BASE 0x4000 22 #define APLIC_IDC_SIZE 32 23 24 /* Interrupt Delivery Control (IDC) structure */ 25 #define APLIC_IDC_IDELIVERY 0x00 26 #define APLIC_IDC_IFORCE 0x04 27 #define APLIC_IDC_ITHRESHOLD 0x08 28 29 #define APLIC_IDC_TOPI 0x18 30 #define APLIC_IDC_TOPI_ID_SHIFT 16 31 #define APLIC_IDC_TOPI_ID_MASK GENMASK_32(25, 16) 32 #define APLIC_IDC_TOPI_PRIO_MASK GENMASK_32(7, 0) 33 34 #define APLIC_IDC_CLAIMI 0x1C 35 36 #define APLIC_DISABLE_IDELIVERY 0 37 #define APLIC_ENABLE_IDELIVERY 1 38 39 #define APLIC_DISABLE_ITHRESHOLD 1 40 #define APLIC_ENABLE_ITHRESHOLD 0 41 42 static struct aplic_data aplic_data __nex_bss; 43 44 static vaddr_t aplic_get_idc_base(void) 45 { 46 struct aplic_data *aplic = &aplic_data; 47 size_t hartid = get_core_pos(); 48 49 return aplic->aplic_base + APLIC_IDC_BASE + hartid * APLIC_IDC_SIZE; 50 } 51 52 static uint32_t aplic_claim_interrupt(void) 53 { 54 uint32_t id = 0; 55 vaddr_t idc_base = aplic_get_idc_base(); 56 57 id = io_read32(idc_base + APLIC_IDC_CLAIMI); 58 id >>= APLIC_IDC_TOPI_ID_SHIFT; 59 60 return id; 61 } 62 63 static void aplic_set_target(struct aplic_data *aplic, uint32_t source, 64 uint32_t hart_idx, uint32_t iprio) 65 { 66 vaddr_t target = 0; 67 uint32_t val = 0; 68 69 val = SHIFT_U32(hart_idx, APLIC_TARGET_HART_IDX_SHIFT) & 70 APLIC_TARGET_HART_IDX_MASK; 71 val |= iprio & APLIC_TARGET_IPRIO_MASK; 72 73 target = aplic->aplic_base + APLIC_TARGET_BASE + 74 (source - 1) * sizeof(uint32_t); 75 io_write32(target, val); 76 } 77 78 static void aplic_init_base_addr(struct aplic_data *aplic, 79 paddr_t aplic_base_pa) 80 { 81 vaddr_t aplic_base = 0; 82 83 assert(cpu_mmu_enabled()); 84 85 aplic_base = core_mmu_get_va(aplic_base_pa, MEM_AREA_IO_SEC, 86 APLIC_SIZE); 87 if (!aplic_base) 88 panic(); 89 90 aplic->aplic_base = aplic_base; 91 aplic->size = APLIC_SIZE; 92 aplic->targets_mmode = false; 93 aplic->num_idc = APLIC_NUM_IDC; 94 aplic->num_source = APLIC_NUM_SOURCE; 95 } 96 97 static void aplic_op_configure(struct itr_chip *chip, size_t it, uint32_t type, 98 uint32_t prio) 99 { 100 struct aplic_data *aplic = container_of(chip, struct aplic_data, chip); 101 size_t hartid = get_core_pos(); 102 103 if (aplic_is_bad_it(aplic, it)) 104 panic(); 105 106 aplic_disable_interrupt(aplic, it); 107 if (aplic_set_source_mode(aplic, it, type)) 108 panic(); 109 aplic_set_target(aplic, it, hartid, prio); 110 } 111 112 static void aplic_op_enable(struct itr_chip *chip, size_t it) 113 { 114 struct aplic_data *aplic = container_of(chip, struct aplic_data, chip); 115 116 if (aplic_is_bad_it(aplic, it)) 117 panic(); 118 119 aplic_enable_interrupt(aplic, it); 120 } 121 122 static void aplic_op_disable(struct itr_chip *chip, size_t it) 123 { 124 struct aplic_data *aplic = container_of(chip, struct aplic_data, chip); 125 126 if (aplic_is_bad_it(aplic, it)) 127 panic(); 128 129 aplic_disable_interrupt(aplic, it); 130 } 131 132 static void aplic_op_raise_pi(struct itr_chip *chip, size_t it) 133 { 134 struct aplic_data *aplic = container_of(chip, struct aplic_data, chip); 135 136 if (aplic_is_bad_it(aplic, it)) 137 panic(); 138 139 aplic_set_pending(aplic, it); 140 } 141 142 static const struct itr_ops aplic_ops = { 143 .configure = aplic_op_configure, 144 .enable = aplic_op_enable, 145 .disable = aplic_op_disable, 146 .mask = aplic_op_disable, 147 .unmask = aplic_op_enable, 148 .raise_pi = aplic_op_raise_pi, 149 }; 150 151 void aplic_init(paddr_t aplic_base_pa) 152 { 153 struct aplic_data *aplic = &aplic_data; 154 TEE_Result res = TEE_ERROR_GENERIC; 155 156 if (IS_ENABLED(CFG_DT)) { 157 res = aplic_init_from_device_tree(aplic); 158 if (res) 159 panic(); 160 } else { 161 aplic_init_base_addr(aplic, aplic_base_pa); 162 } 163 164 aplic->chip.ops = &aplic_ops; 165 166 aplic_init_per_hart(); 167 io_write32(aplic->aplic_base + APLIC_DOMAINCFG, APLIC_DOMAINCFG_IE); 168 169 interrupt_main_init(&aplic_data.chip); 170 } 171 172 void aplic_init_per_hart(void) 173 { 174 vaddr_t idc_base = aplic_get_idc_base(); 175 176 io_write32(idc_base + APLIC_IDC_IDELIVERY, APLIC_ENABLE_IDELIVERY); 177 io_write32(idc_base + APLIC_IDC_ITHRESHOLD, APLIC_ENABLE_ITHRESHOLD); 178 } 179 180 void aplic_it_handle(void) 181 { 182 struct aplic_data *aplic = &aplic_data; 183 uint32_t id = aplic_claim_interrupt(); 184 185 if (id > 0 && id <= aplic->num_source) 186 interrupt_call_handlers(&aplic->chip, id); 187 else 188 DMSG("ignoring interrupt %" PRIu32, id); 189 } 190 191 void aplic_dump_state(void) 192 { 193 } 194