Commit | Line | Data |
---|---|---|
2d242aa2 BG |
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 | ||
7c6337e2 KH |
7 | #include <linux/kernel.h> |
8 | #include <linux/init.h> | |
9 | #include <linux/interrupt.h> | |
10 | #include <linux/irq.h> | |
fced80c7 | 11 | #include <linux/io.h> |
74b0eac2 | 12 | #include <linux/irqdomain.h> |
7c6337e2 | 13 | |
a09e64fb | 14 | #include <mach/hardware.h> |
9e16469c | 15 | #include <mach/cputype.h> |
673dd36f | 16 | #include <mach/common.h> |
7c6337e2 | 17 | #include <asm/mach/irq.h> |
d0064594 | 18 | #include <asm/exception.h> |
7c6337e2 | 19 | |
544ca0b0 BG |
20 | #include "irqs.h" |
21 | ||
919da6f1 BG |
22 | #define DAVINCI_AINTC_FIQ_REG0 0x00 |
23 | #define DAVINCI_AINTC_FIQ_REG1 0x04 | |
24 | #define DAVINCI_AINTC_IRQ_REG0 0x08 | |
25 | #define DAVINCI_AINTC_IRQ_REG1 0x0c | |
26 | #define DAVINCI_AINTC_IRQ_IRQENTRY 0x14 | |
27 | #define DAVINCI_AINTC_IRQ_ENT_REG0 0x18 | |
28 | #define DAVINCI_AINTC_IRQ_ENT_REG1 0x1c | |
29 | #define DAVINCI_AINTC_IRQ_INCTL_REG 0x20 | |
30 | #define DAVINCI_AINTC_IRQ_EABASE_REG 0x24 | |
31 | #define DAVINCI_AINTC_IRQ_INTPRI0_REG 0x30 | |
32 | #define DAVINCI_AINTC_IRQ_INTPRI7_REG 0x4c | |
2b6a2e74 BG |
33 | |
34 | static void __iomem *davinci_aintc_base; | |
35 | static struct irq_domain *davinci_aintc_irq_domain; | |
36 | ||
37 | static inline void davinci_aintc_writel(unsigned long value, int offset) | |
7c6337e2 | 38 | { |
f412384e | 39 | writel_relaxed(value, davinci_aintc_base + offset); |
7c6337e2 KH |
40 | } |
41 | ||
2b6a2e74 | 42 | static inline unsigned long davinci_aintc_readl(int offset) |
d0064594 | 43 | { |
2b6a2e74 | 44 | return readl_relaxed(davinci_aintc_base + offset); |
d0064594 BG |
45 | } |
46 | ||
aac4dd1d | 47 | static __init void |
2b6a2e74 BG |
48 | davinci_aintc_setup_gc(void __iomem *base, |
49 | unsigned int irq_start, unsigned int num) | |
7c6337e2 | 50 | { |
aac4dd1d TG |
51 | struct irq_chip_generic *gc; |
52 | struct irq_chip_type *ct; | |
53 | ||
2b6a2e74 | 54 | gc = irq_get_domain_generic_chip(davinci_aintc_irq_domain, irq_start); |
74b0eac2 BG |
55 | gc->reg_base = base; |
56 | gc->irq_base = irq_start; | |
33e1e5e3 | 57 | |
aac4dd1d | 58 | ct = gc->chip_types; |
659fb32d | 59 | ct->chip.irq_ack = irq_gc_ack_set_bit; |
aac4dd1d TG |
60 | ct->chip.irq_mask = irq_gc_mask_clr_bit; |
61 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | |
62 | ||
2b6a2e74 BG |
63 | ct->regs.ack = DAVINCI_AINTC_IRQ_REG0; |
64 | ct->regs.mask = DAVINCI_AINTC_IRQ_ENT_REG0; | |
aac4dd1d TG |
65 | irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, |
66 | IRQ_NOREQUEST | IRQ_NOPROBE, 0); | |
7c6337e2 KH |
67 | } |
68 | ||
d0064594 | 69 | static asmlinkage void __exception_irq_entry |
2b6a2e74 | 70 | davinci_aintc_handle_irq(struct pt_regs *regs) |
d0064594 | 71 | { |
2b6a2e74 | 72 | int irqnr = davinci_aintc_readl(DAVINCI_AINTC_IRQ_IRQENTRY); |
d0064594 BG |
73 | |
74 | /* | |
75 | * Use the formula for entry vector index generation from section | |
76 | * 8.3.3 of the manual. | |
77 | */ | |
78 | irqnr >>= 2; | |
79 | irqnr -= 1; | |
80 | ||
2b6a2e74 | 81 | handle_domain_irq(davinci_aintc_irq_domain, irqnr, regs); |
d0064594 BG |
82 | } |
83 | ||
7c6337e2 | 84 | /* ARM Interrupt Controller Initialization */ |
2b6a2e74 | 85 | void __init davinci_aintc_init(void) |
7c6337e2 | 86 | { |
aac4dd1d | 87 | unsigned i, j; |
673dd36f | 88 | const u8 *davinci_def_priorities = davinci_soc_info.intc_irq_prios; |
74b0eac2 | 89 | int ret, irq_base; |
7c6337e2 | 90 | |
2b6a2e74 BG |
91 | davinci_aintc_base = ioremap(davinci_soc_info.intc_base, SZ_4K); |
92 | if (WARN_ON(!davinci_aintc_base)) | |
bd808947 CC |
93 | return; |
94 | ||
7c6337e2 | 95 | /* Clear all interrupt requests */ |
2b6a2e74 BG |
96 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0); |
97 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1); | |
98 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0); | |
99 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1); | |
7c6337e2 KH |
100 | |
101 | /* Disable all interrupts */ | |
2b6a2e74 BG |
102 | davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG0); |
103 | davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG1); | |
7c6337e2 KH |
104 | |
105 | /* Interrupts disabled immediately, IRQ entry reflects all */ | |
2b6a2e74 | 106 | davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_INCTL_REG); |
7c6337e2 KH |
107 | |
108 | /* we don't use the hardware vector table, just its entry addresses */ | |
2b6a2e74 | 109 | davinci_aintc_writel(0, DAVINCI_AINTC_IRQ_EABASE_REG); |
7c6337e2 KH |
110 | |
111 | /* Clear all interrupt requests */ | |
2b6a2e74 BG |
112 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0); |
113 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1); | |
114 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0); | |
115 | davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1); | |
7c6337e2 | 116 | |
2b6a2e74 BG |
117 | for (i = DAVINCI_AINTC_IRQ_INTPRI0_REG; |
118 | i <= DAVINCI_AINTC_IRQ_INTPRI7_REG; i += 4) { | |
7c6337e2 KH |
119 | u32 pri; |
120 | ||
9e16469c SR |
121 | for (j = 0, pri = 0; j < 32; j += 4, davinci_def_priorities++) |
122 | pri |= (*davinci_def_priorities & 0x07) << j; | |
2b6a2e74 | 123 | davinci_aintc_writel(pri, i); |
7c6337e2 KH |
124 | } |
125 | ||
74b0eac2 BG |
126 | irq_base = irq_alloc_descs(-1, 0, davinci_soc_info.intc_irq_num, 0); |
127 | if (WARN_ON(irq_base < 0)) | |
128 | return; | |
129 | ||
2b6a2e74 | 130 | davinci_aintc_irq_domain = irq_domain_add_legacy(NULL, |
74b0eac2 BG |
131 | davinci_soc_info.intc_irq_num, |
132 | irq_base, 0, &irq_domain_simple_ops, | |
133 | NULL); | |
2b6a2e74 | 134 | if (WARN_ON(!davinci_aintc_irq_domain)) |
74b0eac2 BG |
135 | return; |
136 | ||
2b6a2e74 BG |
137 | ret = irq_alloc_domain_generic_chips(davinci_aintc_irq_domain, 32, 1, |
138 | "AINTC", handle_edge_irq, | |
139 | IRQ_NOREQUEST | IRQ_NOPROBE, 0, 0); | |
74b0eac2 BG |
140 | if (WARN_ON(ret)) |
141 | return; | |
142 | ||
2b6a2e74 BG |
143 | for (i = 0, j = 0; i < davinci_soc_info.intc_irq_num; |
144 | i += 32, j += 0x04) | |
145 | davinci_aintc_setup_gc(davinci_aintc_base + j, | |
146 | irq_base + i, 32); | |
aac4dd1d | 147 | |
a98ca73e | 148 | irq_set_handler(DAVINCI_INTC_IRQ(IRQ_TINT1_TINT34), handle_level_irq); |
2b6a2e74 | 149 | set_handle_irq(davinci_aintc_handle_irq); |
7c6337e2 | 150 | } |