xref: /optee_os/core/drivers/aplic_direct.c (revision 69e9ad1b8e9db39a5dce0e620ac5ea77fc93f5a5)
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