1/*	$NetBSD: isabus.c,v 1.47 2009/12/16 23:19:07 matt Exp $	*/
2/*	$OpenBSD: isabus.c,v 1.15 1998/03/16 09:38:46 pefo Exp $	*/
3/*	NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp 	*/
4
5/*-
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * William Jolitz and Don Ahn.
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 * 3. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)isa.c	7.2 (Berkeley) 5/12/91
37 */
38/*-
39 * Copyright (c) 1995 Per Fogelstrom
40 * Copyright (c) 1993, 1994 Charles M. Hannum.
41 *
42 * This code is derived from software contributed to Berkeley by
43 * William Jolitz and Don Ahn.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 *    notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 *    notice, this list of conditions and the following disclaimer in the
52 *    documentation and/or other materials provided with the distribution.
53 * 3. All advertising materials mentioning features or use of this software
54 *    must display the following acknowledgement:
55 *	This product includes software developed by the University of
56 *	California, Berkeley and its contributors.
57 * 4. Neither the name of the University nor the names of its contributors
58 *    may be used to endorse or promote products derived from this software
59 *    without specific prior written permission.
60 *
61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * SUCH DAMAGE.
72 *
73 *	@(#)isa.c	7.2 (Berkeley) 5/12/91
74 */
75/*
76 * Mach Operating System
77 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
78 * All Rights Reserved.
79 *
80 * Permission to use, copy, modify and distribute this software and its
81 * documentation is hereby granted, provided that both the copyright
82 * notice and this permission notice appear in all copies of the
83 * software, derivative works or modified versions, and any portions
84 * thereof, and that both notices appear in supporting documentation.
85 *
86 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
87 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
88 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
89 *
90 * Carnegie Mellon requests users of this software to return to
91 *
92 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
93 *  School of Computer Science
94 *  Carnegie Mellon University
95 *  Pittsburgh PA 15213-3890
96 *
97 * any improvements or extensions that they make and grant Carnegie Mellon
98 * the rights to redistribute these changes.
99 */
100/*
101  Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
102
103		All Rights Reserved
104
105Permission to use, copy, modify, and distribute this software and
106its documentation for any purpose and without fee is hereby
107granted, provided that the above copyright notice appears in all
108copies and that both the copyright notice and this permission notice
109appear in supporting documentation, and that the name of Intel
110not be used in advertising or publicity pertaining to distribution
111of the software without specific, written prior permission.
112
113INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
114INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
115IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
116CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
117LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
118NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
119WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
120*/
121
122#include <sys/cdefs.h>
123__KERNEL_RCSID(0, "$NetBSD: isabus.c,v 1.47 2009/12/16 23:19:07 matt Exp $");
124
125#include <sys/param.h>
126#include <sys/proc.h>
127#include <sys/systm.h>
128#include <sys/callout.h>
129#include <sys/time.h>
130#include <sys/kernel.h>
131#include <sys/device.h>
132#include <sys/malloc.h>
133#include <sys/extent.h>
134
135#include <uvm/uvm_extern.h>
136
137#include <machine/cpu.h>
138#include <machine/pio.h>
139#include <machine/autoconf.h>
140#include <machine/intr.h>
141
142#include <mips/locore.h>
143
144#include <dev/ic/i8253reg.h>
145#include <dev/ic/i8259reg.h>
146#include <dev/isa/isareg.h>
147#include <dev/isa/isavar.h>
148#include <arc/isa/isabrvar.h>
149#include <arc/isa/spkrreg.h>
150
151#include <arc/arc/timervar.h>
152
153static int beeping;
154static callout_t sysbeep_ch;
155
156static long isa_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
157static long isa_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
158
159#define	IRQ_SLAVE	2
160
161/* Definition of the driver for autoconfig. */
162static int isabrprint(void *, const char *);
163
164extern struct arc_bus_space arc_bus_io, arc_bus_mem;
165
166static void isabr_attach_hook(device_t , device_t,
167    struct isabus_attach_args *);
168static void isabr_detach_hook(isa_chipset_tag_t, device_t);
169static const struct evcnt *isabr_intr_evcnt(isa_chipset_tag_t, int);
170static void *isabr_intr_establish(isa_chipset_tag_t, int, int, int,
171    int (*)(void *), void *);
172static void isabr_intr_disestablish(isa_chipset_tag_t, void*);
173static void isabr_initicu(void);
174static void intr_calculatemasks(void);
175static int fakeintr(void *a);
176
177struct isabr_config *isabr_conf = NULL;
178uint32_t imask[_IPL_N];	/* XXX */
179
180void
181isabrattach(struct isabr_softc *sc)
182{
183	struct isabus_attach_args iba;
184
185	callout_init(&sysbeep_ch, 0);
186
187	if (isabr_conf == NULL)
188		panic("isabr_conf isn't initialized");
189
190	aprint_normal("\n");
191
192	/* Initialize interrupt controller */
193	isabr_initicu();
194
195	sc->arc_isa_cs.ic_attach_hook = isabr_attach_hook;
196	sc->arc_isa_cs.ic_detach_hook = isabr_detach_hook;
197	sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt;
198	sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
199	sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
200
201	arc_bus_space_init_extent(&arc_bus_mem, (void *)isa_mem_ex_storage,
202	    sizeof(isa_mem_ex_storage));
203	arc_bus_space_init_extent(&arc_bus_io, (void *)isa_io_ex_storage,
204	    sizeof(isa_io_ex_storage));
205
206	iba.iba_iot = &arc_bus_io;
207	iba.iba_memt = &arc_bus_mem;
208	iba.iba_dmat = &sc->sc_dmat;
209	iba.iba_ic = &sc->arc_isa_cs;
210	config_found_ia(sc->sc_dev, "isabus", &iba, isabrprint);
211}
212
213static int
214isabrprint(void *aux, const char *pnp)
215{
216
217        if (pnp)
218                aprint_normal("isa at %s", pnp);
219        aprint_verbose(" isa_io_base 0x%"PRIxVADDR" isa_mem_base 0x%"PRIxVADDR,
220	    arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase);
221        return UNCONF;
222}
223
224
225/*
226 *	Interrupt system driver code
227 *	============================
228 */
229#define LEGAL_IRQ(x)    ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
230
231int	imen;
232int	intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
233struct isa_intrhand *isa_intrhand[ICU_LEN];
234
235static int
236fakeintr(void *a)
237{
238
239	return 0;
240}
241
242/*
243 * Recalculate the interrupt masks from scratch.
244 * We could code special registry and deregistry versions of this function that
245 * would be faster, but the code would be nastier, and we don't expect this to
246 * happen very much anyway.
247 */
248static void
249intr_calculatemasks(void)
250{
251	int irq, level;
252	struct isa_intrhand *q;
253
254	/* First, figure out which levels each IRQ uses. */
255	for (irq = 0; irq < ICU_LEN; irq++) {
256		int levels = 0;
257		for (q = isa_intrhand[irq]; q; q = q->ih_next)
258			levels |= 1 << q->ih_level;
259		intrlevel[irq] = levels;
260	}
261
262	/* Then figure out which IRQs use each level. */
263	for (level = 0; level < _IPL_N; level++) {
264		int irqs = 0;
265		for (irq = 0; irq < ICU_LEN; irq++)
266			if (intrlevel[irq] & (1 << level))
267				irqs |= 1 << irq;
268		imask[level] = irqs;
269	}
270
271	imask[IPL_NONE] = 0;
272
273	imask[IPL_SOFTCLOCK] |= imask[IPL_NONE];
274	imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
275
276	/*
277	 * Enforce a hierarchy that gives slow devices a better chance at not
278	 * dropping data.
279	 */
280	imask[IPL_VM] |= imask[IPL_SOFTNET];
281
282	/*
283	 * Since run queues may be manipulated by both the statclock and tty,
284	 * network, and diskdrivers, clock > tty.
285	 */
286	imask[IPL_SCHED] |= imask[IPL_VM];
287
288	/* And eventually calculate the complete masks. */
289	for (irq = 0; irq < ICU_LEN; irq++) {
290		int irqs = 1 << irq;
291		for (q = isa_intrhand[irq]; q; q = q->ih_next)
292			irqs |= imask[q->ih_level];
293		intrmask[irq] = irqs;
294	}
295
296	/* Lastly, determine which IRQs are actually in use. */
297	{
298		int irqs = 0;
299		for (irq = 0; irq < ICU_LEN; irq++)
300			if (isa_intrhand[irq])
301				irqs |= 1 << irq;
302		if (irqs >= 0x100) /* any IRQs >= 8 in use */
303			irqs |= 1 << IRQ_SLAVE;
304		imen = ~irqs;
305		isa_outb(IO_ICU1 + PIC_OCW1, imen);
306		isa_outb(IO_ICU2 + PIC_OCW1, imen >> 8);
307	}
308}
309
310static void
311isabr_attach_hook(struct device *parent, struct device *self,
312    struct isabus_attach_args *iba)
313{
314
315	/* Nothing to do. */
316}
317
318static void
319isabr_detach_hook(isa_chipset_tag_t ic, device_t self)
320{
321
322	/* Nothing to do. */
323}
324
325static const struct evcnt *
326isabr_intr_evcnt(isa_chipset_tag_t ic, int irq)
327{
328
329	/* XXX for now, no evcnt parent reported */
330	return NULL;
331}
332
333/*
334 *	Establish a ISA bus interrupt.
335 */
336static void *
337isabr_intr_establish(isa_chipset_tag_t ic, int irq, int type, int level,
338    int (*ih_fun)(void *), void *ih_arg)
339{
340	struct isa_intrhand **p, *q, *ih;
341	static struct isa_intrhand fakehand = {NULL, fakeintr};
342
343	/* no point in sleeping unless someone can free memory. */
344	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
345	if (ih == NULL)
346		panic("isa_intr_establish: can't malloc handler info");
347
348	if (!LEGAL_IRQ(irq) || type == IST_NONE)
349		panic("intr_establish: bogus irq or type");
350
351	switch (intrtype[irq]) {
352	case IST_NONE:
353		intrtype[irq] = type;
354		break;
355	case IST_EDGE:
356	case IST_LEVEL:
357		if (type == intrtype[irq])
358			break;
359	case IST_PULSE:
360		if (type != IST_NONE)
361			panic("intr_establish: can't share %s with %s",
362			    isa_intr_typename(intrtype[irq]),
363			    isa_intr_typename(type));
364		break;
365	}
366
367	/*
368	 * Figure out where to put the handler.
369	 * This is O(N^2), but we want to preserve the order, and N is
370	 * generally small.
371	 */
372	for (p = &isa_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
373		;
374
375	/*
376	 * Actually install a fake handler momentarily, since we might be doing
377	 * this with interrupts enabled and don't want the real routine called
378	 * until masking is set up.
379	 */
380	fakehand.ih_level = level;
381	*p = &fakehand;
382
383	intr_calculatemasks();
384
385	/*
386	 * Poke the real handler in now.
387	 */
388	ih->ih_fun = ih_fun;
389	ih->ih_arg = ih_arg;
390	ih->ih_count = 0;
391	ih->ih_next = NULL;
392	ih->ih_level = level;
393	ih->ih_irq = irq;
394	snprintf(ih->ih_evname, sizeof(ih->ih_evname), "irq %d", irq);
395	evcnt_attach_dynamic(&ih->ih_evcnt, EVCNT_TYPE_INTR, NULL, "isa",
396	    ih->ih_evname);
397	*p = ih;
398
399	return ih;
400}
401
402static void
403isabr_intr_disestablish(isa_chipset_tag_t ic, void *arg)
404{
405
406}
407
408/*
409 *	Process an interrupt from the ISA bus.
410 */
411uint32_t
412isabr_iointr(uint32_t mask, struct clockframe *cf)
413{
414	struct isa_intrhand *ih;
415	int isa_vector;
416	int o_imen;
417
418	isa_vector = (*isabr_conf->ic_intr_status)();
419	if (isa_vector < 0)
420		return 0;
421
422	o_imen = imen;
423	imen |= 1 << (isa_vector & (ICU_LEN - 1));
424	if (isa_vector & 0x08) {
425		isa_inb(IO_ICU2 + PIC_OCW1);
426		isa_outb(IO_ICU2 + PIC_OCW1, imen >> 8);
427		isa_outb(IO_ICU2 + PIC_OCW2,
428		    OCW2_SELECT | OCW2_EOI | OCW2_SL |
429		    OCW2_ILS((isa_vector & 7)));
430		isa_outb(IO_ICU1,
431		    OCW2_SELECT | OCW2_EOI | OCW2_SL | IRQ_SLAVE);
432	} else {
433		isa_inb(IO_ICU1 + PIC_OCW1);
434		isa_outb(IO_ICU1 + PIC_OCW1, imen);
435		isa_outb(IO_ICU1 + PIC_OCW2,
436		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(isa_vector));
437	}
438	ih = isa_intrhand[isa_vector];
439	if (isa_vector == 0 && ih) {	/* Clock */	/*XXX*/
440		last_cp0_count = mips3_cp0_count_read();
441		/* XXX: spllowerclock() not allowed */
442		cf->sr &= ~MIPS_SR_INT_IE;
443		if ((*ih->ih_fun)(cf))
444			ih->ih_evcnt.ev_count++;
445		ih = ih->ih_next;
446	}
447	while (ih) {
448		if ((*ih->ih_fun)(ih->ih_arg))
449			ih->ih_evcnt.ev_count++;
450		ih = ih->ih_next;
451	}
452	imen = o_imen;
453	isa_inb(IO_ICU1 + PIC_OCW1);
454	isa_inb(IO_ICU2 + PIC_OCW1);
455	isa_outb(IO_ICU1 + PIC_OCW1, imen);
456	isa_outb(IO_ICU2 + PIC_OCW1, imen >> 8);
457
458	return MIPS_INT_MASK_2;
459}
460
461
462/*
463 * Initialize the Interrupt controller logic.
464 */
465static void
466isabr_initicu(void)
467{
468
469	int i;
470
471	for (i = 0; i < ICU_LEN; i++) {
472		switch (i) {
473		case 2:
474		case 8:
475			intrtype[i] = IST_EDGE;
476			break;
477		default:
478			intrtype[i] = IST_NONE;
479			break;
480		}
481	}
482
483	/* reset; program device, four bytes */
484	isa_outb(IO_ICU1 + PIC_ICW1, ICW1_SELECT | ICW1_IC4);
485	/* starting at this vector index */
486	isa_outb(IO_ICU1 + PIC_ICW2, 0);
487	/* slave on line 2 */
488	isa_outb(IO_ICU1 + PIC_ICW3, ICW3_CASCADE(IRQ_SLAVE));
489	/* 8086 mode */
490	isa_outb(IO_ICU1 + PIC_ICW4, ICW4_8086);
491
492	/* leave interrupts masked */
493	isa_outb(IO_ICU1 + PIC_OCW1, 0xff);
494
495	/* special mask mode (if available) */
496	isa_outb(IO_ICU1 + PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
497	/* Read IRR by default. */
498	isa_outb(IO_ICU1 + PIC_OCW3, OCW3_SELECT | OCW3_RR);
499#ifdef REORDER_IRQ
500	/* pri order 3-7, 0-2 (com2 first) */
501	isa_outb(IO_ICU1 + PIC_OCW2,
502	    OCW2_SELECT | OCW2_R | OCW2_SL OCW2_ILS(3 - 1));
503#endif
504
505	/* reset; program device, four bytes */
506	isa_outb(IO_ICU2 + PIC_ICW1, ICW1_SELECT | ICW1_IC4);
507	/* staring at this vector index */
508	isa_outb(IO_ICU2 + PIC_ICW2, 8);
509	/* slave connected to line 2 of master */
510	isa_outb(IO_ICU2 + PIC_ICW3, ICW3_SIC(IRQ_SLAVE));
511	/* 8086 mode */
512	isa_outb(IO_ICU2 + PIC_ICW4, ICW4_8086);
513
514	/* leave interrupts masked */
515	isa_outb(IO_ICU2 + PIC_OCW1, 0xff);
516
517	/* special mask mode (if available) */
518	isa_outb(IO_ICU2 + PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
519	/* Read IRR by default. */
520	isa_outb(IO_ICU2 + PIC_OCW3, OCW3_SELECT | OCW3_RR);
521}
522
523
524/*
525 *	SPEAKER BEEPER...
526 */
527void
528sysbeepstop(void *arg)
529{
530	int s;
531
532	/* disable counter 2 */
533	s = splhigh();
534	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
535	splx(s);
536	beeping = 0;
537}
538
539void
540sysbeep(int pitch, int period)
541{
542	static int last_pitch, last_period;
543	int s;
544
545	if (cold)
546		return;		/* Can't beep yet. */
547
548	if (beeping)
549		callout_stop(&sysbeep_ch);
550	if (!beeping || last_pitch != pitch) {
551		s = splhigh();
552		isa_outb(IO_TIMER1 + TIMER_MODE,
553		    TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
554		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
555		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
556		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
557		splx(s);
558	}
559	last_pitch = pitch;
560	beeping = last_period = period;
561	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
562}
563
564int
565isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
566{
567	int irq;
568	int maybe_irq = -1;
569	int shared_depth = 0;
570	mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
571	for (irq = 0; mask != 0; mask >>= 1, irq++) {
572		if ((mask & 1) == 0)
573			continue;
574		if (intrtype[irq] == IST_NONE) {
575			*irq_p = irq;
576			return 0;
577		}
578		/* Level interrupts can be shared */
579		if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
580			struct isa_intrhand *ih = isa_intrhand[irq];
581			int depth;
582			if (maybe_irq == -1) {
583 				maybe_irq = irq;
584				continue;
585			}
586			for (depth = 0; ih != NULL; ih = ih->ih_next)
587				depth++;
588			if (depth < shared_depth) {
589				maybe_irq = irq;
590				shared_depth = depth;
591			}
592		}
593	}
594	if (maybe_irq != -1) {
595		*irq_p = maybe_irq;
596		return 0;
597	}
598	return 1;
599}
600