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 <dm.h> 10 #include <irq-generic.h> 11 #include "irq-internal.h" 12 13 DECLARE_GLOBAL_DATA_PTR; 14 15 struct irq_desc { 16 interrupt_handler_t *handle_irq; 17 void *data; 18 u32 flag; 19 u32 count; 20 }; 21 22 struct irqchip_desc { 23 struct irq_chip *gic; 24 struct irq_chip *gpio; 25 struct irq_chip *virq; 26 27 int suspend_irq[PLATFORM_SUSPEND_MAX_IRQ]; 28 int suspend_num; 29 }; 30 31 static struct irq_desc irq_desc[PLATFORM_MAX_IRQ]; 32 static struct irqchip_desc irqchip; 33 static bool intr_setup; 34 35 int bad_irq(int irq) 36 { 37 if (!intr_setup) { 38 IRQ_W("Interrupt framework is not setup\n"); 39 return -EINVAL; 40 } 41 42 if (irq < PLATFORM_MAX_IRQ) { 43 if (!irq_desc[irq].handle_irq) 44 return -EINVAL; 45 } else { 46 if (bad_virq(irq)) { 47 IRQ_E("Unknown virq: %d\n", irq); 48 return -EINVAL; 49 } 50 } 51 52 return 0; 53 } 54 55 /* general interrupt handler for gpio chip */ 56 void __generic_gpio_handle_irq(int irq) 57 { 58 if (bad_irq(irq)) 59 return; 60 61 if (irq < PLATFORM_GIC_MAX_IRQ) { 62 IRQ_W("IRQ %d: Invalid GPIO irq\n", irq); 63 return; 64 } 65 66 if (irq_desc[irq].handle_irq) { 67 irq_desc[irq].count++; 68 irq_desc[irq].handle_irq(irq, irq_desc[irq].data); 69 } 70 } 71 72 void __do_generic_irq_handler(void) 73 { 74 u32 irq; 75 76 assert(irqchip.gic->irq_get); 77 assert(irqchip.gic->irq_eoi); 78 79 irq = irqchip.gic->irq_get(); 80 81 if (irq < PLATFORM_GIC_MAX_IRQ) { 82 if (irq_desc[irq].handle_irq) { 83 irq_desc[irq].count++; 84 irq_desc[irq].handle_irq(irq, irq_desc[irq].data); 85 } 86 } 87 88 irqchip.gic->irq_eoi(irq); 89 } 90 91 int irq_is_busy(int irq) 92 { 93 return (irq >= 0 && irq_desc[irq].handle_irq) ? -EBUSY : 0; 94 } 95 96 static int bad_irq_chip(struct irq_chip *chip) 97 { 98 return (!chip->name || !chip->irq_init || !chip->irq_enable || 99 !chip->irq_disable) ? -EINVAL : 0; 100 } 101 102 static int __do_arch_irq_init(void) 103 { 104 int ret = -EINVAL; 105 106 /* After relocation done, bss data intr_setup */ 107 if (!(gd->flags & GD_FLG_RELOC)) { 108 IRQ_W("Interrupt framework should initialize after reloc\n"); 109 return -EINVAL; 110 } 111 112 /* 113 * We set true before arch_gpio_irq_init() to avoid fail when 114 * request irq for gpio banks. 115 */ 116 intr_setup = true; 117 memset(irq_desc, 0, sizeof(irq_desc)); 118 119 irqchip.gic = arch_gic_get_irqchip(); 120 if (bad_irq_chip(irqchip.gic)) { 121 IRQ_E("Bad gic irqchip\n"); 122 goto out; 123 } 124 125 irqchip.gpio = arch_gpio_get_irqchip(); 126 if (bad_irq_chip(irqchip.gpio)) { 127 IRQ_E("Bad gpio irqchip\n"); 128 goto out; 129 } 130 131 irqchip.virq = arch_virq_get_irqchip(); 132 if (bad_irq_chip(irqchip.virq)) { 133 IRQ_E("Bad virq irqchip\n"); 134 goto out; 135 } 136 137 ret = irqchip.gic->irq_init(); 138 if (ret) { 139 IRQ_E("GIC Interrupt setup failed, ret=%d\n", ret); 140 goto out; 141 } 142 143 ret = irqchip.gpio->irq_init(); 144 if (ret) { 145 IRQ_E("GPIO Interrupt setup failed, ret=%d\n", ret); 146 goto out; 147 } 148 149 ret = irqchip.virq->irq_init(); 150 if (ret) { 151 IRQ_E("VIRQ Interrupt setup failed, ret=%d\n", ret); 152 goto out; 153 } 154 155 return 0; 156 157 out: 158 intr_setup = false; 159 160 return ret; 161 } 162 163 int irq_handler_enable(int irq) 164 { 165 int ret; 166 167 if (bad_irq(irq)) 168 return -EINVAL; 169 170 if (irq < PLATFORM_GIC_MAX_IRQ) 171 ret = irqchip.gic->irq_enable(irq); 172 else if (irq < PLATFORM_GPIO_MAX_IRQ) 173 ret = irqchip.gpio->irq_enable(irq); 174 else 175 ret = irqchip.virq->irq_enable(irq); 176 177 if (!ret && irq < PLATFORM_MAX_IRQ) 178 irq_desc[irq].flag |= IRQ_FLG_ENABLE; 179 180 return ret; 181 } 182 183 int irq_handler_disable(int irq) 184 { 185 int ret; 186 187 if (bad_irq(irq)) 188 return -EINVAL; 189 190 if (irq < PLATFORM_GIC_MAX_IRQ) 191 ret = irqchip.gic->irq_disable(irq); 192 else if (irq < PLATFORM_GPIO_MAX_IRQ) 193 ret = irqchip.gpio->irq_disable(irq); 194 else 195 ret = irqchip.virq->irq_disable(irq); 196 197 if (!ret && irq < PLATFORM_MAX_IRQ) 198 irq_desc[irq].flag &= ~IRQ_FLG_ENABLE; 199 200 return ret; 201 } 202 203 int irq_set_irq_type(int irq, unsigned int type) 204 { 205 if (bad_irq(irq)) 206 return -EINVAL; 207 208 if (irq < PLATFORM_GIC_MAX_IRQ) 209 return irqchip.gic->irq_set_type(irq, type); 210 else if (irq < PLATFORM_GPIO_MAX_IRQ) 211 return irqchip.gpio->irq_set_type(irq, type); 212 else 213 return -ENOSYS; 214 } 215 216 int irq_revert_irq_type(int irq) 217 { 218 if (bad_irq(irq)) 219 return -EINVAL; 220 221 if (irq < PLATFORM_GIC_MAX_IRQ) 222 return 0; 223 else if (irq < PLATFORM_GPIO_MAX_IRQ) 224 return irqchip.gpio->irq_revert_type(irq); 225 else 226 return -ENOSYS; 227 } 228 229 int irq_get_gpio_level(int irq) 230 { 231 if (bad_irq(irq)) 232 return -EINVAL; 233 234 if (irq < PLATFORM_GIC_MAX_IRQ) 235 return 0; 236 else if (irq < PLATFORM_GPIO_MAX_IRQ) 237 return irqchip.gpio->irq_get_gpio_level(irq); 238 else 239 return -ENOSYS; 240 } 241 242 void irq_install_handler(int irq, interrupt_handler_t *handler, void *data) 243 { 244 if (!intr_setup) { 245 IRQ_W("Interrupt framework is not intr_setup\n"); 246 return; 247 } 248 249 if (irq < PLATFORM_MAX_IRQ) { 250 if (!handler || irq_desc[irq].handle_irq) 251 return; 252 irq_desc[irq].handle_irq = handler; 253 irq_desc[irq].data = data; 254 } else { 255 virq_install_handler(irq, handler, data); 256 } 257 } 258 259 void irq_free_handler(int irq) 260 { 261 if (irq_handler_disable(irq)) 262 return; 263 264 if (irq < PLATFORM_MAX_IRQ) { 265 irq_desc[irq].handle_irq = NULL; 266 irq_desc[irq].data = NULL; 267 } else { 268 virq_free_handler(irq); 269 } 270 } 271 272 int irq_handler_enable_suspend_only(int irq) 273 { 274 if (bad_irq(irq)) 275 return -EINVAL; 276 277 if (irqchip.suspend_num >= PLATFORM_SUSPEND_MAX_IRQ) { 278 printf("Over max count(%d) of suspend irq\n", 279 PLATFORM_SUSPEND_MAX_IRQ); 280 return -EPERM; 281 } 282 283 irqchip.suspend_irq[irqchip.suspend_num++] = irq; 284 return 0; 285 } 286 287 int irqs_suspend(void) 288 { 289 int i; 290 291 for (i = 0; i < irqchip.suspend_num; i++) 292 irq_handler_enable(irqchip.suspend_irq[i]); 293 294 return irqchip.gic->irq_suspend(); 295 } 296 297 int irqs_resume(void) 298 { 299 int i; 300 301 for (i = 0; i < irqchip.suspend_num; i++) 302 irq_handler_disable(irqchip.suspend_irq[i]); 303 304 return irqchip.gic->irq_resume(); 305 } 306 307 #ifdef CONFIG_ARM64 308 static void cpu_local_irq_enable(void) 309 { 310 asm volatile("msr daifclr, #0x02"); 311 } 312 313 static int cpu_local_irq_disable(void) 314 { 315 asm volatile("msr daifset, #0x02"); 316 return 0; 317 } 318 319 void do_irq(struct pt_regs *pt_regs, unsigned int esr) 320 { 321 #ifdef CONFIG_ROCKCHIP_DEBUGGER 322 printf("\n>>> Rockchip Debugger:\n"); 323 show_regs(pt_regs); 324 #endif 325 326 __do_generic_irq_handler(); 327 } 328 #else 329 static void cpu_local_irq_enable(void) 330 { 331 unsigned long cpsr; 332 333 __asm__ __volatile__("mrs %0, cpsr\n" 334 "bic %0, %0, #0x80\n" 335 "msr cpsr_c, %0" 336 : "=r" (cpsr) : : "memory"); 337 } 338 339 static int cpu_local_irq_disable(void) 340 { 341 unsigned long old_cpsr, new_cpsr; 342 343 __asm__ __volatile__("mrs %0, cpsr\n" 344 "orr %1, %0, #0xc0\n" 345 "msr cpsr_c, %1" 346 : "=r" (old_cpsr), "=r" (new_cpsr) 347 : 348 : "memory"); 349 350 return (old_cpsr & 0x80) == 0; 351 } 352 353 void do_irq(struct pt_regs *pt_regs) 354 { 355 #ifdef CONFIG_ROCKCHIP_DEBUGGER 356 printf("\n>>> Rockchp Debugger:\n"); 357 show_regs(pt_regs); 358 #endif 359 360 __do_generic_irq_handler(); 361 } 362 #endif 363 364 int arch_interrupt_init(void) 365 { 366 #ifndef CONFIG_ARM64 367 unsigned long cpsr __maybe_unused; 368 369 /* stack has been reserved in: arch_reserve_stacks() */ 370 IRQ_STACK_START = gd->irq_sp; 371 IRQ_STACK_START_IN = gd->irq_sp; 372 373 __asm__ __volatile__("mrs %0, cpsr\n" 374 : "=r" (cpsr) 375 : 376 : "memory"); 377 378 __asm__ __volatile__("msr cpsr_c, %0\n" 379 "mov sp, %1\n" 380 : 381 : "r" (IRQ_MODE | I_BIT | 382 F_BIT | (cpsr & ~FIQ_MODE)), 383 "r" (IRQ_STACK_START) 384 : "memory"); 385 386 __asm__ __volatile__("msr cpsr_c, %0" 387 : 388 : "r" (cpsr) 389 : "memory"); 390 #endif 391 return __do_arch_irq_init(); 392 } 393 394 int interrupt_init(void) 395 { 396 return arch_interrupt_init(); 397 } 398 399 void enable_interrupts(void) 400 { 401 cpu_local_irq_enable(); 402 } 403 404 int disable_interrupts(void) 405 { 406 return cpu_local_irq_disable(); 407 } 408 409 static int do_dump_irqs(cmd_tbl_t *cmdtp, int flag, 410 int argc, char * const argv[]) 411 412 { 413 struct udevice *dev; 414 char *drv_name; 415 int pirq; 416 417 printf(" IRQ En Handler Driver Name Trig\n"); 418 printf("----------------------------------------------------------------------\n"); 419 420 for (pirq = 0; pirq < PLATFORM_MAX_IRQ; pirq++) { 421 if (!irq_desc[pirq].handle_irq) 422 continue; 423 424 dev = (struct udevice *)irq_desc[pirq].data; 425 if (strstr(dev->name, "gpio")) 426 drv_name = "IRQ"; 427 else 428 drv_name = dev->driver->name; 429 430 printf(" %3d %d 0x%08lx %-12s %-12s %d\n", 431 pirq, irq_desc[pirq].flag & IRQ_FLG_ENABLE ? 1 : 0, 432 (ulong)irq_desc[pirq].handle_irq, 433 drv_name, dev->name, irq_desc[pirq].count); 434 435 virqs_show(pirq); 436 } 437 438 return 0; 439 } 440 441 U_BOOT_CMD( 442 dump_irqs, 1, 1, do_dump_irqs, "Dump IRQs", "" 443 ); 444