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