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