xref: /rk3399_rockchip-uboot/drivers/irq/irq-gic.c (revision 5ce558eee1d84a2b85f2bbc4c4547c8ea1c1dae4)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <asm/io.h>
8 #include <asm/gic.h>
9 #include <config.h>
10 #include <irq-generic.h>
11 #include "irq-gic.h"
12 
13 typedef enum INT_TRIG {
14 	INT_LEVEL_TRIGGER,
15 	INT_EDGE_TRIGGER
16 } eINT_TRIG;
17 
18 typedef enum INT_SECURE {
19 	INT_SECURE,
20 	INT_NOSECURE
21 } eINT_SECURE;
22 
23 typedef enum INT_SIGTYPE {
24 	INT_SIGTYPE_IRQ,
25 	INT_SIGTYPE_FIQ
26 } eINT_SIGTYPE;
27 
28 #define g_gicd		((pGICD_REG)GICD_BASE)
29 #define g_gicc		((pGICC_REG)GICC_BASE)
30 
31 __maybe_unused static u8 g_gic_cpumask = 0x01;
32 
33 static inline void int_set_prio_filter(u32 nprio)
34 {
35 	g_gicc->iccpmr = (nprio & 0xff);
36 }
37 
38 static inline void int_enable_distributor(void)
39 {
40 	g_gicd->icddcr = 0x01;
41 }
42 
43 static inline void int_disable_distributor(void)
44 {
45 	g_gicd->icddcr = 0x00;
46 }
47 
48 static inline void int_enable_secure_signal(void)
49 {
50 	g_gicc->iccicr |= 0x01;
51 }
52 
53 static inline void int_disable_secure_signal(void)
54 {
55 	g_gicc->iccicr &= (~0x01);
56 }
57 
58 static inline void int_enable_nosecure_signal(void)
59 {
60 	g_gicc->iccicr |= 0x02;
61 }
62 
63 static inline void int_disable_nosecure_signal(void)
64 {
65 	g_gicc->iccicr &= (~0x02);
66 }
67 
68 static int gic_irq_set_trigger(int irq, eINT_TRIG ntrig)
69 {
70 	u32 group, offset;
71 
72 	if (irq >= PLATFORM_GIC_IRQS_NR)
73 		return -EINVAL;
74 
75 	group = irq / 16;
76 	offset = irq % 16;
77 
78 	if (ntrig == INT_LEVEL_TRIGGER)
79 		g_gicd->icdicfr[group] &= (~(1 << (2 * offset + 1)));
80 	else
81 		g_gicd->icdicfr[group] |= (1 << (2 * offset + 1));
82 
83 	return 0;
84 }
85 
86 __maybe_unused static int gic_irq_set_pending(int irq)
87 {
88 	u32 group, offset;
89 
90 	if (irq >= PLATFORM_GIC_IRQS_NR)
91 		return -EINVAL;
92 
93 	group = irq / 32;
94 	offset = irq % 32;
95 	g_gicd->icdispr[group] = (0x1 << offset);
96 
97 	return 0;
98 }
99 
100 __maybe_unused static int gic_irq_clear_pending(int irq)
101 {
102 	u32 group, offset;
103 
104 	if (irq >= PLATFORM_GIC_IRQS_NR)
105 		return -EINVAL;
106 
107 	group = irq / 32;
108 	offset = irq % 32;
109 	g_gicd->icdicpr[group] = (0x1 << offset);
110 
111 	return 0;
112 }
113 
114 __maybe_unused static int gic_irq_set_secure(int irq, eINT_SECURE nsecure)
115 {
116 	u32 group, offset;
117 
118 	if (irq >= PLATFORM_GIC_IRQS_NR)
119 		return -EINVAL;
120 
121 	group = irq / 32;
122 	offset = irq % 32;
123 	g_gicd->icdiser[group] |= nsecure << offset;
124 
125 	return 0;
126 }
127 
128 __maybe_unused static u32 gic_get_cpumask(void)
129 {
130 	u32 mask = 0, i;
131 
132 	for (i = mask = 0; i < 32; i += 4) {
133 		mask = g_gicd->itargetsr[i];
134 		mask |= mask >> 16;
135 		mask |= mask >> 8;
136 		if (mask)
137 			break;
138 	}
139 
140 	if (!mask)
141 		printf("GIC CPU mask not found.\n");
142 
143 	debug("GIC CPU mask = 0x%08x\n", mask);
144 
145 	return mask;
146 }
147 
148 static int gic_irq_enable(int irq)
149 {
150 #ifdef CONFIG_GICV2
151 	u32 shift = (irq % 4) * 8;
152 	u32 offset = (irq / 4);
153 	u32 M, N;
154 
155 	if (irq >= PLATFORM_GIC_IRQS_NR)
156 		return -EINVAL;
157 
158 	M = irq / 32;
159 	N = irq % 32;
160 
161 	g_gicc->iccicr &= (~0x08);
162 	g_gicd->icdiser[M] = (0x1 << N);
163 	g_gicd->itargetsr[offset] &= ~(0xFF << shift);
164 	g_gicd->itargetsr[offset] |= (g_gic_cpumask << shift);
165 #else
166 	u32 M, N;
167 
168 	if (irq >= PLATFORM_GIC_IRQS_NR)
169 		return -EINVAL;
170 
171 	M = irq / 32;
172 	N = irq % 32;
173 	g_gicd->icdiser[M] = (0x1 << N);
174 #endif
175 
176 	return 0;
177 }
178 
179 static int gic_irq_disable(int irq)
180 {
181 	u32 group, offset;
182 
183 	if (irq >= PLATFORM_GIC_IRQS_NR)
184 		return -EINVAL;
185 
186 	group = irq / 32;
187 	offset = irq % 32;
188 	g_gicd->icdicer[group] = (0x1 << offset);
189 
190 	return 0;
191 }
192 
193 /*
194  * irq_set_type - set the irq trigger type for an irq
195  *
196  * @irq: irq number
197  * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see asm/arch/irq.h
198  */
199 static int gic_irq_set_type(int irq, unsigned int type)
200 {
201 	unsigned int int_type;
202 
203 	switch (type) {
204 	case IRQ_TYPE_EDGE_RISING:
205 	case IRQ_TYPE_EDGE_FALLING:
206 		int_type = INT_EDGE_TRIGGER;
207 		break;
208 	case IRQ_TYPE_LEVEL_HIGH:
209 	case IRQ_TYPE_LEVEL_LOW:
210 		int_type = INT_LEVEL_TRIGGER;
211 		break;
212 	default:
213 		return -EINVAL;
214 	}
215 
216 	gic_irq_set_trigger(irq, int_type);
217 
218 	return 0;
219 }
220 
221 static void gic_irq_eoi(int irq)
222 {
223 #ifdef CONFIG_GICV2
224 	g_gicc->icceoir = irq;
225 #else
226 	asm volatile("msr " __stringify(ICC_EOIR1_EL1) ", %0"
227 			: : "r" ((u64)irq));
228 	asm volatile("msr " __stringify(ICC_DIR_EL1) ", %0"
229 			: : "r" ((u64)irq));
230 	isb();
231 #endif
232 }
233 
234 static int gic_irq_get(void)
235 {
236 #ifdef CONFIG_GICV2
237 	return g_gicc->icciar & 0x3ff; /* bit9 - bit0 */
238 #else
239 	u64 irqstat;
240 
241 	asm volatile("mrs %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
242 	return (u32)irqstat & 0x3ff;
243 #endif
244 }
245 
246 static int gic_irq_init(void)
247 {
248 	/* GICV3 done in: arch/arm/cpu/armv8/start.S */
249 #ifdef CONFIG_GICV2
250 	/* end of interrupt */
251 	g_gicc->icceoir = PLATFORM_GIC_IRQS_NR;
252 
253 	/* disable gicc and gicd */
254 	g_gicc->iccicr = 0x00;
255 	g_gicd->icddcr = 0x00;
256 
257 	/* enable interrupt */
258 	g_gicd->icdicer[0] = 0xFFFFFFFF;
259 	g_gicd->icdicer[1] = 0xFFFFFFFF;
260 	g_gicd->icdicer[2] = 0xFFFFFFFF;
261 	g_gicd->icdicer[3] = 0xFFFFFFFF;
262 	g_gicd->icdicfr[3] &= ~(1 << 1);
263 
264 	/* set interrupt priority threhold min: 256 */
265 	int_set_prio_filter(0xff);
266 	int_enable_secure_signal();
267 	int_enable_nosecure_signal();
268 	int_enable_distributor();
269 
270 	g_gic_cpumask = gic_get_cpumask();
271 #endif
272 
273 	return 0;
274 }
275 
276 static struct irq_chip gic_irq_chip = {
277 	.name		= "gic-irq-chip",
278 	.irq_init	= gic_irq_init,
279 	.irq_get	= gic_irq_get,
280 	.irq_enable	= gic_irq_enable,
281 	.irq_disable	= gic_irq_disable,
282 	.irq_eoi	= gic_irq_eoi,
283 	.irq_set_type	= gic_irq_set_type,
284 };
285 
286 struct irq_chip *arch_gic_irq_init(void)
287 {
288 	return &gic_irq_chip;
289 }
290