Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
0002 /*
0003  * Microsemi Ocelot IRQ controller driver
0004  *
0005  * Copyright (c) 2017 Microsemi Corporation
0006  */
0007 #include <linux/bitops.h>
0008 #include <linux/irq.h>
0009 #include <linux/of_address.h>
0010 #include <linux/of_irq.h>
0011 #include <linux/irqchip.h>
0012 #include <linux/irqchip/chained_irq.h>
0013 #include <linux/interrupt.h>
0014 
0015 #define ICPU_CFG_INTR_DST_INTR_IDENT(_p, x) ((_p)->reg_off_ident + 0x4 * (x))
0016 #define ICPU_CFG_INTR_INTR_TRIGGER(_p, x)   ((_p)->reg_off_trigger + 0x4 * (x))
0017 
0018 #define FLAGS_HAS_TRIGGER   BIT(0)
0019 #define FLAGS_NEED_INIT_ENABLE  BIT(1)
0020 
0021 struct chip_props {
0022     u8 flags;
0023     u8 reg_off_sticky;
0024     u8 reg_off_ena;
0025     u8 reg_off_ena_clr;
0026     u8 reg_off_ena_set;
0027     u8 reg_off_ident;
0028     u8 reg_off_trigger;
0029     u8 reg_off_ena_irq0;
0030     u8 n_irq;
0031 };
0032 
0033 static struct chip_props ocelot_props = {
0034     .flags          = FLAGS_HAS_TRIGGER,
0035     .reg_off_sticky     = 0x10,
0036     .reg_off_ena        = 0x18,
0037     .reg_off_ena_clr    = 0x1c,
0038     .reg_off_ena_set    = 0x20,
0039     .reg_off_ident      = 0x38,
0040     .reg_off_trigger    = 0x5c,
0041     .n_irq          = 24,
0042 };
0043 
0044 static struct chip_props serval_props = {
0045     .flags          = FLAGS_HAS_TRIGGER,
0046     .reg_off_sticky     = 0xc,
0047     .reg_off_ena        = 0x14,
0048     .reg_off_ena_clr    = 0x18,
0049     .reg_off_ena_set    = 0x1c,
0050     .reg_off_ident      = 0x20,
0051     .reg_off_trigger    = 0x4,
0052     .n_irq          = 24,
0053 };
0054 
0055 static struct chip_props luton_props = {
0056     .flags          = FLAGS_NEED_INIT_ENABLE,
0057     .reg_off_sticky     = 0,
0058     .reg_off_ena        = 0x4,
0059     .reg_off_ena_clr    = 0x8,
0060     .reg_off_ena_set    = 0xc,
0061     .reg_off_ident      = 0x18,
0062     .reg_off_ena_irq0   = 0x14,
0063     .n_irq          = 28,
0064 };
0065 
0066 static struct chip_props jaguar2_props = {
0067     .flags          = FLAGS_HAS_TRIGGER,
0068     .reg_off_sticky     = 0x10,
0069     .reg_off_ena        = 0x18,
0070     .reg_off_ena_clr    = 0x1c,
0071     .reg_off_ena_set    = 0x20,
0072     .reg_off_ident      = 0x38,
0073     .reg_off_trigger    = 0x5c,
0074     .n_irq          = 29,
0075 };
0076 
0077 static void ocelot_irq_unmask(struct irq_data *data)
0078 {
0079     struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
0080     struct irq_domain *d = data->domain;
0081     struct chip_props *p = d->host_data;
0082     struct irq_chip_type *ct = irq_data_get_chip_type(data);
0083     unsigned int mask = data->mask;
0084     u32 val;
0085 
0086     irq_gc_lock(gc);
0087     val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 0)) |
0088         irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 1));
0089     if (!(val & mask))
0090         irq_reg_writel(gc, mask, p->reg_off_sticky);
0091 
0092     *ct->mask_cache &= ~mask;
0093     irq_reg_writel(gc, mask, p->reg_off_ena_set);
0094     irq_gc_unlock(gc);
0095 }
0096 
0097 static void ocelot_irq_handler(struct irq_desc *desc)
0098 {
0099     struct irq_chip *chip = irq_desc_get_chip(desc);
0100     struct irq_domain *d = irq_desc_get_handler_data(desc);
0101     struct chip_props *p = d->host_data;
0102     struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
0103     u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(p, 0));
0104 
0105     chained_irq_enter(chip, desc);
0106 
0107     while (reg) {
0108         u32 hwirq = __fls(reg);
0109 
0110         generic_handle_domain_irq(d, hwirq);
0111         reg &= ~(BIT(hwirq));
0112     }
0113 
0114     chained_irq_exit(chip, desc);
0115 }
0116 
0117 static int __init vcoreiii_irq_init(struct device_node *node,
0118                     struct device_node *parent,
0119                     struct chip_props *p)
0120 {
0121     struct irq_domain *domain;
0122     struct irq_chip_generic *gc;
0123     int parent_irq, ret;
0124 
0125     parent_irq = irq_of_parse_and_map(node, 0);
0126     if (!parent_irq)
0127         return -EINVAL;
0128 
0129     domain = irq_domain_add_linear(node, p->n_irq,
0130                        &irq_generic_chip_ops, NULL);
0131     if (!domain) {
0132         pr_err("%pOFn: unable to add irq domain\n", node);
0133         return -ENOMEM;
0134     }
0135 
0136     ret = irq_alloc_domain_generic_chips(domain, p->n_irq, 1,
0137                          "icpu", handle_level_irq,
0138                          0, 0, 0);
0139     if (ret) {
0140         pr_err("%pOFn: unable to alloc irq domain gc\n", node);
0141         goto err_domain_remove;
0142     }
0143 
0144     gc = irq_get_domain_generic_chip(domain, 0);
0145     gc->reg_base = of_iomap(node, 0);
0146     if (!gc->reg_base) {
0147         pr_err("%pOFn: unable to map resource\n", node);
0148         ret = -ENOMEM;
0149         goto err_gc_free;
0150     }
0151 
0152     gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
0153     gc->chip_types[0].regs.ack = p->reg_off_sticky;
0154     if (p->flags & FLAGS_HAS_TRIGGER) {
0155         gc->chip_types[0].regs.mask = p->reg_off_ena_clr;
0156         gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask;
0157         gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
0158     } else {
0159         gc->chip_types[0].regs.enable = p->reg_off_ena_set;
0160         gc->chip_types[0].regs.disable = p->reg_off_ena_clr;
0161         gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
0162         gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
0163     }
0164 
0165     /* Mask and ack all interrupts */
0166     irq_reg_writel(gc, 0, p->reg_off_ena);
0167     irq_reg_writel(gc, 0xffffffff, p->reg_off_sticky);
0168 
0169     /* Overall init */
0170     if (p->flags & FLAGS_NEED_INIT_ENABLE)
0171         irq_reg_writel(gc, BIT(0), p->reg_off_ena_irq0);
0172 
0173     domain->host_data = p;
0174     irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler,
0175                      domain);
0176 
0177     return 0;
0178 
0179 err_gc_free:
0180     irq_free_generic_chip(gc);
0181 
0182 err_domain_remove:
0183     irq_domain_remove(domain);
0184 
0185     return ret;
0186 }
0187 
0188 static int __init ocelot_irq_init(struct device_node *node,
0189                   struct device_node *parent)
0190 {
0191     return vcoreiii_irq_init(node, parent, &ocelot_props);
0192 }
0193 
0194 IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init);
0195 
0196 static int __init serval_irq_init(struct device_node *node,
0197                   struct device_node *parent)
0198 {
0199     return vcoreiii_irq_init(node, parent, &serval_props);
0200 }
0201 
0202 IRQCHIP_DECLARE(serval_icpu, "mscc,serval-icpu-intr", serval_irq_init);
0203 
0204 static int __init luton_irq_init(struct device_node *node,
0205                  struct device_node *parent)
0206 {
0207     return vcoreiii_irq_init(node, parent, &luton_props);
0208 }
0209 
0210 IRQCHIP_DECLARE(luton_icpu, "mscc,luton-icpu-intr", luton_irq_init);
0211 
0212 static int __init jaguar2_irq_init(struct device_node *node,
0213                    struct device_node *parent)
0214 {
0215     return vcoreiii_irq_init(node, parent, &jaguar2_props);
0216 }
0217 
0218 IRQCHIP_DECLARE(jaguar2_icpu, "mscc,jaguar2-icpu-intr", jaguar2_irq_init);