xref: /rk3399_rockchip-uboot/drivers/irq/irq-generic.c (revision ebe3d004b5204f9b59ee847789b50de99cba5bdc)
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 int irq_is_busy(int irq)
68 {
69 	return (irq >= 0 && irqs_desc[irq].handle_irq) ? -EBUSY : 0;
70 }
71 
72 static int chip_irq_bad(struct irq_chip *chip)
73 {
74 	if (!chip->name ||
75 	    !chip->irq_init ||
76 	    !chip->irq_enable ||
77 	    !chip->irq_disable ||
78 	    !chip->irq_set_type)
79 		return -EINVAL;
80 
81 	return 0;
82 }
83 
84 static int _do_arch_irq_init(void)
85 {
86 	int irq, err = -EINVAL;
87 
88 	/* After relocation done, bss data initialized */
89 	if (!(gd->flags & GD_FLG_RELOC)) {
90 		printf("WARN: interrupt should be init after reloc\n");
91 		return -EINVAL;
92 	}
93 
94 	/*
95 	 * should set true before arch_gpio_irq_init(), otherwise
96 	 *  can't request irqs for gpio banks.
97 	 */
98 	initialized = true;
99 
100 	for (irq = 0; irq < PLATFORM_MAX_IRQS_NR; irq++) {
101 		irqs_desc[irq].handle_irq = NULL;
102 		irqs_desc[irq].data = NULL;
103 	}
104 
105 	gic_irq_chip = arch_gic_irq_init();
106 	if (chip_irq_bad(gic_irq_chip)) {
107 		printf("ERROR: bad gic irq chip\n");
108 		goto out;
109 	}
110 
111 	gpio_irq_chip = arch_gpio_irq_init();
112 	if (chip_irq_bad(gpio_irq_chip)) {
113 		printf("ERROR: bad gpio irq chip\n");
114 		goto out;
115 	}
116 
117 	err = gic_irq_chip->irq_init();
118 	if (err) {
119 		printf("ERROR: gic interrupt init failed\n");
120 		goto out;
121 	}
122 
123 	err = gpio_irq_chip->irq_init();
124 	if (err) {
125 		printf("ERROR: gpio interrupt init failed\n");
126 		goto out;
127 	}
128 
129 	return 0;
130 
131 out:
132 	initialized = false;
133 
134 	return err;
135 }
136 
137 int irq_handler_enable(int irq)
138 {
139 	if (irq_bad(irq))
140 		return -EINVAL;
141 
142 	if (irq < PLATFORM_GIC_IRQS_NR)
143 		return gic_irq_chip->irq_enable(irq);
144 	else
145 		return gpio_irq_chip->irq_enable(irq);
146 }
147 
148 int irq_handler_disable(int irq)
149 {
150 	if (irq_bad(irq))
151 		return -EINVAL;
152 
153 	if (irq < PLATFORM_GIC_IRQS_NR)
154 		return gic_irq_chip->irq_disable(irq);
155 	else
156 		return gpio_irq_chip->irq_disable(irq);
157 }
158 
159 int irq_set_irq_type(int irq, unsigned int type)
160 {
161 	if (irq_bad(irq))
162 		return -EINVAL;
163 
164 	if (irq < PLATFORM_GIC_IRQS_NR)
165 		return gic_irq_chip->irq_set_type(irq, type);
166 	else
167 		return gpio_irq_chip->irq_set_type(irq, type);
168 }
169 
170 int irq_revert_irq_type(int irq)
171 {
172 	if (irq_bad(irq))
173 		return -EINVAL;
174 
175 	if (irq < PLATFORM_GIC_IRQS_NR)
176 		return 0;
177 	else
178 		return gpio_irq_chip->irq_revert_type(irq);
179 }
180 
181 int irq_get_gpio_level(int irq)
182 {
183 	if (irq_bad(irq))
184 		return -EINVAL;
185 
186 	if (irq < PLATFORM_GIC_IRQS_NR)
187 		return 0;
188 	else
189 		return gpio_irq_chip->irq_get_gpio_level(irq);
190 }
191 
192 void irq_install_handler(int irq, interrupt_handler_t *handler, void *data)
193 {
194 	if (irq_bad(irq))
195 		return;
196 
197 	irqs_desc[irq].handle_irq = handler;
198 	irqs_desc[irq].data = data;
199 }
200 
201 void irq_free_handler(int irq)
202 {
203 	if (irq_handler_disable(irq))
204 		return;
205 
206 	irqs_desc[irq].handle_irq = NULL;
207 	irqs_desc[irq].data = NULL;
208 }
209 
210 int irqs_suspend(void)
211 {
212 	int err;
213 
214 	err = gic_irq_chip->irq_suspend();
215 	if (err) {
216 		printf("ERROR: irqs suspend failed\n");
217 		return err;
218 	}
219 
220 	return 0;
221 }
222 
223 int irqs_resume(void)
224 {
225 	int err;
226 
227 	err = gic_irq_chip->irq_resume();
228 	if (err) {
229 		printf("ERROR: irqs resume failed\n");
230 		return err;
231 	}
232 
233 	return 0;
234 }
235 
236 #ifdef CONFIG_ARM64
237 static void cpu_local_irq_enable(void)
238 {
239 	asm volatile("msr daifclr, #0x02");
240 }
241 
242 static int cpu_local_irq_disable(void)
243 {
244 	asm volatile("msr daifset, #0x02");
245 
246 	return 0;
247 }
248 
249 void do_irq(struct pt_regs *pt_regs, unsigned int esr)
250 {
251 #ifdef CONFIG_ROCKCHIP_DEBUGGER
252 	printf("\n>>> Rockchip Debugger:\n");
253 	show_regs(pt_regs);
254 #endif
255 
256 	_do_generic_irq_handler();
257 }
258 #else
259 static void cpu_local_irq_enable(void)
260 {
261 	unsigned long cpsr;
262 
263 	__asm__ __volatile__("mrs %0, cpsr\n"
264 			     "bic %0, %0, #0x80\n"
265 			     "msr cpsr_c, %0"
266 			     : "=r" (cpsr) : : "memory");
267 }
268 
269 static int cpu_local_irq_disable(void)
270 {
271 	unsigned long old_cpsr, new_cpsr;
272 
273 	__asm__ __volatile__("mrs %0, cpsr\n"
274 			     "orr %1, %0, #0xc0\n"
275 			     "msr cpsr_c, %1"
276 			     : "=r" (old_cpsr), "=r" (new_cpsr)
277 			     :
278 			     : "memory");
279 
280 	return (old_cpsr & 0x80) == 0;
281 }
282 
283 void do_irq(struct pt_regs *pt_regs)
284 {
285 #ifdef CONFIG_ROCKCHIP_DEBUGGER
286 	printf("\n>>> Rockchp Debugger:\n");
287 	show_regs(pt_regs);
288 #endif
289 
290 	_do_generic_irq_handler();
291 }
292 #endif
293 
294 int arch_interrupt_init(void)
295 {
296 #ifndef CONFIG_ARM64
297 	unsigned long cpsr __maybe_unused;
298 
299 	/* stack has been reserved in: arch_reserve_stacks() */
300 	IRQ_STACK_START = gd->irq_sp;
301 	IRQ_STACK_START_IN = gd->irq_sp;
302 
303 	__asm__ __volatile__("mrs %0, cpsr\n"
304 			     : "=r" (cpsr)
305 			     :
306 			     : "memory");
307 
308 	__asm__ __volatile__("msr cpsr_c, %0\n"
309 			     "mov sp, %1\n"
310 			     :
311 			     : "r" (IRQ_MODE | I_BIT |
312 				    F_BIT | (cpsr & ~FIQ_MODE)),
313 			       "r" (IRQ_STACK_START)
314 			     : "memory");
315 
316 	__asm__ __volatile__("msr cpsr_c, %0"
317 			     :
318 			     : "r" (cpsr)
319 			     : "memory");
320 #endif
321 	return _do_arch_irq_init();
322 }
323 
324 int interrupt_init(void)
325 {
326 	return arch_interrupt_init();
327 }
328 
329 void enable_interrupts(void)
330 {
331 	cpu_local_irq_enable();
332 }
333 
334 int disable_interrupts(void)
335 {
336 	return cpu_local_irq_disable();
337 }
338