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