Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * The R_INTC in Allwinner A31 and newer SoCs manages several types of
0004  * interrupts, as shown below:
0005  *
0006  *             NMI IRQ                DIRECT IRQs           MUXED IRQs
0007  *              bit 0                  bits 1-15^           bits 19-31
0008  *
0009  *   +---------+                      +---------+    +---------+  +---------+
0010  *   | NMI Pad |                      |  IRQ d  |    |  IRQ m  |  | IRQ m+7 |
0011  *   +---------+                      +---------+    +---------+  +---------+
0012  *        |                             |     |         |    |      |    |
0013  *        |                             |     |         |    |......|    |
0014  * +------V------+ +------------+       |     |         | +--V------V--+ |
0015  * |   Invert/   | | Write 1 to |       |     |         | |  AND with  | |
0016  * | Edge Detect | | PENDING[0] |       |     |         | |  MUX[m/8]  | |
0017  * +-------------+ +------------+       |     |         | +------------+ |
0018  *            |       |                 |     |         |       |        |
0019  *         +--V-------V--+           +--V--+  |      +--V--+    |     +--V--+
0020  *         | Set    Reset|           | GIC |  |      | GIC |    |     | GIC |
0021  *         |    Latch    |           | SPI |  |      | SPI |... |  ...| SPI |
0022  *         +-------------+           | N+d |  |      |  m  |    |     | m+7 |
0023  *             |     |               +-----+  |      +-----+    |     +-----+
0024  *             |     |                        |                 |
0025  *     +-------V-+ +-V----------+   +---------V--+     +--------V--------+
0026  *     | GIC SPI | |  AND with  |   |  AND with  |     |    AND with     |
0027  *     | N (=32) | |  ENABLE[0] |   |  ENABLE[d] |     |  ENABLE[19+m/8] |
0028  *     +---------+ +------------+   +------------+     +-----------------+
0029  *                        |                |                    |
0030  *                 +------V-----+   +------V-----+     +--------V--------+
0031  *                 |    Read    |   |    Read    |     |     Read        |
0032  *                 | PENDING[0] |   | PENDING[d] |     | PENDING[19+m/8] |
0033  *                 +------------+   +------------+     +-----------------+
0034  *
0035  * ^ bits 16-18 are direct IRQs for peripherals with banked interrupts, such as
0036  *   the MSGBOX. These IRQs do not map to any GIC SPI.
0037  *
0038  * The H6 variant adds two more (banked) direct IRQs and implements the full
0039  * set of 128 mux bits. This requires a second set of top-level registers.
0040  */
0041 
0042 #include <linux/bitmap.h>
0043 #include <linux/interrupt.h>
0044 #include <linux/irq.h>
0045 #include <linux/irqchip.h>
0046 #include <linux/irqdomain.h>
0047 #include <linux/of.h>
0048 #include <linux/of_address.h>
0049 #include <linux/of_irq.h>
0050 #include <linux/syscore_ops.h>
0051 
0052 #include <dt-bindings/interrupt-controller/arm-gic.h>
0053 
0054 #define SUN6I_NMI_CTRL          (0x0c)
0055 #define SUN6I_IRQ_PENDING(n)        (0x10 + 4 * (n))
0056 #define SUN6I_IRQ_ENABLE(n)     (0x40 + 4 * (n))
0057 #define SUN6I_MUX_ENABLE(n)     (0xc0 + 4 * (n))
0058 
0059 #define SUN6I_NMI_SRC_TYPE_LEVEL_LOW    0
0060 #define SUN6I_NMI_SRC_TYPE_EDGE_FALLING 1
0061 #define SUN6I_NMI_SRC_TYPE_LEVEL_HIGH   2
0062 #define SUN6I_NMI_SRC_TYPE_EDGE_RISING  3
0063 
0064 #define SUN6I_NMI_BIT           BIT(0)
0065 
0066 #define SUN6I_NMI_NEEDS_ACK     ((void *)1)
0067 
0068 #define SUN6I_NR_TOP_LEVEL_IRQS     64
0069 #define SUN6I_NR_DIRECT_IRQS        16
0070 #define SUN6I_NR_MUX_BITS       128
0071 
0072 struct sun6i_r_intc_variant {
0073     u32     first_mux_irq;
0074     u32     nr_mux_irqs;
0075     u32     mux_valid[BITS_TO_U32(SUN6I_NR_MUX_BITS)];
0076 };
0077 
0078 static void __iomem *base;
0079 static irq_hw_number_t nmi_hwirq;
0080 static DECLARE_BITMAP(wake_irq_enabled, SUN6I_NR_TOP_LEVEL_IRQS);
0081 static DECLARE_BITMAP(wake_mux_enabled, SUN6I_NR_MUX_BITS);
0082 static DECLARE_BITMAP(wake_mux_valid, SUN6I_NR_MUX_BITS);
0083 
0084 static void sun6i_r_intc_ack_nmi(void)
0085 {
0086     writel_relaxed(SUN6I_NMI_BIT, base + SUN6I_IRQ_PENDING(0));
0087 }
0088 
0089 static void sun6i_r_intc_nmi_ack(struct irq_data *data)
0090 {
0091     if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH)
0092         sun6i_r_intc_ack_nmi();
0093     else
0094         data->chip_data = SUN6I_NMI_NEEDS_ACK;
0095 }
0096 
0097 static void sun6i_r_intc_nmi_eoi(struct irq_data *data)
0098 {
0099     /* For oneshot IRQs, delay the ack until the IRQ is unmasked. */
0100     if (data->chip_data == SUN6I_NMI_NEEDS_ACK && !irqd_irq_masked(data)) {
0101         data->chip_data = NULL;
0102         sun6i_r_intc_ack_nmi();
0103     }
0104 
0105     irq_chip_eoi_parent(data);
0106 }
0107 
0108 static void sun6i_r_intc_nmi_unmask(struct irq_data *data)
0109 {
0110     if (data->chip_data == SUN6I_NMI_NEEDS_ACK) {
0111         data->chip_data = NULL;
0112         sun6i_r_intc_ack_nmi();
0113     }
0114 
0115     irq_chip_unmask_parent(data);
0116 }
0117 
0118 static int sun6i_r_intc_nmi_set_type(struct irq_data *data, unsigned int type)
0119 {
0120     u32 nmi_src_type;
0121 
0122     switch (type) {
0123     case IRQ_TYPE_EDGE_RISING:
0124         nmi_src_type = SUN6I_NMI_SRC_TYPE_EDGE_RISING;
0125         break;
0126     case IRQ_TYPE_EDGE_FALLING:
0127         nmi_src_type = SUN6I_NMI_SRC_TYPE_EDGE_FALLING;
0128         break;
0129     case IRQ_TYPE_LEVEL_HIGH:
0130         nmi_src_type = SUN6I_NMI_SRC_TYPE_LEVEL_HIGH;
0131         break;
0132     case IRQ_TYPE_LEVEL_LOW:
0133         nmi_src_type = SUN6I_NMI_SRC_TYPE_LEVEL_LOW;
0134         break;
0135     default:
0136         return -EINVAL;
0137     }
0138 
0139     writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
0140 
0141     /*
0142      * The "External NMI" GIC input connects to a latch inside R_INTC, not
0143      * directly to the pin. So the GIC trigger type does not depend on the
0144      * NMI pin trigger type.
0145      */
0146     return irq_chip_set_type_parent(data, IRQ_TYPE_LEVEL_HIGH);
0147 }
0148 
0149 static int sun6i_r_intc_nmi_set_irqchip_state(struct irq_data *data,
0150                           enum irqchip_irq_state which,
0151                           bool state)
0152 {
0153     if (which == IRQCHIP_STATE_PENDING && !state)
0154         sun6i_r_intc_ack_nmi();
0155 
0156     return irq_chip_set_parent_state(data, which, state);
0157 }
0158 
0159 static int sun6i_r_intc_irq_set_wake(struct irq_data *data, unsigned int on)
0160 {
0161     unsigned long offset_from_nmi = data->hwirq - nmi_hwirq;
0162 
0163     if (offset_from_nmi < SUN6I_NR_DIRECT_IRQS)
0164         assign_bit(offset_from_nmi, wake_irq_enabled, on);
0165     else if (test_bit(data->hwirq, wake_mux_valid))
0166         assign_bit(data->hwirq, wake_mux_enabled, on);
0167     else
0168         /* Not wakeup capable. */
0169         return -EPERM;
0170 
0171     return 0;
0172 }
0173 
0174 static struct irq_chip sun6i_r_intc_nmi_chip = {
0175     .name           = "sun6i-r-intc",
0176     .irq_ack        = sun6i_r_intc_nmi_ack,
0177     .irq_mask       = irq_chip_mask_parent,
0178     .irq_unmask     = sun6i_r_intc_nmi_unmask,
0179     .irq_eoi        = sun6i_r_intc_nmi_eoi,
0180     .irq_set_affinity   = irq_chip_set_affinity_parent,
0181     .irq_set_type       = sun6i_r_intc_nmi_set_type,
0182     .irq_set_irqchip_state  = sun6i_r_intc_nmi_set_irqchip_state,
0183     .irq_set_wake       = sun6i_r_intc_irq_set_wake,
0184     .flags          = IRQCHIP_SET_TYPE_MASKED,
0185 };
0186 
0187 static struct irq_chip sun6i_r_intc_wakeup_chip = {
0188     .name           = "sun6i-r-intc",
0189     .irq_mask       = irq_chip_mask_parent,
0190     .irq_unmask     = irq_chip_unmask_parent,
0191     .irq_eoi        = irq_chip_eoi_parent,
0192     .irq_set_affinity   = irq_chip_set_affinity_parent,
0193     .irq_set_type       = irq_chip_set_type_parent,
0194     .irq_set_wake       = sun6i_r_intc_irq_set_wake,
0195     .flags          = IRQCHIP_SET_TYPE_MASKED,
0196 };
0197 
0198 static int sun6i_r_intc_domain_translate(struct irq_domain *domain,
0199                      struct irq_fwspec *fwspec,
0200                      unsigned long *hwirq,
0201                      unsigned int *type)
0202 {
0203     /* Accept the old two-cell binding for the NMI only. */
0204     if (fwspec->param_count == 2 && fwspec->param[0] == 0) {
0205         *hwirq = nmi_hwirq;
0206         *type  = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
0207         return 0;
0208     }
0209 
0210     /* Otherwise this binding should match the GIC SPI binding. */
0211     if (fwspec->param_count < 3)
0212         return -EINVAL;
0213     if (fwspec->param[0] != GIC_SPI)
0214         return -EINVAL;
0215 
0216     *hwirq = fwspec->param[1];
0217     *type  = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
0218 
0219     return 0;
0220 }
0221 
0222 static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
0223                      unsigned int virq,
0224                      unsigned int nr_irqs, void *arg)
0225 {
0226     struct irq_fwspec *fwspec = arg;
0227     struct irq_fwspec gic_fwspec;
0228     unsigned long hwirq;
0229     unsigned int type;
0230     int i, ret;
0231 
0232     ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
0233     if (ret)
0234         return ret;
0235     if (hwirq + nr_irqs > SUN6I_NR_MUX_BITS)
0236         return -EINVAL;
0237 
0238     /* Construct a GIC-compatible fwspec from this fwspec. */
0239     gic_fwspec = (struct irq_fwspec) {
0240         .fwnode      = domain->parent->fwnode,
0241         .param_count = 3,
0242         .param       = { GIC_SPI, hwirq, type },
0243     };
0244 
0245     ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
0246     if (ret)
0247         return ret;
0248 
0249     for (i = 0; i < nr_irqs; ++i, ++hwirq, ++virq) {
0250         if (hwirq == nmi_hwirq) {
0251             irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
0252                               &sun6i_r_intc_nmi_chip,
0253                               NULL);
0254             irq_set_handler(virq, handle_fasteoi_ack_irq);
0255         } else {
0256             irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
0257                               &sun6i_r_intc_wakeup_chip,
0258                               NULL);
0259         }
0260     }
0261 
0262     return 0;
0263 }
0264 
0265 static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
0266     .translate  = sun6i_r_intc_domain_translate,
0267     .alloc      = sun6i_r_intc_domain_alloc,
0268     .free       = irq_domain_free_irqs_common,
0269 };
0270 
0271 static int sun6i_r_intc_suspend(void)
0272 {
0273     u32 buf[BITS_TO_U32(max(SUN6I_NR_TOP_LEVEL_IRQS, SUN6I_NR_MUX_BITS))];
0274     int i;
0275 
0276     /* Wake IRQs are enabled during system sleep and shutdown. */
0277     bitmap_to_arr32(buf, wake_irq_enabled, SUN6I_NR_TOP_LEVEL_IRQS);
0278     for (i = 0; i < BITS_TO_U32(SUN6I_NR_TOP_LEVEL_IRQS); ++i)
0279         writel_relaxed(buf[i], base + SUN6I_IRQ_ENABLE(i));
0280     bitmap_to_arr32(buf, wake_mux_enabled, SUN6I_NR_MUX_BITS);
0281     for (i = 0; i < BITS_TO_U32(SUN6I_NR_MUX_BITS); ++i)
0282         writel_relaxed(buf[i], base + SUN6I_MUX_ENABLE(i));
0283 
0284     return 0;
0285 }
0286 
0287 static void sun6i_r_intc_resume(void)
0288 {
0289     int i;
0290 
0291     /* Only the NMI is relevant during normal operation. */
0292     writel_relaxed(SUN6I_NMI_BIT, base + SUN6I_IRQ_ENABLE(0));
0293     for (i = 1; i < BITS_TO_U32(SUN6I_NR_TOP_LEVEL_IRQS); ++i)
0294         writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
0295 }
0296 
0297 static void sun6i_r_intc_shutdown(void)
0298 {
0299     sun6i_r_intc_suspend();
0300 }
0301 
0302 static struct syscore_ops sun6i_r_intc_syscore_ops = {
0303     .suspend    = sun6i_r_intc_suspend,
0304     .resume     = sun6i_r_intc_resume,
0305     .shutdown   = sun6i_r_intc_shutdown,
0306 };
0307 
0308 static int __init sun6i_r_intc_init(struct device_node *node,
0309                     struct device_node *parent,
0310                     const struct sun6i_r_intc_variant *v)
0311 {
0312     struct irq_domain *domain, *parent_domain;
0313     struct of_phandle_args nmi_parent;
0314     int ret;
0315 
0316     /* Extract the NMI hwirq number from the OF node. */
0317     ret = of_irq_parse_one(node, 0, &nmi_parent);
0318     if (ret)
0319         return ret;
0320     if (nmi_parent.args_count < 3 ||
0321         nmi_parent.args[0] != GIC_SPI ||
0322         nmi_parent.args[2] != IRQ_TYPE_LEVEL_HIGH)
0323         return -EINVAL;
0324     nmi_hwirq = nmi_parent.args[1];
0325 
0326     bitmap_set(wake_irq_enabled, v->first_mux_irq, v->nr_mux_irqs);
0327     bitmap_from_arr32(wake_mux_valid, v->mux_valid, SUN6I_NR_MUX_BITS);
0328 
0329     parent_domain = irq_find_host(parent);
0330     if (!parent_domain) {
0331         pr_err("%pOF: Failed to obtain parent domain\n", node);
0332         return -ENXIO;
0333     }
0334 
0335     base = of_io_request_and_map(node, 0, NULL);
0336     if (IS_ERR(base)) {
0337         pr_err("%pOF: Failed to map MMIO region\n", node);
0338         return PTR_ERR(base);
0339     }
0340 
0341     domain = irq_domain_add_hierarchy(parent_domain, 0, 0, node,
0342                       &sun6i_r_intc_domain_ops, NULL);
0343     if (!domain) {
0344         pr_err("%pOF: Failed to allocate domain\n", node);
0345         iounmap(base);
0346         return -ENOMEM;
0347     }
0348 
0349     register_syscore_ops(&sun6i_r_intc_syscore_ops);
0350 
0351     sun6i_r_intc_ack_nmi();
0352     sun6i_r_intc_resume();
0353 
0354     return 0;
0355 }
0356 
0357 static const struct sun6i_r_intc_variant sun6i_a31_r_intc_variant __initconst = {
0358     .first_mux_irq  = 19,
0359     .nr_mux_irqs    = 13,
0360     .mux_valid  = { 0xffffffff, 0xfff80000, 0xffffffff, 0x0000000f },
0361 };
0362 
0363 static int __init sun6i_a31_r_intc_init(struct device_node *node,
0364                     struct device_node *parent)
0365 {
0366     return sun6i_r_intc_init(node, parent, &sun6i_a31_r_intc_variant);
0367 }
0368 IRQCHIP_DECLARE(sun6i_a31_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_a31_r_intc_init);
0369 
0370 static const struct sun6i_r_intc_variant sun50i_h6_r_intc_variant __initconst = {
0371     .first_mux_irq  = 21,
0372     .nr_mux_irqs    = 16,
0373     .mux_valid  = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
0374 };
0375 
0376 static int __init sun50i_h6_r_intc_init(struct device_node *node,
0377                     struct device_node *parent)
0378 {
0379     return sun6i_r_intc_init(node, parent, &sun50i_h6_r_intc_variant);
0380 }
0381 IRQCHIP_DECLARE(sun50i_h6_r_intc, "allwinner,sun50i-h6-r-intc", sun50i_h6_r_intc_init);