xref: /rk3399_rockchip-uboot/drivers/irq/irq-generic.c (revision 5ec685037a799ecdc53ecb1a12a9ed5a9cecb4f4)
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 void irq_install_handler(int irq, interrupt_handler_t *handler, void *data)
166 {
167 	if (irq_bad(irq))
168 		return;
169 
170 	irqs_desc[irq].handle_irq = handler;
171 	irqs_desc[irq].data = data;
172 }
173 
174 void irq_free_handler(int irq)
175 {
176 	if (irq_handler_disable(irq))
177 		return;
178 
179 	irqs_desc[irq].handle_irq = NULL;
180 	irqs_desc[irq].data = NULL;
181 }
182 
183 int irqs_suspend(void)
184 {
185 	int err;
186 
187 	err = gic_irq_chip->irq_suspend();
188 	if (err) {
189 		printf("ERROR: irqs suspend failed\n");
190 		return err;
191 	}
192 
193 	return 0;
194 }
195 
196 int irqs_resume(void)
197 {
198 	int err;
199 
200 	err = gic_irq_chip->irq_resume();
201 	if (err) {
202 		printf("ERROR: irqs resume failed\n");
203 		return err;
204 	}
205 
206 	return 0;
207 }
208 
209 #ifdef CONFIG_ARM64
210 static void cpu_local_irq_enable(void)
211 {
212 	asm volatile("msr daifclr, #0x02");
213 }
214 
215 static int cpu_local_irq_disable(void)
216 {
217 	asm volatile("msr daifset, #0x02");
218 
219 	return 0;
220 }
221 
222 void do_irq(struct pt_regs *pt_regs, unsigned int esr)
223 {
224 	_do_generic_irq_handler();
225 }
226 #else
227 static void cpu_local_irq_enable(void)
228 {
229 	unsigned long cpsr;
230 
231 	__asm__ __volatile__("mrs %0, cpsr\n"
232 			     "bic %0, %0, #0x80\n"
233 			     "msr cpsr_c, %0"
234 			     : "=r" (cpsr) : : "memory");
235 }
236 
237 static int cpu_local_irq_disable(void)
238 {
239 	unsigned long old_cpsr, new_cpsr;
240 
241 	__asm__ __volatile__("mrs %0, cpsr\n"
242 			     "orr %1, %0, #0xc0\n"
243 			     "msr cpsr_c, %1"
244 			     : "=r" (old_cpsr), "=r" (new_cpsr)
245 			     :
246 			     : "memory");
247 
248 	return (old_cpsr & 0x80) == 0;
249 }
250 
251 void do_irq(struct pt_regs *pt_regs)
252 {
253 	_do_generic_irq_handler();
254 }
255 #endif
256 
257 int arch_interrupt_init(void)
258 {
259 #ifndef CONFIG_ARM64
260 	unsigned long cpsr __maybe_unused;
261 
262 	/* stack has been reserved in: arch_reserve_stacks() */
263 	IRQ_STACK_START = gd->irq_sp;
264 
265 	__asm__ __volatile__("mrs %0, cpsr\n"
266 			     : "=r" (cpsr)
267 			     :
268 			     : "memory");
269 
270 	__asm__ __volatile__("msr cpsr_c, %0\n"
271 			     "mov sp, %1\n"
272 			     :
273 			     : "r" (IRQ_MODE | I_BIT |
274 				    F_BIT | (cpsr & ~FIQ_MODE)),
275 			       "r" (IRQ_STACK_START)
276 			     : "memory");
277 
278 	__asm__ __volatile__("msr cpsr_c, %0"
279 			     :
280 			     : "r" (cpsr)
281 			     : "memory");
282 #endif
283 	return _do_arch_irq_init();
284 }
285 
286 int interrupt_init(void)
287 {
288 	return arch_interrupt_init();
289 }
290 
291 void enable_interrupts(void)
292 {
293 	cpu_local_irq_enable();
294 }
295 
296 int disable_interrupts(void)
297 {
298 	return cpu_local_irq_disable();
299 }
300