Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Broadcom BCM7038 style Level 1 interrupt controller driver
0004  *
0005  * Copyright (C) 2014 Broadcom Corporation
0006  * Author: Kevin Cernekee
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME  ": " fmt
0010 
0011 #include <linux/bitops.h>
0012 #include <linux/kernel.h>
0013 #include <linux/init.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/io.h>
0016 #include <linux/ioport.h>
0017 #include <linux/irq.h>
0018 #include <linux/irqdomain.h>
0019 #include <linux/module.h>
0020 #include <linux/of.h>
0021 #include <linux/of_irq.h>
0022 #include <linux/of_address.h>
0023 #include <linux/of_platform.h>
0024 #include <linux/platform_device.h>
0025 #include <linux/slab.h>
0026 #include <linux/smp.h>
0027 #include <linux/types.h>
0028 #include <linux/irqchip.h>
0029 #include <linux/irqchip/chained_irq.h>
0030 #include <linux/syscore_ops.h>
0031 
0032 #define IRQS_PER_WORD       32
0033 #define REG_BYTES_PER_IRQ_WORD  (sizeof(u32) * 4)
0034 #define MAX_WORDS       8
0035 
0036 struct bcm7038_l1_cpu;
0037 
0038 struct bcm7038_l1_chip {
0039     raw_spinlock_t      lock;
0040     unsigned int        n_words;
0041     struct irq_domain   *domain;
0042     struct bcm7038_l1_cpu   *cpus[NR_CPUS];
0043 #ifdef CONFIG_PM_SLEEP
0044     struct list_head    list;
0045     u32         wake_mask[MAX_WORDS];
0046 #endif
0047     u32         irq_fwd_mask[MAX_WORDS];
0048     u8          affinity[MAX_WORDS * IRQS_PER_WORD];
0049 };
0050 
0051 struct bcm7038_l1_cpu {
0052     void __iomem        *map_base;
0053     u32         mask_cache[];
0054 };
0055 
0056 /*
0057  * STATUS/MASK_STATUS/MASK_SET/MASK_CLEAR are packed one right after another:
0058  *
0059  * 7038:
0060  *   0x1000_1400: W0_STATUS
0061  *   0x1000_1404: W1_STATUS
0062  *   0x1000_1408: W0_MASK_STATUS
0063  *   0x1000_140c: W1_MASK_STATUS
0064  *   0x1000_1410: W0_MASK_SET
0065  *   0x1000_1414: W1_MASK_SET
0066  *   0x1000_1418: W0_MASK_CLEAR
0067  *   0x1000_141c: W1_MASK_CLEAR
0068  *
0069  * 7445:
0070  *   0xf03e_1500: W0_STATUS
0071  *   0xf03e_1504: W1_STATUS
0072  *   0xf03e_1508: W2_STATUS
0073  *   0xf03e_150c: W3_STATUS
0074  *   0xf03e_1510: W4_STATUS
0075  *   0xf03e_1514: W0_MASK_STATUS
0076  *   0xf03e_1518: W1_MASK_STATUS
0077  *   [...]
0078  */
0079 
0080 static inline unsigned int reg_status(struct bcm7038_l1_chip *intc,
0081                       unsigned int word)
0082 {
0083     return (0 * intc->n_words + word) * sizeof(u32);
0084 }
0085 
0086 static inline unsigned int reg_mask_status(struct bcm7038_l1_chip *intc,
0087                        unsigned int word)
0088 {
0089     return (1 * intc->n_words + word) * sizeof(u32);
0090 }
0091 
0092 static inline unsigned int reg_mask_set(struct bcm7038_l1_chip *intc,
0093                     unsigned int word)
0094 {
0095     return (2 * intc->n_words + word) * sizeof(u32);
0096 }
0097 
0098 static inline unsigned int reg_mask_clr(struct bcm7038_l1_chip *intc,
0099                     unsigned int word)
0100 {
0101     return (3 * intc->n_words + word) * sizeof(u32);
0102 }
0103 
0104 static inline u32 l1_readl(void __iomem *reg)
0105 {
0106     if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
0107         return ioread32be(reg);
0108     else
0109         return readl(reg);
0110 }
0111 
0112 static inline void l1_writel(u32 val, void __iomem *reg)
0113 {
0114     if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
0115         iowrite32be(val, reg);
0116     else
0117         writel(val, reg);
0118 }
0119 
0120 static void bcm7038_l1_irq_handle(struct irq_desc *desc)
0121 {
0122     struct bcm7038_l1_chip *intc = irq_desc_get_handler_data(desc);
0123     struct bcm7038_l1_cpu *cpu;
0124     struct irq_chip *chip = irq_desc_get_chip(desc);
0125     unsigned int idx;
0126 
0127 #if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
0128     cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
0129 #else
0130     cpu = intc->cpus[0];
0131 #endif
0132 
0133     chained_irq_enter(chip, desc);
0134 
0135     for (idx = 0; idx < intc->n_words; idx++) {
0136         int base = idx * IRQS_PER_WORD;
0137         unsigned long pending, flags;
0138         int hwirq;
0139 
0140         raw_spin_lock_irqsave(&intc->lock, flags);
0141         pending = l1_readl(cpu->map_base + reg_status(intc, idx)) &
0142               ~cpu->mask_cache[idx];
0143         raw_spin_unlock_irqrestore(&intc->lock, flags);
0144 
0145         for_each_set_bit(hwirq, &pending, IRQS_PER_WORD)
0146             generic_handle_domain_irq(intc->domain, base + hwirq);
0147     }
0148 
0149     chained_irq_exit(chip, desc);
0150 }
0151 
0152 static void __bcm7038_l1_unmask(struct irq_data *d, unsigned int cpu_idx)
0153 {
0154     struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
0155     u32 word = d->hwirq / IRQS_PER_WORD;
0156     u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
0157 
0158     intc->cpus[cpu_idx]->mask_cache[word] &= ~mask;
0159     l1_writel(mask, intc->cpus[cpu_idx]->map_base +
0160             reg_mask_clr(intc, word));
0161 }
0162 
0163 static void __bcm7038_l1_mask(struct irq_data *d, unsigned int cpu_idx)
0164 {
0165     struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
0166     u32 word = d->hwirq / IRQS_PER_WORD;
0167     u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
0168 
0169     intc->cpus[cpu_idx]->mask_cache[word] |= mask;
0170     l1_writel(mask, intc->cpus[cpu_idx]->map_base +
0171             reg_mask_set(intc, word));
0172 }
0173 
0174 static void bcm7038_l1_unmask(struct irq_data *d)
0175 {
0176     struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
0177     unsigned long flags;
0178 
0179     raw_spin_lock_irqsave(&intc->lock, flags);
0180     __bcm7038_l1_unmask(d, intc->affinity[d->hwirq]);
0181     raw_spin_unlock_irqrestore(&intc->lock, flags);
0182 }
0183 
0184 static void bcm7038_l1_mask(struct irq_data *d)
0185 {
0186     struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
0187     unsigned long flags;
0188 
0189     raw_spin_lock_irqsave(&intc->lock, flags);
0190     __bcm7038_l1_mask(d, intc->affinity[d->hwirq]);
0191     raw_spin_unlock_irqrestore(&intc->lock, flags);
0192 }
0193 
0194 #if defined(CONFIG_MIPS) && defined(CONFIG_SMP)
0195 static int bcm7038_l1_set_affinity(struct irq_data *d,
0196                    const struct cpumask *dest,
0197                    bool force)
0198 {
0199     struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
0200     unsigned long flags;
0201     irq_hw_number_t hw = d->hwirq;
0202     u32 word = hw / IRQS_PER_WORD;
0203     u32 mask = BIT(hw % IRQS_PER_WORD);
0204     unsigned int first_cpu = cpumask_any_and(dest, cpu_online_mask);
0205     bool was_disabled;
0206 
0207     raw_spin_lock_irqsave(&intc->lock, flags);
0208 
0209     was_disabled = !!(intc->cpus[intc->affinity[hw]]->mask_cache[word] &
0210               mask);
0211     __bcm7038_l1_mask(d, intc->affinity[hw]);
0212     intc->affinity[hw] = first_cpu;
0213     if (!was_disabled)
0214         __bcm7038_l1_unmask(d, first_cpu);
0215 
0216     raw_spin_unlock_irqrestore(&intc->lock, flags);
0217     irq_data_update_effective_affinity(d, cpumask_of(first_cpu));
0218 
0219     return 0;
0220 }
0221 #endif
0222 
0223 static int __init bcm7038_l1_init_one(struct device_node *dn,
0224                       unsigned int idx,
0225                       struct bcm7038_l1_chip *intc)
0226 {
0227     struct resource res;
0228     resource_size_t sz;
0229     struct bcm7038_l1_cpu *cpu;
0230     unsigned int i, n_words, parent_irq;
0231     int ret;
0232 
0233     if (of_address_to_resource(dn, idx, &res))
0234         return -EINVAL;
0235     sz = resource_size(&res);
0236     n_words = sz / REG_BYTES_PER_IRQ_WORD;
0237 
0238     if (n_words > MAX_WORDS)
0239         return -EINVAL;
0240     else if (!intc->n_words)
0241         intc->n_words = n_words;
0242     else if (intc->n_words != n_words)
0243         return -EINVAL;
0244 
0245     ret = of_property_read_u32_array(dn , "brcm,int-fwd-mask",
0246                      intc->irq_fwd_mask, n_words);
0247     if (ret != 0 && ret != -EINVAL) {
0248         /* property exists but has the wrong number of words */
0249         pr_err("invalid brcm,int-fwd-mask property\n");
0250         return -EINVAL;
0251     }
0252 
0253     cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32),
0254                     GFP_KERNEL);
0255     if (!cpu)
0256         return -ENOMEM;
0257 
0258     cpu->map_base = ioremap(res.start, sz);
0259     if (!cpu->map_base)
0260         return -ENOMEM;
0261 
0262     for (i = 0; i < n_words; i++) {
0263         l1_writel(~intc->irq_fwd_mask[i],
0264               cpu->map_base + reg_mask_set(intc, i));
0265         l1_writel(intc->irq_fwd_mask[i],
0266               cpu->map_base + reg_mask_clr(intc, i));
0267         cpu->mask_cache[i] = ~intc->irq_fwd_mask[i];
0268     }
0269 
0270     parent_irq = irq_of_parse_and_map(dn, idx);
0271     if (!parent_irq) {
0272         pr_err("failed to map parent interrupt %d\n", parent_irq);
0273         return -EINVAL;
0274     }
0275 
0276     if (of_property_read_bool(dn, "brcm,irq-can-wake"))
0277         enable_irq_wake(parent_irq);
0278 
0279     irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle,
0280                      intc);
0281 
0282     return 0;
0283 }
0284 
0285 #ifdef CONFIG_PM_SLEEP
0286 /*
0287  * We keep a list of bcm7038_l1_chip used for suspend/resume. This hack is
0288  * used because the struct chip_type suspend/resume hooks are not called
0289  * unless chip_type is hooked onto a generic_chip. Since this driver does
0290  * not use generic_chip, we need to manually hook our resume/suspend to
0291  * syscore_ops.
0292  */
0293 static LIST_HEAD(bcm7038_l1_intcs_list);
0294 static DEFINE_RAW_SPINLOCK(bcm7038_l1_intcs_lock);
0295 
0296 static int bcm7038_l1_suspend(void)
0297 {
0298     struct bcm7038_l1_chip *intc;
0299     int boot_cpu, word;
0300     u32 val;
0301 
0302     /* Wakeup interrupt should only come from the boot cpu */
0303 #if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
0304     boot_cpu = cpu_logical_map(0);
0305 #else
0306     boot_cpu = 0;
0307 #endif
0308 
0309     list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
0310         for (word = 0; word < intc->n_words; word++) {
0311             val = intc->wake_mask[word] | intc->irq_fwd_mask[word];
0312             l1_writel(~val,
0313                 intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
0314             l1_writel(val,
0315                 intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
0316         }
0317     }
0318 
0319     return 0;
0320 }
0321 
0322 static void bcm7038_l1_resume(void)
0323 {
0324     struct bcm7038_l1_chip *intc;
0325     int boot_cpu, word;
0326 
0327 #if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
0328     boot_cpu = cpu_logical_map(0);
0329 #else
0330     boot_cpu = 0;
0331 #endif
0332 
0333     list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
0334         for (word = 0; word < intc->n_words; word++) {
0335             l1_writel(intc->cpus[boot_cpu]->mask_cache[word],
0336                 intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
0337             l1_writel(~intc->cpus[boot_cpu]->mask_cache[word],
0338                 intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
0339         }
0340     }
0341 }
0342 
0343 static struct syscore_ops bcm7038_l1_syscore_ops = {
0344     .suspend    = bcm7038_l1_suspend,
0345     .resume     = bcm7038_l1_resume,
0346 };
0347 
0348 static int bcm7038_l1_set_wake(struct irq_data *d, unsigned int on)
0349 {
0350     struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
0351     unsigned long flags;
0352     u32 word = d->hwirq / IRQS_PER_WORD;
0353     u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
0354 
0355     raw_spin_lock_irqsave(&intc->lock, flags);
0356     if (on)
0357         intc->wake_mask[word] |= mask;
0358     else
0359         intc->wake_mask[word] &= ~mask;
0360     raw_spin_unlock_irqrestore(&intc->lock, flags);
0361 
0362     return 0;
0363 }
0364 #endif
0365 
0366 static struct irq_chip bcm7038_l1_irq_chip = {
0367     .name           = "bcm7038-l1",
0368     .irq_mask       = bcm7038_l1_mask,
0369     .irq_unmask     = bcm7038_l1_unmask,
0370 #if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
0371     .irq_set_affinity   = bcm7038_l1_set_affinity,
0372 #endif
0373 #ifdef CONFIG_PM_SLEEP
0374     .irq_set_wake       = bcm7038_l1_set_wake,
0375 #endif
0376 };
0377 
0378 static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq,
0379               irq_hw_number_t hw_irq)
0380 {
0381     struct bcm7038_l1_chip *intc = d->host_data;
0382     u32 mask = BIT(hw_irq % IRQS_PER_WORD);
0383     u32 word = hw_irq / IRQS_PER_WORD;
0384 
0385     if (intc->irq_fwd_mask[word] & mask)
0386         return -EPERM;
0387 
0388     irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq);
0389     irq_set_chip_data(virq, d->host_data);
0390     irqd_set_single_target(irq_get_irq_data(virq));
0391     return 0;
0392 }
0393 
0394 static const struct irq_domain_ops bcm7038_l1_domain_ops = {
0395     .xlate          = irq_domain_xlate_onecell,
0396     .map            = bcm7038_l1_map,
0397 };
0398 
0399 static int __init bcm7038_l1_of_init(struct device_node *dn,
0400                   struct device_node *parent)
0401 {
0402     struct bcm7038_l1_chip *intc;
0403     int idx, ret;
0404 
0405     intc = kzalloc(sizeof(*intc), GFP_KERNEL);
0406     if (!intc)
0407         return -ENOMEM;
0408 
0409     raw_spin_lock_init(&intc->lock);
0410     for_each_possible_cpu(idx) {
0411         ret = bcm7038_l1_init_one(dn, idx, intc);
0412         if (ret < 0) {
0413             if (idx)
0414                 break;
0415             pr_err("failed to remap intc L1 registers\n");
0416             goto out_free;
0417         }
0418     }
0419 
0420     intc->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * intc->n_words,
0421                          &bcm7038_l1_domain_ops,
0422                          intc);
0423     if (!intc->domain) {
0424         ret = -ENOMEM;
0425         goto out_unmap;
0426     }
0427 
0428 #ifdef CONFIG_PM_SLEEP
0429     /* Add bcm7038_l1_chip into a list */
0430     raw_spin_lock(&bcm7038_l1_intcs_lock);
0431     list_add_tail(&intc->list, &bcm7038_l1_intcs_list);
0432     raw_spin_unlock(&bcm7038_l1_intcs_lock);
0433 
0434     if (list_is_singular(&bcm7038_l1_intcs_list))
0435         register_syscore_ops(&bcm7038_l1_syscore_ops);
0436 #endif
0437 
0438     pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
0439         dn, IRQS_PER_WORD * intc->n_words);
0440 
0441     return 0;
0442 
0443 out_unmap:
0444     for_each_possible_cpu(idx) {
0445         struct bcm7038_l1_cpu *cpu = intc->cpus[idx];
0446 
0447         if (cpu) {
0448             if (cpu->map_base)
0449                 iounmap(cpu->map_base);
0450             kfree(cpu);
0451         }
0452     }
0453 out_free:
0454     kfree(intc);
0455     return ret;
0456 }
0457 
0458 IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7038_l1)
0459 IRQCHIP_MATCH("brcm,bcm7038-l1-intc", bcm7038_l1_of_init)
0460 IRQCHIP_PLATFORM_DRIVER_END(bcm7038_l1)
0461 MODULE_DESCRIPTION("Broadcom STB 7038-style L1/L2 interrupt controller");
0462 MODULE_LICENSE("GPL v2");