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