xref: /linux/arch/alpha/kernel/sys_sable.c (revision 55d0969c451159cff86949b38c39171cab962069)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *	linux/arch/alpha/kernel/sys_sable.c
4  *
5  *	Copyright (C) 1995 David A Rusling
6  *	Copyright (C) 1996 Jay A Estabrook
7  *	Copyright (C) 1998, 1999 Richard Henderson
8  *
9  * Code supporting the Sable, Sable-Gamma, and Lynx systems.
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <linux/mm.h>
15 #include <linux/sched.h>
16 #include <linux/pci.h>
17 #include <linux/init.h>
18 
19 #include <asm/ptrace.h>
20 #include <asm/dma.h>
21 #include <asm/irq.h>
22 #include <asm/mmu_context.h>
23 #include <asm/io.h>
24 #include <asm/core_t2.h>
25 #include <asm/tlbflush.h>
26 
27 #include "proto.h"
28 #include "irq_impl.h"
29 #include "pci_impl.h"
30 #include "machvec_impl.h"
31 
32 DEFINE_SPINLOCK(sable_lynx_irq_lock);
33 
34 typedef struct irq_swizzle_struct
35 {
36 	char irq_to_mask[64];
37 	char mask_to_irq[64];
38 
39 	/* Note mask bit is true for DISABLED irqs.  */
40 	unsigned long shadow_mask;
41 
42 	void (*update_irq_hw)(unsigned long bit, unsigned long mask);
43 	void (*ack_irq_hw)(unsigned long bit);
44 
45 } irq_swizzle_t;
46 
47 static irq_swizzle_t *sable_lynx_irq_swizzle;
48 
49 static void sable_lynx_init_irq(int nr_of_irqs);
50 
51 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SABLE)
52 
53 /***********************************************************************/
54 /*
55  *   For SABLE, which is really baroque, we manage 40 IRQ's, but the
56  *   hardware really only supports 24, not via normal ISA PIC,
57  *   but cascaded custom 8259's, etc.
58  *	 0-7  (char at 536)
59  *	 8-15 (char at 53a)
60  *	16-23 (char at 53c)
61  *
62  * Summary Registers (536/53a/53c):
63  *
64  * Bit      Meaning               Kernel IRQ
65  *------------------------------------------
66  * 0        PCI slot 0			34
67  * 1        NCR810 (builtin)		33
68  * 2        TULIP (builtin)		32
69  * 3        mouse			12
70  * 4        PCI slot 1			35
71  * 5        PCI slot 2			36
72  * 6        keyboard			1
73  * 7        floppy			6
74  * 8        COM2			3
75  * 9        parallel port		7
76  *10        EISA irq 3			-
77  *11        EISA irq 4			-
78  *12        EISA irq 5			5
79  *13        EISA irq 6			-
80  *14        EISA irq 7			-
81  *15        COM1			4
82  *16        EISA irq 9			9
83  *17        EISA irq 10			10
84  *18        EISA irq 11			11
85  *19        EISA irq 12			-
86  *20        EISA irq 13			-
87  *21        EISA irq 14			14
88  *22        NC				15
89  *23        IIC				-
90  */
91 
92 static void
93 sable_update_irq_hw(unsigned long bit, unsigned long mask)
94 {
95 	int port = 0x537;
96 
97 	if (bit >= 16) {
98 		port = 0x53d;
99 		mask >>= 16;
100 	} else if (bit >= 8) {
101 		port = 0x53b;
102 		mask >>= 8;
103 	}
104 
105 	outb(mask, port);
106 }
107 
108 static void
109 sable_ack_irq_hw(unsigned long bit)
110 {
111 	int port, val1, val2;
112 
113 	if (bit >= 16) {
114 		port = 0x53c;
115 		val1 = 0xE0 | (bit - 16);
116 		val2 = 0xE0 | 4;
117 	} else if (bit >= 8) {
118 		port = 0x53a;
119 		val1 = 0xE0 | (bit - 8);
120 		val2 = 0xE0 | 3;
121 	} else {
122 		port = 0x536;
123 		val1 = 0xE0 | (bit - 0);
124 		val2 = 0xE0 | 1;
125 	}
126 
127 	outb(val1, port);	/* ack the slave */
128 	outb(val2, 0x534);	/* ack the master */
129 }
130 
131 static irq_swizzle_t sable_irq_swizzle = {
132 	{
133 		-1,  6, -1,  8, 15, 12,  7,  9,	/* pseudo PIC  0-7  */
134 		-1, 16, 17, 18,  3, -1, 21, 22,	/* pseudo PIC  8-15 */
135 		-1, -1, -1, -1, -1, -1, -1, -1,	/* pseudo EISA 0-7  */
136 		-1, -1, -1, -1, -1, -1, -1, -1,	/* pseudo EISA 8-15  */
137 		 2,  1,  0,  4,  5, -1, -1, -1,	/* pseudo PCI */
138 		-1, -1, -1, -1, -1, -1, -1, -1,	/*  */
139 		-1, -1, -1, -1, -1, -1, -1, -1,	/*  */
140 		-1, -1, -1, -1, -1, -1, -1, -1 	/*  */
141 	},
142 	{
143 		34, 33, 32, 12, 35, 36,  1,  6,	/* mask 0-7  */
144 		 3,  7, -1, -1,  5, -1, -1,  4,	/* mask 8-15  */
145 		 9, 10, 11, -1, -1, 14, 15, -1,	/* mask 16-23  */
146 		-1, -1, -1, -1, -1, -1, -1, -1,	/*  */
147 		-1, -1, -1, -1, -1, -1, -1, -1,	/*  */
148 		-1, -1, -1, -1, -1, -1, -1, -1,	/*  */
149 		-1, -1, -1, -1, -1, -1, -1, -1,	/*  */
150 		-1, -1, -1, -1, -1, -1, -1, -1	/*  */
151 	},
152 	-1,
153 	sable_update_irq_hw,
154 	sable_ack_irq_hw
155 };
156 
157 static void __init
158 sable_init_irq(void)
159 {
160 	outb(-1, 0x537);	/* slave 0 */
161 	outb(-1, 0x53b);	/* slave 1 */
162 	outb(-1, 0x53d);	/* slave 2 */
163 	outb(0x44, 0x535);	/* enable cascades in master */
164 
165 	sable_lynx_irq_swizzle = &sable_irq_swizzle;
166 	sable_lynx_init_irq(40);
167 }
168 
169 /*
170  * PCI Fixup configuration for ALPHA SABLE (2100).
171  *
172  * The device to slot mapping looks like:
173  *
174  * Slot     Device
175  *  0       TULIP
176  *  1       SCSI
177  *  2       PCI-EISA bridge
178  *  3       none
179  *  4       none
180  *  5       none
181  *  6       PCI on board slot 0
182  *  7       PCI on board slot 1
183  *  8       PCI on board slot 2
184  *
185  *
186  * This two layered interrupt approach means that we allocate IRQ 16 and
187  * above for PCI interrupts.  The IRQ relates to which bit the interrupt
188  * comes in on.  This makes interrupt processing much easier.
189  */
190 /*
191  * NOTE: the IRQ assignments below are arbitrary, but need to be consistent
192  * with the values in the irq swizzling tables above.
193  */
194 
195 static int
196 sable_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
197 {
198 	static char irq_tab[9][5] = {
199 		/*INT    INTA   INTB   INTC   INTD */
200 		{ 32+0,  32+0,  32+0,  32+0,  32+0},  /* IdSel 0,  TULIP  */
201 		{ 32+1,  32+1,  32+1,  32+1,  32+1},  /* IdSel 1,  SCSI   */
202 		{   -1,    -1,    -1,    -1,    -1},  /* IdSel 2,  SIO   */
203 		{   -1,    -1,    -1,    -1,    -1},  /* IdSel 3,  none   */
204 		{   -1,    -1,    -1,    -1,    -1},  /* IdSel 4,  none   */
205 		{   -1,    -1,    -1,    -1,    -1},  /* IdSel 5,  none   */
206 		{ 32+2,  32+2,  32+2,  32+2,  32+2},  /* IdSel 6,  slot 0 */
207 		{ 32+3,  32+3,  32+3,  32+3,  32+3},  /* IdSel 7,  slot 1 */
208 		{ 32+4,  32+4,  32+4,  32+4,  32+4}   /* IdSel 8,  slot 2 */
209 	};
210 	long min_idsel = 0, max_idsel = 8, irqs_per_slot = 5;
211 	return COMMON_TABLE_LOOKUP;
212 }
213 #endif /* defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SABLE) */
214 
215 /***********************************************************************/
216 /* GENERIC irq routines */
217 
218 static inline void
219 sable_lynx_enable_irq(struct irq_data *d)
220 {
221 	unsigned long bit, mask;
222 
223 	bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
224 	spin_lock(&sable_lynx_irq_lock);
225 	mask = sable_lynx_irq_swizzle->shadow_mask &= ~(1UL << bit);
226 	sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
227 	spin_unlock(&sable_lynx_irq_lock);
228 #if 0
229 	printk("%s: mask 0x%lx bit 0x%lx irq 0x%x\n",
230 	       __func__, mask, bit, irq);
231 #endif
232 }
233 
234 static void
235 sable_lynx_disable_irq(struct irq_data *d)
236 {
237 	unsigned long bit, mask;
238 
239 	bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
240 	spin_lock(&sable_lynx_irq_lock);
241 	mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
242 	sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
243 	spin_unlock(&sable_lynx_irq_lock);
244 #if 0
245 	printk("%s: mask 0x%lx bit 0x%lx irq 0x%x\n",
246 	       __func__, mask, bit, irq);
247 #endif
248 }
249 
250 static void
251 sable_lynx_mask_and_ack_irq(struct irq_data *d)
252 {
253 	unsigned long bit, mask;
254 
255 	bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
256 	spin_lock(&sable_lynx_irq_lock);
257 	mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
258 	sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
259 	sable_lynx_irq_swizzle->ack_irq_hw(bit);
260 	spin_unlock(&sable_lynx_irq_lock);
261 }
262 
263 static struct irq_chip sable_lynx_irq_type = {
264 	.name		= "SABLE/LYNX",
265 	.irq_unmask	= sable_lynx_enable_irq,
266 	.irq_mask	= sable_lynx_disable_irq,
267 	.irq_mask_ack	= sable_lynx_mask_and_ack_irq,
268 };
269 
270 static void
271 sable_lynx_srm_device_interrupt(unsigned long vector)
272 {
273 	/* Note that the vector reported by the SRM PALcode corresponds
274 	   to the interrupt mask bits, but we have to manage via the
275 	   so-called legacy IRQs for many common devices.  */
276 
277 	int bit, irq;
278 
279 	bit = (vector - 0x800) >> 4;
280 	irq = sable_lynx_irq_swizzle->mask_to_irq[bit];
281 #if 0
282 	printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n",
283 	       __func__, vector, bit, irq);
284 #endif
285 	handle_irq(irq);
286 }
287 
288 static void __init
289 sable_lynx_init_irq(int nr_of_irqs)
290 {
291 	long i;
292 
293 	for (i = 0; i < nr_of_irqs; ++i) {
294 		irq_set_chip_and_handler(i, &sable_lynx_irq_type,
295 					 handle_level_irq);
296 		irq_set_status_flags(i, IRQ_LEVEL);
297 	}
298 
299 	common_init_isa_dma();
300 }
301 
302 static void __init
303 sable_lynx_init_pci(void)
304 {
305 	common_init_pci();
306 }
307 
308 /*****************************************************************/
309 /*
310  * The System Vectors
311  *
312  * In order that T2_HAE_ADDRESS should be a constant, we play
313  * these games with GAMMA_BIAS.
314  */
315 
316 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SABLE)
317 #undef GAMMA_BIAS
318 #define GAMMA_BIAS _GAMMA_BIAS
319 struct alpha_machine_vector sable_gamma_mv __initmv = {
320 	.vector_name		= "Sable-Gamma",
321 	DO_EV5_MMU,
322 	DO_DEFAULT_RTC,
323 	DO_T2_IO,
324 	.machine_check		= t2_machine_check,
325 	.max_isa_dma_address	= ALPHA_SABLE_MAX_ISA_DMA_ADDRESS,
326 	.min_io_address		= EISA_DEFAULT_IO_BASE,
327 	.min_mem_address	= T2_DEFAULT_MEM_BASE,
328 
329 	.nr_irqs		= 40,
330 	.device_interrupt	= sable_lynx_srm_device_interrupt,
331 
332 	.init_arch		= t2_init_arch,
333 	.init_irq		= sable_init_irq,
334 	.init_rtc		= common_init_rtc,
335 	.init_pci		= sable_lynx_init_pci,
336 	.kill_arch		= t2_kill_arch,
337 	.pci_map_irq		= sable_map_irq,
338 	.pci_swizzle		= common_swizzle,
339 
340 	.sys = { .t2 = {
341 	    .gamma_bias		= _GAMMA_BIAS
342 	} }
343 };
344 ALIAS_MV(sable_gamma)
345 #endif /* GENERIC || SABLE */
346