1178481Sjb// SPDX-License-Identifier: GPL-2.0-or-later 2178481Sjb/* 3178481Sjb * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 4178481Sjb * Ingenic XBurst platform IRQ support 5178481Sjb */ 6178481Sjb 7178481Sjb#include <linux/errno.h> 8178481Sjb#include <linux/init.h> 9178481Sjb#include <linux/types.h> 10178481Sjb#include <linux/interrupt.h> 11178481Sjb#include <linux/ioport.h> 12178481Sjb#include <linux/irqchip.h> 13178481Sjb#include <linux/of_address.h> 14178481Sjb#include <linux/of_irq.h> 15178481Sjb#include <linux/timex.h> 16178481Sjb#include <linux/slab.h> 17178481Sjb#include <linux/delay.h> 18178481Sjb 19178481Sjb#include <asm/io.h> 20178481Sjb 21178481Sjbstruct ingenic_intc_data { 22178481Sjb void __iomem *base; 23178481Sjb struct irq_domain *domain; 24178481Sjb unsigned num_chips; 25178481Sjb}; 26178481Sjb 27178481Sjb#define JZ_REG_INTC_STATUS 0x00 28178481Sjb#define JZ_REG_INTC_MASK 0x04 29178481Sjb#define JZ_REG_INTC_SET_MASK 0x08 30178481Sjb#define JZ_REG_INTC_CLEAR_MASK 0x0c 31178481Sjb#define JZ_REG_INTC_PENDING 0x10 32178481Sjb#define CHIP_SIZE 0x20 33178481Sjb 34178481Sjbstatic irqreturn_t intc_cascade(int irq, void *data) 35178481Sjb{ 36178481Sjb struct ingenic_intc_data *intc = irq_get_handler_data(irq); 37178481Sjb struct irq_domain *domain = intc->domain; 38178481Sjb struct irq_chip_generic *gc; 39178481Sjb uint32_t pending; 40178481Sjb unsigned i; 41178481Sjb 42178481Sjb for (i = 0; i < intc->num_chips; i++) { 43178481Sjb gc = irq_get_domain_generic_chip(domain, i * 32); 44178481Sjb 45178481Sjb pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING); 46178481Sjb if (!pending) 47178481Sjb continue; 48178481Sjb 49178481Sjb while (pending) { 50178481Sjb int bit = __fls(pending); 51178481Sjb 52178481Sjb generic_handle_domain_irq(domain, bit + (i * 32)); 53178481Sjb pending &= ~BIT(bit); 54178481Sjb } 55178481Sjb } 56178481Sjb 57178481Sjb return IRQ_HANDLED; 58178481Sjb} 59178481Sjb 60178481Sjbstatic int __init ingenic_intc_of_init(struct device_node *node, 61178481Sjb unsigned num_chips) 62178481Sjb{ 63178481Sjb struct ingenic_intc_data *intc; 64178481Sjb struct irq_chip_generic *gc; 65178481Sjb struct irq_chip_type *ct; 66178481Sjb struct irq_domain *domain; 67178481Sjb int parent_irq, err = 0; 68178481Sjb unsigned i; 69178481Sjb 70178481Sjb intc = kzalloc(sizeof(*intc), GFP_KERNEL); 71178481Sjb if (!intc) { 72178481Sjb err = -ENOMEM; 73178481Sjb goto out_err; 74178546Sjb } 75178481Sjb 76178481Sjb parent_irq = irq_of_parse_and_map(node, 0); 77178481Sjb if (!parent_irq) { 78178481Sjb err = -EINVAL; 79178481Sjb goto out_free; 80178481Sjb } 81178481Sjb 82178481Sjb err = irq_set_handler_data(parent_irq, intc); 83178481Sjb if (err) 84178481Sjb goto out_unmap_irq; 85178481Sjb 86178481Sjb intc->num_chips = num_chips; 87178481Sjb intc->base = of_iomap(node, 0); 88178481Sjb if (!intc->base) { 89178481Sjb err = -ENODEV; 90178481Sjb goto out_unmap_irq; 91178546Sjb } 92178481Sjb 93178481Sjb domain = irq_domain_add_linear(node, num_chips * 32, 94178481Sjb &irq_generic_chip_ops, NULL); 95178481Sjb if (!domain) { 96178481Sjb err = -ENOMEM; 97178481Sjb goto out_unmap_base; 98178481Sjb } 99178481Sjb 100178481Sjb intc->domain = domain; 101178481Sjb 102178481Sjb err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC", 103178481Sjb handle_level_irq, 0, 104178481Sjb IRQ_NOPROBE | IRQ_LEVEL, 0); 105178481Sjb if (err) 106178481Sjb goto out_domain_remove; 107178481Sjb 108178481Sjb for (i = 0; i < num_chips; i++) { 109178481Sjb gc = irq_get_domain_generic_chip(domain, i * 32); 110178481Sjb 111178481Sjb gc->wake_enabled = IRQ_MSK(32); 112178481Sjb gc->reg_base = intc->base + (i * CHIP_SIZE); 113178481Sjb 114178481Sjb ct = gc->chip_types; 115178481Sjb ct->regs.enable = JZ_REG_INTC_CLEAR_MASK; 116178481Sjb ct->regs.disable = JZ_REG_INTC_SET_MASK; 117178481Sjb ct->chip.irq_unmask = irq_gc_unmask_enable_reg; 118178481Sjb ct->chip.irq_mask = irq_gc_mask_disable_reg; 119178481Sjb ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; 120178481Sjb ct->chip.irq_set_wake = irq_gc_set_wake; 121178481Sjb ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND; 122178481Sjb 123178481Sjb /* Mask all irqs */ 124178481Sjb irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK); 125178481Sjb } 126178481Sjb 127178481Sjb if (request_irq(parent_irq, intc_cascade, IRQF_NO_SUSPEND, 128178481Sjb "SoC intc cascade interrupt", NULL)) 129178481Sjb pr_err("Failed to register SoC intc cascade interrupt\n"); 130178481Sjb return 0; 131178481Sjb 132178481Sjbout_domain_remove: 133178481Sjb irq_domain_remove(domain); 134178481Sjbout_unmap_base: 135178481Sjb iounmap(intc->base); 136178481Sjbout_unmap_irq: 137178481Sjb irq_dispose_mapping(parent_irq); 138178481Sjbout_free: 139178481Sjb kfree(intc); 140178481Sjbout_err: 141178481Sjb return err; 142178481Sjb} 143178481Sjb 144178481Sjbstatic int __init intc_1chip_of_init(struct device_node *node, 145178481Sjb struct device_node *parent) 146178481Sjb{ 147178481Sjb return ingenic_intc_of_init(node, 1); 148178481Sjb} 149178481SjbIRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", intc_1chip_of_init); 150178481SjbIRQCHIP_DECLARE(jz4725b_intc, "ingenic,jz4725b-intc", intc_1chip_of_init); 151178481Sjb 152178481Sjbstatic int __init intc_2chip_of_init(struct device_node *node, 153178481Sjb struct device_node *parent) 154178481Sjb{ 155178481Sjb return ingenic_intc_of_init(node, 2); 156178481Sjb} 157178481SjbIRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc", intc_2chip_of_init); 158178481SjbIRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init); 159178481SjbIRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init); 160178481SjbIRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init); 161178481Sjb