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 goto out_iounmap; 134 } 135 136 err = irq_alloc_domain_generic_chips(priv->domain, 32, 2, 137 node->full_name, handle_level_irq, 138 IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN, 0, 139 IRQ_GC_INIT_MASK_CACHE); 140 if (err) { 141 pr_err("ls1x-irq: unable to register IRQ domain\n"); 142 goto out_free_domain; 143 } 144 145 /* Mask all irqs */ 146 writel(0x0, priv->intc_base + LS_REG_INTC_EN); 147 148 /* Ack all irqs */ 149 writel(0xffffffff, priv->intc_base + LS_REG_INTC_CLR); 150 151 /* Set all irqs to high level triggered */ 152 writel(0xffffffff, priv->intc_base + LS_REG_INTC_POL); 153 154 gc = irq_get_domain_generic_chip(priv->domain, 0); 155 156 gc->reg_base = priv->intc_base; 157 158 ct = gc->chip_types; 159 ct[0].type = IRQ_TYPE_LEVEL_MASK; 160 ct[0].regs.mask = LS_REG_INTC_EN; 161 ct[0].regs.ack = LS_REG_INTC_CLR; 162 ct[0].chip.irq_unmask = irq_gc_mask_set_bit; 163 ct[0].chip.irq_mask = irq_gc_mask_clr_bit; 164 ct[0].chip.irq_ack = irq_gc_ack_set_bit; 165 ct[0].chip.irq_set_type = ls_intc_set_type; 166 ct[0].handler = handle_level_irq; 167 168 ct[1].type = IRQ_TYPE_EDGE_BOTH; 169 ct[1].regs.mask = LS_REG_INTC_EN; 170 ct[1].regs.ack = LS_REG_INTC_CLR; 171 ct[1].chip.irq_unmask = irq_gc_mask_set_bit; 172 ct[1].chip.irq_mask = irq_gc_mask_clr_bit; 173 ct[1].chip.irq_ack = irq_gc_ack_set_bit; 174 ct[1].chip.irq_set_type = ls_intc_set_type; 175 ct[1].handler = handle_edge_irq; 176 177 irq_set_chained_handler_and_data(parent_irq, 178 ls1x_chained_handle_irq, priv); 179 180 return 0; 181 182 out_free_domain: 183 irq_domain_remove(priv->domain); 184 out_iounmap: 185 iounmap(priv->intc_base); 186 out_free_priv: 187 kfree(priv); 188 189 return err; 190 } 191 192 IRQCHIP_DECLARE(ls1x_intc, "loongson,ls1x-intc", ls1x_intc_of_init); 193