File Index
Files and directories
Sign in
FILE

sys_sable.c

File preview with syntax highlighting.

linux-6.19.14/arch/alpha/kernel/sys_sable.c C
  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
 32DEFINE_SPINLOCK(sable_lynx_irq_lock);
 33
 34typedef 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
 47static irq_swizzle_t *sable_lynx_irq_swizzle;
 48
 49static 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
 92static void
 93sable_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
108static void
109sable_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
131static 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
157static void __init
158sable_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
195static int
196sable_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
218static inline void
219sable_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
234static void
235sable_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
250static void
251sable_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
263static 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
270static void 
271sable_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
288static void __init
289sable_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
302static void __init
303sable_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
319struct 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};
344ALIAS_MV(sable_gamma)
345#endif /* GENERIC || SABLE */
~/ Read-only file preview.