1 // SPDX-License-Identifier: GPL-2.0-or-later
3 // Copyright (C) 2006, 2019 Texas Instruments.
5 // Interrupt handler for DaVinci boards.
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>
13 #include <linux/irqdomain.h>
15 #include <asm/exception.h>
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
29 static void __iomem
*davinci_aintc_base
;
30 static struct irq_domain
*davinci_aintc_irq_domain
;
32 static inline void davinci_aintc_writel(unsigned long value
, int offset
)
34 writel_relaxed(value
, davinci_aintc_base
+ offset
);
37 static inline unsigned long davinci_aintc_readl(int offset
)
39 return readl_relaxed(davinci_aintc_base
+ offset
);
43 davinci_aintc_setup_gc(void __iomem
*base
,
44 unsigned int irq_start
, unsigned int num
)
46 struct irq_chip_generic
*gc
;
47 struct irq_chip_type
*ct
;
49 gc
= irq_get_domain_generic_chip(davinci_aintc_irq_domain
, irq_start
);
51 gc
->irq_base
= irq_start
;
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
;
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);
64 static asmlinkage
void __exception_irq_entry
65 davinci_aintc_handle_irq(struct pt_regs
*regs
)
67 int irqnr
= davinci_aintc_readl(DAVINCI_AINTC_IRQ_IRQENTRY
);
70 * Use the formula for entry vector index generation from section
71 * 8.3.3 of the manual.
76 handle_domain_irq(davinci_aintc_irq_domain
, irqnr
, regs
);
79 /* ARM Interrupt Controller Initialization */
80 void __init
davinci_aintc_init(const struct davinci_aintc_config
*config
)
82 unsigned int irq_off
, reg_off
, prio
, shift
;
87 req
= request_mem_region(config
->reg
.start
,
88 resource_size(&config
->reg
),
91 pr_err("%s: register range busy\n", __func__
);
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__
);
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
);
108 /* Disable all interrupts */
109 davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG0
);
110 davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG1
);
112 /* Interrupts disabled immediately, IRQ entry reflects all */
113 davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_INCTL_REG
);
115 /* we don't use the hardware vector table, just its entry addresses */
116 davinci_aintc_writel(0, DAVINCI_AINTC_IRQ_EABASE_REG
);
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
);
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
);
132 irq_base
= irq_alloc_descs(-1, 0, config
->num_irqs
, 0);
134 pr_err("%s: unable to allocate interrupt descriptors: %d\n",
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__
);
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);
151 pr_err("%s: unable to allocate generic irq chips for domain\n",
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);
162 set_handle_irq(davinci_aintc_handle_irq
);