1/*
2 *	linux/arch/alpha/kernel/sys_cabriolet.c
3 *
4 *	Copyright (C) 1995 David A Rusling
5 *	Copyright (C) 1996 Jay A Estabrook
6 *	Copyright (C) 1998, 1999, 2000 Richard Henderson
7 *
8 * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164,
9 * PC164 and LX164.
10 */
11
12#include <linux/config.h>
13#include <linux/kernel.h>
14#include <linux/types.h>
15#include <linux/mm.h>
16#include <linux/sched.h>
17#include <linux/pci.h>
18#include <linux/init.h>
19
20#include <asm/ptrace.h>
21#include <asm/system.h>
22#include <asm/dma.h>
23#include <asm/irq.h>
24#include <asm/bitops.h>
25#include <asm/mmu_context.h>
26#include <asm/io.h>
27#include <asm/pgtable.h>
28#include <asm/core_apecs.h>
29#include <asm/core_cia.h>
30#include <asm/core_lca.h>
31
32#include "proto.h"
33#include "irq_impl.h"
34#include "pci_impl.h"
35#include "machvec_impl.h"
36
37
38/* Note mask bit is true for DISABLED irqs.  */
39static unsigned long cached_irq_mask = ~0UL;
40
41static inline void
42cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
43{
44	int ofs = (irq - 16) / 8;
45	outb(mask >> (16 + ofs * 8), 0x804 + ofs);
46}
47
48static inline void
49cabriolet_enable_irq(unsigned int irq)
50{
51	cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq));
52}
53
54static void
55cabriolet_disable_irq(unsigned int irq)
56{
57	cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
58}
59
60static unsigned int
61cabriolet_startup_irq(unsigned int irq)
62{
63	cabriolet_enable_irq(irq);
64	return 0; /* never anything pending */
65}
66
67static void
68cabriolet_end_irq(unsigned int irq)
69{
70	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
71		cabriolet_enable_irq(irq);
72}
73
74static struct hw_interrupt_type cabriolet_irq_type = {
75	typename:	"CABRIOLET",
76	startup:	cabriolet_startup_irq,
77	shutdown:	cabriolet_disable_irq,
78	enable:		cabriolet_enable_irq,
79	disable:	cabriolet_disable_irq,
80	ack:		cabriolet_disable_irq,
81	end:		cabriolet_end_irq,
82};
83
84static void
85cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
86{
87	unsigned long pld;
88	unsigned int i;
89
90	/* Read the interrupt summary registers */
91	pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
92
93	/*
94	 * Now for every possible bit set, work through them and call
95	 * the appropriate interrupt handler.
96	 */
97	while (pld) {
98		i = ffz(~pld);
99		pld &= pld - 1;	/* clear least bit set */
100		if (i == 4) {
101			isa_device_interrupt(v, r);
102		} else {
103			handle_irq(16 + i, r);
104		}
105	}
106}
107
108static void __init
109common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r))
110{
111	init_i8259a_irqs();
112
113	if (alpha_using_srm) {
114		alpha_mv.device_interrupt = srm_dev_int;
115		init_srm_irqs(35, 0);
116	}
117	else {
118		long i;
119
120		outb(0xff, 0x804);
121		outb(0xff, 0x805);
122		outb(0xff, 0x806);
123
124		for (i = 16; i < 35; ++i) {
125			irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
126			irq_desc[i].handler = &cabriolet_irq_type;
127		}
128	}
129
130	common_init_isa_dma();
131	setup_irq(16+4, &isa_cascade_irqaction);
132}
133
134static void __init
135cabriolet_init_irq(void)
136{
137	common_init_irq(srm_device_interrupt);
138}
139
140#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
141/* In theory, the PC164 has the same interrupt hardware as the other
142   Cabriolet based systems.  However, something got screwed up late
143   in the development cycle which broke the interrupt masking hardware.
144   Repeat, it is not possible to mask and ack interrupts.  At all.
145
146   In an attempt to work around this, while processing interrupts,
147   we do not allow the IPL to drop below what it is currently.  This
148   prevents the possibility of recursion.
149
150   ??? Another option might be to force all PCI devices to use edge
151   triggered rather than level triggered interrupts.  That might be
152   too invasive though.  */
153
154static void
155pc164_srm_device_interrupt(unsigned long v, struct pt_regs *r)
156{
157	__min_ipl = getipl();
158	srm_device_interrupt(v, r);
159	__min_ipl = 0;
160}
161
162static void
163pc164_device_interrupt(unsigned long v, struct pt_regs *r)
164{
165	__min_ipl = getipl();
166	cabriolet_device_interrupt(v, r);
167	__min_ipl = 0;
168}
169
170static void __init
171pc164_init_irq(void)
172{
173	common_init_irq(pc164_srm_device_interrupt);
174}
175#endif
176
177/*
178 * The EB66+ is very similar to the EB66 except that it does not have
179 * the on-board NCR and Tulip chips.  In the code below, I have used
180 * slot number to refer to the id select line and *not* the slot
181 * number used in the EB66+ documentation.  However, in the table,
182 * I've given the slot number, the id select line and the Jxx number
183 * that's printed on the board.  The interrupt pins from the PCI slots
184 * are wired into 3 interrupt summary registers at 0x804, 0x805 and
185 * 0x806 ISA.
186 *
187 * In the table, -1 means don't assign an IRQ number.  This is usually
188 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
189 */
190
191static inline int __init
192eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
193{
194	static char irq_tab[5][5] __initdata = {
195		/*INT  INTA  INTB  INTC   INTD */
196		{16+0, 16+0, 16+5,  16+9, 16+13},  /* IdSel 6,  slot 0, J25 */
197		{16+1, 16+1, 16+6, 16+10, 16+14},  /* IdSel 7,  slot 1, J26 */
198		{  -1,   -1,   -1,    -1,    -1},  /* IdSel 8,  SIO         */
199		{16+2, 16+2, 16+7, 16+11, 16+15},  /* IdSel 9,  slot 2, J27 */
200		{16+3, 16+3, 16+8, 16+12,  16+6}   /* IdSel 10, slot 3, J28 */
201	};
202	const long min_idsel = 6, max_idsel = 10, irqs_per_slot = 5;
203	return COMMON_TABLE_LOOKUP;
204}
205
206
207/*
208 * The AlphaPC64 is very similar to the EB66+ except that its slots
209 * are numbered differently.  In the code below, I have used slot
210 * number to refer to the id select line and *not* the slot number
211 * used in the AlphaPC64 documentation.  However, in the table, I've
212 * given the slot number, the id select line and the Jxx number that's
213 * printed on the board.  The interrupt pins from the PCI slots are
214 * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806
215 * ISA.
216 *
217 * In the table, -1 means don't assign an IRQ number.  This is usually
218 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
219 */
220
221static inline int __init
222cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
223{
224	static char irq_tab[5][5] __initdata = {
225		/*INT   INTA  INTB  INTC   INTD */
226		{ 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5,  slot 2, J21 */
227		{ 16+0, 16+0, 16+5,  16+9, 16+13}, /* IdSel 6,  slot 0, J19 */
228		{ 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7,  slot 1, J20 */
229		{   -1,   -1,   -1,    -1,    -1}, /* IdSel 8,  SIO         */
230		{ 16+3, 16+3, 16+8, 16+12, 16+16}  /* IdSel 9,  slot 3, J22 */
231	};
232	const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5;
233	return COMMON_TABLE_LOOKUP;
234}
235
236static inline void __init
237cabriolet_init_pci(void)
238{
239	common_init_pci();
240	ns87312_enable_ide(0x398);
241}
242
243static inline void __init
244cia_cab_init_pci(void)
245{
246	cia_init_pci();
247	ns87312_enable_ide(0x398);
248}
249
250/*
251 * The PC164 and LX164 have 19 PCI interrupts, four from each of the four
252 * PCI slots, the SIO, PCI/IDE, and USB.
253 *
254 * Each of the interrupts can be individually masked. This is
255 * accomplished by setting the appropriate bit in the mask register.
256 * A bit is set by writing a "1" to the desired position in the mask
257 * register and cleared by writing a "0". There are 3 mask registers
258 * located at ISA address 804h, 805h and 806h.
259 *
260 * An I/O read at ISA address 804h, 805h, 806h will return the
261 * state of the 11 PCI interrupts and not the state of the MASKED
262 * interrupts.
263 *
264 * Note: A write to I/O 804h, 805h, and 806h the mask register will be
265 * updated.
266 *
267 *
268 * 				ISA DATA<7:0>
269 * ISA     +--------------------------------------------------------------+
270 * ADDRESS |   7   |   6   |   5   |   4   |   3   |   2  |   1   |   0   |
271 *         +==============================================================+
272 * 0x804   | INTB0 |  USB  |  IDE  |  SIO  | INTA3 |INTA2 | INTA1 | INTA0 |
273 *         +--------------------------------------------------------------+
274 * 0x805   | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 |
275 *         +--------------------------------------------------------------+
276 * 0x806   | Rsrv  | Rsrv  | Rsrv  | Rsrv  | Rsrv  |INTD3 | INTD2 | INTD1 |
277 *         +--------------------------------------------------------------+
278 *         * Rsrv = reserved bits
279 *         Note: The mask register is write-only.
280 *
281 * IdSel
282 *   5	 32 bit PCI option slot 2
283 *   6	 64 bit PCI option slot 0
284 *   7	 64 bit PCI option slot 1
285 *   8	 Saturn I/O
286 *   9	 32 bit PCI option slot 3
287 *  10	 USB
288 *  11	 IDE
289 *
290 */
291
292static inline int __init
293alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
294{
295	static char irq_tab[7][5] __initdata = {
296		/*INT   INTA  INTB   INTC   INTD */
297		{ 16+2, 16+2, 16+9,  16+13, 16+17}, /* IdSel  5, slot 2, J20 */
298		{ 16+0, 16+0, 16+7,  16+11, 16+15}, /* IdSel  6, slot 0, J29 */
299		{ 16+1, 16+1, 16+8,  16+12, 16+16}, /* IdSel  7, slot 1, J26 */
300		{   -1,   -1,   -1,    -1,    -1},  /* IdSel  8, SIO */
301		{ 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel  9, slot 3, J19 */
302		{ 16+6, 16+6, 16+6,  16+6,  16+6},  /* IdSel 10, USB */
303		{ 16+5, 16+5, 16+5,  16+5,  16+5}   /* IdSel 11, IDE */
304	};
305	const long min_idsel = 5, max_idsel = 11, irqs_per_slot = 5;
306	return COMMON_TABLE_LOOKUP;
307}
308
309static inline void __init
310alphapc164_init_pci(void)
311{
312	cia_init_pci();
313	SMC93x_Init();
314}
315
316
317/*
318 * The System Vector
319 */
320
321#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET)
322struct alpha_machine_vector cabriolet_mv __initmv = {
323	vector_name:		"Cabriolet",
324	DO_EV4_MMU,
325	DO_DEFAULT_RTC,
326	DO_APECS_IO,
327	DO_APECS_BUS,
328	machine_check:		apecs_machine_check,
329	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
330	min_io_address:		DEFAULT_IO_BASE,
331	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
332
333	nr_irqs:		35,
334	device_interrupt:	cabriolet_device_interrupt,
335
336	init_arch:		apecs_init_arch,
337	init_irq:		cabriolet_init_irq,
338	init_rtc:		common_init_rtc,
339	init_pci:		cabriolet_init_pci,
340	kill_arch:		NULL,
341	pci_map_irq:		cabriolet_map_irq,
342	pci_swizzle:		common_swizzle,
343};
344#ifndef CONFIG_ALPHA_EB64P
345ALIAS_MV(cabriolet)
346#endif
347#endif
348
349#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164)
350struct alpha_machine_vector eb164_mv __initmv = {
351	vector_name:		"EB164",
352	DO_EV5_MMU,
353	DO_DEFAULT_RTC,
354	DO_CIA_IO,
355	DO_CIA_BUS,
356	machine_check:		cia_machine_check,
357	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
358	min_io_address:		DEFAULT_IO_BASE,
359	min_mem_address:	CIA_DEFAULT_MEM_BASE,
360
361	nr_irqs:		35,
362	device_interrupt:	cabriolet_device_interrupt,
363
364	init_arch:		cia_init_arch,
365	init_irq:		cabriolet_init_irq,
366	init_rtc:		common_init_rtc,
367	init_pci:		cia_cab_init_pci,
368	pci_map_irq:		cabriolet_map_irq,
369	pci_swizzle:		common_swizzle,
370};
371ALIAS_MV(eb164)
372#endif
373
374#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P)
375struct alpha_machine_vector eb66p_mv __initmv = {
376	vector_name:		"EB66+",
377	DO_EV4_MMU,
378	DO_DEFAULT_RTC,
379	DO_LCA_IO,
380	DO_LCA_BUS,
381	machine_check:		lca_machine_check,
382	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
383	min_io_address:		DEFAULT_IO_BASE,
384	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
385
386	nr_irqs:		35,
387	device_interrupt:	cabriolet_device_interrupt,
388
389	init_arch:		lca_init_arch,
390	init_irq:		cabriolet_init_irq,
391	init_rtc:		common_init_rtc,
392	init_pci:		cabriolet_init_pci,
393	pci_map_irq:		eb66p_map_irq,
394	pci_swizzle:		common_swizzle,
395};
396ALIAS_MV(eb66p)
397#endif
398
399#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164)
400struct alpha_machine_vector lx164_mv __initmv = {
401	vector_name:		"LX164",
402	DO_EV5_MMU,
403	DO_DEFAULT_RTC,
404	DO_PYXIS_IO,
405	DO_CIA_BUS,
406	machine_check:		cia_machine_check,
407	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
408	min_io_address:		DEFAULT_IO_BASE,
409	min_mem_address:	DEFAULT_MEM_BASE,
410	pci_dac_offset:		PYXIS_DAC_OFFSET,
411
412	nr_irqs:		35,
413	device_interrupt:	cabriolet_device_interrupt,
414
415	init_arch:		pyxis_init_arch,
416	init_irq:		cabriolet_init_irq,
417	init_rtc:		common_init_rtc,
418	init_pci:		alphapc164_init_pci,
419	pci_map_irq:		alphapc164_map_irq,
420	pci_swizzle:		common_swizzle,
421};
422ALIAS_MV(lx164)
423#endif
424
425#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
426struct alpha_machine_vector pc164_mv __initmv = {
427	vector_name:		"PC164",
428	DO_EV5_MMU,
429	DO_DEFAULT_RTC,
430	DO_CIA_IO,
431	DO_CIA_BUS,
432	machine_check:		cia_machine_check,
433	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
434	min_io_address:		DEFAULT_IO_BASE,
435	min_mem_address:	CIA_DEFAULT_MEM_BASE,
436
437	nr_irqs:		35,
438	device_interrupt:	pc164_device_interrupt,
439
440	init_arch:		cia_init_arch,
441	init_irq:		pc164_init_irq,
442	init_rtc:		common_init_rtc,
443	init_pci:		alphapc164_init_pci,
444	pci_map_irq:		alphapc164_map_irq,
445	pci_swizzle:		common_swizzle,
446};
447ALIAS_MV(pc164)
448#endif
449