Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * PQ2 ADS-style PCI interrupt controller
0004  *
0005  * Copyright 2007 Freescale Semiconductor, Inc.
0006  * Author: Scott Wood <scottwood@freescale.com>
0007  *
0008  * Loosely based on mpc82xx ADS support by Vitaly Bordug <vbordug@ru.mvista.com>
0009  * Copyright (c) 2006 MontaVista Software, Inc.
0010  */
0011 
0012 #include <linux/init.h>
0013 #include <linux/spinlock.h>
0014 #include <linux/irq.h>
0015 #include <linux/types.h>
0016 #include <linux/slab.h>
0017 #include <linux/of_irq.h>
0018 
0019 #include <asm/io.h>
0020 #include <asm/cpm2.h>
0021 
0022 #include "pq2.h"
0023 
0024 static DEFINE_RAW_SPINLOCK(pci_pic_lock);
0025 
0026 struct pq2ads_pci_pic {
0027     struct device_node *node;
0028     struct irq_domain *host;
0029 
0030     struct {
0031         u32 stat;
0032         u32 mask;
0033     } __iomem *regs;
0034 };
0035 
0036 #define NUM_IRQS 32
0037 
0038 static void pq2ads_pci_mask_irq(struct irq_data *d)
0039 {
0040     struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
0041     int irq = NUM_IRQS - irqd_to_hwirq(d) - 1;
0042 
0043     if (irq != -1) {
0044         unsigned long flags;
0045         raw_spin_lock_irqsave(&pci_pic_lock, flags);
0046 
0047         setbits32(&priv->regs->mask, 1 << irq);
0048         mb();
0049 
0050         raw_spin_unlock_irqrestore(&pci_pic_lock, flags);
0051     }
0052 }
0053 
0054 static void pq2ads_pci_unmask_irq(struct irq_data *d)
0055 {
0056     struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
0057     int irq = NUM_IRQS - irqd_to_hwirq(d) - 1;
0058 
0059     if (irq != -1) {
0060         unsigned long flags;
0061 
0062         raw_spin_lock_irqsave(&pci_pic_lock, flags);
0063         clrbits32(&priv->regs->mask, 1 << irq);
0064         raw_spin_unlock_irqrestore(&pci_pic_lock, flags);
0065     }
0066 }
0067 
0068 static struct irq_chip pq2ads_pci_ic = {
0069     .name = "PQ2 ADS PCI",
0070     .irq_mask = pq2ads_pci_mask_irq,
0071     .irq_mask_ack = pq2ads_pci_mask_irq,
0072     .irq_ack = pq2ads_pci_mask_irq,
0073     .irq_unmask = pq2ads_pci_unmask_irq,
0074     .irq_enable = pq2ads_pci_unmask_irq,
0075     .irq_disable = pq2ads_pci_mask_irq
0076 };
0077 
0078 static void pq2ads_pci_irq_demux(struct irq_desc *desc)
0079 {
0080     struct pq2ads_pci_pic *priv = irq_desc_get_handler_data(desc);
0081     u32 stat, mask, pend;
0082     int bit;
0083 
0084     for (;;) {
0085         stat = in_be32(&priv->regs->stat);
0086         mask = in_be32(&priv->regs->mask);
0087 
0088         pend = stat & ~mask;
0089 
0090         if (!pend)
0091             break;
0092 
0093         for (bit = 0; pend != 0; ++bit, pend <<= 1) {
0094             if (pend & 0x80000000)
0095                 generic_handle_domain_irq(priv->host, bit);
0096         }
0097     }
0098 }
0099 
0100 static int pci_pic_host_map(struct irq_domain *h, unsigned int virq,
0101                 irq_hw_number_t hw)
0102 {
0103     irq_set_status_flags(virq, IRQ_LEVEL);
0104     irq_set_chip_data(virq, h->host_data);
0105     irq_set_chip_and_handler(virq, &pq2ads_pci_ic, handle_level_irq);
0106     return 0;
0107 }
0108 
0109 static const struct irq_domain_ops pci_pic_host_ops = {
0110     .map = pci_pic_host_map,
0111 };
0112 
0113 int __init pq2ads_pci_init_irq(void)
0114 {
0115     struct pq2ads_pci_pic *priv;
0116     struct irq_domain *host;
0117     struct device_node *np;
0118     int ret = -ENODEV;
0119     int irq;
0120 
0121     np = of_find_compatible_node(NULL, NULL, "fsl,pq2ads-pci-pic");
0122     if (!np) {
0123         printk(KERN_ERR "No pci pic node in device tree.\n");
0124         goto out;
0125     }
0126 
0127     irq = irq_of_parse_and_map(np, 0);
0128     if (!irq) {
0129         printk(KERN_ERR "No interrupt in pci pic node.\n");
0130         goto out_put_node;
0131     }
0132 
0133     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0134     if (!priv) {
0135         ret = -ENOMEM;
0136         goto out_unmap_irq;
0137     }
0138 
0139     /* PCI interrupt controller registers: status and mask */
0140     priv->regs = of_iomap(np, 0);
0141     if (!priv->regs) {
0142         printk(KERN_ERR "Cannot map PCI PIC registers.\n");
0143         goto out_free_kmalloc;
0144     }
0145 
0146     /* mask all PCI interrupts */
0147     out_be32(&priv->regs->mask, ~0);
0148     mb();
0149 
0150     host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv);
0151     if (!host) {
0152         ret = -ENOMEM;
0153         goto out_unmap_regs;
0154     }
0155 
0156     priv->host = host;
0157     irq_set_handler_data(irq, priv);
0158     irq_set_chained_handler(irq, pq2ads_pci_irq_demux);
0159     ret = 0;
0160     goto out_put_node;
0161 
0162 out_unmap_regs:
0163     iounmap(priv->regs);
0164 out_free_kmalloc:
0165     kfree(priv);
0166 out_unmap_irq:
0167     irq_dispose_mapping(irq);
0168 out_put_node:
0169     of_node_put(np);
0170 out:
0171     return ret;
0172 }