xref: /openbsd-src/sys/arch/alpha/pci/sio_pic.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: sio_pic.c,v 1.29 2008/08/09 16:41:21 miod Exp $	*/
2 /* $NetBSD: sio_pic.c,v 1.28 2000/06/06 03:10:13 thorpej Exp $ */
3 
4 /*-
5  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
36  * All rights reserved.
37  *
38  * Author: Chris G. Demetriou
39  *
40  * Permission to use, copy, modify and distribute this software and
41  * its documentation is hereby granted, provided that both the copyright
42  * notice and this permission notice appear in all copies of the
43  * software, derivative works or modified versions, and any portions
44  * thereof, and that both notices appear in supporting documentation.
45  *
46  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
48  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49  *
50  * Carnegie Mellon requests users of this software to return to
51  *
52  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53  *  School of Computer Science
54  *  Carnegie Mellon University
55  *  Pittsburgh PA 15213-3890
56  *
57  * any improvements or extensions that they make and grant Carnegie the
58  * rights to redistribute these changes.
59  */
60 
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 
64 #include <sys/device.h>
65 #include <sys/malloc.h>
66 #include <sys/syslog.h>
67 
68 #include <machine/intr.h>
69 #include <machine/bus.h>
70 
71 #include <dev/pci/pcireg.h>
72 #include <dev/pci/pcivar.h>
73 #include <dev/pci/pcidevs.h>
74 
75 #include <dev/pci/cy82c693reg.h>
76 #include <dev/pci/cy82c693var.h>
77 
78 #include <dev/isa/isareg.h>
79 #include <dev/isa/isavar.h>
80 #include <alpha/pci/siovar.h>
81 
82 #include "sio.h"
83 
84 /*
85  * To add to the long history of wonderful PROM console traits,
86  * AlphaStation PROMs don't reset themselves completely on boot!
87  * Therefore, if an interrupt was turned on when the kernel was
88  * started, we're not going to EVER turn it off...  I don't know
89  * what will happen if new interrupts (that the PROM console doesn't
90  * want) are turned on.  I'll burn that bridge when I come to it.
91  */
92 #define	BROKEN_PROM_CONSOLE
93 
94 /*
95  * Private functions and variables.
96  */
97 
98 bus_space_tag_t sio_iot;
99 pci_chipset_tag_t sio_pc;
100 bus_space_handle_t sio_ioh_icu1, sio_ioh_icu2;
101 
102 #define	ICU_LEN		16		/* number of ISA IRQs */
103 
104 static struct alpha_shared_intr *sio_intr;
105 
106 #ifndef STRAY_MAX
107 #define	STRAY_MAX	5
108 #endif
109 
110 #ifdef BROKEN_PROM_CONSOLE
111 /*
112  * If prom console is broken, must remember the initial interrupt
113  * settings and enforce them.  WHEE!
114  */
115 u_int8_t initial_ocw1[2];
116 u_int8_t initial_elcr[2];
117 #endif
118 
119 void		sio_setirqstat(int, int, int);
120 int		sio_intr_alloc(void *, int, int, int *);
121 
122 u_int8_t	(*sio_read_elcr)(int);
123 void		(*sio_write_elcr)(int, u_int8_t);
124 static void	specific_eoi(int);
125 #ifdef BROKEN_PROM_CONSOLE
126 void		sio_intr_shutdown(void *);
127 #endif
128 
129 /******************** i82378 SIO ELCR functions ********************/
130 
131 int		i82378_setup_elcr(void);
132 u_int8_t	i82378_read_elcr(int);
133 void		i82378_write_elcr(int, u_int8_t);
134 
135 bus_space_handle_t sio_ioh_elcr;
136 
137 int
138 i82378_setup_elcr()
139 {
140 	int rv;
141 
142 	/*
143 	 * We could probe configuration space to see that there's
144 	 * actually an SIO present, but we are using this as a
145 	 * fall-back in case nothing else matches.
146 	 */
147 
148 	rv = bus_space_map(sio_iot, 0x4d0, 2, 0, &sio_ioh_elcr);
149 
150 	if (rv == 0) {
151 		sio_read_elcr = i82378_read_elcr;
152 		sio_write_elcr = i82378_write_elcr;
153 	}
154 
155 	return (rv);
156 }
157 
158 u_int8_t
159 i82378_read_elcr(elcr)
160 	int elcr;
161 {
162 
163 	return (bus_space_read_1(sio_iot, sio_ioh_elcr, elcr));
164 }
165 
166 void
167 i82378_write_elcr(elcr, val)
168 	int elcr;
169 	u_int8_t val;
170 {
171 
172 	bus_space_write_1(sio_iot, sio_ioh_elcr, elcr, val);
173 }
174 
175 /******************** Cypress CY82C693 ELCR functions ********************/
176 
177 int		cy82c693_setup_elcr(void);
178 u_int8_t	cy82c693_read_elcr(int);
179 void		cy82c693_write_elcr(int, u_int8_t);
180 
181 const struct cy82c693_handle *sio_cy82c693_handle;
182 
183 int
184 cy82c693_setup_elcr()
185 {
186 	int device, maxndevs;
187 	pcitag_t tag;
188 	pcireg_t id;
189 
190 	/*
191 	 * Search PCI configuration space for a Cypress CY82C693.
192 	 *
193 	 * Note we can make some assumptions about our bus number
194 	 * here, because:
195 	 *
196 	 *	(1) there can be at most one ISA/EISA bridge per PCI bus, and
197 	 *
198 	 *	(2) any ISA/EISA bridges must be attached to primary PCI
199 	 *	    busses (i.e. bus zero).
200 	 */
201 
202 	maxndevs = pci_bus_maxdevs(sio_pc, 0);
203 
204 	for (device = 0; device < maxndevs; device++) {
205 		tag = pci_make_tag(sio_pc, 0, device, 0);
206 		id = pci_conf_read(sio_pc, tag, PCI_ID_REG);
207 
208 		/* Invalid vendor ID value? */
209 		if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
210 			continue;
211 		/* XXX Not invalid, but we've done this ~forever. */
212 		if (PCI_VENDOR(id) == 0)
213 			continue;
214 
215 		if (PCI_VENDOR(id) != PCI_VENDOR_CONTAQ ||
216 		    PCI_PRODUCT(id) != PCI_PRODUCT_CONTAQ_82C693)
217 			continue;
218 
219 		/*
220 		 * Found one!
221 		 */
222 
223 #if 0
224 		printf("cy82c693_setup_elcr: found 82C693 at device %d\n",
225 		    device);
226 #endif
227 
228 		sio_cy82c693_handle = cy82c693_init(sio_iot);
229 		sio_read_elcr = cy82c693_read_elcr;
230 		sio_write_elcr = cy82c693_write_elcr;
231 
232 		return (0);
233 	}
234 
235 	/*
236 	 * Didn't find a CY82C693.
237 	 */
238 	return (ENODEV);
239 }
240 
241 u_int8_t
242 cy82c693_read_elcr(elcr)
243 	int elcr;
244 {
245 
246 	return (cy82c693_read(sio_cy82c693_handle, CONFIG_ELCR1 + elcr));
247 }
248 
249 void
250 cy82c693_write_elcr(elcr, val)
251 	int elcr;
252 	u_int8_t val;
253 {
254 
255 	cy82c693_write(sio_cy82c693_handle, CONFIG_ELCR1 + elcr, val);
256 }
257 
258 /******************** ELCR access function configuration ********************/
259 
260 /*
261  * Put the Intel SIO at the end, so we fall back on it if we don't
262  * find anything else.  If any of the non-Intel functions find a
263  * matching device, but are unable to map it for whatever reason,
264  * they should panic.
265  */
266 
267 int (*sio_elcr_setup_funcs[])(void) = {
268 	cy82c693_setup_elcr,
269 	i82378_setup_elcr,
270 	NULL,
271 };
272 
273 /******************** Shared SIO/Cypress functions ********************/
274 
275 void
276 sio_setirqstat(irq, enabled, type)
277 	int irq, enabled;
278 	int type;
279 {
280 	u_int8_t ocw1[2], elcr[2];
281 	int icu, bit;
282 
283 #if 0
284 	printf("sio_setirqstat: irq %d: %s, %s\n", irq,
285 	    enabled ? "enabled" : "disabled", isa_intr_typename(type));
286 #endif
287 
288 	icu = irq / 8;
289 	bit = irq % 8;
290 
291 	ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
292 	ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
293 	elcr[0] = (*sio_read_elcr)(0);				/* XXX */
294 	elcr[1] = (*sio_read_elcr)(1);				/* XXX */
295 
296 	/*
297 	 * interrupt enable: set bit to mask (disable) interrupt.
298 	 */
299 	if (enabled)
300 		ocw1[icu] &= ~(1 << bit);
301 	else
302 		ocw1[icu] |= 1 << bit;
303 
304 	/*
305 	 * interrupt type select: set bit to get level-triggered.
306 	 */
307 	if (type == IST_LEVEL)
308 		elcr[icu] |= 1 << bit;
309 	else
310 		elcr[icu] &= ~(1 << bit);
311 
312 #ifdef not_here
313 	/* see the init function... */
314 	ocw1[0] &= ~0x04;		/* always enable IRQ2 on first PIC */
315 	elcr[0] &= ~0x07;		/* IRQ[0-2] must be edge-triggered */
316 	elcr[1] &= ~0x21;		/* IRQ[13,8] must be edge-triggered */
317 #endif
318 
319 	bus_space_write_1(sio_iot, sio_ioh_icu1, 1, ocw1[0]);
320 	bus_space_write_1(sio_iot, sio_ioh_icu2, 1, ocw1[1]);
321 	(*sio_write_elcr)(0, elcr[0]);				/* XXX */
322 	(*sio_write_elcr)(1, elcr[1]);				/* XXX */
323 }
324 
325 void
326 sio_intr_setup(pc, iot)
327 	pci_chipset_tag_t pc;
328 	bus_space_tag_t iot;
329 {
330 #ifdef notyet
331 	char *cp;
332 #endif
333 	int i;
334 
335 	sio_iot = iot;
336 	sio_pc = pc;
337 
338 	if (bus_space_map(sio_iot, IO_ICU1, 2, 0, &sio_ioh_icu1) ||
339 	    bus_space_map(sio_iot, IO_ICU2, 2, 0, &sio_ioh_icu2))
340 		panic("sio_intr_setup: can't map ICU I/O ports");
341 
342 	for (i = 0; sio_elcr_setup_funcs[i] != NULL; i++)
343 		if ((*sio_elcr_setup_funcs[i])() == 0)
344 			break;
345 	if (sio_elcr_setup_funcs[i] == NULL)
346 		panic("sio_intr_setup: can't map ELCR");
347 
348 #ifdef BROKEN_PROM_CONSOLE
349 	/*
350 	 * Remember the initial values, so we can restore them later.
351 	 */
352 	initial_ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
353 	initial_ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
354 	initial_elcr[0] = (*sio_read_elcr)(0);			/* XXX */
355 	initial_elcr[1] = (*sio_read_elcr)(1);			/* XXX */
356 	shutdownhook_establish(sio_intr_shutdown, 0);
357 #endif
358 
359 	sio_intr = alpha_shared_intr_alloc(ICU_LEN);
360 
361 	/*
362 	 * set up initial values for interrupt enables.
363 	 */
364 	for (i = 0; i < ICU_LEN; i++) {
365 		alpha_shared_intr_set_maxstrays(sio_intr, i, STRAY_MAX);
366 
367 		switch (i) {
368 		case 0:
369 		case 1:
370 		case 8:
371 		case 13:
372 			/*
373 			 * IRQs 0, 1, 8, and 13 must always be
374 			 * edge-triggered.
375 			 */
376 			sio_setirqstat(i, 0, IST_EDGE);
377 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
378 			    IST_EDGE);
379 			specific_eoi(i);
380 			break;
381 
382 		case 2:
383 			/*
384 			 * IRQ 2 must be edge-triggered, and should be
385 			 * enabled (otherwise IRQs 8-15 are ignored).
386 			 */
387 			sio_setirqstat(i, 1, IST_EDGE);
388 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
389 			    IST_UNUSABLE);
390 			break;
391 
392 		default:
393 			/*
394 			 * Otherwise, disable the IRQ and set its
395 			 * type to (effectively) "unknown."
396 			 */
397 			sio_setirqstat(i, 0, IST_NONE);
398 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
399 			    IST_NONE);
400 			specific_eoi(i);
401 			break;
402 		}
403 	}
404 }
405 
406 #ifdef BROKEN_PROM_CONSOLE
407 void
408 sio_intr_shutdown(arg)
409 	void *arg;
410 {
411 	/*
412 	 * Restore the initial values, to make the PROM happy.
413 	 */
414 	bus_space_write_1(sio_iot, sio_ioh_icu1, 1, initial_ocw1[0]);
415 	bus_space_write_1(sio_iot, sio_ioh_icu2, 1, initial_ocw1[1]);
416 	(*sio_write_elcr)(0, initial_elcr[0]);			/* XXX */
417 	(*sio_write_elcr)(1, initial_elcr[1]);			/* XXX */
418 }
419 #endif
420 
421 const char *
422 sio_intr_string(v, irq)
423 	void *v;
424 	int irq;
425 {
426 	static char irqstr[12];		/* 8 + 2 + NULL + sanity */
427 
428 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
429 		panic("sio_intr_string: bogus isa irq 0x%x", irq);
430 
431 	snprintf(irqstr, sizeof irqstr, "isa irq %d", irq);
432 	return (irqstr);
433 }
434 
435 int
436 sio_intr_line(v, irq)
437 	void *v;
438 	int irq;
439 {
440 	return (irq);
441 }
442 
443 void *
444 sio_intr_establish(v, irq, type, level, fn, arg, name)
445 	void *v, *arg;
446         int irq;
447         int type;
448         int level;
449         int (*fn)(void *);
450 	char *name;
451 {
452 	void *cookie;
453 
454 	if (irq >= ICU_LEN || type == IST_NONE)
455 		panic("sio_intr_establish: bogus irq or type");
456 
457 	cookie = alpha_shared_intr_establish(sio_intr, irq, type, level, fn,
458 	    arg, name);
459 
460 	if (cookie != NULL &&
461 	    alpha_shared_intr_firstactive(sio_intr, irq)) {
462 		scb_set(0x800 + SCB_IDXTOVEC(irq), sio_iointr, NULL);
463 		sio_setirqstat(irq, 1,
464 		    alpha_shared_intr_get_sharetype(sio_intr, irq));
465 	}
466 
467 	return (cookie);
468 }
469 
470 void
471 sio_intr_disestablish(v, cookie)
472 	void *v;
473 	void *cookie;
474 {
475 	struct alpha_shared_intrhand *ih = cookie;
476 	int s, ist, irq = ih->ih_num;
477 
478 	s = splhigh();
479 
480 	/* Remove it from the link. */
481 	alpha_shared_intr_disestablish(sio_intr, cookie, "isa irq");
482 
483 	/*
484 	 * Decide if we should disable the interrupt.  We must ensure
485 	 * that:
486 	 *
487 	 *	- An initially-enabled interrupt is never disabled.
488 	 *	- An initially-LT interrupt is never untyped.
489 	 */
490 	if (alpha_shared_intr_isactive(sio_intr, irq) == 0) {
491 		/*
492 		 * IRQs 0, 1, 8, and 13 must always be edge-triggered
493 		 * (see setup).
494 		 */
495 		switch (irq) {
496 		case 0:
497 		case 1:
498 		case 8:
499 		case 13:
500 			/*
501 			 * If the interrupt was initially level-triggered
502 			 * a warning was printed in setup.
503 			 */
504 			ist = IST_EDGE;
505 			break;
506 
507 		default:
508 			ist = IST_NONE;
509 			break;
510 		}
511 		sio_setirqstat(irq, 0, ist);
512 		alpha_shared_intr_set_dfltsharetype(sio_intr, irq, ist);
513 
514 		/* Release our SCB vector. */
515 		scb_free(0x800 + SCB_IDXTOVEC(irq));
516 	}
517 
518 	splx(s);
519 }
520 
521 void
522 sio_iointr(arg, vec)
523 	void *arg;
524 	unsigned long vec;
525 {
526 	int irq;
527 
528 	irq = SCB_VECTOIDX(vec - 0x800);
529 
530 #ifdef DIAGNOSTIC
531 	if (irq >= ICU_LEN || irq < 0)
532 		panic("sio_iointr: irq out of range (%d)", irq);
533 #endif
534 
535 	if (!alpha_shared_intr_dispatch(sio_intr, irq))
536 		alpha_shared_intr_stray(sio_intr, irq, "isa irq");
537 	else
538 		alpha_shared_intr_reset_strays(sio_intr, irq);
539 
540 	/*
541 	 * Some versions of the machines which use the SIO
542 	 * (or is it some PALcode revisions on those machines?)
543 	 * require the non-specific EOI to be fed to the PIC(s)
544 	 * by the interrupt handler.
545 	 */
546 	specific_eoi(irq);
547 }
548 
549 #define	LEGAL_IRQ(x)	((x) >= 0 && (x) < ICU_LEN && (x) != 2)
550 
551 int
552 sio_intr_alloc(v, mask, type, irq)
553 	void *v;
554 	int mask;
555 	int type;
556 	int *irq;
557 {
558 	int i, tmp, bestirq, count;
559 	struct alpha_shared_intrhand **p, *q;
560 
561 	if (type == IST_NONE)
562 		panic("intr_alloc: bogus type");
563 
564 	bestirq = -1;
565 	count = -1;
566 
567 	/* some interrupts should never be dynamically allocated */
568 	mask &= 0xdef8;
569 
570 	/*
571 	 * XXX some interrupts will be used later (6 for fdc, 12 for pms).
572 	 * the right answer is to do "breadth-first" searching of devices.
573 	 */
574 	mask &= 0xefbf;
575 
576 	for (i = 0; i < ICU_LEN; i++) {
577 		if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
578 			continue;
579 
580 		switch(sio_intr[i].intr_sharetype) {
581 		case IST_NONE:
582 			/*
583 			 * if nothing's using the irq, just return it
584 			 */
585 			*irq = i;
586 			return (0);
587 
588 		case IST_EDGE:
589 		case IST_LEVEL:
590 			if (type != sio_intr[i].intr_sharetype)
591 				continue;
592 			/*
593 			 * if the irq is shareable, count the number of other
594 			 * handlers, and if it's smaller than the last irq like
595 			 * this, remember it
596 			 *
597 			 * XXX We should probably also consider the
598 			 * interrupt level and stick IPL_TTY with other
599 			 * IPL_TTY, etc.
600 			 */
601 			for (p = &TAILQ_FIRST(&sio_intr[i].intr_q), tmp = 0;
602 			     (q = *p) != NULL; p = &TAILQ_NEXT(q, ih_q), tmp++)
603 				;
604 			if ((bestirq == -1) || (count > tmp)) {
605 				bestirq = i;
606 				count = tmp;
607 			}
608 			break;
609 
610 		case IST_PULSE:
611 			/* this just isn't shareable */
612 			continue;
613 		}
614 	}
615 
616 	if (bestirq == -1)
617 		return (1);
618 
619 	*irq = bestirq;
620 
621 	return (0);
622 }
623 
624 static void
625 specific_eoi(irq)
626 	int irq;
627 {
628 	if (irq > 7) {
629 		bus_space_write_1(sio_iot,
630 		    sio_ioh_icu2, 0, 0x60 | (irq & 0x07));	/* XXX */
631 		irq = 2;
632 	}
633 	bus_space_write_1(sio_iot, sio_ioh_icu1, 0, 0x60 | irq);
634 }
635