1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c7c42ec2SSimon Arlott /* 3c7c42ec2SSimon Arlott * Broadcom BCM6345 style Level 1 interrupt controller driver 4c7c42ec2SSimon Arlott * 5c7c42ec2SSimon Arlott * Copyright (C) 2014 Broadcom Corporation 6c7c42ec2SSimon Arlott * Copyright 2015 Simon Arlott 7c7c42ec2SSimon Arlott * 8c7c42ec2SSimon Arlott * This is based on the BCM7038 (which supports SMP) but with a single 9c7c42ec2SSimon Arlott * enable register instead of separate mask/set/clear registers. 10c7c42ec2SSimon Arlott * 11c7c42ec2SSimon Arlott * The BCM3380 has a similar mask/status register layout, but each pair 12c7c42ec2SSimon Arlott * of words is at separate locations (and SMP is not supported). 13c7c42ec2SSimon Arlott * 14c7c42ec2SSimon Arlott * ENABLE/STATUS words are packed next to each other for each CPU: 15c7c42ec2SSimon Arlott * 16c7c42ec2SSimon Arlott * BCM6368: 17c7c42ec2SSimon Arlott * 0x1000_0020: CPU0_W0_ENABLE 18c7c42ec2SSimon Arlott * 0x1000_0024: CPU0_W1_ENABLE 19c7c42ec2SSimon Arlott * 0x1000_0028: CPU0_W0_STATUS IRQs 31-63 20c7c42ec2SSimon Arlott * 0x1000_002c: CPU0_W1_STATUS IRQs 0-31 21c7c42ec2SSimon Arlott * 0x1000_0030: CPU1_W0_ENABLE 22c7c42ec2SSimon Arlott * 0x1000_0034: CPU1_W1_ENABLE 23c7c42ec2SSimon Arlott * 0x1000_0038: CPU1_W0_STATUS IRQs 31-63 24c7c42ec2SSimon Arlott * 0x1000_003c: CPU1_W1_STATUS IRQs 0-31 25c7c42ec2SSimon Arlott * 26c7c42ec2SSimon Arlott * BCM63168: 27c7c42ec2SSimon Arlott * 0x1000_0020: CPU0_W0_ENABLE 28c7c42ec2SSimon Arlott * 0x1000_0024: CPU0_W1_ENABLE 29c7c42ec2SSimon Arlott * 0x1000_0028: CPU0_W2_ENABLE 30c7c42ec2SSimon Arlott * 0x1000_002c: CPU0_W3_ENABLE 31c7c42ec2SSimon Arlott * 0x1000_0030: CPU0_W0_STATUS IRQs 96-127 32c7c42ec2SSimon Arlott * 0x1000_0034: CPU0_W1_STATUS IRQs 64-95 33c7c42ec2SSimon Arlott * 0x1000_0038: CPU0_W2_STATUS IRQs 32-63 34c7c42ec2SSimon Arlott * 0x1000_003c: CPU0_W3_STATUS IRQs 0-31 35c7c42ec2SSimon Arlott * 0x1000_0040: CPU1_W0_ENABLE 36c7c42ec2SSimon Arlott * 0x1000_0044: CPU1_W1_ENABLE 37c7c42ec2SSimon Arlott * 0x1000_0048: CPU1_W2_ENABLE 38c7c42ec2SSimon Arlott * 0x1000_004c: CPU1_W3_ENABLE 39c7c42ec2SSimon Arlott * 0x1000_0050: CPU1_W0_STATUS IRQs 96-127 40c7c42ec2SSimon Arlott * 0x1000_0054: CPU1_W1_STATUS IRQs 64-95 41c7c42ec2SSimon Arlott * 0x1000_0058: CPU1_W2_STATUS IRQs 32-63 42c7c42ec2SSimon Arlott * 0x1000_005c: CPU1_W3_STATUS IRQs 0-31 43c7c42ec2SSimon Arlott * 44c7c42ec2SSimon Arlott * IRQs are numbered in CPU native endian order 45c7c42ec2SSimon Arlott * (which is big-endian in these examples) 46c7c42ec2SSimon Arlott */ 47c7c42ec2SSimon Arlott 48c7c42ec2SSimon Arlott #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 49c7c42ec2SSimon Arlott 50c7c42ec2SSimon Arlott #include <linux/bitops.h> 51c7c42ec2SSimon Arlott #include <linux/cpumask.h> 52c7c42ec2SSimon Arlott #include <linux/kernel.h> 53c7c42ec2SSimon Arlott #include <linux/init.h> 54c7c42ec2SSimon Arlott #include <linux/interrupt.h> 55c7c42ec2SSimon Arlott #include <linux/io.h> 56c7c42ec2SSimon Arlott #include <linux/ioport.h> 57c7c42ec2SSimon Arlott #include <linux/irq.h> 58c7c42ec2SSimon Arlott #include <linux/irqdomain.h> 59c7c42ec2SSimon Arlott #include <linux/module.h> 60c7c42ec2SSimon Arlott #include <linux/of.h> 61c7c42ec2SSimon Arlott #include <linux/of_irq.h> 62c7c42ec2SSimon Arlott #include <linux/of_address.h> 63c7c42ec2SSimon Arlott #include <linux/of_platform.h> 64c7c42ec2SSimon Arlott #include <linux/platform_device.h> 65c7c42ec2SSimon Arlott #include <linux/slab.h> 66c7c42ec2SSimon Arlott #include <linux/smp.h> 67c7c42ec2SSimon Arlott #include <linux/types.h> 68c7c42ec2SSimon Arlott #include <linux/irqchip.h> 69c7c42ec2SSimon Arlott #include <linux/irqchip/chained_irq.h> 70c7c42ec2SSimon Arlott 71c7c42ec2SSimon Arlott #define IRQS_PER_WORD 32 72c7c42ec2SSimon Arlott #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 2) 73c7c42ec2SSimon Arlott 74c7c42ec2SSimon Arlott struct bcm6345_l1_cpu; 75c7c42ec2SSimon Arlott 76c7c42ec2SSimon Arlott struct bcm6345_l1_chip { 77c7c42ec2SSimon Arlott raw_spinlock_t lock; 78c7c42ec2SSimon Arlott unsigned int n_words; 79c7c42ec2SSimon Arlott struct irq_domain *domain; 80c7c42ec2SSimon Arlott struct cpumask cpumask; 81c7c42ec2SSimon Arlott struct bcm6345_l1_cpu *cpus[NR_CPUS]; 82c7c42ec2SSimon Arlott }; 83c7c42ec2SSimon Arlott 84c7c42ec2SSimon Arlott struct bcm6345_l1_cpu { 85c7c42ec2SSimon Arlott void __iomem *map_base; 86c7c42ec2SSimon Arlott unsigned int parent_irq; 87c7c42ec2SSimon Arlott u32 enable_cache[]; 88c7c42ec2SSimon Arlott }; 89c7c42ec2SSimon Arlott 90c7c42ec2SSimon Arlott static inline unsigned int reg_enable(struct bcm6345_l1_chip *intc, 91c7c42ec2SSimon Arlott unsigned int word) 92c7c42ec2SSimon Arlott { 93c7c42ec2SSimon Arlott #ifdef __BIG_ENDIAN 94c7c42ec2SSimon Arlott return (1 * intc->n_words - word - 1) * sizeof(u32); 95c7c42ec2SSimon Arlott #else 96c7c42ec2SSimon Arlott return (0 * intc->n_words + word) * sizeof(u32); 97c7c42ec2SSimon Arlott #endif 98c7c42ec2SSimon Arlott } 99c7c42ec2SSimon Arlott 100c7c42ec2SSimon Arlott static inline unsigned int reg_status(struct bcm6345_l1_chip *intc, 101c7c42ec2SSimon Arlott unsigned int word) 102c7c42ec2SSimon Arlott { 103c7c42ec2SSimon Arlott #ifdef __BIG_ENDIAN 104c7c42ec2SSimon Arlott return (2 * intc->n_words - word - 1) * sizeof(u32); 105c7c42ec2SSimon Arlott #else 106c7c42ec2SSimon Arlott return (1 * intc->n_words + word) * sizeof(u32); 107c7c42ec2SSimon Arlott #endif 108c7c42ec2SSimon Arlott } 109c7c42ec2SSimon Arlott 110c7c42ec2SSimon Arlott static inline unsigned int cpu_for_irq(struct bcm6345_l1_chip *intc, 111c7c42ec2SSimon Arlott struct irq_data *d) 112c7c42ec2SSimon Arlott { 113c7c42ec2SSimon Arlott return cpumask_first_and(&intc->cpumask, irq_data_get_affinity_mask(d)); 114c7c42ec2SSimon Arlott } 115c7c42ec2SSimon Arlott 116c7c42ec2SSimon Arlott static void bcm6345_l1_irq_handle(struct irq_desc *desc) 117c7c42ec2SSimon Arlott { 118c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc = irq_desc_get_handler_data(desc); 119c7c42ec2SSimon Arlott struct bcm6345_l1_cpu *cpu; 120c7c42ec2SSimon Arlott struct irq_chip *chip = irq_desc_get_chip(desc); 121c7c42ec2SSimon Arlott unsigned int idx; 122c7c42ec2SSimon Arlott 123c7c42ec2SSimon Arlott #ifdef CONFIG_SMP 124c7c42ec2SSimon Arlott cpu = intc->cpus[cpu_logical_map(smp_processor_id())]; 125c7c42ec2SSimon Arlott #else 126c7c42ec2SSimon Arlott cpu = intc->cpus[0]; 127c7c42ec2SSimon Arlott #endif 128c7c42ec2SSimon Arlott 129c7c42ec2SSimon Arlott chained_irq_enter(chip, desc); 130c7c42ec2SSimon Arlott 131c7c42ec2SSimon Arlott for (idx = 0; idx < intc->n_words; idx++) { 132c7c42ec2SSimon Arlott int base = idx * IRQS_PER_WORD; 133c7c42ec2SSimon Arlott unsigned long pending; 134c7c42ec2SSimon Arlott irq_hw_number_t hwirq; 135c7c42ec2SSimon Arlott unsigned int irq; 136c7c42ec2SSimon Arlott 137c7c42ec2SSimon Arlott pending = __raw_readl(cpu->map_base + reg_status(intc, idx)); 138c7c42ec2SSimon Arlott pending &= __raw_readl(cpu->map_base + reg_enable(intc, idx)); 139c7c42ec2SSimon Arlott 140c7c42ec2SSimon Arlott for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { 141c7c42ec2SSimon Arlott irq = irq_linear_revmap(intc->domain, base + hwirq); 142c7c42ec2SSimon Arlott if (irq) 143c7c42ec2SSimon Arlott do_IRQ(irq); 144c7c42ec2SSimon Arlott else 145c7c42ec2SSimon Arlott spurious_interrupt(); 146c7c42ec2SSimon Arlott } 147c7c42ec2SSimon Arlott } 148c7c42ec2SSimon Arlott 149c7c42ec2SSimon Arlott chained_irq_exit(chip, desc); 150c7c42ec2SSimon Arlott } 151c7c42ec2SSimon Arlott 152c7c42ec2SSimon Arlott static inline void __bcm6345_l1_unmask(struct irq_data *d) 153c7c42ec2SSimon Arlott { 154c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d); 155c7c42ec2SSimon Arlott u32 word = d->hwirq / IRQS_PER_WORD; 156c7c42ec2SSimon Arlott u32 mask = BIT(d->hwirq % IRQS_PER_WORD); 157c7c42ec2SSimon Arlott unsigned int cpu_idx = cpu_for_irq(intc, d); 158c7c42ec2SSimon Arlott 159c7c42ec2SSimon Arlott intc->cpus[cpu_idx]->enable_cache[word] |= mask; 160c7c42ec2SSimon Arlott __raw_writel(intc->cpus[cpu_idx]->enable_cache[word], 161c7c42ec2SSimon Arlott intc->cpus[cpu_idx]->map_base + reg_enable(intc, word)); 162c7c42ec2SSimon Arlott } 163c7c42ec2SSimon Arlott 164c7c42ec2SSimon Arlott static inline void __bcm6345_l1_mask(struct irq_data *d) 165c7c42ec2SSimon Arlott { 166c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d); 167c7c42ec2SSimon Arlott u32 word = d->hwirq / IRQS_PER_WORD; 168c7c42ec2SSimon Arlott u32 mask = BIT(d->hwirq % IRQS_PER_WORD); 169c7c42ec2SSimon Arlott unsigned int cpu_idx = cpu_for_irq(intc, d); 170c7c42ec2SSimon Arlott 171c7c42ec2SSimon Arlott intc->cpus[cpu_idx]->enable_cache[word] &= ~mask; 172c7c42ec2SSimon Arlott __raw_writel(intc->cpus[cpu_idx]->enable_cache[word], 173c7c42ec2SSimon Arlott intc->cpus[cpu_idx]->map_base + reg_enable(intc, word)); 174c7c42ec2SSimon Arlott } 175c7c42ec2SSimon Arlott 176c7c42ec2SSimon Arlott static void bcm6345_l1_unmask(struct irq_data *d) 177c7c42ec2SSimon Arlott { 178c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d); 179c7c42ec2SSimon Arlott unsigned long flags; 180c7c42ec2SSimon Arlott 181c7c42ec2SSimon Arlott raw_spin_lock_irqsave(&intc->lock, flags); 182c7c42ec2SSimon Arlott __bcm6345_l1_unmask(d); 183c7c42ec2SSimon Arlott raw_spin_unlock_irqrestore(&intc->lock, flags); 184c7c42ec2SSimon Arlott } 185c7c42ec2SSimon Arlott 186c7c42ec2SSimon Arlott static void bcm6345_l1_mask(struct irq_data *d) 187c7c42ec2SSimon Arlott { 188c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d); 189c7c42ec2SSimon Arlott unsigned long flags; 190c7c42ec2SSimon Arlott 191c7c42ec2SSimon Arlott raw_spin_lock_irqsave(&intc->lock, flags); 192c7c42ec2SSimon Arlott __bcm6345_l1_mask(d); 193c7c42ec2SSimon Arlott raw_spin_unlock_irqrestore(&intc->lock, flags); 194c7c42ec2SSimon Arlott } 195c7c42ec2SSimon Arlott 196c7c42ec2SSimon Arlott static int bcm6345_l1_set_affinity(struct irq_data *d, 197c7c42ec2SSimon Arlott const struct cpumask *dest, 198c7c42ec2SSimon Arlott bool force) 199c7c42ec2SSimon Arlott { 200c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc = irq_data_get_irq_chip_data(d); 201c7c42ec2SSimon Arlott u32 word = d->hwirq / IRQS_PER_WORD; 202c7c42ec2SSimon Arlott u32 mask = BIT(d->hwirq % IRQS_PER_WORD); 203c7c42ec2SSimon Arlott unsigned int old_cpu = cpu_for_irq(intc, d); 204c7c42ec2SSimon Arlott unsigned int new_cpu; 205c7c42ec2SSimon Arlott struct cpumask valid; 206c7c42ec2SSimon Arlott unsigned long flags; 207c7c42ec2SSimon Arlott bool enabled; 208c7c42ec2SSimon Arlott 209c7c42ec2SSimon Arlott if (!cpumask_and(&valid, &intc->cpumask, dest)) 210c7c42ec2SSimon Arlott return -EINVAL; 211c7c42ec2SSimon Arlott 212c7c42ec2SSimon Arlott new_cpu = cpumask_any_and(&valid, cpu_online_mask); 213c7c42ec2SSimon Arlott if (new_cpu >= nr_cpu_ids) 214c7c42ec2SSimon Arlott return -EINVAL; 215c7c42ec2SSimon Arlott 216c7c42ec2SSimon Arlott dest = cpumask_of(new_cpu); 217c7c42ec2SSimon Arlott 218c7c42ec2SSimon Arlott raw_spin_lock_irqsave(&intc->lock, flags); 219c7c42ec2SSimon Arlott if (old_cpu != new_cpu) { 220c7c42ec2SSimon Arlott enabled = intc->cpus[old_cpu]->enable_cache[word] & mask; 221c7c42ec2SSimon Arlott if (enabled) 222c7c42ec2SSimon Arlott __bcm6345_l1_mask(d); 223c7c42ec2SSimon Arlott cpumask_copy(irq_data_get_affinity_mask(d), dest); 224c7c42ec2SSimon Arlott if (enabled) 225c7c42ec2SSimon Arlott __bcm6345_l1_unmask(d); 226c7c42ec2SSimon Arlott } else { 227c7c42ec2SSimon Arlott cpumask_copy(irq_data_get_affinity_mask(d), dest); 228c7c42ec2SSimon Arlott } 229c7c42ec2SSimon Arlott raw_spin_unlock_irqrestore(&intc->lock, flags); 230c7c42ec2SSimon Arlott 231d0ed5e8eSMarc Zyngier irq_data_update_effective_affinity(d, cpumask_of(new_cpu)); 232d0ed5e8eSMarc Zyngier 233c7c42ec2SSimon Arlott return IRQ_SET_MASK_OK_NOCOPY; 234c7c42ec2SSimon Arlott } 235c7c42ec2SSimon Arlott 236c7c42ec2SSimon Arlott static int __init bcm6345_l1_init_one(struct device_node *dn, 237c7c42ec2SSimon Arlott unsigned int idx, 238c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc) 239c7c42ec2SSimon Arlott { 240c7c42ec2SSimon Arlott struct resource res; 241c7c42ec2SSimon Arlott resource_size_t sz; 242c7c42ec2SSimon Arlott struct bcm6345_l1_cpu *cpu; 243c7c42ec2SSimon Arlott unsigned int i, n_words; 244c7c42ec2SSimon Arlott 245c7c42ec2SSimon Arlott if (of_address_to_resource(dn, idx, &res)) 246c7c42ec2SSimon Arlott return -EINVAL; 247c7c42ec2SSimon Arlott sz = resource_size(&res); 248c7c42ec2SSimon Arlott n_words = sz / REG_BYTES_PER_IRQ_WORD; 249c7c42ec2SSimon Arlott 250c7c42ec2SSimon Arlott if (!intc->n_words) 251c7c42ec2SSimon Arlott intc->n_words = n_words; 252c7c42ec2SSimon Arlott else if (intc->n_words != n_words) 253c7c42ec2SSimon Arlott return -EINVAL; 254c7c42ec2SSimon Arlott 255c7c42ec2SSimon Arlott cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), 256c7c42ec2SSimon Arlott GFP_KERNEL); 257c7c42ec2SSimon Arlott if (!cpu) 258c7c42ec2SSimon Arlott return -ENOMEM; 259c7c42ec2SSimon Arlott 260c7c42ec2SSimon Arlott cpu->map_base = ioremap(res.start, sz); 261c7c42ec2SSimon Arlott if (!cpu->map_base) 262c7c42ec2SSimon Arlott return -ENOMEM; 263c7c42ec2SSimon Arlott 264c7c42ec2SSimon Arlott for (i = 0; i < n_words; i++) { 265c7c42ec2SSimon Arlott cpu->enable_cache[i] = 0; 266c7c42ec2SSimon Arlott __raw_writel(0, cpu->map_base + reg_enable(intc, i)); 267c7c42ec2SSimon Arlott } 268c7c42ec2SSimon Arlott 269c7c42ec2SSimon Arlott cpu->parent_irq = irq_of_parse_and_map(dn, idx); 270c7c42ec2SSimon Arlott if (!cpu->parent_irq) { 271c7c42ec2SSimon Arlott pr_err("failed to map parent interrupt %d\n", cpu->parent_irq); 272c7c42ec2SSimon Arlott return -EINVAL; 273c7c42ec2SSimon Arlott } 274c7c42ec2SSimon Arlott irq_set_chained_handler_and_data(cpu->parent_irq, 275c7c42ec2SSimon Arlott bcm6345_l1_irq_handle, intc); 276c7c42ec2SSimon Arlott 277c7c42ec2SSimon Arlott return 0; 278c7c42ec2SSimon Arlott } 279c7c42ec2SSimon Arlott 280c7c42ec2SSimon Arlott static struct irq_chip bcm6345_l1_irq_chip = { 281c7c42ec2SSimon Arlott .name = "bcm6345-l1", 282c7c42ec2SSimon Arlott .irq_mask = bcm6345_l1_mask, 283c7c42ec2SSimon Arlott .irq_unmask = bcm6345_l1_unmask, 284c7c42ec2SSimon Arlott .irq_set_affinity = bcm6345_l1_set_affinity, 285c7c42ec2SSimon Arlott }; 286c7c42ec2SSimon Arlott 287c7c42ec2SSimon Arlott static int bcm6345_l1_map(struct irq_domain *d, unsigned int virq, 288c7c42ec2SSimon Arlott irq_hw_number_t hw_irq) 289c7c42ec2SSimon Arlott { 290c7c42ec2SSimon Arlott irq_set_chip_and_handler(virq, 291c7c42ec2SSimon Arlott &bcm6345_l1_irq_chip, handle_percpu_irq); 292c7c42ec2SSimon Arlott irq_set_chip_data(virq, d->host_data); 293d0ed5e8eSMarc Zyngier irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq))); 294c7c42ec2SSimon Arlott return 0; 295c7c42ec2SSimon Arlott } 296c7c42ec2SSimon Arlott 297c7c42ec2SSimon Arlott static const struct irq_domain_ops bcm6345_l1_domain_ops = { 298c7c42ec2SSimon Arlott .xlate = irq_domain_xlate_onecell, 299c7c42ec2SSimon Arlott .map = bcm6345_l1_map, 300c7c42ec2SSimon Arlott }; 301c7c42ec2SSimon Arlott 302c7c42ec2SSimon Arlott static int __init bcm6345_l1_of_init(struct device_node *dn, 303c7c42ec2SSimon Arlott struct device_node *parent) 304c7c42ec2SSimon Arlott { 305c7c42ec2SSimon Arlott struct bcm6345_l1_chip *intc; 306c7c42ec2SSimon Arlott unsigned int idx; 307c7c42ec2SSimon Arlott int ret; 308c7c42ec2SSimon Arlott 309c7c42ec2SSimon Arlott intc = kzalloc(sizeof(*intc), GFP_KERNEL); 310c7c42ec2SSimon Arlott if (!intc) 311c7c42ec2SSimon Arlott return -ENOMEM; 312c7c42ec2SSimon Arlott 313c7c42ec2SSimon Arlott for_each_possible_cpu(idx) { 314c7c42ec2SSimon Arlott ret = bcm6345_l1_init_one(dn, idx, intc); 315c7c42ec2SSimon Arlott if (ret) 316c7c42ec2SSimon Arlott pr_err("failed to init intc L1 for cpu %d: %d\n", 317c7c42ec2SSimon Arlott idx, ret); 318c7c42ec2SSimon Arlott else 319c7c42ec2SSimon Arlott cpumask_set_cpu(idx, &intc->cpumask); 320c7c42ec2SSimon Arlott } 321c7c42ec2SSimon Arlott 322c7c42ec2SSimon Arlott if (!cpumask_weight(&intc->cpumask)) { 323c7c42ec2SSimon Arlott ret = -ENODEV; 324c7c42ec2SSimon Arlott goto out_free; 325c7c42ec2SSimon Arlott } 326c7c42ec2SSimon Arlott 327c7c42ec2SSimon Arlott raw_spin_lock_init(&intc->lock); 328c7c42ec2SSimon Arlott 329c7c42ec2SSimon Arlott intc->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * intc->n_words, 330c7c42ec2SSimon Arlott &bcm6345_l1_domain_ops, 331c7c42ec2SSimon Arlott intc); 332c7c42ec2SSimon Arlott if (!intc->domain) { 333c7c42ec2SSimon Arlott ret = -ENOMEM; 334c7c42ec2SSimon Arlott goto out_unmap; 335c7c42ec2SSimon Arlott } 336c7c42ec2SSimon Arlott 337c7c42ec2SSimon Arlott pr_info("registered BCM6345 L1 intc (IRQs: %d)\n", 338c7c42ec2SSimon Arlott IRQS_PER_WORD * intc->n_words); 339c7c42ec2SSimon Arlott for_each_cpu(idx, &intc->cpumask) { 340c7c42ec2SSimon Arlott struct bcm6345_l1_cpu *cpu = intc->cpus[idx]; 341c7c42ec2SSimon Arlott 342c7c42ec2SSimon Arlott pr_info(" CPU%u at MMIO 0x%p (irq = %d)\n", idx, 343c7c42ec2SSimon Arlott cpu->map_base, cpu->parent_irq); 344c7c42ec2SSimon Arlott } 345c7c42ec2SSimon Arlott 346c7c42ec2SSimon Arlott return 0; 347c7c42ec2SSimon Arlott 348c7c42ec2SSimon Arlott out_unmap: 349c7c42ec2SSimon Arlott for_each_possible_cpu(idx) { 350c7c42ec2SSimon Arlott struct bcm6345_l1_cpu *cpu = intc->cpus[idx]; 351c7c42ec2SSimon Arlott 352c7c42ec2SSimon Arlott if (cpu) { 353c7c42ec2SSimon Arlott if (cpu->map_base) 354c7c42ec2SSimon Arlott iounmap(cpu->map_base); 355c7c42ec2SSimon Arlott kfree(cpu); 356c7c42ec2SSimon Arlott } 357c7c42ec2SSimon Arlott } 358c7c42ec2SSimon Arlott out_free: 359c7c42ec2SSimon Arlott kfree(intc); 360c7c42ec2SSimon Arlott return ret; 361c7c42ec2SSimon Arlott } 362c7c42ec2SSimon Arlott 363c7c42ec2SSimon Arlott IRQCHIP_DECLARE(bcm6345_l1, "brcm,bcm6345-l1-intc", bcm6345_l1_of_init); 364