1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 4 * Ingenic XBurst platform IRQ support 5 */ 6 7 #include <linux/errno.h> 8 #include <linux/init.h> 9 #include <linux/types.h> 10 #include <linux/interrupt.h> 11 #include <linux/ioport.h> 12 #include <linux/irqchip.h> 13 #include <linux/of_address.h> 14 #include <linux/of_irq.h> 15 #include <linux/timex.h> 16 #include <linux/slab.h> 17 #include <linux/delay.h> 18 19 #include <asm/io.h> 20 #include <asm/mach-jz4740/irq.h> 21 22 struct ingenic_intc_data { 23 void __iomem *base; 24 struct irq_domain *domain; 25 unsigned num_chips; 26 }; 27 28 #define JZ_REG_INTC_STATUS 0x00 29 #define JZ_REG_INTC_MASK 0x04 30 #define JZ_REG_INTC_SET_MASK 0x08 31 #define JZ_REG_INTC_CLEAR_MASK 0x0c 32 #define JZ_REG_INTC_PENDING 0x10 33 #define CHIP_SIZE 0x20 34 35 static irqreturn_t intc_cascade(int irq, void *data) 36 { 37 struct ingenic_intc_data *intc = irq_get_handler_data(irq); 38 struct irq_domain *domain = intc->domain; 39 struct irq_chip_generic *gc; 40 uint32_t pending; 41 unsigned i; 42 43 for (i = 0; i < intc->num_chips; i++) { 44 gc = irq_get_domain_generic_chip(domain, i * 32); 45 46 pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING); 47 if (!pending) 48 continue; 49 50 while (pending) { 51 int bit = __fls(pending); 52 53 irq = irq_find_mapping(domain, bit + (i * 32)); 54 generic_handle_irq(irq); 55 pending &= ~BIT(bit); 56 } 57 } 58 59 return IRQ_HANDLED; 60 } 61 62 static struct irqaction intc_cascade_action = { 63 .handler = intc_cascade, 64 .name = "SoC intc cascade interrupt", 65 }; 66 67 static int __init ingenic_intc_of_init(struct device_node *node, 68 unsigned num_chips) 69 { 70 struct ingenic_intc_data *intc; 71 struct irq_chip_generic *gc; 72 struct irq_chip_type *ct; 73 struct irq_domain *domain; 74 int parent_irq, err = 0; 75 unsigned i; 76 77 intc = kzalloc(sizeof(*intc), GFP_KERNEL); 78 if (!intc) { 79 err = -ENOMEM; 80 goto out_err; 81 } 82 83 parent_irq = irq_of_parse_and_map(node, 0); 84 if (!parent_irq) { 85 err = -EINVAL; 86 goto out_free; 87 } 88 89 err = irq_set_handler_data(parent_irq, intc); 90 if (err) 91 goto out_unmap_irq; 92 93 intc->num_chips = num_chips; 94 intc->base = of_iomap(node, 0); 95 if (!intc->base) { 96 err = -ENODEV; 97 goto out_unmap_irq; 98 } 99 100 domain = irq_domain_add_legacy(node, num_chips * 32, 101 JZ4740_IRQ_BASE, 0, 102 &irq_generic_chip_ops, NULL); 103 if (!domain) { 104 err = -ENOMEM; 105 goto out_unmap_base; 106 } 107 108 intc->domain = domain; 109 110 err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC", 111 handle_level_irq, 0, 112 IRQ_NOPROBE | IRQ_LEVEL, 0); 113 if (err) 114 goto out_domain_remove; 115 116 for (i = 0; i < num_chips; i++) { 117 gc = irq_get_domain_generic_chip(domain, i * 32); 118 119 gc->wake_enabled = IRQ_MSK(32); 120 gc->reg_base = intc->base + (i * CHIP_SIZE); 121 122 ct = gc->chip_types; 123 ct->regs.enable = JZ_REG_INTC_CLEAR_MASK; 124 ct->regs.disable = JZ_REG_INTC_SET_MASK; 125 ct->chip.irq_unmask = irq_gc_unmask_enable_reg; 126 ct->chip.irq_mask = irq_gc_mask_disable_reg; 127 ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; 128 ct->chip.irq_set_wake = irq_gc_set_wake; 129 ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND; 130 131 /* Mask all irqs */ 132 irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK); 133 } 134 135 setup_irq(parent_irq, &intc_cascade_action); 136 return 0; 137 138 out_domain_remove: 139 irq_domain_remove(domain); 140 out_unmap_base: 141 iounmap(intc->base); 142 out_unmap_irq: 143 irq_dispose_mapping(parent_irq); 144 out_free: 145 kfree(intc); 146 out_err: 147 return err; 148 } 149 150 static int __init intc_1chip_of_init(struct device_node *node, 151 struct device_node *parent) 152 { 153 return ingenic_intc_of_init(node, 1); 154 } 155 IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", intc_1chip_of_init); 156 IRQCHIP_DECLARE(jz4725b_intc, "ingenic,jz4725b-intc", intc_1chip_of_init); 157 158 static int __init intc_2chip_of_init(struct device_node *node, 159 struct device_node *parent) 160 { 161 return ingenic_intc_of_init(node, 2); 162 } 163 IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init); 164 IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init); 165 IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init); 166