Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / arm / mach-iop13xx / irq.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * iop13xx IRQ handling / support functions
4  * Copyright (c) 2005-2006, Intel Corporation.
5  */
6 #include <linux/init.h>
7 #include <linux/interrupt.h>
8 #include <linux/list.h>
9 #include <linux/sysctl.h>
10 #include <linux/uaccess.h>
11 #include <asm/mach/irq.h>
12 #include <asm/irq.h>
13 #include <mach/hardware.h>
14 #include <mach/irqs.h>
15 #include "msi.h"
16
17 /* INTCTL0 CP6 R0 Page 4
18  */
19 static u32 read_intctl_0(void)
20 {
21         u32 val;
22         asm volatile("mrc p6, 0, %0, c0, c4, 0":"=r" (val));
23         return val;
24 }
25 static void write_intctl_0(u32 val)
26 {
27         asm volatile("mcr p6, 0, %0, c0, c4, 0"::"r" (val));
28 }
29
30 /* INTCTL1 CP6 R1 Page 4
31  */
32 static u32 read_intctl_1(void)
33 {
34         u32 val;
35         asm volatile("mrc p6, 0, %0, c1, c4, 0":"=r" (val));
36         return val;
37 }
38 static void write_intctl_1(u32 val)
39 {
40         asm volatile("mcr p6, 0, %0, c1, c4, 0"::"r" (val));
41 }
42
43 /* INTCTL2 CP6 R2 Page 4
44  */
45 static u32 read_intctl_2(void)
46 {
47         u32 val;
48         asm volatile("mrc p6, 0, %0, c2, c4, 0":"=r" (val));
49         return val;
50 }
51 static void write_intctl_2(u32 val)
52 {
53         asm volatile("mcr p6, 0, %0, c2, c4, 0"::"r" (val));
54 }
55
56 /* INTCTL3 CP6 R3 Page 4
57  */
58 static u32 read_intctl_3(void)
59 {
60         u32 val;
61         asm volatile("mrc p6, 0, %0, c3, c4, 0":"=r" (val));
62         return val;
63 }
64 static void write_intctl_3(u32 val)
65 {
66         asm volatile("mcr p6, 0, %0, c3, c4, 0"::"r" (val));
67 }
68
69 /* INTSTR0 CP6 R0 Page 5
70  */
71 static void write_intstr_0(u32 val)
72 {
73         asm volatile("mcr p6, 0, %0, c0, c5, 0"::"r" (val));
74 }
75
76 /* INTSTR1 CP6 R1 Page 5
77  */
78 static void write_intstr_1(u32 val)
79 {
80         asm volatile("mcr p6, 0, %0, c1, c5, 0"::"r" (val));
81 }
82
83 /* INTSTR2 CP6 R2 Page 5
84  */
85 static void write_intstr_2(u32 val)
86 {
87         asm volatile("mcr p6, 0, %0, c2, c5, 0"::"r" (val));
88 }
89
90 /* INTSTR3 CP6 R3 Page 5
91  */
92 static void write_intstr_3(u32 val)
93 {
94         asm volatile("mcr p6, 0, %0, c3, c5, 0"::"r" (val));
95 }
96
97 /* INTBASE CP6 R0 Page 2
98  */
99 static void write_intbase(u32 val)
100 {
101         asm volatile("mcr p6, 0, %0, c0, c2, 0"::"r" (val));
102 }
103
104 /* INTSIZE CP6 R2 Page 2
105  */
106 static void write_intsize(u32 val)
107 {
108         asm volatile("mcr p6, 0, %0, c2, c2, 0"::"r" (val));
109 }
110
111 /* 0 = Interrupt Masked and 1 = Interrupt not masked */
112 static void
113 iop13xx_irq_mask0 (struct irq_data *d)
114 {
115         write_intctl_0(read_intctl_0() & ~(1 << (d->irq - 0)));
116 }
117
118 static void
119 iop13xx_irq_mask1 (struct irq_data *d)
120 {
121         write_intctl_1(read_intctl_1() & ~(1 << (d->irq - 32)));
122 }
123
124 static void
125 iop13xx_irq_mask2 (struct irq_data *d)
126 {
127         write_intctl_2(read_intctl_2() & ~(1 << (d->irq - 64)));
128 }
129
130 static void
131 iop13xx_irq_mask3 (struct irq_data *d)
132 {
133         write_intctl_3(read_intctl_3() & ~(1 << (d->irq - 96)));
134 }
135
136 static void
137 iop13xx_irq_unmask0(struct irq_data *d)
138 {
139         write_intctl_0(read_intctl_0() | (1 << (d->irq - 0)));
140 }
141
142 static void
143 iop13xx_irq_unmask1(struct irq_data *d)
144 {
145         write_intctl_1(read_intctl_1() | (1 << (d->irq - 32)));
146 }
147
148 static void
149 iop13xx_irq_unmask2(struct irq_data *d)
150 {
151         write_intctl_2(read_intctl_2() | (1 << (d->irq - 64)));
152 }
153
154 static void
155 iop13xx_irq_unmask3(struct irq_data *d)
156 {
157         write_intctl_3(read_intctl_3() | (1 << (d->irq - 96)));
158 }
159
160 static struct irq_chip iop13xx_irqchip1 = {
161         .name       = "IOP13xx-1",
162         .irq_ack    = iop13xx_irq_mask0,
163         .irq_mask   = iop13xx_irq_mask0,
164         .irq_unmask = iop13xx_irq_unmask0,
165 };
166
167 static struct irq_chip iop13xx_irqchip2 = {
168         .name       = "IOP13xx-2",
169         .irq_ack    = iop13xx_irq_mask1,
170         .irq_mask   = iop13xx_irq_mask1,
171         .irq_unmask = iop13xx_irq_unmask1,
172 };
173
174 static struct irq_chip iop13xx_irqchip3 = {
175         .name       = "IOP13xx-3",
176         .irq_ack    = iop13xx_irq_mask2,
177         .irq_mask   = iop13xx_irq_mask2,
178         .irq_unmask = iop13xx_irq_unmask2,
179 };
180
181 static struct irq_chip iop13xx_irqchip4 = {
182         .name       = "IOP13xx-4",
183         .irq_ack    = iop13xx_irq_mask3,
184         .irq_mask   = iop13xx_irq_mask3,
185         .irq_unmask = iop13xx_irq_unmask3,
186 };
187
188 extern void iop_init_cp6_handler(void);
189
190 void __init iop13xx_init_irq(void)
191 {
192         unsigned int i;
193
194         iop_init_cp6_handler();
195
196         /* disable all interrupts */
197         write_intctl_0(0);
198         write_intctl_1(0);
199         write_intctl_2(0);
200         write_intctl_3(0);
201
202         /* treat all as IRQ */
203         write_intstr_0(0);
204         write_intstr_1(0);
205         write_intstr_2(0);
206         write_intstr_3(0);
207
208         /* initialize the interrupt vector generator */
209         write_intbase(INTBASE);
210         write_intsize(INTSIZE_4);
211
212         for(i = 0; i <= IRQ_IOP13XX_HPI; i++) {
213                 if (i < 32)
214                         irq_set_chip(i, &iop13xx_irqchip1);
215                 else if (i < 64)
216                         irq_set_chip(i, &iop13xx_irqchip2);
217                 else if (i < 96)
218                         irq_set_chip(i, &iop13xx_irqchip3);
219                 else
220                         irq_set_chip(i, &iop13xx_irqchip4);
221
222                 irq_set_handler(i, handle_level_irq);
223                 irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE);
224         }
225
226         iop13xx_msi_init();
227 }