Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
0004  *  Loongson HTPIC IRQ support
0005  */
0006 
0007 #include <linux/init.h>
0008 #include <linux/of_address.h>
0009 #include <linux/of_irq.h>
0010 #include <linux/irqchip.h>
0011 #include <linux/irqchip/chained_irq.h>
0012 #include <linux/irq.h>
0013 #include <linux/io.h>
0014 #include <linux/syscore_ops.h>
0015 
0016 #include <asm/i8259.h>
0017 
0018 #define HTPIC_MAX_PARENT_IRQ    4
0019 #define HTINT_NUM_VECTORS   8
0020 #define HTINT_EN_OFF        0x20
0021 
0022 struct loongson_htpic {
0023     void __iomem *base;
0024     struct irq_domain *domain;
0025 };
0026 
0027 static struct loongson_htpic *htpic;
0028 
0029 static void htpic_irq_dispatch(struct irq_desc *desc)
0030 {
0031     struct loongson_htpic *priv = irq_desc_get_handler_data(desc);
0032     struct irq_chip *chip = irq_desc_get_chip(desc);
0033     uint32_t pending;
0034 
0035     chained_irq_enter(chip, desc);
0036     pending = readl(priv->base);
0037     /* Ack all IRQs at once, otherwise IRQ flood might happen */
0038     writel(pending, priv->base);
0039 
0040     if (!pending)
0041         spurious_interrupt();
0042 
0043     while (pending) {
0044         int bit = __ffs(pending);
0045 
0046         if (unlikely(bit > 15)) {
0047             spurious_interrupt();
0048             break;
0049         }
0050 
0051         generic_handle_domain_irq(priv->domain, bit);
0052         pending &= ~BIT(bit);
0053     }
0054     chained_irq_exit(chip, desc);
0055 }
0056 
0057 static void htpic_reg_init(void)
0058 {
0059     int i;
0060 
0061     for (i = 0; i < HTINT_NUM_VECTORS; i++) {
0062         /* Disable all HT Vectors */
0063         writel(0x0, htpic->base + HTINT_EN_OFF + i * 0x4);
0064         /* Read back to force write */
0065         (void) readl(htpic->base + i * 0x4);
0066         /* Ack all possible pending IRQs */
0067         writel(GENMASK(31, 0), htpic->base + i * 0x4);
0068     }
0069 
0070     /* Enable 16 vectors for PIC */
0071     writel(0xffff, htpic->base + HTINT_EN_OFF);
0072 }
0073 
0074 static void htpic_resume(void)
0075 {
0076     htpic_reg_init();
0077 }
0078 
0079 struct syscore_ops htpic_syscore_ops = {
0080     .resume     = htpic_resume,
0081 };
0082 
0083 static int __init htpic_of_init(struct device_node *node, struct device_node *parent)
0084 {
0085     unsigned int parent_irq[4];
0086     int i, err;
0087     int num_parents = 0;
0088 
0089     if (htpic) {
0090         pr_err("loongson-htpic: Only one HTPIC is allowed in the system\n");
0091         return -ENODEV;
0092     }
0093 
0094     htpic = kzalloc(sizeof(*htpic), GFP_KERNEL);
0095     if (!htpic)
0096         return -ENOMEM;
0097 
0098     htpic->base = of_iomap(node, 0);
0099     if (!htpic->base) {
0100         err = -ENODEV;
0101         goto out_free;
0102     }
0103 
0104     htpic->domain = __init_i8259_irqs(node);
0105     if (!htpic->domain) {
0106         pr_err("loongson-htpic: Failed to initialize i8259 IRQs\n");
0107         err = -ENOMEM;
0108         goto out_iounmap;
0109     }
0110 
0111     /* Interrupt may come from any of the 4 interrupt line */
0112     for (i = 0; i < HTPIC_MAX_PARENT_IRQ; i++) {
0113         parent_irq[i] = irq_of_parse_and_map(node, i);
0114         if (parent_irq[i] <= 0)
0115             break;
0116 
0117         num_parents++;
0118     }
0119 
0120     if (!num_parents) {
0121         pr_err("loongson-htpic: Failed to get parent irqs\n");
0122         err = -ENODEV;
0123         goto out_remove_domain;
0124     }
0125 
0126     htpic_reg_init();
0127 
0128     for (i = 0; i < num_parents; i++) {
0129         irq_set_chained_handler_and_data(parent_irq[i],
0130                         htpic_irq_dispatch, htpic);
0131     }
0132 
0133     register_syscore_ops(&htpic_syscore_ops);
0134 
0135     return 0;
0136 
0137 out_remove_domain:
0138     irq_domain_remove(htpic->domain);
0139 out_iounmap:
0140     iounmap(htpic->base);
0141 out_free:
0142     kfree(htpic);
0143     return err;
0144 }
0145 
0146 IRQCHIP_DECLARE(loongson_htpic, "loongson,htpic-1.0", htpic_of_init);