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
aplic_get_idc_base(void)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
aplic_claim_interrupt(void)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
aplic_set_target(struct aplic_data * aplic,uint32_t source,uint32_t hart_idx,uint32_t iprio)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
aplic_init_base_addr(struct aplic_data * aplic,paddr_t aplic_base_pa)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
aplic_op_configure(struct itr_chip * chip,size_t it,uint32_t type,uint32_t prio)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
aplic_op_enable(struct itr_chip * chip,size_t it)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
aplic_op_disable(struct itr_chip * chip,size_t it)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
aplic_op_raise_pi(struct itr_chip * chip,size_t it)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
aplic_init(paddr_t aplic_base_pa)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
aplic_init_per_hart(void)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
aplic_it_handle(void)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
aplic_dump_state(void)191 void aplic_dump_state(void)
192 {
193 }
194