1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2014 Mans Rullgard <mans@mansr.com> 4 */ 5 6#include <linux/init.h> 7#include <linux/irq.h> 8#include <linux/irqchip.h> 9#include <linux/irqchip/chained_irq.h> 10#include <linux/ioport.h> 11#include <linux/io.h> 12#include <linux/of_address.h> 13#include <linux/of_irq.h> 14#include <linux/slab.h> 15 16#define IRQ0_CTL_BASE 0x0000 17#define IRQ1_CTL_BASE 0x0100 18#define EDGE_CTL_BASE 0x0200 19#define IRQ2_CTL_BASE 0x0300 20 21#define IRQ_CTL_HI 0x18 22#define EDGE_CTL_HI 0x20 23 24#define IRQ_STATUS 0x00 25#define IRQ_RAWSTAT 0x04 26#define IRQ_EN_SET 0x08 27#define IRQ_EN_CLR 0x0c 28#define IRQ_SOFT_SET 0x10 29#define IRQ_SOFT_CLR 0x14 30 31#define EDGE_STATUS 0x00 32#define EDGE_RAWSTAT 0x04 33#define EDGE_CFG_RISE 0x08 34#define EDGE_CFG_FALL 0x0c 35#define EDGE_CFG_RISE_SET 0x10 36#define EDGE_CFG_RISE_CLR 0x14 37#define EDGE_CFG_FALL_SET 0x18 38#define EDGE_CFG_FALL_CLR 0x1c 39 40struct tangox_irq_chip { 41 void __iomem *base; 42 unsigned long ctl; 43}; 44 45static inline u32 intc_readl(struct tangox_irq_chip *chip, int reg) 46{ 47 return readl_relaxed(chip->base + reg); 48} 49 50static inline void intc_writel(struct tangox_irq_chip *chip, int reg, u32 val) 51{ 52 writel_relaxed(val, chip->base + reg); 53} 54 55static void tangox_dispatch_irqs(struct irq_domain *dom, unsigned int status, 56 int base) 57{ 58 unsigned int hwirq; 59 unsigned int virq; 60 61 while (status) { 62 hwirq = __ffs(status); 63 virq = irq_find_mapping(dom, base + hwirq); 64 if (virq) 65 generic_handle_irq(virq); 66 status &= ~BIT(hwirq); 67 } 68} 69 70static void tangox_irq_handler(struct irq_desc *desc) 71{ 72 struct irq_domain *dom = irq_desc_get_handler_data(desc); 73 struct irq_chip *host_chip = irq_desc_get_chip(desc); 74 struct tangox_irq_chip *chip = dom->host_data; 75 unsigned int status_lo, status_hi; 76 77 chained_irq_enter(host_chip, desc); 78 79 status_lo = intc_readl(chip, chip->ctl + IRQ_STATUS); 80 status_hi = intc_readl(chip, chip->ctl + IRQ_CTL_HI + IRQ_STATUS); 81 82 tangox_dispatch_irqs(dom, status_lo, 0); 83 tangox_dispatch_irqs(dom, status_hi, 32); 84 85 chained_irq_exit(host_chip, desc); 86} 87 88static int tangox_irq_set_type(struct irq_data *d, unsigned int flow_type) 89{ 90 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 91 struct tangox_irq_chip *chip = gc->domain->host_data; 92 struct irq_chip_regs *regs = &gc->chip_types[0].regs; 93 94 switch (flow_type & IRQ_TYPE_SENSE_MASK) { 95 case IRQ_TYPE_EDGE_RISING: 96 intc_writel(chip, regs->type + EDGE_CFG_RISE_SET, d->mask); 97 intc_writel(chip, regs->type + EDGE_CFG_FALL_CLR, d->mask); 98 break; 99 100 case IRQ_TYPE_EDGE_FALLING: 101 intc_writel(chip, regs->type + EDGE_CFG_RISE_CLR, d->mask); 102 intc_writel(chip, regs->type + EDGE_CFG_FALL_SET, d->mask); 103 break; 104 105 case IRQ_TYPE_LEVEL_HIGH: 106 intc_writel(chip, regs->type + EDGE_CFG_RISE_CLR, d->mask); 107 intc_writel(chip, regs->type + EDGE_CFG_FALL_CLR, d->mask); 108 break; 109 110 case IRQ_TYPE_LEVEL_LOW: 111 intc_writel(chip, regs->type + EDGE_CFG_RISE_SET, d->mask); 112 intc_writel(chip, regs->type + EDGE_CFG_FALL_SET, d->mask); 113 break; 114 115 default: 116 pr_err("Invalid trigger mode %x for IRQ %d\n", 117 flow_type, d->irq); 118 return -EINVAL; 119 } 120 121 return irq_setup_alt_chip(d, flow_type); 122} 123 124static void __init tangox_irq_init_chip(struct irq_chip_generic *gc, 125 unsigned long ctl_offs, 126 unsigned long edge_offs) 127{ 128 struct tangox_irq_chip *chip = gc->domain->host_data; 129 struct irq_chip_type *ct = gc->chip_types; 130 unsigned long ctl_base = chip->ctl + ctl_offs; 131 unsigned long edge_base = EDGE_CTL_BASE + edge_offs; 132 int i; 133 134 gc->reg_base = chip->base; 135 gc->unused = 0; 136 137 for (i = 0; i < 2; i++) { 138 ct[i].chip.irq_ack = irq_gc_ack_set_bit; 139 ct[i].chip.irq_mask = irq_gc_mask_disable_reg; 140 ct[i].chip.irq_mask_ack = irq_gc_mask_disable_and_ack_set; 141 ct[i].chip.irq_unmask = irq_gc_unmask_enable_reg; 142 ct[i].chip.irq_set_type = tangox_irq_set_type; 143 ct[i].chip.name = gc->domain->name; 144 145 ct[i].regs.enable = ctl_base + IRQ_EN_SET; 146 ct[i].regs.disable = ctl_base + IRQ_EN_CLR; 147 ct[i].regs.ack = edge_base + EDGE_RAWSTAT; 148 ct[i].regs.type = edge_base; 149 } 150 151 ct[0].type = IRQ_TYPE_LEVEL_MASK; 152 ct[0].handler = handle_level_irq; 153 154 ct[1].type = IRQ_TYPE_EDGE_BOTH; 155 ct[1].handler = handle_edge_irq; 156 157 intc_writel(chip, ct->regs.disable, 0xffffffff); 158 intc_writel(chip, ct->regs.ack, 0xffffffff); 159} 160 161static void __init tangox_irq_domain_init(struct irq_domain *dom) 162{ 163 struct irq_chip_generic *gc; 164 int i; 165 166 for (i = 0; i < 2; i++) { 167 gc = irq_get_domain_generic_chip(dom, i * 32); 168 tangox_irq_init_chip(gc, i * IRQ_CTL_HI, i * EDGE_CTL_HI); 169 } 170} 171 172static int __init tangox_irq_init(void __iomem *base, struct resource *baseres, 173 struct device_node *node) 174{ 175 struct tangox_irq_chip *chip; 176 struct irq_domain *dom; 177 struct resource res; 178 int irq; 179 int err; 180 181 irq = irq_of_parse_and_map(node, 0); 182 if (!irq) 183 panic("%pOFn: failed to get IRQ", node); 184 185 err = of_address_to_resource(node, 0, &res); 186 if (err) 187 panic("%pOFn: failed to get address", node); 188 189 chip = kzalloc(sizeof(*chip), GFP_KERNEL); 190 chip->ctl = res.start - baseres->start; 191 chip->base = base; 192 193 dom = irq_domain_add_linear(node, 64, &irq_generic_chip_ops, chip); 194 if (!dom) 195 panic("%pOFn: failed to create irqdomain", node); 196 197 err = irq_alloc_domain_generic_chips(dom, 32, 2, node->name, 198 handle_level_irq, 0, 0, 0); 199 if (err) 200 panic("%pOFn: failed to allocate irqchip", node); 201 202 tangox_irq_domain_init(dom); 203 204 irq_set_chained_handler_and_data(irq, tangox_irq_handler, dom); 205 206 return 0; 207} 208 209static int __init tangox_of_irq_init(struct device_node *node, 210 struct device_node *parent) 211{ 212 struct device_node *c; 213 struct resource res; 214 void __iomem *base; 215 216 base = of_iomap(node, 0); 217 if (!base) 218 panic("%pOFn: of_iomap failed", node); 219 220 of_address_to_resource(node, 0, &res); 221 222 for_each_child_of_node(node, c) 223 tangox_irq_init(base, &res, c); 224 225 return 0; 226} 227IRQCHIP_DECLARE(tangox_intc, "sigma,smp8642-intc", tangox_of_irq_init); 228