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