root/drivers/irqchip/irq-davinci-aintc.c

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

DEFINITIONS

This source file includes following definitions.
  1. davinci_aintc_writel
  2. davinci_aintc_readl
  3. davinci_aintc_setup_gc
  4. davinci_aintc_handle_irq
  5. davinci_aintc_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 //
   3 // Copyright (C) 2006, 2019 Texas Instruments.
   4 //
   5 // Interrupt handler for DaVinci boards.
   6 
   7 #include <linux/kernel.h>
   8 #include <linux/init.h>
   9 #include <linux/interrupt.h>
  10 #include <linux/irq.h>
  11 #include <linux/irqchip/irq-davinci-aintc.h>
  12 #include <linux/io.h>
  13 #include <linux/irqdomain.h>
  14 
  15 #include <asm/exception.h>
  16 
  17 #define DAVINCI_AINTC_FIQ_REG0          0x00
  18 #define DAVINCI_AINTC_FIQ_REG1          0x04
  19 #define DAVINCI_AINTC_IRQ_REG0          0x08
  20 #define DAVINCI_AINTC_IRQ_REG1          0x0c
  21 #define DAVINCI_AINTC_IRQ_IRQENTRY      0x14
  22 #define DAVINCI_AINTC_IRQ_ENT_REG0      0x18
  23 #define DAVINCI_AINTC_IRQ_ENT_REG1      0x1c
  24 #define DAVINCI_AINTC_IRQ_INCTL_REG     0x20
  25 #define DAVINCI_AINTC_IRQ_EABASE_REG    0x24
  26 #define DAVINCI_AINTC_IRQ_INTPRI0_REG   0x30
  27 #define DAVINCI_AINTC_IRQ_INTPRI7_REG   0x4c
  28 
  29 static void __iomem *davinci_aintc_base;
  30 static struct irq_domain *davinci_aintc_irq_domain;
  31 
  32 static inline void davinci_aintc_writel(unsigned long value, int offset)
  33 {
  34         writel_relaxed(value, davinci_aintc_base + offset);
  35 }
  36 
  37 static inline unsigned long davinci_aintc_readl(int offset)
  38 {
  39         return readl_relaxed(davinci_aintc_base + offset);
  40 }
  41 
  42 static __init void
  43 davinci_aintc_setup_gc(void __iomem *base,
  44                        unsigned int irq_start, unsigned int num)
  45 {
  46         struct irq_chip_generic *gc;
  47         struct irq_chip_type *ct;
  48 
  49         gc = irq_get_domain_generic_chip(davinci_aintc_irq_domain, irq_start);
  50         gc->reg_base = base;
  51         gc->irq_base = irq_start;
  52 
  53         ct = gc->chip_types;
  54         ct->chip.irq_ack = irq_gc_ack_set_bit;
  55         ct->chip.irq_mask = irq_gc_mask_clr_bit;
  56         ct->chip.irq_unmask = irq_gc_mask_set_bit;
  57 
  58         ct->regs.ack = DAVINCI_AINTC_IRQ_REG0;
  59         ct->regs.mask = DAVINCI_AINTC_IRQ_ENT_REG0;
  60         irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
  61                                IRQ_NOREQUEST | IRQ_NOPROBE, 0);
  62 }
  63 
  64 static asmlinkage void __exception_irq_entry
  65 davinci_aintc_handle_irq(struct pt_regs *regs)
  66 {
  67         int irqnr = davinci_aintc_readl(DAVINCI_AINTC_IRQ_IRQENTRY);
  68 
  69         /*
  70          * Use the formula for entry vector index generation from section
  71          * 8.3.3 of the manual.
  72          */
  73         irqnr >>= 2;
  74         irqnr -= 1;
  75 
  76         handle_domain_irq(davinci_aintc_irq_domain, irqnr, regs);
  77 }
  78 
  79 /* ARM Interrupt Controller Initialization */
  80 void __init davinci_aintc_init(const struct davinci_aintc_config *config)
  81 {
  82         unsigned int irq_off, reg_off, prio, shift;
  83         void __iomem *req;
  84         int ret, irq_base;
  85         const u8 *prios;
  86 
  87         req = request_mem_region(config->reg.start,
  88                                  resource_size(&config->reg),
  89                                  "davinci-cp-intc");
  90         if (!req) {
  91                 pr_err("%s: register range busy\n", __func__);
  92                 return;
  93         }
  94 
  95         davinci_aintc_base = ioremap(config->reg.start,
  96                                      resource_size(&config->reg));
  97         if (!davinci_aintc_base) {
  98                 pr_err("%s: unable to ioremap register range\n", __func__);
  99                 return;
 100         }
 101 
 102         /* Clear all interrupt requests */
 103         davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0);
 104         davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1);
 105         davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0);
 106         davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1);
 107 
 108         /* Disable all interrupts */
 109         davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG0);
 110         davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG1);
 111 
 112         /* Interrupts disabled immediately, IRQ entry reflects all */
 113         davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_INCTL_REG);
 114 
 115         /* we don't use the hardware vector table, just its entry addresses */
 116         davinci_aintc_writel(0, DAVINCI_AINTC_IRQ_EABASE_REG);
 117 
 118         /* Clear all interrupt requests */
 119         davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0);
 120         davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1);
 121         davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0);
 122         davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1);
 123 
 124         prios = config->prios;
 125         for (reg_off = DAVINCI_AINTC_IRQ_INTPRI0_REG;
 126              reg_off <= DAVINCI_AINTC_IRQ_INTPRI7_REG; reg_off += 4) {
 127                 for (shift = 0, prio = 0; shift < 32; shift += 4, prios++)
 128                         prio |= (*prios & 0x07) << shift;
 129                 davinci_aintc_writel(prio, reg_off);
 130         }
 131 
 132         irq_base = irq_alloc_descs(-1, 0, config->num_irqs, 0);
 133         if (irq_base < 0) {
 134                 pr_err("%s: unable to allocate interrupt descriptors: %d\n",
 135                        __func__, irq_base);
 136                 return;
 137         }
 138 
 139         davinci_aintc_irq_domain = irq_domain_add_legacy(NULL,
 140                                                 config->num_irqs, irq_base, 0,
 141                                                 &irq_domain_simple_ops, NULL);
 142         if (!davinci_aintc_irq_domain) {
 143                 pr_err("%s: unable to create interrupt domain\n", __func__);
 144                 return;
 145         }
 146 
 147         ret = irq_alloc_domain_generic_chips(davinci_aintc_irq_domain, 32, 1,
 148                                              "AINTC", handle_edge_irq,
 149                                              IRQ_NOREQUEST | IRQ_NOPROBE, 0, 0);
 150         if (ret) {
 151                 pr_err("%s: unable to allocate generic irq chips for domain\n",
 152                        __func__);
 153                 return;
 154         }
 155 
 156         for (irq_off = 0, reg_off = 0;
 157              irq_off < config->num_irqs;
 158              irq_off += 32, reg_off += 0x04)
 159                 davinci_aintc_setup_gc(davinci_aintc_base + reg_off,
 160                                        irq_base + irq_off, 32);
 161 
 162         set_handle_irq(davinci_aintc_handle_irq);
 163 }

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