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 
iomd_get_irq_nr(void)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 
iomd_handle_irq(struct pt_regs * regs)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 
iomd_get_base(struct irq_data * d)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 
iomd_set_base_mask(unsigned int irq,void __iomem * base,u32 mask)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 
iomd_irq_mask_ack(struct irq_data * d)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 
iomd_irq_mask(struct irq_data * d)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 
iomd_irq_unmask(struct irq_data * d)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 
rpc_init_irq(void)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 }
227