GNU Linux-libre 5.19-rc6-gnu
[releases.git] / arch / arm / mach-rpc / irq.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/init.h>
3 #include <linux/list.h>
4 #include <linux/io.h>
5
6 #include <asm/mach/irq.h>
7 #include <asm/hardware/iomd.h>
8 #include <asm/irq.h>
9 #include <asm/fiq.h>
10
11 // These are offsets from the stat register for each IRQ bank
12 #define STAT    0x00
13 #define REQ     0x04
14 #define CLR     0x04
15 #define MASK    0x08
16
17 static const u8 irq_prio_h[256] = {
18          0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10,
19         12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10,
20         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
21         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
22         14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10,
23         14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10,
24         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
25         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
26         15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
27         15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
28         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
29         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
30         15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
31         15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
32         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
33         13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
34 };
35
36 static const u8 irq_prio_d[256] = {
37          0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
38         20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
39         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
40         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
41         22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
42         22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
43         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
44         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
45         23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
46         23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
47         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
48         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
49         22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
50         22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
51         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
52         21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
53 };
54
55 static const u8 irq_prio_l[256] = {
56          0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
57          4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
58          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
59          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
60          6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3,
61          6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3,
62          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
63          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
64          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
65          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
66          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
67          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
68          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
69          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
70          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
71          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
72 };
73
74 static int iomd_get_irq_nr(void)
75 {
76         int irq;
77         u8 reg;
78
79         /* get highest priority first */
80         reg = readb(IOC_BASE + IOMD_IRQREQB);
81         irq = irq_prio_h[reg];
82         if (irq)
83                 return irq;
84
85         /* get DMA  */
86         reg = readb(IOC_BASE + IOMD_DMAREQ);
87         irq = irq_prio_d[reg];
88         if (irq)
89                 return irq;
90
91         /* get low priority */
92         reg = readb(IOC_BASE + IOMD_IRQREQA);
93         irq = irq_prio_l[reg];
94         if (irq)
95                 return irq;
96         return 0;
97 }
98
99 static void iomd_handle_irq(struct pt_regs *regs)
100 {
101         int irq;
102
103         do {
104                 irq = iomd_get_irq_nr();
105                 if (irq)
106                         generic_handle_irq(irq);
107         } while (irq);
108 }
109
110 static void __iomem *iomd_get_base(struct irq_data *d)
111 {
112         void *cd = irq_data_get_irq_chip_data(d);
113
114         return (void __iomem *)(unsigned long)cd;
115 }
116
117 static void iomd_set_base_mask(unsigned int irq, void __iomem *base, u32 mask)
118 {
119         struct irq_data *d = irq_get_irq_data(irq);
120
121         d->mask = mask;
122         irq_set_chip_data(irq, (void *)(unsigned long)base);
123 }
124
125 static void iomd_irq_mask_ack(struct irq_data *d)
126 {
127         void __iomem *base = iomd_get_base(d);
128         unsigned int val, mask = d->mask;
129
130         val = readb(base + MASK);
131         writeb(val & ~mask, base + MASK);
132         writeb(mask, base + CLR);
133 }
134
135 static void iomd_irq_mask(struct irq_data *d)
136 {
137         void __iomem *base = iomd_get_base(d);
138         unsigned int val, mask = d->mask;
139
140         val = readb(base + MASK);
141         writeb(val & ~mask, base + MASK);
142 }
143
144 static void iomd_irq_unmask(struct irq_data *d)
145 {
146         void __iomem *base = iomd_get_base(d);
147         unsigned int val, mask = d->mask;
148
149         val = readb(base + MASK);
150         writeb(val | mask, base + MASK);
151 }
152
153 static struct irq_chip iomd_chip_clr = {
154         .irq_mask_ack   = iomd_irq_mask_ack,
155         .irq_mask       = iomd_irq_mask,
156         .irq_unmask     = iomd_irq_unmask,
157 };
158
159 static struct irq_chip iomd_chip_noclr = {
160         .irq_mask       = iomd_irq_mask,
161         .irq_unmask     = iomd_irq_unmask,
162 };
163
164 extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;
165
166 void __init rpc_init_irq(void)
167 {
168         unsigned int irq, clr, set;
169
170         iomd_writeb(0, IOMD_IRQMASKA);
171         iomd_writeb(0, IOMD_IRQMASKB);
172         iomd_writeb(0, IOMD_FIQMASK);
173         iomd_writeb(0, IOMD_DMAMASK);
174
175         set_fiq_handler(&rpc_default_fiq_start,
176                 &rpc_default_fiq_end - &rpc_default_fiq_start);
177
178         set_handle_irq(iomd_handle_irq);
179
180         for (irq = 0; irq < NR_IRQS; irq++) {
181                 clr = IRQ_NOREQUEST;
182                 set = 0;
183
184                 if (irq <= 6 || (irq >= 9 && irq <= 15))
185                         clr |= IRQ_NOPROBE;
186
187                 if (irq == 21 || (irq >= 16 && irq <= 19) ||
188                     irq == IRQ_KEYBOARDTX)
189                         set |= IRQ_NOAUTOEN;
190
191                 switch (irq) {
192                 case 0 ... 7:
193                         irq_set_chip_and_handler(irq, &iomd_chip_clr,
194                                                  handle_level_irq);
195                         irq_modify_status(irq, clr, set);
196                         iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATA,
197                                            BIT(irq));
198                         break;
199
200                 case 8 ... 15:
201                         irq_set_chip_and_handler(irq, &iomd_chip_noclr,
202                                                  handle_level_irq);
203                         irq_modify_status(irq, clr, set);
204                         iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATB,
205                                            BIT(irq - 8));
206                         break;
207
208                 case 16 ... 21:
209                         irq_set_chip_and_handler(irq, &iomd_chip_noclr,
210                                                  handle_level_irq);
211                         irq_modify_status(irq, clr, set);
212                         iomd_set_base_mask(irq, IOMD_BASE + IOMD_DMASTAT,
213                                            BIT(irq - 16));
214                         break;
215
216                 case 64 ... 71:
217                         irq_set_chip(irq, &iomd_chip_noclr);
218                         irq_modify_status(irq, clr, set);
219                         iomd_set_base_mask(irq, IOMD_BASE + IOMD_FIQSTAT,
220                                            BIT(irq - 64));
221                         break;
222                 }
223         }
224
225         init_FIQ(FIQ_START);
226 }