xref: /rk3399_rockchip-uboot/drivers/irq/irq-generic.c (revision e17ddcea32b2fa7b82fb079f37195855a55e39a2)
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/u-boot-arm.h>
9 #include <irq-generic.h>
10 #include "irq-gic.h"
11 #include "irq-gpio.h"
12 
13 DECLARE_GLOBAL_DATA_PTR;
14 
15 struct irq_desc {
16 	interrupt_handler_t *handle_irq;
17 	void *data;
18 };
19 
20 static struct irq_desc irqs_desc[PLATFORM_MAX_IRQS_NR];
21 static struct irq_chip *gic_irq_chip, *gpio_irq_chip;
22 static bool initialized;
23 
24 static int irq_bad(int irq)
25 {
26 	if (irq >= PLATFORM_MAX_IRQS_NR) {
27 		printf("WARN: IRQ %d is out of max supported IRQ %d\n",
28 		       irq, PLATFORM_MAX_IRQS_NR);
29 		return -EINVAL;
30 	}
31 
32 	if (!initialized) {
33 		printf("WARN: Interrupt framework is not initialized\n");
34 		return -EINVAL;
35 	}
36 
37 	return 0;
38 }
39 
40 /* general interrupt handler for gpio chip */
41 void _generic_gpio_handle_irq(int irq)
42 {
43 	if (irq_bad(irq))
44 		return;
45 
46 	if (irq < PLATFORM_GIC_IRQS_NR) {
47 		printf("WRAN: IRQ %d is not a GPIO irq\n", irq);
48 		return;
49 	}
50 
51 	if (irqs_desc[irq].handle_irq)
52 		irqs_desc[irq].handle_irq(irq, irqs_desc[irq].data);
53 }
54 
55 void _do_generic_irq_handler(void)
56 {
57 	u32 irq = gic_irq_chip->irq_get();
58 
59 	if (irq < PLATFORM_GIC_IRQS_NR) {
60 		if (irqs_desc[irq].handle_irq)
61 			irqs_desc[irq].handle_irq(irq, irqs_desc[irq].data);
62 	}
63 
64 	gic_irq_chip->irq_eoi(irq);
65 }
66 
67 static int chip_irq_bad(struct irq_chip *chip)
68 {
69 	if (!chip->name ||
70 	    !chip->irq_init ||
71 	    !chip->irq_enable ||
72 	    !chip->irq_disable ||
73 	    !chip->irq_set_type)
74 		return -EINVAL;
75 
76 	return 0;
77 }
78 
79 static int _do_arch_irq_init(void)
80 {
81 	int irq, err = -EINVAL;
82 
83 	/* After relocation done, bss data initialized */
84 	if (!(gd->flags & GD_FLG_RELOC)) {
85 		printf("WARN: interrupt should be init after reloc\n");
86 		return -EINVAL;
87 	}
88 
89 	/*
90 	 * should set true before arch_gpio_irq_init(), otherwise
91 	 *  can't request irqs for gpio banks.
92 	 */
93 	initialized = true;
94 
95 	for (irq = 0; irq < PLATFORM_MAX_IRQS_NR; irq++) {
96 		irqs_desc[irq].handle_irq = NULL;
97 		irqs_desc[irq].data = NULL;
98 	}
99 
100 	gic_irq_chip = arch_gic_irq_init();
101 	if (chip_irq_bad(gic_irq_chip)) {
102 		printf("ERROR: bad gic irq chip\n");
103 		goto out;
104 	}
105 
106 	gpio_irq_chip = arch_gpio_irq_init();
107 	if (chip_irq_bad(gpio_irq_chip)) {
108 		printf("ERROR: bad gpio irq chip\n");
109 		goto out;
110 	}
111 
112 	err = gic_irq_chip->irq_init();
113 	if (err) {
114 		printf("ERROR: gic interrupt init failed\n");
115 		goto out;
116 	}
117 
118 	err = gpio_irq_chip->irq_init();
119 	if (err) {
120 		printf("ERROR: gpio interrupt init failed\n");
121 		goto out;
122 	}
123 
124 	return 0;
125 
126 out:
127 	initialized = false;
128 
129 	return err;
130 }
131 
132 int irq_handler_enable(int irq)
133 {
134 	if (irq_bad(irq))
135 		return -EINVAL;
136 
137 	if (irq < PLATFORM_GIC_IRQS_NR)
138 		return gic_irq_chip->irq_enable(irq);
139 	else
140 		return gpio_irq_chip->irq_enable(irq);
141 }
142 
143 int irq_handler_disable(int irq)
144 {
145 	if (irq_bad(irq))
146 		return -EINVAL;
147 
148 	if (irq < PLATFORM_GIC_IRQS_NR)
149 		return gic_irq_chip->irq_disable(irq);
150 	else
151 		return gpio_irq_chip->irq_disable(irq);
152 }
153 
154 int irq_set_irq_type(int irq, unsigned int type)
155 {
156 	if (irq_bad(irq))
157 		return -EINVAL;
158 
159 	if (irq < PLATFORM_GIC_IRQS_NR)
160 		return gic_irq_chip->irq_set_type(irq, type);
161 	else
162 		return gpio_irq_chip->irq_set_type(irq, type);
163 }
164 
165 int irq_revert_irq_type(int irq)
166 {
167 	if (irq_bad(irq))
168 		return -EINVAL;
169 
170 	if (irq < PLATFORM_GIC_IRQS_NR)
171 		return 0;
172 	else
173 		return gpio_irq_chip->irq_revert_type(irq);
174 }
175 
176 int irq_get_gpio_level(int irq)
177 {
178 	if (irq_bad(irq))
179 		return -EINVAL;
180 
181 	if (irq < PLATFORM_GIC_IRQS_NR)
182 		return 0;
183 	else
184 		return gpio_irq_chip->irq_get_gpio_level(irq);
185 }
186 
187 void irq_install_handler(int irq, interrupt_handler_t *handler, void *data)
188 {
189 	if (irq_bad(irq))
190 		return;
191 
192 	irqs_desc[irq].handle_irq = handler;
193 	irqs_desc[irq].data = data;
194 }
195 
196 void irq_free_handler(int irq)
197 {
198 	if (irq_handler_disable(irq))
199 		return;
200 
201 	irqs_desc[irq].handle_irq = NULL;
202 	irqs_desc[irq].data = NULL;
203 }
204 
205 int irqs_suspend(void)
206 {
207 	int err;
208 
209 	err = gic_irq_chip->irq_suspend();
210 	if (err) {
211 		printf("ERROR: irqs suspend failed\n");
212 		return err;
213 	}
214 
215 	return 0;
216 }
217 
218 int irqs_resume(void)
219 {
220 	int err;
221 
222 	err = gic_irq_chip->irq_resume();
223 	if (err) {
224 		printf("ERROR: irqs resume failed\n");
225 		return err;
226 	}
227 
228 	return 0;
229 }
230 
231 #ifdef CONFIG_ARM64
232 static void cpu_local_irq_enable(void)
233 {
234 	asm volatile("msr daifclr, #0x02");
235 }
236 
237 static int cpu_local_irq_disable(void)
238 {
239 	asm volatile("msr daifset, #0x02");
240 
241 	return 0;
242 }
243 
244 void do_irq(struct pt_regs *pt_regs, unsigned int esr)
245 {
246 	_do_generic_irq_handler();
247 }
248 #else
249 static void cpu_local_irq_enable(void)
250 {
251 	unsigned long cpsr;
252 
253 	__asm__ __volatile__("mrs %0, cpsr\n"
254 			     "bic %0, %0, #0x80\n"
255 			     "msr cpsr_c, %0"
256 			     : "=r" (cpsr) : : "memory");
257 }
258 
259 static int cpu_local_irq_disable(void)
260 {
261 	unsigned long old_cpsr, new_cpsr;
262 
263 	__asm__ __volatile__("mrs %0, cpsr\n"
264 			     "orr %1, %0, #0xc0\n"
265 			     "msr cpsr_c, %1"
266 			     : "=r" (old_cpsr), "=r" (new_cpsr)
267 			     :
268 			     : "memory");
269 
270 	return (old_cpsr & 0x80) == 0;
271 }
272 
273 void do_irq(struct pt_regs *pt_regs)
274 {
275 	_do_generic_irq_handler();
276 }
277 #endif
278 
279 int arch_interrupt_init(void)
280 {
281 #ifndef CONFIG_ARM64
282 	unsigned long cpsr __maybe_unused;
283 
284 	/* stack has been reserved in: arch_reserve_stacks() */
285 	IRQ_STACK_START = gd->irq_sp;
286 
287 	__asm__ __volatile__("mrs %0, cpsr\n"
288 			     : "=r" (cpsr)
289 			     :
290 			     : "memory");
291 
292 	__asm__ __volatile__("msr cpsr_c, %0\n"
293 			     "mov sp, %1\n"
294 			     :
295 			     : "r" (IRQ_MODE | I_BIT |
296 				    F_BIT | (cpsr & ~FIQ_MODE)),
297 			       "r" (IRQ_STACK_START)
298 			     : "memory");
299 
300 	__asm__ __volatile__("msr cpsr_c, %0"
301 			     :
302 			     : "r" (cpsr)
303 			     : "memory");
304 #endif
305 	return _do_arch_irq_init();
306 }
307 
308 int interrupt_init(void)
309 {
310 	return arch_interrupt_init();
311 }
312 
313 void enable_interrupts(void)
314 {
315 	cpu_local_irq_enable();
316 }
317 
318 int disable_interrupts(void)
319 {
320 	return cpu_local_irq_disable();
321 }
322