14e6670feSJoseph Chen /* 24e6670feSJoseph Chen * (C) Copyright 2017 Rockchip Electronics Co., Ltd 34e6670feSJoseph Chen * 44e6670feSJoseph Chen * SPDX-License-Identifier: GPL-2.0+ 54e6670feSJoseph Chen */ 64e6670feSJoseph Chen 74e6670feSJoseph Chen #include <asm/io.h> 84e6670feSJoseph Chen #include <asm/u-boot-arm.h> 94e6670feSJoseph Chen #include <irq-generic.h> 10cf344252SJoseph Chen #include "irq-internal.h" 114e6670feSJoseph Chen 124e6670feSJoseph Chen DECLARE_GLOBAL_DATA_PTR; 134e6670feSJoseph Chen 144e6670feSJoseph Chen struct irq_desc { 1542865eb5SJoseph Chen interrupt_handler_t *handle_irq; 1642865eb5SJoseph Chen void *data; 174e6670feSJoseph Chen }; 184e6670feSJoseph Chen 19cf344252SJoseph Chen struct irqchip_desc { 20cf344252SJoseph Chen struct irq_chip *gic; 21cf344252SJoseph Chen struct irq_chip *gpio; 2241766119SJoseph Chen struct irq_chip *virq; 2341766119SJoseph Chen 24*2c4e90c1SJoseph Chen int suspend_irq[PLATFORM_SUSPEND_MAX_IRQ]; 25*2c4e90c1SJoseph Chen int suspend_num; 26cf344252SJoseph Chen }; 274e6670feSJoseph Chen 28cf344252SJoseph Chen static struct irq_desc irq_desc[PLATFORM_MAX_IRQ]; 29cf344252SJoseph Chen static struct irqchip_desc irqchip; 30cf344252SJoseph Chen static bool intr_setup; 31cf344252SJoseph Chen 32cf344252SJoseph Chen int bad_irq(int irq) 334e6670feSJoseph Chen { 34cf344252SJoseph Chen if (!intr_setup) { 35cf344252SJoseph Chen IRQ_W("Interrupt framework is not setup\n"); 364e6670feSJoseph Chen return -EINVAL; 374e6670feSJoseph Chen } 384e6670feSJoseph Chen 3941766119SJoseph Chen if (irq < PLATFORM_MAX_IRQ) { 4041766119SJoseph Chen if (!irq_desc[irq].handle_irq) 4141766119SJoseph Chen return -EINVAL; 4241766119SJoseph Chen } else { 4341766119SJoseph Chen if (bad_virq(irq)) { 4441766119SJoseph Chen IRQ_E("Unknown virq: %d\n", irq); 454e6670feSJoseph Chen return -EINVAL; 464e6670feSJoseph Chen } 4741766119SJoseph Chen } 484e6670feSJoseph Chen 4941766119SJoseph Chen return 0; 504e6670feSJoseph Chen } 514e6670feSJoseph Chen 524e6670feSJoseph Chen /* general interrupt handler for gpio chip */ 53269512fdSJoseph Chen void __generic_gpio_handle_irq(int irq) 544e6670feSJoseph Chen { 55269512fdSJoseph Chen if (bad_irq(irq)) 564e6670feSJoseph Chen return; 574e6670feSJoseph Chen 58cf344252SJoseph Chen if (irq < PLATFORM_GIC_MAX_IRQ) { 59cf344252SJoseph Chen IRQ_W("IRQ %d: Invalid GPIO irq\n", irq); 604e6670feSJoseph Chen return; 614e6670feSJoseph Chen } 624e6670feSJoseph Chen 63cf344252SJoseph Chen if (irq_desc[irq].handle_irq) 64cf344252SJoseph Chen irq_desc[irq].handle_irq(irq, irq_desc[irq].data); 654e6670feSJoseph Chen } 664e6670feSJoseph Chen 67269512fdSJoseph Chen void __do_generic_irq_handler(void) 684e6670feSJoseph Chen { 69cf344252SJoseph Chen u32 irq; 704e6670feSJoseph Chen 71cf344252SJoseph Chen assert(irqchip.gic->irq_get); 72cf344252SJoseph Chen assert(irqchip.gic->irq_eoi); 73cf344252SJoseph Chen 74cf344252SJoseph Chen irq = irqchip.gic->irq_get(); 75cf344252SJoseph Chen 76cf344252SJoseph Chen if (irq < PLATFORM_GIC_MAX_IRQ) { 77cf344252SJoseph Chen if (irq_desc[irq].handle_irq) 78cf344252SJoseph Chen irq_desc[irq].handle_irq(irq, irq_desc[irq].data); 794e6670feSJoseph Chen } 804e6670feSJoseph Chen 81cf344252SJoseph Chen irqchip.gic->irq_eoi(irq); 824e6670feSJoseph Chen } 834e6670feSJoseph Chen 848696cc38SJoseph Chen int irq_is_busy(int irq) 858696cc38SJoseph Chen { 86cf344252SJoseph Chen return (irq >= 0 && irq_desc[irq].handle_irq) ? -EBUSY : 0; 878696cc38SJoseph Chen } 888696cc38SJoseph Chen 89269512fdSJoseph Chen static int bad_irq_chip(struct irq_chip *chip) 904e6670feSJoseph Chen { 91cf344252SJoseph Chen return (!chip->name || !chip->irq_init || !chip->irq_enable || 9241766119SJoseph Chen !chip->irq_disable) ? -EINVAL : 0; 934e6670feSJoseph Chen } 944e6670feSJoseph Chen 95269512fdSJoseph Chen static int __do_arch_irq_init(void) 964e6670feSJoseph Chen { 97cf344252SJoseph Chen int ret = -EINVAL; 984e6670feSJoseph Chen 99cf344252SJoseph Chen /* After relocation done, bss data intr_setup */ 1004e6670feSJoseph Chen if (!(gd->flags & GD_FLG_RELOC)) { 101269512fdSJoseph Chen IRQ_W("Interrupt framework should initialize after reloc\n"); 1024e6670feSJoseph Chen return -EINVAL; 1034e6670feSJoseph Chen } 1044e6670feSJoseph Chen 1054e6670feSJoseph Chen /* 106269512fdSJoseph Chen * We set true before arch_gpio_irq_init() to avoid fail when 107269512fdSJoseph Chen * request irq for gpio banks. 1084e6670feSJoseph Chen */ 109cf344252SJoseph Chen intr_setup = true; 110cf344252SJoseph Chen memset(irq_desc, 0, sizeof(irq_desc)); 1114e6670feSJoseph Chen 112cf344252SJoseph Chen irqchip.gic = arch_gic_get_irqchip(); 113cf344252SJoseph Chen if (bad_irq_chip(irqchip.gic)) { 114269512fdSJoseph Chen IRQ_E("Bad gic irqchip\n"); 1154e6670feSJoseph Chen goto out; 1164e6670feSJoseph Chen } 1174e6670feSJoseph Chen 118cf344252SJoseph Chen irqchip.gpio = arch_gpio_get_irqchip(); 119cf344252SJoseph Chen if (bad_irq_chip(irqchip.gpio)) { 120269512fdSJoseph Chen IRQ_E("Bad gpio irqchip\n"); 1214e6670feSJoseph Chen goto out; 1224e6670feSJoseph Chen } 1234e6670feSJoseph Chen 12441766119SJoseph Chen irqchip.virq = arch_virq_get_irqchip(); 12541766119SJoseph Chen if (bad_irq_chip(irqchip.virq)) { 12641766119SJoseph Chen IRQ_E("Bad virq irqchip\n"); 12741766119SJoseph Chen goto out; 12841766119SJoseph Chen } 12941766119SJoseph Chen 130cf344252SJoseph Chen ret = irqchip.gic->irq_init(); 131cf344252SJoseph Chen if (ret) { 132cf344252SJoseph Chen IRQ_E("GIC Interrupt setup failed, ret=%d\n", ret); 1334e6670feSJoseph Chen goto out; 1344e6670feSJoseph Chen } 1354e6670feSJoseph Chen 136cf344252SJoseph Chen ret = irqchip.gpio->irq_init(); 137cf344252SJoseph Chen if (ret) { 138cf344252SJoseph Chen IRQ_E("GPIO Interrupt setup failed, ret=%d\n", ret); 1394e6670feSJoseph Chen goto out; 1404e6670feSJoseph Chen } 1414e6670feSJoseph Chen 14241766119SJoseph Chen ret = irqchip.virq->irq_init(); 14341766119SJoseph Chen if (ret) { 14441766119SJoseph Chen IRQ_E("VIRQ Interrupt setup failed, ret=%d\n", ret); 14541766119SJoseph Chen goto out; 14641766119SJoseph Chen } 14741766119SJoseph Chen 1484e6670feSJoseph Chen return 0; 1494e6670feSJoseph Chen 1504e6670feSJoseph Chen out: 151cf344252SJoseph Chen intr_setup = false; 1524e6670feSJoseph Chen 153cf344252SJoseph Chen return ret; 1544e6670feSJoseph Chen } 1554e6670feSJoseph Chen 1564e6670feSJoseph Chen int irq_handler_enable(int irq) 1574e6670feSJoseph Chen { 158269512fdSJoseph Chen if (bad_irq(irq)) 1594e6670feSJoseph Chen return -EINVAL; 1604e6670feSJoseph Chen 161cf344252SJoseph Chen if (irq < PLATFORM_GIC_MAX_IRQ) 162cf344252SJoseph Chen return irqchip.gic->irq_enable(irq); 16341766119SJoseph Chen else if (irq < PLATFORM_GPIO_MAX_IRQ) 164cf344252SJoseph Chen return irqchip.gpio->irq_enable(irq); 16541766119SJoseph Chen else 16641766119SJoseph Chen return irqchip.virq->irq_enable(irq); 1674e6670feSJoseph Chen } 1684e6670feSJoseph Chen 1694e6670feSJoseph Chen int irq_handler_disable(int irq) 1704e6670feSJoseph Chen { 171269512fdSJoseph Chen if (bad_irq(irq)) 1724e6670feSJoseph Chen return -EINVAL; 1734e6670feSJoseph Chen 174cf344252SJoseph Chen if (irq < PLATFORM_GIC_MAX_IRQ) 175cf344252SJoseph Chen return irqchip.gic->irq_disable(irq); 17641766119SJoseph Chen else if (irq < PLATFORM_GPIO_MAX_IRQ) 177cf344252SJoseph Chen return irqchip.gpio->irq_disable(irq); 17841766119SJoseph Chen else 17941766119SJoseph Chen return irqchip.virq->irq_disable(irq); 1804e6670feSJoseph Chen } 1814e6670feSJoseph Chen 1824e6670feSJoseph Chen int irq_set_irq_type(int irq, unsigned int type) 1834e6670feSJoseph Chen { 184269512fdSJoseph Chen if (bad_irq(irq)) 1854e6670feSJoseph Chen return -EINVAL; 1864e6670feSJoseph Chen 187cf344252SJoseph Chen if (irq < PLATFORM_GIC_MAX_IRQ) 188cf344252SJoseph Chen return irqchip.gic->irq_set_type(irq, type); 18941766119SJoseph Chen else if (irq < PLATFORM_GPIO_MAX_IRQ) 190cf344252SJoseph Chen return irqchip.gpio->irq_set_type(irq, type); 19141766119SJoseph Chen else 19241766119SJoseph Chen return -ENOSYS; 1934e6670feSJoseph Chen } 1944e6670feSJoseph Chen 195c234b81eSJoseph Chen int irq_revert_irq_type(int irq) 196c234b81eSJoseph Chen { 197269512fdSJoseph Chen if (bad_irq(irq)) 198c234b81eSJoseph Chen return -EINVAL; 199c234b81eSJoseph Chen 200cf344252SJoseph Chen if (irq < PLATFORM_GIC_MAX_IRQ) 201c234b81eSJoseph Chen return 0; 20241766119SJoseph Chen else if (irq < PLATFORM_GPIO_MAX_IRQ) 203cf344252SJoseph Chen return irqchip.gpio->irq_revert_type(irq); 20441766119SJoseph Chen else 20541766119SJoseph Chen return -ENOSYS; 206c234b81eSJoseph Chen } 207c234b81eSJoseph Chen 208c234b81eSJoseph Chen int irq_get_gpio_level(int irq) 209c234b81eSJoseph Chen { 210269512fdSJoseph Chen if (bad_irq(irq)) 211c234b81eSJoseph Chen return -EINVAL; 212c234b81eSJoseph Chen 213cf344252SJoseph Chen if (irq < PLATFORM_GIC_MAX_IRQ) 214c234b81eSJoseph Chen return 0; 21541766119SJoseph Chen else if (irq < PLATFORM_GPIO_MAX_IRQ) 216cf344252SJoseph Chen return irqchip.gpio->irq_get_gpio_level(irq); 21741766119SJoseph Chen else 21841766119SJoseph Chen return -ENOSYS; 219c234b81eSJoseph Chen } 220c234b81eSJoseph Chen 2214e6670feSJoseph Chen void irq_install_handler(int irq, interrupt_handler_t *handler, void *data) 2224e6670feSJoseph Chen { 223cf344252SJoseph Chen if (!intr_setup) { 224cf344252SJoseph Chen IRQ_W("Interrupt framework is not intr_setup\n"); 2254e6670feSJoseph Chen return; 226269512fdSJoseph Chen } 227269512fdSJoseph Chen 22841766119SJoseph Chen if (irq < PLATFORM_MAX_IRQ) { 229cf344252SJoseph Chen if (!handler || irq_desc[irq].handle_irq) 230cf344252SJoseph Chen return; 231cf344252SJoseph Chen irq_desc[irq].handle_irq = handler; 232cf344252SJoseph Chen irq_desc[irq].data = data; 23341766119SJoseph Chen } else { 23441766119SJoseph Chen virq_install_handler(irq, handler, data); 23541766119SJoseph Chen } 2364e6670feSJoseph Chen } 2374e6670feSJoseph Chen 2384e6670feSJoseph Chen void irq_free_handler(int irq) 2394e6670feSJoseph Chen { 2400e508c4fSJoseph Chen if (irq_handler_disable(irq)) 2414e6670feSJoseph Chen return; 2424e6670feSJoseph Chen 24341766119SJoseph Chen if (irq < PLATFORM_MAX_IRQ) { 244cf344252SJoseph Chen irq_desc[irq].handle_irq = NULL; 245cf344252SJoseph Chen irq_desc[irq].data = NULL; 24641766119SJoseph Chen } else { 24741766119SJoseph Chen virq_free_handler(irq); 24841766119SJoseph Chen } 2494e6670feSJoseph Chen } 2504e6670feSJoseph Chen 251*2c4e90c1SJoseph Chen int irq_handler_enable_suspend_only(int irq) 252*2c4e90c1SJoseph Chen { 253*2c4e90c1SJoseph Chen if (bad_irq(irq)) 254*2c4e90c1SJoseph Chen return -EINVAL; 255*2c4e90c1SJoseph Chen 256*2c4e90c1SJoseph Chen if (irqchip.suspend_num >= PLATFORM_SUSPEND_MAX_IRQ) { 257*2c4e90c1SJoseph Chen printf("Over max count(%d) of suspend irq\n", 258*2c4e90c1SJoseph Chen PLATFORM_SUSPEND_MAX_IRQ); 259*2c4e90c1SJoseph Chen return -EPERM; 260*2c4e90c1SJoseph Chen } 261*2c4e90c1SJoseph Chen 262*2c4e90c1SJoseph Chen irqchip.suspend_irq[irqchip.suspend_num++] = irq; 263*2c4e90c1SJoseph Chen return 0; 264*2c4e90c1SJoseph Chen } 265*2c4e90c1SJoseph Chen 266ed837edfSJoseph Chen int irqs_suspend(void) 267ed837edfSJoseph Chen { 268*2c4e90c1SJoseph Chen int i; 269*2c4e90c1SJoseph Chen 270*2c4e90c1SJoseph Chen for (i = 0; i < irqchip.suspend_num; i++) 271*2c4e90c1SJoseph Chen irq_handler_enable(irqchip.suspend_irq[i]); 272*2c4e90c1SJoseph Chen 273cf344252SJoseph Chen return irqchip.gic->irq_suspend(); 274ed837edfSJoseph Chen } 275ed837edfSJoseph Chen 276ed837edfSJoseph Chen int irqs_resume(void) 277ed837edfSJoseph Chen { 278*2c4e90c1SJoseph Chen int i; 279*2c4e90c1SJoseph Chen 280*2c4e90c1SJoseph Chen for (i = 0; i < irqchip.suspend_num; i++) 281*2c4e90c1SJoseph Chen irq_handler_disable(irqchip.suspend_irq[i]); 282*2c4e90c1SJoseph Chen 283cf344252SJoseph Chen return irqchip.gic->irq_resume(); 284ed837edfSJoseph Chen } 285ed837edfSJoseph Chen 2864e6670feSJoseph Chen #ifdef CONFIG_ARM64 2874e6670feSJoseph Chen static void cpu_local_irq_enable(void) 2884e6670feSJoseph Chen { 2894e6670feSJoseph Chen asm volatile("msr daifclr, #0x02"); 2904e6670feSJoseph Chen } 2914e6670feSJoseph Chen 2924e6670feSJoseph Chen static int cpu_local_irq_disable(void) 2934e6670feSJoseph Chen { 2944e6670feSJoseph Chen asm volatile("msr daifset, #0x02"); 2954e6670feSJoseph Chen return 0; 2964e6670feSJoseph Chen } 2974e6670feSJoseph Chen 2984e6670feSJoseph Chen void do_irq(struct pt_regs *pt_regs, unsigned int esr) 2994e6670feSJoseph Chen { 300c563adc7SJoseph Chen #ifdef CONFIG_ROCKCHIP_DEBUGGER 301c563adc7SJoseph Chen printf("\n>>> Rockchip Debugger:\n"); 302c563adc7SJoseph Chen show_regs(pt_regs); 303c563adc7SJoseph Chen #endif 304c563adc7SJoseph Chen 305269512fdSJoseph Chen __do_generic_irq_handler(); 3064e6670feSJoseph Chen } 3074e6670feSJoseph Chen #else 3084e6670feSJoseph Chen static void cpu_local_irq_enable(void) 3094e6670feSJoseph Chen { 3104e6670feSJoseph Chen unsigned long cpsr; 3114e6670feSJoseph Chen 3124e6670feSJoseph Chen __asm__ __volatile__("mrs %0, cpsr\n" 3134e6670feSJoseph Chen "bic %0, %0, #0x80\n" 3144e6670feSJoseph Chen "msr cpsr_c, %0" 3154e6670feSJoseph Chen : "=r" (cpsr) : : "memory"); 3164e6670feSJoseph Chen } 3174e6670feSJoseph Chen 3184e6670feSJoseph Chen static int cpu_local_irq_disable(void) 3194e6670feSJoseph Chen { 3204e6670feSJoseph Chen unsigned long old_cpsr, new_cpsr; 3214e6670feSJoseph Chen 3224e6670feSJoseph Chen __asm__ __volatile__("mrs %0, cpsr\n" 3234e6670feSJoseph Chen "orr %1, %0, #0xc0\n" 3244e6670feSJoseph Chen "msr cpsr_c, %1" 3254e6670feSJoseph Chen : "=r" (old_cpsr), "=r" (new_cpsr) 3264e6670feSJoseph Chen : 3274e6670feSJoseph Chen : "memory"); 3284e6670feSJoseph Chen 3294e6670feSJoseph Chen return (old_cpsr & 0x80) == 0; 3304e6670feSJoseph Chen } 3314e6670feSJoseph Chen 3324e6670feSJoseph Chen void do_irq(struct pt_regs *pt_regs) 3334e6670feSJoseph Chen { 334c563adc7SJoseph Chen #ifdef CONFIG_ROCKCHIP_DEBUGGER 335c563adc7SJoseph Chen printf("\n>>> Rockchp Debugger:\n"); 336c563adc7SJoseph Chen show_regs(pt_regs); 337c563adc7SJoseph Chen #endif 338c563adc7SJoseph Chen 339269512fdSJoseph Chen __do_generic_irq_handler(); 3404e6670feSJoseph Chen } 3414e6670feSJoseph Chen #endif 3424e6670feSJoseph Chen 3434e6670feSJoseph Chen int arch_interrupt_init(void) 3444e6670feSJoseph Chen { 3454e6670feSJoseph Chen #ifndef CONFIG_ARM64 3464e6670feSJoseph Chen unsigned long cpsr __maybe_unused; 3474e6670feSJoseph Chen 3484e6670feSJoseph Chen /* stack has been reserved in: arch_reserve_stacks() */ 3494e6670feSJoseph Chen IRQ_STACK_START = gd->irq_sp; 350c15709b5SJoseph Chen IRQ_STACK_START_IN = gd->irq_sp; 3514e6670feSJoseph Chen 3524e6670feSJoseph Chen __asm__ __volatile__("mrs %0, cpsr\n" 3534e6670feSJoseph Chen : "=r" (cpsr) 3544e6670feSJoseph Chen : 3554e6670feSJoseph Chen : "memory"); 3564e6670feSJoseph Chen 3574e6670feSJoseph Chen __asm__ __volatile__("msr cpsr_c, %0\n" 3584e6670feSJoseph Chen "mov sp, %1\n" 3594e6670feSJoseph Chen : 3604e6670feSJoseph Chen : "r" (IRQ_MODE | I_BIT | 3614e6670feSJoseph Chen F_BIT | (cpsr & ~FIQ_MODE)), 3624e6670feSJoseph Chen "r" (IRQ_STACK_START) 3634e6670feSJoseph Chen : "memory"); 3644e6670feSJoseph Chen 3654e6670feSJoseph Chen __asm__ __volatile__("msr cpsr_c, %0" 3664e6670feSJoseph Chen : 3674e6670feSJoseph Chen : "r" (cpsr) 3684e6670feSJoseph Chen : "memory"); 3694e6670feSJoseph Chen #endif 370269512fdSJoseph Chen return __do_arch_irq_init(); 3714e6670feSJoseph Chen } 3724e6670feSJoseph Chen 3734e6670feSJoseph Chen int interrupt_init(void) 3744e6670feSJoseph Chen { 3754e6670feSJoseph Chen return arch_interrupt_init(); 3764e6670feSJoseph Chen } 3774e6670feSJoseph Chen 3784e6670feSJoseph Chen void enable_interrupts(void) 3794e6670feSJoseph Chen { 3804e6670feSJoseph Chen cpu_local_irq_enable(); 3814e6670feSJoseph Chen } 3824e6670feSJoseph Chen 3834e6670feSJoseph Chen int disable_interrupts(void) 3844e6670feSJoseph Chen { 3854e6670feSJoseph Chen return cpu_local_irq_disable(); 3864e6670feSJoseph Chen } 387