• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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