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