0001
0002
0003
0004
0005
0006
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
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
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
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
0288
0289
0290
0291
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
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
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");