xref: /optee_os/core/drivers/plic.c (revision 3f6ed0a62ed0264f05743f692202e7fc1b98d6c7)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2022-2023 NXP
4  */
5 
6 #include <assert.h>
7 #include <config.h>
8 #include <drivers/plic.h>
9 #include <io.h>
10 #include <kernel/dt.h>
11 #include <kernel/interrupt.h>
12 #include <kernel/panic.h>
13 #include <mm/core_memprot.h>
14 #include <mm/core_mmu.h>
15 #include <trace.h>
16 
17 #define PLIC_PRIORITY_OFFSET		0
18 #define PLIC_PENDING_OFFSET		0x1000
19 #define PLIC_ENABLE_OFFSET		0x2000
20 #define PLIC_THRESHOLD_OFFSET		0x200000
21 #define PLIC_CLAIM_OFFSET		0x200004
22 
23 #define PLIC_PRIORITY_SHIFT_PER_SOURCE	U(2)
24 #define PLIC_PENDING_SHIFT_PER_SOURCE	U(0)
25 
26 #define PLIC_ENABLE_SHIFT_PER_TARGET	U(7)
27 #define PLIC_THRESHOLD_SHIFT_PER_TARGET	U(12)
28 #define PLIC_CLAIM_SHIFT_PER_TARGET	U(12)
29 
30 #define PLIC_PRIORITY(base, source) \
31 		((base) + PLIC_PRIORITY_OFFSET + \
32 		SHIFT_U32(source, PLIC_PRIORITY_SHIFT_PER_SOURCE) \
33 	)
34 #define PLIC_PENDING(base, source) \
35 		((base) + PLIC_PENDING_OFFSET + \
36 		(4 * ((source) / 32)) \
37 	)
38 #define PLIC_ENABLE(base, source, hart) \
39 		((base) + PLIC_ENABLE_OFFSET + \
40 		SHIFT_U32(hart, PLIC_ENABLE_SHIFT_PER_TARGET) +\
41 		(4 * ((source) / 32)) \
42 	)
43 #define PLIC_THRESHOLD(base, hart) \
44 		((base) + PLIC_THRESHOLD_OFFSET + \
45 		SHIFT_U32(hart, PLIC_THRESHOLD_SHIFT_PER_TARGET) \
46 	)
47 #define PLIC_COMPLETE(base, hart) \
48 		((base) + PLIC_CLAIM_OFFSET + \
49 		SHIFT_U32(hart, PLIC_CLAIM_SHIFT_PER_TARGET) \
50 	)
51 #define PLIC_CLAIM(base, hart) PLIC_COMPLETE(base, hart)
52 
53 register_phys_mem_pgdir(MEM_AREA_IO_SEC, PLIC_BASE, PLIC_REG_SIZE);
54 
55 static bool __maybe_unused
56 plic_is_pending(struct plic_data *pd, uint32_t source)
57 {
58 	return io_read32(PLIC_PENDING(pd->plic_base, source)) &
59 	       BIT(source % 32);
60 }
61 
62 static void plic_set_pending(struct plic_data *pd, uint32_t source)
63 {
64 	io_setbits32(PLIC_PENDING(pd->plic_base, source), BIT(source % 32));
65 }
66 
67 static void plic_enable_interrupt(struct plic_data *pd, uint32_t source)
68 {
69 	io_setbits32(PLIC_ENABLE(pd->plic_base, source, get_core_pos()),
70 		     BIT(source & 0x1f));
71 }
72 
73 static uint32_t __maybe_unused
74 plic_get_interrupt_enable(struct plic_data *pd, uint32_t source)
75 {
76 	return io_read32(PLIC_ENABLE(pd->plic_base, source, get_core_pos())) &
77 	       BIT(source & 0x1f);
78 }
79 
80 static void plic_disable_interrupt(struct plic_data *pd, uint32_t source)
81 {
82 	io_clrbits32(PLIC_ENABLE(pd->plic_base, source, get_core_pos()),
83 		     BIT(source & 0x1f));
84 }
85 
86 static uint32_t __maybe_unused plic_get_threshold(struct plic_data *pd)
87 {
88 	return io_read32(PLIC_THRESHOLD(pd->plic_base, get_core_pos()));
89 }
90 
91 static void plic_set_threshold(struct plic_data *pd, uint32_t threshold)
92 {
93 	io_write32(PLIC_THRESHOLD(pd->plic_base, get_core_pos()), threshold);
94 }
95 
96 static uint32_t __maybe_unused
97 plic_get_priority(struct plic_data *pd, uint32_t source)
98 {
99 	return io_read32(PLIC_PRIORITY(pd->plic_base, source));
100 }
101 
102 static void plic_set_priority(struct plic_data *pd, uint32_t source,
103 			      uint32_t priority)
104 {
105 	io_write32(PLIC_PRIORITY(pd->plic_base, source), priority);
106 }
107 
108 static uint32_t plic_claim_interrupt(struct plic_data *pd)
109 {
110 	return io_read32(PLIC_CLAIM(pd->plic_base, get_core_pos()));
111 }
112 
113 static void plic_complete_interrupt(struct plic_data *pd, uint32_t source)
114 {
115 	io_write32(PLIC_CLAIM(pd->plic_base, get_core_pos()), source);
116 }
117 
118 static void plic_op_add(struct itr_chip *chip, size_t it,
119 			uint32_t type __unused,
120 			uint32_t prio)
121 {
122 	struct plic_data *pd = container_of(chip, struct plic_data, chip);
123 
124 	if (it > pd->max_it)
125 		panic();
126 
127 	plic_disable_interrupt(pd, it);
128 	plic_set_priority(pd, it, prio);
129 }
130 
131 static void plic_op_enable(struct itr_chip *chip, size_t it)
132 {
133 	struct plic_data *pd = container_of(chip, struct plic_data, chip);
134 
135 	if (it > pd->max_it)
136 		panic();
137 
138 	plic_enable_interrupt(pd, it);
139 }
140 
141 static void plic_op_disable(struct itr_chip *chip, size_t it)
142 {
143 	struct plic_data *pd = container_of(chip, struct plic_data, chip);
144 
145 	if (it > pd->max_it)
146 		panic();
147 
148 	plic_disable_interrupt(pd, it);
149 }
150 
151 static void plic_op_raise_pi(struct itr_chip *chip, size_t it)
152 {
153 	struct plic_data *pd = container_of(chip, struct plic_data, chip);
154 
155 	if (it > pd->max_it)
156 		panic();
157 
158 	plic_set_pending(pd, it);
159 }
160 
161 static void plic_op_raise_sgi(struct itr_chip *chip __unused,
162 			      size_t it __unused, uint8_t cpu_mask __unused)
163 {
164 }
165 
166 static void plic_op_set_affinity(struct itr_chip *chip __unused,
167 				 size_t it __unused, uint8_t cpu_mask __unused)
168 {
169 }
170 
171 static int plic_dt_get_irq(const uint32_t *properties __unused,
172 			   int count __unused, uint32_t *type __unused,
173 			   uint32_t *prio __unused)
174 {
175 	return DT_INFO_INVALID_INTERRUPT;
176 }
177 
178 static size_t probe_max_it(vaddr_t plic_base __unused)
179 {
180 	return PLIC_NUM_SOURCES;
181 }
182 
183 static const struct itr_ops plic_ops = {
184 	.add = plic_op_add,
185 	.enable = plic_op_enable,
186 	.disable = plic_op_disable,
187 	.raise_pi = plic_op_raise_pi,
188 	.raise_sgi = plic_op_raise_sgi,
189 	.set_affinity = plic_op_set_affinity,
190 };
191 
192 void plic_init_base_addr(struct plic_data *pd, paddr_t plic_base_pa)
193 {
194 	vaddr_t plic_base = 0;
195 
196 	assert(cpu_mmu_enabled());
197 
198 	plic_base = core_mmu_get_va(plic_base_pa, MEM_AREA_IO_SEC,
199 				    PLIC_REG_SIZE);
200 	if (!plic_base)
201 		panic();
202 
203 	pd->plic_base = plic_base;
204 	pd->max_it = probe_max_it(plic_base);
205 	pd->chip.ops = &plic_ops;
206 
207 	if (IS_ENABLED(CFG_DT))
208 		pd->chip.dt_get_irq = plic_dt_get_irq;
209 }
210 
211 void plic_hart_init(struct plic_data *pd __unused)
212 {
213 	/* TODO: To be called by secondary harts */
214 }
215 
216 void plic_init(struct plic_data *pd, paddr_t plic_base_pa)
217 {
218 	size_t n = 0;
219 
220 	plic_init_base_addr(pd, plic_base_pa);
221 
222 	for (n = 0; n <= pd->max_it; n++) {
223 		plic_disable_interrupt(pd, n);
224 		plic_set_priority(pd, n, 1);
225 	}
226 
227 	plic_set_threshold(pd, 0);
228 }
229 
230 void plic_it_handle(struct plic_data *pd)
231 {
232 	uint32_t id = plic_claim_interrupt(pd);
233 
234 	if (id <= pd->max_it)
235 		itr_handle(id);
236 	else
237 		DMSG("ignoring interrupt %" PRIu32, id);
238 
239 	plic_complete_interrupt(pd, id);
240 }
241