Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: i8259: DT support

Support probing the i8259 programmable interrupt controller, as found on
the Malta board, and using its interrupts via device tree.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: Andrew Bresticker <abrestic@chromium.org>
Cc: linux-kernel@vger.kernel.org
Patchwork: http://patchwork.linux-mips.org/patch/10114/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Paul Burton and committed by
Ralf Baechle
5f93ef5c e8823d26

+42 -2
+1
arch/mips/include/asm/i8259.h
··· 41 41 extern void make_8259A_irq(unsigned int irq); 42 42 43 43 extern void init_i8259_irqs(void); 44 + extern int i8259_of_init(struct device_node *node, struct device_node *parent); 44 45 45 46 /* 46 47 * Do the traditional i8259 interrupt polling thing. This is for the few
+41 -2
arch/mips/kernel/i8259.c
··· 14 14 #include <linux/interrupt.h> 15 15 #include <linux/irqdomain.h> 16 16 #include <linux/kernel.h> 17 + #include <linux/of_irq.h> 17 18 #include <linux/spinlock.h> 18 19 #include <linux/syscore_ops.h> 19 20 #include <linux/irq.h> 20 21 21 22 #include <asm/i8259.h> 22 23 #include <asm/io.h> 24 + 25 + #include "../../drivers/irqchip/irqchip.h" 23 26 24 27 /* 25 28 * This is the 'legacy' 8259A Programmable Interrupt Controller, ··· 330 327 * driver compatibility reasons interrupts 0 - 15 to be the i8259 331 328 * interrupts even if the hardware uses a different interrupt numbering. 332 329 */ 333 - void __init init_i8259_irqs(void) 330 + struct irq_domain * __init __init_i8259_irqs(struct device_node *node) 334 331 { 335 332 struct irq_domain *domain; 336 333 ··· 339 336 340 337 init_8259A(0); 341 338 342 - domain = irq_domain_add_legacy(NULL, 16, I8259A_IRQ_BASE, 0, 339 + domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0, 343 340 &i8259A_ops, NULL); 344 341 if (!domain) 345 342 panic("Failed to add i8259 IRQ domain"); 346 343 347 344 setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); 345 + return domain; 348 346 } 347 + 348 + void __init init_i8259_irqs(void) 349 + { 350 + __init_i8259_irqs(NULL); 351 + } 352 + 353 + static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) 354 + { 355 + struct irq_domain *domain = irq_get_handler_data(irq); 356 + int hwirq = i8259_irq(); 357 + 358 + if (hwirq < 0) 359 + return; 360 + 361 + irq = irq_linear_revmap(domain, hwirq); 362 + generic_handle_irq(irq); 363 + } 364 + 365 + int __init i8259_of_init(struct device_node *node, struct device_node *parent) 366 + { 367 + struct irq_domain *domain; 368 + unsigned int parent_irq; 369 + 370 + parent_irq = irq_of_parse_and_map(node, 0); 371 + if (!parent_irq) { 372 + pr_err("Failed to map i8259 parent IRQ\n"); 373 + return -ENODEV; 374 + } 375 + 376 + domain = __init_i8259_irqs(node); 377 + irq_set_handler_data(parent_irq, domain); 378 + irq_set_chained_handler(parent_irq, i8259_irq_dispatch); 379 + return 0; 380 + } 381 + IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init);