Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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