1 /* 2 * Broadcom BCM7038 style Level 1 interrupt controller driver 3 * 4 * Copyright (C) 2014 Broadcom Corporation 5 * Author: Kevin Cernekee 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 14 #include <linux/bitops.h> 15 #include <linux/kconfig.h> 16 #include <linux/kernel.h> 17 #include <linux/init.h> 18 #include <linux/interrupt.h> 19 #include <linux/io.h> 20 #include <linux/ioport.h> 21 #include <linux/irq.h> 22 #include <linux/irqdomain.h> 23 #include <linux/module.h> 24 #include <linux/of.h> 25 #include <linux/of_irq.h> 26 #include <linux/of_address.h> 27 #include <linux/of_platform.h> 28 #include <linux/platform_device.h> 29 #include <linux/slab.h> 30 #include <linux/smp.h> 31 #include <linux/types.h> 32 #include <linux/irqchip/chained_irq.h> 33 34 #include "irqchip.h" 35 36 #define IRQS_PER_WORD 32 37 #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4) 38 #define MAX_WORDS 8 39 40 struct bcm7038_l1_cpu; 41 42 struct bcm7038_l1_chip { 43 raw_spinlock_t lock; 44 unsigned int n_words; 45 struct irq_domain *domain; 46 struct bcm7038_l1_cpu *cpus[NR_CPUS]; 47 u8 affinity[MAX_WORDS * IRQS_PER_WORD]; 48 }; 49 50 struct bcm7038_l1_cpu { 51 void __iomem *map_base; 52 u32 mask_cache[0]; 53 }; 54 55 /* 56 * STATUS/MASK_STATUS/MASK_SET/MASK_CLEAR are packed one right after another: 57 * 58 * 7038: 59 * 0x1000_1400: W0_STATUS 60 * 0x1000_1404: W1_STATUS 61 * 0x1000_1408: W0_MASK_STATUS 62 * 0x1000_140c: W1_MASK_STATUS 63 * 0x1000_1410: W0_MASK_SET 64 * 0x1000_1414: W1_MASK_SET 65 * 0x1000_1418: W0_MASK_CLEAR 66 * 0x1000_141c: W1_MASK_CLEAR 67 * 68 * 7445: 69 * 0xf03e_1500: W0_STATUS 70 * 0xf03e_1504: W1_STATUS 71 * 0xf03e_1508: W2_STATUS 72 * 0xf03e_150c: W3_STATUS 73 * 0xf03e_1510: W4_STATUS 74 * 0xf03e_1514: W0_MASK_STATUS 75 * 0xf03e_1518: W1_MASK_STATUS 76 * [...] 77 */ 78 79 static inline unsigned int reg_status(struct bcm7038_l1_chip *intc, 80 unsigned int word) 81 { 82 return (0 * intc->n_words + word) * sizeof(u32); 83 } 84 85 static inline unsigned int reg_mask_status(struct bcm7038_l1_chip *intc, 86 unsigned int word) 87 { 88 return (1 * intc->n_words + word) * sizeof(u32); 89 } 90 91 static inline unsigned int reg_mask_set(struct bcm7038_l1_chip *intc, 92 unsigned int word) 93 { 94 return (2 * intc->n_words + word) * sizeof(u32); 95 } 96 97 static inline unsigned int reg_mask_clr(struct bcm7038_l1_chip *intc, 98 unsigned int word) 99 { 100 return (3 * intc->n_words + word) * sizeof(u32); 101 } 102 103 static inline u32 l1_readl(void __iomem *reg) 104 { 105 if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 106 return ioread32be(reg); 107 else 108 return readl(reg); 109 } 110 111 static inline void l1_writel(u32 val, void __iomem *reg) 112 { 113 if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 114 iowrite32be(val, reg); 115 else 116 writel(val, reg); 117 } 118 119 static void bcm7038_l1_irq_handle(unsigned int irq, struct irq_desc *desc) 120 { 121 struct bcm7038_l1_chip *intc = irq_desc_get_handler_data(desc); 122 struct bcm7038_l1_cpu *cpu; 123 struct irq_chip *chip = irq_desc_get_chip(desc); 124 unsigned int idx; 125 126 #ifdef CONFIG_SMP 127 cpu = intc->cpus[cpu_logical_map(smp_processor_id())]; 128 #else 129 cpu = intc->cpus[0]; 130 #endif 131 132 chained_irq_enter(chip, desc); 133 134 for (idx = 0; idx < intc->n_words; idx++) { 135 int base = idx * IRQS_PER_WORD; 136 unsigned long pending, flags; 137 int hwirq; 138 139 raw_spin_lock_irqsave(&intc->lock, flags); 140 pending = l1_readl(cpu->map_base + reg_status(intc, idx)) & 141 ~cpu->mask_cache[idx]; 142 raw_spin_unlock_irqrestore(&intc->lock, flags); 143 144 for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { 145 generic_handle_irq(irq_find_mapping(intc->domain, 146 base + hwirq)); 147 } 148 } 149 150 chained_irq_exit(chip, desc); 151 } 152 153 static void __bcm7038_l1_unmask(struct irq_data *d, unsigned int cpu_idx) 154 { 155 struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); 156 u32 word = d->hwirq / IRQS_PER_WORD; 157 u32 mask = BIT(d->hwirq % IRQS_PER_WORD); 158 159 intc->cpus[cpu_idx]->mask_cache[word] &= ~mask; 160 l1_writel(mask, intc->cpus[cpu_idx]->map_base + 161 reg_mask_clr(intc, word)); 162 } 163 164 static void __bcm7038_l1_mask(struct irq_data *d, unsigned int cpu_idx) 165 { 166 struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); 167 u32 word = d->hwirq / IRQS_PER_WORD; 168 u32 mask = BIT(d->hwirq % IRQS_PER_WORD); 169 170 intc->cpus[cpu_idx]->mask_cache[word] |= mask; 171 l1_writel(mask, intc->cpus[cpu_idx]->map_base + 172 reg_mask_set(intc, word)); 173 } 174 175 static void bcm7038_l1_unmask(struct irq_data *d) 176 { 177 struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); 178 unsigned long flags; 179 180 raw_spin_lock_irqsave(&intc->lock, flags); 181 __bcm7038_l1_unmask(d, intc->affinity[d->hwirq]); 182 raw_spin_unlock_irqrestore(&intc->lock, flags); 183 } 184 185 static void bcm7038_l1_mask(struct irq_data *d) 186 { 187 struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); 188 unsigned long flags; 189 190 raw_spin_lock_irqsave(&intc->lock, flags); 191 __bcm7038_l1_mask(d, intc->affinity[d->hwirq]); 192 raw_spin_unlock_irqrestore(&intc->lock, flags); 193 } 194 195 static int bcm7038_l1_set_affinity(struct irq_data *d, 196 const struct cpumask *dest, 197 bool force) 198 { 199 struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d); 200 unsigned long flags; 201 irq_hw_number_t hw = d->hwirq; 202 u32 word = hw / IRQS_PER_WORD; 203 u32 mask = BIT(hw % IRQS_PER_WORD); 204 unsigned int first_cpu = cpumask_any_and(dest, cpu_online_mask); 205 bool was_disabled; 206 207 raw_spin_lock_irqsave(&intc->lock, flags); 208 209 was_disabled = !!(intc->cpus[intc->affinity[hw]]->mask_cache[word] & 210 mask); 211 __bcm7038_l1_mask(d, intc->affinity[hw]); 212 intc->affinity[hw] = first_cpu; 213 if (!was_disabled) 214 __bcm7038_l1_unmask(d, first_cpu); 215 216 raw_spin_unlock_irqrestore(&intc->lock, flags); 217 return 0; 218 } 219 220 static int __init bcm7038_l1_init_one(struct device_node *dn, 221 unsigned int idx, 222 struct bcm7038_l1_chip *intc) 223 { 224 struct resource res; 225 resource_size_t sz; 226 struct bcm7038_l1_cpu *cpu; 227 unsigned int i, n_words, parent_irq; 228 229 if (of_address_to_resource(dn, idx, &res)) 230 return -EINVAL; 231 sz = resource_size(&res); 232 n_words = sz / REG_BYTES_PER_IRQ_WORD; 233 234 if (n_words > MAX_WORDS) 235 return -EINVAL; 236 else if (!intc->n_words) 237 intc->n_words = n_words; 238 else if (intc->n_words != n_words) 239 return -EINVAL; 240 241 cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), 242 GFP_KERNEL); 243 if (!cpu) 244 return -ENOMEM; 245 246 cpu->map_base = ioremap(res.start, sz); 247 if (!cpu->map_base) 248 return -ENOMEM; 249 250 for (i = 0; i < n_words; i++) { 251 l1_writel(0xffffffff, cpu->map_base + reg_mask_set(intc, i)); 252 cpu->mask_cache[i] = 0xffffffff; 253 } 254 255 parent_irq = irq_of_parse_and_map(dn, idx); 256 if (!parent_irq) { 257 pr_err("failed to map parent interrupt %d\n", parent_irq); 258 return -EINVAL; 259 } 260 irq_set_handler_data(parent_irq, intc); 261 irq_set_chained_handler(parent_irq, bcm7038_l1_irq_handle); 262 263 return 0; 264 } 265 266 static struct irq_chip bcm7038_l1_irq_chip = { 267 .name = "bcm7038-l1", 268 .irq_mask = bcm7038_l1_mask, 269 .irq_unmask = bcm7038_l1_unmask, 270 .irq_set_affinity = bcm7038_l1_set_affinity, 271 }; 272 273 static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, 274 irq_hw_number_t hw_irq) 275 { 276 irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq); 277 irq_set_chip_data(virq, d->host_data); 278 return 0; 279 } 280 281 static const struct irq_domain_ops bcm7038_l1_domain_ops = { 282 .xlate = irq_domain_xlate_onecell, 283 .map = bcm7038_l1_map, 284 }; 285 286 int __init bcm7038_l1_of_init(struct device_node *dn, 287 struct device_node *parent) 288 { 289 struct bcm7038_l1_chip *intc; 290 int idx, ret; 291 292 intc = kzalloc(sizeof(*intc), GFP_KERNEL); 293 if (!intc) 294 return -ENOMEM; 295 296 raw_spin_lock_init(&intc->lock); 297 for_each_possible_cpu(idx) { 298 ret = bcm7038_l1_init_one(dn, idx, intc); 299 if (ret < 0) { 300 if (idx) 301 break; 302 pr_err("failed to remap intc L1 registers\n"); 303 goto out_free; 304 } 305 } 306 307 intc->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * intc->n_words, 308 &bcm7038_l1_domain_ops, 309 intc); 310 if (!intc->domain) { 311 ret = -ENOMEM; 312 goto out_unmap; 313 } 314 315 pr_info("registered BCM7038 L1 intc (mem: 0x%p, IRQs: %d)\n", 316 intc->cpus[0]->map_base, IRQS_PER_WORD * intc->n_words); 317 318 return 0; 319 320 out_unmap: 321 for_each_possible_cpu(idx) { 322 struct bcm7038_l1_cpu *cpu = intc->cpus[idx]; 323 324 if (cpu) { 325 if (cpu->map_base) 326 iounmap(cpu->map_base); 327 kfree(cpu); 328 } 329 } 330 out_free: 331 kfree(intc); 332 return ret; 333 } 334 335 IRQCHIP_DECLARE(bcm7038_l1, "brcm,bcm7038-l1-intc", bcm7038_l1_of_init); 336