Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Generic Broadcom Set Top Box Level 2 Interrupt controller driver
0004  *
0005  * Copyright (C) 2014-2017 Broadcom
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME  ": " fmt
0009 
0010 #include <linux/init.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/of.h>
0016 #include <linux/of_irq.h>
0017 #include <linux/of_address.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/irq.h>
0021 #include <linux/io.h>
0022 #include <linux/irqdomain.h>
0023 #include <linux/irqchip.h>
0024 #include <linux/irqchip/chained_irq.h>
0025 
0026 struct brcmstb_intc_init_params {
0027     irq_flow_handler_t handler;
0028     int cpu_status;
0029     int cpu_clear;
0030     int cpu_mask_status;
0031     int cpu_mask_set;
0032     int cpu_mask_clear;
0033 };
0034 
0035 /* Register offsets in the L2 latched interrupt controller */
0036 static const struct brcmstb_intc_init_params l2_edge_intc_init = {
0037     .handler        = handle_edge_irq,
0038     .cpu_status     = 0x00,
0039     .cpu_clear      = 0x08,
0040     .cpu_mask_status    = 0x0c,
0041     .cpu_mask_set       = 0x10,
0042     .cpu_mask_clear     = 0x14
0043 };
0044 
0045 /* Register offsets in the L2 level interrupt controller */
0046 static const struct brcmstb_intc_init_params l2_lvl_intc_init = {
0047     .handler        = handle_level_irq,
0048     .cpu_status     = 0x00,
0049     .cpu_clear      = -1, /* Register not present */
0050     .cpu_mask_status    = 0x04,
0051     .cpu_mask_set       = 0x08,
0052     .cpu_mask_clear     = 0x0C
0053 };
0054 
0055 /* L2 intc private data structure */
0056 struct brcmstb_l2_intc_data {
0057     struct irq_domain *domain;
0058     struct irq_chip_generic *gc;
0059     int status_offset;
0060     int mask_offset;
0061     bool can_wake;
0062     u32 saved_mask; /* for suspend/resume */
0063 };
0064 
0065 /**
0066  * brcmstb_l2_mask_and_ack - Mask and ack pending interrupt
0067  * @d: irq_data
0068  *
0069  * Chip has separate enable/disable registers instead of a single mask
0070  * register and pending interrupt is acknowledged by setting a bit.
0071  *
0072  * Note: This function is generic and could easily be added to the
0073  * generic irqchip implementation if there ever becomes a will to do so.
0074  * Perhaps with a name like irq_gc_mask_disable_and_ack_set().
0075  *
0076  * e.g.: https://patchwork.kernel.org/patch/9831047/
0077  */
0078 static void brcmstb_l2_mask_and_ack(struct irq_data *d)
0079 {
0080     struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
0081     struct irq_chip_type *ct = irq_data_get_chip_type(d);
0082     u32 mask = d->mask;
0083 
0084     irq_gc_lock(gc);
0085     irq_reg_writel(gc, mask, ct->regs.disable);
0086     *ct->mask_cache &= ~mask;
0087     irq_reg_writel(gc, mask, ct->regs.ack);
0088     irq_gc_unlock(gc);
0089 }
0090 
0091 static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc)
0092 {
0093     struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc);
0094     struct irq_chip *chip = irq_desc_get_chip(desc);
0095     unsigned int irq;
0096     u32 status;
0097 
0098     chained_irq_enter(chip, desc);
0099 
0100     status = irq_reg_readl(b->gc, b->status_offset) &
0101         ~(irq_reg_readl(b->gc, b->mask_offset));
0102 
0103     if (status == 0) {
0104         raw_spin_lock(&desc->lock);
0105         handle_bad_irq(desc);
0106         raw_spin_unlock(&desc->lock);
0107         goto out;
0108     }
0109 
0110     do {
0111         irq = ffs(status) - 1;
0112         status &= ~(1 << irq);
0113         generic_handle_domain_irq(b->domain, irq);
0114     } while (status);
0115 out:
0116     chained_irq_exit(chip, desc);
0117 }
0118 
0119 static void brcmstb_l2_intc_suspend(struct irq_data *d)
0120 {
0121     struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
0122     struct irq_chip_type *ct = irq_data_get_chip_type(d);
0123     struct brcmstb_l2_intc_data *b = gc->private;
0124     unsigned long flags;
0125 
0126     irq_gc_lock_irqsave(gc, flags);
0127     /* Save the current mask */
0128     b->saved_mask = irq_reg_readl(gc, ct->regs.mask);
0129 
0130     if (b->can_wake) {
0131         /* Program the wakeup mask */
0132         irq_reg_writel(gc, ~gc->wake_active, ct->regs.disable);
0133         irq_reg_writel(gc, gc->wake_active, ct->regs.enable);
0134     }
0135     irq_gc_unlock_irqrestore(gc, flags);
0136 }
0137 
0138 static void brcmstb_l2_intc_resume(struct irq_data *d)
0139 {
0140     struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
0141     struct irq_chip_type *ct = irq_data_get_chip_type(d);
0142     struct brcmstb_l2_intc_data *b = gc->private;
0143     unsigned long flags;
0144 
0145     irq_gc_lock_irqsave(gc, flags);
0146     if (ct->chip.irq_ack) {
0147         /* Clear unmasked non-wakeup interrupts */
0148         irq_reg_writel(gc, ~b->saved_mask & ~gc->wake_active,
0149                 ct->regs.ack);
0150     }
0151 
0152     /* Restore the saved mask */
0153     irq_reg_writel(gc, b->saved_mask, ct->regs.disable);
0154     irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable);
0155     irq_gc_unlock_irqrestore(gc, flags);
0156 }
0157 
0158 static int __init brcmstb_l2_intc_of_init(struct device_node *np,
0159                       struct device_node *parent,
0160                       const struct brcmstb_intc_init_params
0161                       *init_params)
0162 {
0163     unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
0164     struct brcmstb_l2_intc_data *data;
0165     struct irq_chip_type *ct;
0166     int ret;
0167     unsigned int flags;
0168     int parent_irq;
0169     void __iomem *base;
0170 
0171     data = kzalloc(sizeof(*data), GFP_KERNEL);
0172     if (!data)
0173         return -ENOMEM;
0174 
0175     base = of_iomap(np, 0);
0176     if (!base) {
0177         pr_err("failed to remap intc L2 registers\n");
0178         ret = -ENOMEM;
0179         goto out_free;
0180     }
0181 
0182     /* Disable all interrupts by default */
0183     writel(0xffffffff, base + init_params->cpu_mask_set);
0184 
0185     /* Wakeup interrupts may be retained from S5 (cold boot) */
0186     data->can_wake = of_property_read_bool(np, "brcm,irq-can-wake");
0187     if (!data->can_wake && (init_params->cpu_clear >= 0))
0188         writel(0xffffffff, base + init_params->cpu_clear);
0189 
0190     parent_irq = irq_of_parse_and_map(np, 0);
0191     if (!parent_irq) {
0192         pr_err("failed to find parent interrupt\n");
0193         ret = -EINVAL;
0194         goto out_unmap;
0195     }
0196 
0197     data->domain = irq_domain_add_linear(np, 32,
0198                 &irq_generic_chip_ops, NULL);
0199     if (!data->domain) {
0200         ret = -ENOMEM;
0201         goto out_unmap;
0202     }
0203 
0204     /* MIPS chips strapped for BE will automagically configure the
0205      * peripheral registers for CPU-native byte order.
0206      */
0207     flags = 0;
0208     if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
0209         flags |= IRQ_GC_BE_IO;
0210 
0211     /* Allocate a single Generic IRQ chip for this node */
0212     ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
0213             np->full_name, init_params->handler, clr, 0, flags);
0214     if (ret) {
0215         pr_err("failed to allocate generic irq chip\n");
0216         goto out_free_domain;
0217     }
0218 
0219     /* Set the IRQ chaining logic */
0220     irq_set_chained_handler_and_data(parent_irq,
0221                      brcmstb_l2_intc_irq_handle, data);
0222 
0223     data->gc = irq_get_domain_generic_chip(data->domain, 0);
0224     data->gc->reg_base = base;
0225     data->gc->private = data;
0226     data->status_offset = init_params->cpu_status;
0227     data->mask_offset = init_params->cpu_mask_status;
0228 
0229     ct = data->gc->chip_types;
0230 
0231     if (init_params->cpu_clear >= 0) {
0232         ct->regs.ack = init_params->cpu_clear;
0233         ct->chip.irq_ack = irq_gc_ack_set_bit;
0234         ct->chip.irq_mask_ack = brcmstb_l2_mask_and_ack;
0235     } else {
0236         /* No Ack - but still slightly more efficient to define this */
0237         ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
0238     }
0239 
0240     ct->chip.irq_mask = irq_gc_mask_disable_reg;
0241     ct->regs.disable = init_params->cpu_mask_set;
0242     ct->regs.mask = init_params->cpu_mask_status;
0243 
0244     ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
0245     ct->regs.enable = init_params->cpu_mask_clear;
0246 
0247     ct->chip.irq_suspend = brcmstb_l2_intc_suspend;
0248     ct->chip.irq_resume = brcmstb_l2_intc_resume;
0249     ct->chip.irq_pm_shutdown = brcmstb_l2_intc_suspend;
0250 
0251     if (data->can_wake) {
0252         /* This IRQ chip can wake the system, set all child interrupts
0253          * in wake_enabled mask
0254          */
0255         data->gc->wake_enabled = 0xffffffff;
0256         ct->chip.irq_set_wake = irq_gc_set_wake;
0257         enable_irq_wake(parent_irq);
0258     }
0259 
0260     pr_info("registered L2 intc (%pOF, parent irq: %d)\n", np, parent_irq);
0261 
0262     return 0;
0263 
0264 out_free_domain:
0265     irq_domain_remove(data->domain);
0266 out_unmap:
0267     iounmap(base);
0268 out_free:
0269     kfree(data);
0270     return ret;
0271 }
0272 
0273 static int __init brcmstb_l2_edge_intc_of_init(struct device_node *np,
0274     struct device_node *parent)
0275 {
0276     return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init);
0277 }
0278 
0279 static int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np,
0280     struct device_node *parent)
0281 {
0282     return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init);
0283 }
0284 
0285 IRQCHIP_PLATFORM_DRIVER_BEGIN(brcmstb_l2)
0286 IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init)
0287 IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init)
0288 IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init)
0289 IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init)
0290 IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2)
0291 MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller");
0292 MODULE_LICENSE("GPL v2");