1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019, Jiaxun Yang <jiaxun.yang@flygoat.com> 4 * Loongson-1 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/io.h> 16 #include <linux/irqchip/chained_irq.h> 17 18 #define LS_REG_INTC_STATUS 0x00 19 #define LS_REG_INTC_EN 0x04 20 #define LS_REG_INTC_SET 0x08 21 #define LS_REG_INTC_CLR 0x0c 22 #define LS_REG_INTC_POL 0x10 23 #define LS_REG_INTC_EDGE 0x14 24 25 /** 26 * struct ls1x_intc_priv - private ls1x-intc data. 27 * @domain: IRQ domain. 28 * @intc_base: IO Base of intc registers. 29 */ 30 31 struct ls1x_intc_priv { 32 struct irq_domain *domain; 33 void __iomem *intc_base; 34 }; 35 36 37 static void ls1x_chained_handle_irq(struct irq_desc *desc) 38 { 39 struct ls1x_intc_priv *priv = irq_desc_get_handler_data(desc); 40 struct irq_chip *chip = irq_desc_get_chip(desc); 41 u32 pending; 42 43 chained_irq_enter(chip, desc); 44 pending = readl(priv->intc_base + LS_REG_INTC_STATUS) & 45 readl(priv->intc_base + LS_REG_INTC_EN); 46 47 if (!pending) 48 spurious_interrupt(); 49 50 while (pending) { 51 int bit = __ffs(pending); 52 53 generic_handle_irq(irq_find_mapping(priv->domain, bit)); 54 pending &= ~BIT(bit); 55 } 56 57 chained_irq_exit(chip, desc); 58 } 59 60 static void ls_intc_set_bit(struct irq_chip_generic *gc, 61 unsigned int offset, 62 u32 mask, bool set) 63 { 64 if (set) 65 writel(readl(gc->reg_base + offset) | mask, 66 gc->reg_base + offset); 67 else 68 writel(readl(gc->reg_base + offset) & ~mask, 69 gc->reg_base + offset); 70 } 71 72 static int ls_intc_set_type(struct irq_data *data, unsigned int type) 73 { 74 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 75 u32 mask = data->mask; 76 77 switch (type) { 78 case IRQ_TYPE_LEVEL_HIGH: 79 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, false); 80 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, true); 81 break; 82 case IRQ_TYPE_LEVEL_LOW: 83 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, false); 84 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, false); 85 break; 86 case IRQ_TYPE_EDGE_RISING: 87 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, true); 88 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, true); 89 break; 90 case IRQ_TYPE_EDGE_FALLING: 91 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, true); 92 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, false); 93 break; 94 default: 95 return -EINVAL; 96 } 97 98 irqd_set_trigger_type(data, type); 99 return irq_setup_alt_chip(data, type); 100 } 101 102 103 static int __init ls1x_intc_of_init(struct device_node *node, 104 struct device_node *parent) 105 { 106 struct irq_chip_generic *gc; 107 struct irq_chip_type *ct; 108 struct ls1x_intc_priv *priv; 109 int parent_irq, err = 0; 110 111 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 112 if (!priv) 113 return -ENOMEM; 114 115 priv->intc_base = of_iomap(node, 0); 116 if (!priv->intc_base) { 117 err = -ENODEV; 118 goto out_free_priv; 119 } 120 121 parent_irq = irq_of_parse_and_map(node, 0); 122 if (!parent_irq) { 123 pr_err("ls1x-irq: unable to get parent irq\n"); 124 err = -ENODEV; 125 goto out_iounmap; 126 } 127 128 /* Set up an IRQ domain */ 129 priv->domain = irq_domain_add_linear(node, 32, &irq_generic_chip_ops, 130 NULL); 131 if (!priv->domain) { 132 pr_err("ls1x-irq: cannot add IRQ domain\n"); 133 err = -ENOMEM; 134 goto out_iounmap; 135 } 136 137 err = irq_alloc_domain_generic_chips(priv->domain, 32, 2, 138 node->full_name, handle_level_irq, 139 IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN, 0, 140 IRQ_GC_INIT_MASK_CACHE); 141 if (err) { 142 pr_err("ls1x-irq: unable to register IRQ domain\n"); 143 goto out_free_domain; 144 } 145 146 /* Mask all irqs */ 147 writel(0x0, priv->intc_base + LS_REG_INTC_EN); 148 149 /* Ack all irqs */ 150 writel(0xffffffff, priv->intc_base + LS_REG_INTC_CLR); 151 152 /* Set all irqs to high level triggered */ 153 writel(0xffffffff, priv->intc_base + LS_REG_INTC_POL); 154 155 gc = irq_get_domain_generic_chip(priv->domain, 0); 156 157 gc->reg_base = priv->intc_base; 158 159 ct = gc->chip_types; 160 ct[0].type = IRQ_TYPE_LEVEL_MASK; 161 ct[0].regs.mask = LS_REG_INTC_EN; 162 ct[0].regs.ack = LS_REG_INTC_CLR; 163 ct[0].chip.irq_unmask = irq_gc_mask_set_bit; 164 ct[0].chip.irq_mask = irq_gc_mask_clr_bit; 165 ct[0].chip.irq_ack = irq_gc_ack_set_bit; 166 ct[0].chip.irq_set_type = ls_intc_set_type; 167 ct[0].handler = handle_level_irq; 168 169 ct[1].type = IRQ_TYPE_EDGE_BOTH; 170 ct[1].regs.mask = LS_REG_INTC_EN; 171 ct[1].regs.ack = LS_REG_INTC_CLR; 172 ct[1].chip.irq_unmask = irq_gc_mask_set_bit; 173 ct[1].chip.irq_mask = irq_gc_mask_clr_bit; 174 ct[1].chip.irq_ack = irq_gc_ack_set_bit; 175 ct[1].chip.irq_set_type = ls_intc_set_type; 176 ct[1].handler = handle_edge_irq; 177 178 irq_set_chained_handler_and_data(parent_irq, 179 ls1x_chained_handle_irq, priv); 180 181 return 0; 182 183 out_free_domain: 184 irq_domain_remove(priv->domain); 185 out_iounmap: 186 iounmap(priv->intc_base); 187 out_free_priv: 188 kfree(priv); 189 190 return err; 191 } 192 193 IRQCHIP_DECLARE(ls1x_intc, "loongson,ls1x-intc", ls1x_intc_of_init); 194