root/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pq2ads_pci_mask_irq
  2. pq2ads_pci_unmask_irq
  3. pq2ads_pci_irq_demux
  4. pci_pic_host_map
  5. pq2ads_pci_init_irq

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * PQ2 ADS-style PCI interrupt controller
   4  *
   5  * Copyright 2007 Freescale Semiconductor, Inc.
   6  * Author: Scott Wood <scottwood@freescale.com>
   7  *
   8  * Loosely based on mpc82xx ADS support by Vitaly Bordug <vbordug@ru.mvista.com>
   9  * Copyright (c) 2006 MontaVista Software, Inc.
  10  */
  11 
  12 #include <linux/init.h>
  13 #include <linux/spinlock.h>
  14 #include <linux/irq.h>
  15 #include <linux/types.h>
  16 #include <linux/slab.h>
  17 
  18 #include <asm/io.h>
  19 #include <asm/prom.h>
  20 #include <asm/cpm2.h>
  21 
  22 #include "pq2.h"
  23 
  24 static DEFINE_RAW_SPINLOCK(pci_pic_lock);
  25 
  26 struct pq2ads_pci_pic {
  27         struct device_node *node;
  28         struct irq_domain *host;
  29 
  30         struct {
  31                 u32 stat;
  32                 u32 mask;
  33         } __iomem *regs;
  34 };
  35 
  36 #define NUM_IRQS 32
  37 
  38 static void pq2ads_pci_mask_irq(struct irq_data *d)
  39 {
  40         struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
  41         int irq = NUM_IRQS - irqd_to_hwirq(d) - 1;
  42 
  43         if (irq != -1) {
  44                 unsigned long flags;
  45                 raw_spin_lock_irqsave(&pci_pic_lock, flags);
  46 
  47                 setbits32(&priv->regs->mask, 1 << irq);
  48                 mb();
  49 
  50                 raw_spin_unlock_irqrestore(&pci_pic_lock, flags);
  51         }
  52 }
  53 
  54 static void pq2ads_pci_unmask_irq(struct irq_data *d)
  55 {
  56         struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
  57         int irq = NUM_IRQS - irqd_to_hwirq(d) - 1;
  58 
  59         if (irq != -1) {
  60                 unsigned long flags;
  61 
  62                 raw_spin_lock_irqsave(&pci_pic_lock, flags);
  63                 clrbits32(&priv->regs->mask, 1 << irq);
  64                 raw_spin_unlock_irqrestore(&pci_pic_lock, flags);
  65         }
  66 }
  67 
  68 static struct irq_chip pq2ads_pci_ic = {
  69         .name = "PQ2 ADS PCI",
  70         .irq_mask = pq2ads_pci_mask_irq,
  71         .irq_mask_ack = pq2ads_pci_mask_irq,
  72         .irq_ack = pq2ads_pci_mask_irq,
  73         .irq_unmask = pq2ads_pci_unmask_irq,
  74         .irq_enable = pq2ads_pci_unmask_irq,
  75         .irq_disable = pq2ads_pci_mask_irq
  76 };
  77 
  78 static void pq2ads_pci_irq_demux(struct irq_desc *desc)
  79 {
  80         struct pq2ads_pci_pic *priv = irq_desc_get_handler_data(desc);
  81         u32 stat, mask, pend;
  82         int bit;
  83 
  84         for (;;) {
  85                 stat = in_be32(&priv->regs->stat);
  86                 mask = in_be32(&priv->regs->mask);
  87 
  88                 pend = stat & ~mask;
  89 
  90                 if (!pend)
  91                         break;
  92 
  93                 for (bit = 0; pend != 0; ++bit, pend <<= 1) {
  94                         if (pend & 0x80000000) {
  95                                 int virq = irq_linear_revmap(priv->host, bit);
  96                                 generic_handle_irq(virq);
  97                         }
  98                 }
  99         }
 100 }
 101 
 102 static int pci_pic_host_map(struct irq_domain *h, unsigned int virq,
 103                             irq_hw_number_t hw)
 104 {
 105         irq_set_status_flags(virq, IRQ_LEVEL);
 106         irq_set_chip_data(virq, h->host_data);
 107         irq_set_chip_and_handler(virq, &pq2ads_pci_ic, handle_level_irq);
 108         return 0;
 109 }
 110 
 111 static const struct irq_domain_ops pci_pic_host_ops = {
 112         .map = pci_pic_host_map,
 113 };
 114 
 115 int __init pq2ads_pci_init_irq(void)
 116 {
 117         struct pq2ads_pci_pic *priv;
 118         struct irq_domain *host;
 119         struct device_node *np;
 120         int ret = -ENODEV;
 121         int irq;
 122 
 123         np = of_find_compatible_node(NULL, NULL, "fsl,pq2ads-pci-pic");
 124         if (!np) {
 125                 printk(KERN_ERR "No pci pic node in device tree.\n");
 126                 of_node_put(np);
 127                 goto out;
 128         }
 129 
 130         irq = irq_of_parse_and_map(np, 0);
 131         if (!irq) {
 132                 printk(KERN_ERR "No interrupt in pci pic node.\n");
 133                 of_node_put(np);
 134                 goto out;
 135         }
 136 
 137         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 138         if (!priv) {
 139                 of_node_put(np);
 140                 ret = -ENOMEM;
 141                 goto out_unmap_irq;
 142         }
 143 
 144         /* PCI interrupt controller registers: status and mask */
 145         priv->regs = of_iomap(np, 0);
 146         if (!priv->regs) {
 147                 printk(KERN_ERR "Cannot map PCI PIC registers.\n");
 148                 goto out_free_kmalloc;
 149         }
 150 
 151         /* mask all PCI interrupts */
 152         out_be32(&priv->regs->mask, ~0);
 153         mb();
 154 
 155         host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv);
 156         if (!host) {
 157                 ret = -ENOMEM;
 158                 goto out_unmap_regs;
 159         }
 160 
 161         priv->host = host;
 162         irq_set_handler_data(irq, priv);
 163         irq_set_chained_handler(irq, pq2ads_pci_irq_demux);
 164 
 165         of_node_put(np);
 166         return 0;
 167 
 168 out_unmap_regs:
 169         iounmap(priv->regs);
 170 out_free_kmalloc:
 171         kfree(priv);
 172         of_node_put(np);
 173 out_unmap_irq:
 174         irq_dispose_mapping(irq);
 175 out:
 176         return ret;
 177 }

/* [<][>][^][v][top][bottom][index][help] */