1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #include <arch/tools.h>
13 #include <arch/mmu.h>
14 #include <arch/machine/smp.h>
15 #include <common/types.h>
16 #include <common/macro.h>
17 #include <mm/mm.h>
18 #include <object/irq.h>
19
20 static int nr_lines;
21
22 enum gic_op_t {
23 GICV3_OP_SET_PRIO = 1,
24 GICV3_OP_SET_GROUP,
25 GICV3_OP_SET_TARGET,
26 GICV3_OP_SET_PENDING,
27 GICV3_OP_MASK,
28 };
29
set32(vaddr_t addr,u32 set_mask)30 static inline void set32(vaddr_t addr, u32 set_mask)
31 {
32 put32(addr, get32(addr) | set_mask);
33 }
34
clr32(vaddr_t addr,u32 set_mask)35 static inline void clr32(vaddr_t addr, u32 set_mask)
36 {
37 put32(addr, get32(addr) & ~set_mask);
38 }
39
gicv3_enable_sre(void)40 static inline bool gicv3_enable_sre(void)
41 {
42 u32 val;
43
44 val = read_sys_reg(ICC_SRE_EL1);
45 if (val & ICC_SRE_EL1_SRE)
46 return true;
47
48 val |= ICC_SRE_EL1_SRE;
49 write_sys_reg(ICC_SRE_EL1, val);
50 isb();
51 val = read_sys_reg(ICC_SRE_EL1);
52
53 return !!(val & ICC_SRE_EL1_SRE);
54 }
55
gicv3_set_routing(u64 cpumask,void * rout_reg)56 static inline void gicv3_set_routing(u64 cpumask, void *rout_reg)
57 {
58 put32((u64)rout_reg, (u32)cpumask);
59 put32((u64)(rout_reg + 4), (u32)(cpumask >> 32));
60 }
61
62 /* Wait for completion of a redist change */
gic_wait_redist_complete(void)63 static void gic_wait_redist_complete(void)
64 {
65 while (get32(GICR_PER_CPU_BASE(smp_get_cpu_id())) & GICD_CTLR_RWP);
66 }
67
68 /* Wait for completion of a dist change */
gic_wait_dist_complete(void)69 static inline void gic_wait_dist_complete(void)
70 {
71 while (get32(GICD_BASE) & GICD_CTLR_RWP);
72 }
73
gicv3_distributor_init(void)74 void gicv3_distributor_init(void)
75 {
76 unsigned int gic_type_reg, i, val;
77 unsigned long cpumask;
78
79 gic_type_reg = get32(GICD_TYPER);
80 nr_lines = GICD_TYPER_IRQS(gic_type_reg);
81
82 kinfo("nr_lines %d\n", nr_lines);
83
84 /* Disable the distributor. */
85 put32(GICD_CTLR, 0);
86 gic_wait_dist_complete();
87
88 /* Enable distributor with ARE_S, Group1S and Group0 */
89 val = get32(GICD_CTLR);
90 put32(GICD_CTLR, val | GICD_CTLR_ARE_S | GICD_CTLR_ENABLE_G1_S | GICD_CTLR_ENABLE_G0);
91 }
92
gicv3_init_cpu_interface(void)93 static void gicv3_init_cpu_interface(void)
94 {
95 unsigned int val;
96
97 /* Make sure that the SRE bit has been set. */
98 if (!gicv3_enable_sre()) {
99 BUG("GICv3 fatal error: SRE bit not set (disabled at EL2)\n");
100 return;
101 }
102
103 val = read_sys_reg(ICC_CTLR_EL1);
104 write_sys_reg(ICC_CTLR_EL1, val & ~(1 << ICC_CTLR_EL1_EOImode_SHIFT));
105 isb();
106
107 val = read_sys_reg(ICC_IGRPEN1_EL1);
108 write_sys_reg(ICC_IGRPEN1_EL1, 1);
109 isb();
110 }
111
gicv3_redistributor_init(void)112 static void gicv3_redistributor_init(void)
113 {
114 unsigned int gic_wake_reg;
115 unsigned long redis_base, sgi_base;
116
117 redis_base = GICR_PER_CPU_BASE(smp_get_cpu_id());
118
119 /* Clear processor sleep and wait till childasleep is cleard. */
120 gic_wake_reg = get32(redis_base + GICR_WAKER_OFFSET);
121 gic_wake_reg &= ~GICR_WAKER_ProcessorSleep;
122 put32(redis_base + GICR_WAKER_OFFSET, gic_wake_reg);
123 while (get32(redis_base + GICR_WAKER_OFFSET) & GICR_WAKER_ChildrenAsleep);
124
125 gic_wait_redist_complete();
126
127 /* Initialise cpu interface registers. */
128 gicv3_init_cpu_interface();
129 }
130
gicv3_set_irq_group(int irq,int ns)131 int gicv3_set_irq_group(int irq, int ns)
132 {
133 int idx = irq / NUM_INTS_PER_REG;
134 u32 mask = 1 << (irq % NUM_INTS_PER_REG);
135
136 if (ns) {
137 set32(GICD_IGROUPR(idx), mask);
138 clr32(GICD_IGRPMODR(idx), mask);
139 } else {
140 clr32(GICD_IGROUPR(idx), mask);
141 set32(GICD_IGRPMODR(idx), mask);
142 }
143
144 gic_wait_dist_complete();
145 return 0;
146 }
147
gicv3_enable_irqno(int irq)148 void gicv3_enable_irqno(int irq)
149 {
150 int cpu_id;
151
152 if (irq < 32) {
153 BUG_ON(1);
154 } else {
155 /* irq in distributor. */
156 put32(GICD_BASE + GICD_ISENABLER_OFFSET + ((irq >> 5) << 2),
157 (1 << (irq % 32)));
158 gic_wait_dist_complete();
159 }
160 }
161
gicv3_disable_irqno(int irq)162 void gicv3_disable_irqno(int irq)
163 {
164 int cpu_id;
165
166 if (irq < 32) {
167 BUG_ON(1);
168 // irq in redist
169 cpu_id = smp_get_cpu_id();
170 put32(GICR_PER_CPU_BASE(cpu_id) + GICR_SGI_BASE_OFFSET
171 + GICR_ICENABLER0_OFFSET,
172 (1 << (irq % 32)));
173 gic_wait_redist_complete();
174 } else {
175 // irq in dist
176 put32(GICD_BASE + GICD_ICENABLER_OFFSET + ((irq >> 5) << 2),
177 (1 << (irq % 32)));
178 gic_wait_dist_complete();
179 }
180 }
181
gicv3_set_irq_target(int irq,unsigned int cpuid)182 int gicv3_set_irq_target(int irq, unsigned int cpuid)
183 {
184 unsigned int mpidr;
185 unsigned long cpumask;
186
187 if (cpuid != 0) {
188 return -EINVAL;
189 }
190
191 asm volatile("mrs %0, mpidr_el1\n\t" : "=r"(mpidr));
192 gicv3_disable_irqno(irq);
193 cpumask = ((mpidr >> 0) & 0xff) |
194 (((mpidr >> 8) & 0xff) << 8) |
195 (((mpidr >> 16) & 0xff) << 16) |
196 ((((unsigned long)mpidr >> 24) & 0xff) << 32);
197 gicv3_set_routing(cpumask, (void *)(GICD_IROUTER + irq * 8));
198 gicv3_enable_irqno(irq);
199 gic_wait_dist_complete();
200
201 return 0;
202 }
203
gicv3_set_irq_prio(int irq,int prio)204 int gicv3_set_irq_prio(int irq, int prio)
205 {
206 put8(GICD_IPRIORITYR + irq, prio);
207 return 0;
208 }
209
gicv3_set_irq_pending(int irq,bool set)210 int gicv3_set_irq_pending(int irq, bool set)
211 {
212 int idx = irq / NUM_INTS_PER_REG;
213 u32 mask = 1 << (irq % NUM_INTS_PER_REG);
214
215 if (set) {
216 set32(GICD_ISPENDR(idx), mask);
217 } else {
218 set32(GICD_ICPENDR(idx), mask);
219 }
220
221 return 0;
222 }
223
gicv3_ack_irq(int irq)224 void gicv3_ack_irq(int irq)
225 {
226 write_sys_reg(ICC_EOIR1_EL1, irq);
227 }
228
plat_interrupt_init(void)229 void plat_interrupt_init(void)
230 {
231 unsigned int cpuid = smp_get_cpu_id();
232
233 if (cpuid == 0)
234 gicv3_distributor_init();
235
236 gicv3_redistributor_init();
237 }
238
plat_send_ipi(u32 cpu,u32 ipi)239 void plat_send_ipi(u32 cpu, u32 ipi)
240 {
241 BUG("ipi not implemented\n");
242 }
243
plat_enable_irqno(int irq)244 void plat_enable_irqno(int irq)
245 {
246 gicv3_enable_irqno(irq);
247 }
248
plat_disable_irqno(int irq)249 void plat_disable_irqno(int irq)
250 {
251 gicv3_disable_irqno(irq);
252 }
253
plat_ack_irq(int irq)254 void plat_ack_irq(int irq)
255 {
256 }
257
plat_handle_irq(void)258 void plat_handle_irq(void)
259 {
260 unsigned int irqnr = 0;
261 unsigned int irqstat = 0;
262 int ret;
263
264 irqstat = read_sys_reg(ICC_IAR1_EL1);
265 dsb(sy);
266 irqnr = irqstat & 0x3ff;
267
268 gicv3_ack_irq(irqnr);
269
270 if (likely(irqnr > 15 && irqnr < 1020)) {
271 kinfo("%s: recv irq %d\n", __func__, irqnr);
272 user_handle_irq(irqnr);
273 } else if (irqnr < 16) {
274 BUG("NO SGI in TEE now\n");
275 }
276
277 isb();
278 }
279
gic_op_raise_pi(size_t it)280 void gic_op_raise_pi(size_t it)
281 {
282 gicv3_set_irq_pending(it, true);
283 }
284
gicv3_irq_mask(int irq,bool mask)285 int gicv3_irq_mask(int irq, bool mask)
286 {
287 if (mask) {
288 gicv3_disable_irqno(irq);
289 } else {
290 gicv3_enable_irqno(irq);
291 }
292 return 0;
293 }
294
gicv3_op(int irq,int op,long val)295 int gicv3_op(int irq, int op, long val)
296 {
297 int ret;
298
299 if (irq < 0 || irq >= MAX_IRQ_NUM) {
300 ret = -EINVAL;
301 goto out;
302 }
303
304 switch (op) {
305 case GICV3_OP_SET_PRIO:
306 ret = gicv3_set_irq_prio(irq, (int)val);
307 break;
308 case GICV3_OP_SET_GROUP:
309 ret = gicv3_set_irq_group(irq, (int)val);
310 break;
311 case GICV3_OP_SET_TARGET:
312 ret = gicv3_set_irq_target(irq, (int)val);
313 break;
314 case GICV3_OP_SET_PENDING:
315 ret = gicv3_set_irq_pending(irq, (bool)val);
316 break;
317 case GICV3_OP_MASK:
318 ret = gicv3_irq_mask(irq, (bool)val);
319 break;
320 default:
321 ret = -EINVAL;
322 break;
323 }
324
325 out:
326 return ret;
327 }
328