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