root/drivers/irqchip/irq-xilinx-intc.c

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

DEFINITIONS

This source file includes following definitions.
  1. xintc_write
  2. xintc_read
  3. intc_enable_or_unmask
  4. intc_disable_or_mask
  5. intc_ack
  6. intc_mask_ack
  7. xintc_get_irq
  8. xintc_map
  9. xil_intc_irq_handler
  10. xilinx_intc_of_init

   1 /*
   2  * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu>
   3  * Copyright (C) 2012-2013 Xilinx, Inc.
   4  * Copyright (C) 2007-2009 PetaLogix
   5  * Copyright (C) 2006 Atmark Techno, Inc.
   6  *
   7  * This file is subject to the terms and conditions of the GNU General Public
   8  * License. See the file "COPYING" in the main directory of this archive
   9  * for more details.
  10  */
  11 
  12 #include <linux/irqdomain.h>
  13 #include <linux/irq.h>
  14 #include <linux/irqchip.h>
  15 #include <linux/irqchip/chained_irq.h>
  16 #include <linux/of_address.h>
  17 #include <linux/io.h>
  18 #include <linux/jump_label.h>
  19 #include <linux/bug.h>
  20 #include <linux/of_irq.h>
  21 
  22 /* No one else should require these constants, so define them locally here. */
  23 #define ISR 0x00                        /* Interrupt Status Register */
  24 #define IPR 0x04                        /* Interrupt Pending Register */
  25 #define IER 0x08                        /* Interrupt Enable Register */
  26 #define IAR 0x0c                        /* Interrupt Acknowledge Register */
  27 #define SIE 0x10                        /* Set Interrupt Enable bits */
  28 #define CIE 0x14                        /* Clear Interrupt Enable bits */
  29 #define IVR 0x18                        /* Interrupt Vector Register */
  30 #define MER 0x1c                        /* Master Enable Register */
  31 
  32 #define MER_ME (1<<0)
  33 #define MER_HIE (1<<1)
  34 
  35 static DEFINE_STATIC_KEY_FALSE(xintc_is_be);
  36 
  37 struct xintc_irq_chip {
  38         void            __iomem *base;
  39         struct          irq_domain *root_domain;
  40         u32             intr_mask;
  41 };
  42 
  43 static struct xintc_irq_chip *xintc_irqc;
  44 
  45 static void xintc_write(int reg, u32 data)
  46 {
  47         if (static_branch_unlikely(&xintc_is_be))
  48                 iowrite32be(data, xintc_irqc->base + reg);
  49         else
  50                 iowrite32(data, xintc_irqc->base + reg);
  51 }
  52 
  53 static unsigned int xintc_read(int reg)
  54 {
  55         if (static_branch_unlikely(&xintc_is_be))
  56                 return ioread32be(xintc_irqc->base + reg);
  57         else
  58                 return ioread32(xintc_irqc->base + reg);
  59 }
  60 
  61 static void intc_enable_or_unmask(struct irq_data *d)
  62 {
  63         unsigned long mask = 1 << d->hwirq;
  64 
  65         pr_debug("irq-xilinx: enable_or_unmask: %ld\n", d->hwirq);
  66 
  67         /* ack level irqs because they can't be acked during
  68          * ack function since the handle_level_irq function
  69          * acks the irq before calling the interrupt handler
  70          */
  71         if (irqd_is_level_type(d))
  72                 xintc_write(IAR, mask);
  73 
  74         xintc_write(SIE, mask);
  75 }
  76 
  77 static void intc_disable_or_mask(struct irq_data *d)
  78 {
  79         pr_debug("irq-xilinx: disable: %ld\n", d->hwirq);
  80         xintc_write(CIE, 1 << d->hwirq);
  81 }
  82 
  83 static void intc_ack(struct irq_data *d)
  84 {
  85         pr_debug("irq-xilinx: ack: %ld\n", d->hwirq);
  86         xintc_write(IAR, 1 << d->hwirq);
  87 }
  88 
  89 static void intc_mask_ack(struct irq_data *d)
  90 {
  91         unsigned long mask = 1 << d->hwirq;
  92 
  93         pr_debug("irq-xilinx: disable_and_ack: %ld\n", d->hwirq);
  94         xintc_write(CIE, mask);
  95         xintc_write(IAR, mask);
  96 }
  97 
  98 static struct irq_chip intc_dev = {
  99         .name = "Xilinx INTC",
 100         .irq_unmask = intc_enable_or_unmask,
 101         .irq_mask = intc_disable_or_mask,
 102         .irq_ack = intc_ack,
 103         .irq_mask_ack = intc_mask_ack,
 104 };
 105 
 106 unsigned int xintc_get_irq(void)
 107 {
 108         unsigned int hwirq, irq = -1;
 109 
 110         hwirq = xintc_read(IVR);
 111         if (hwirq != -1U)
 112                 irq = irq_find_mapping(xintc_irqc->root_domain, hwirq);
 113 
 114         pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
 115 
 116         return irq;
 117 }
 118 
 119 static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
 120 {
 121         if (xintc_irqc->intr_mask & (1 << hw)) {
 122                 irq_set_chip_and_handler_name(irq, &intc_dev,
 123                                                 handle_edge_irq, "edge");
 124                 irq_clear_status_flags(irq, IRQ_LEVEL);
 125         } else {
 126                 irq_set_chip_and_handler_name(irq, &intc_dev,
 127                                                 handle_level_irq, "level");
 128                 irq_set_status_flags(irq, IRQ_LEVEL);
 129         }
 130         return 0;
 131 }
 132 
 133 static const struct irq_domain_ops xintc_irq_domain_ops = {
 134         .xlate = irq_domain_xlate_onetwocell,
 135         .map = xintc_map,
 136 };
 137 
 138 static void xil_intc_irq_handler(struct irq_desc *desc)
 139 {
 140         struct irq_chip *chip = irq_desc_get_chip(desc);
 141         u32 pending;
 142 
 143         chained_irq_enter(chip, desc);
 144         do {
 145                 pending = xintc_get_irq();
 146                 if (pending == -1U)
 147                         break;
 148                 generic_handle_irq(pending);
 149         } while (true);
 150         chained_irq_exit(chip, desc);
 151 }
 152 
 153 static int __init xilinx_intc_of_init(struct device_node *intc,
 154                                              struct device_node *parent)
 155 {
 156         u32 nr_irq;
 157         int ret, irq;
 158         struct xintc_irq_chip *irqc;
 159 
 160         if (xintc_irqc) {
 161                 pr_err("irq-xilinx: Multiple instances aren't supported\n");
 162                 return -EINVAL;
 163         }
 164 
 165         irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
 166         if (!irqc)
 167                 return -ENOMEM;
 168 
 169         xintc_irqc = irqc;
 170 
 171         irqc->base = of_iomap(intc, 0);
 172         BUG_ON(!irqc->base);
 173 
 174         ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
 175         if (ret < 0) {
 176                 pr_err("irq-xilinx: unable to read xlnx,num-intr-inputs\n");
 177                 goto err_alloc;
 178         }
 179 
 180         ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &irqc->intr_mask);
 181         if (ret < 0) {
 182                 pr_warn("irq-xilinx: unable to read xlnx,kind-of-intr\n");
 183                 irqc->intr_mask = 0;
 184         }
 185 
 186         if (irqc->intr_mask >> nr_irq)
 187                 pr_warn("irq-xilinx: mismatch in kind-of-intr param\n");
 188 
 189         pr_info("irq-xilinx: %pOF: num_irq=%d, edge=0x%x\n",
 190                 intc, nr_irq, irqc->intr_mask);
 191 
 192 
 193         /*
 194          * Disable all external interrupts until they are
 195          * explicity requested.
 196          */
 197         xintc_write(IER, 0);
 198 
 199         /* Acknowledge any pending interrupts just in case. */
 200         xintc_write(IAR, 0xffffffff);
 201 
 202         /* Turn on the Master Enable. */
 203         xintc_write(MER, MER_HIE | MER_ME);
 204         if (!(xintc_read(MER) & (MER_HIE | MER_ME))) {
 205                 static_branch_enable(&xintc_is_be);
 206                 xintc_write(MER, MER_HIE | MER_ME);
 207         }
 208 
 209         irqc->root_domain = irq_domain_add_linear(intc, nr_irq,
 210                                                   &xintc_irq_domain_ops, irqc);
 211         if (!irqc->root_domain) {
 212                 pr_err("irq-xilinx: Unable to create IRQ domain\n");
 213                 goto err_alloc;
 214         }
 215 
 216         if (parent) {
 217                 irq = irq_of_parse_and_map(intc, 0);
 218                 if (irq) {
 219                         irq_set_chained_handler_and_data(irq,
 220                                                          xil_intc_irq_handler,
 221                                                          irqc);
 222                 } else {
 223                         pr_err("irq-xilinx: interrupts property not in DT\n");
 224                         ret = -EINVAL;
 225                         goto err_alloc;
 226                 }
 227         } else {
 228                 irq_set_default_host(irqc->root_domain);
 229         }
 230 
 231         return 0;
 232 
 233 err_alloc:
 234         xintc_irqc = NULL;
 235         kfree(irqc);
 236         return ret;
 237 
 238 }
 239 
 240 IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
 241 IRQCHIP_DECLARE(xilinx_intc_opb, "xlnx,opb-intc-1.00.c", xilinx_intc_of_init);

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