1/* $OpenBSD: ioasic.c,v 1.19 2022/03/13 08:04:13 mpi Exp $ */
2/* $NetBSD: ioasic.c,v 1.34 2000/07/18 06:10:06 thorpej Exp $ */
3
4/*-
5 * Copyright (c) 1997, 1998 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) 1994, 1995, 1996 Carnegie-Mellon University.
36 * All rights reserved.
37 *
38 * Author: Keith Bostic, 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/kernel.h>
63#include <sys/systm.h>
64#include <sys/device.h>
65#include <sys/malloc.h>
66#include <sys/timeout.h>
67
68#include <machine/autoconf.h>
69#include <machine/bus.h>
70#include <machine/pte.h>
71#include <machine/rpb.h>
72
73#include <dev/tc/tcvar.h>
74#include <dev/tc/ioasicreg.h>
75#include <dev/tc/ioasicvar.h>
76#ifdef DEC_3000_300
77#include <alpha/tc/tc_3000_300.h>
78#endif
79
80/* Definition of the driver for autoconfig. */
81int	ioasicmatch(struct device *, void *, void *);
82void	ioasicattach(struct device *, struct device *, void *);
83
84const struct cfattach ioasic_ca = {
85	sizeof(struct ioasic_softc), ioasicmatch, ioasicattach,
86};
87
88struct cfdriver ioasic_cd = {
89	NULL, "ioasic", DV_DULL,
90};
91
92int	ioasic_intr(void *);
93int	ioasic_intrnull(void *);
94void	ioasic_led_blink(void *);
95
96#define	C(x)	((void *)(u_long)(x))
97#define	KV(x)	(ALPHA_PHYS_TO_K0SEG(x))
98
99#define	IOASIC_DEV_LANCE	0
100#define	IOASIC_DEV_SCC0		1
101#define	IOASIC_DEV_SCC1		2
102#define	IOASIC_DEV_ISDN		3
103
104#define	IOASIC_DEV_BOGUS	-1
105
106#define	IOASIC_NCOOKIES		4
107
108struct ioasic_dev ioasic_devs[] = {
109	{ "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE),
110	  IOASIC_INTR_LANCE, },
111	{ "z8530   ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0),
112	  IOASIC_INTR_SCC_0, },
113	{ "z8530   ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1),
114	  IOASIC_INTR_SCC_1, },
115	{ "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS),
116	  0, },
117	{ "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN),
118	  IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD,  },
119};
120int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]);
121
122struct ioasicintr {
123	int	(*iai_func)(void *);
124	void	*iai_arg;
125	struct evcount iai_count;
126} ioasicintrs[IOASIC_NCOOKIES];
127
128tc_addr_t ioasic_base;		/* XXX XXX XXX */
129
130/* There can be only one. */
131int ioasicfound;
132
133int
134ioasicmatch(parent, cfdata, aux)
135	struct device *parent;
136	void *cfdata, *aux;
137{
138	struct tc_attach_args *ta = aux;
139
140	/* Make sure that we're looking for this type of device. */
141	if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
142		return (0);
143
144	/* Check that it can actually exist. */
145	if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
146		panic("ioasicmatch: how did we get here?");
147
148	if (ioasicfound)
149		return (0);
150
151	return (1);
152}
153
154void
155ioasicattach(parent, self, aux)
156	struct device *parent, *self;
157	void *aux;
158{
159	struct ioasic_softc *sc = (struct ioasic_softc *)self;
160	struct tc_attach_args *ta = aux;
161#ifdef DEC_3000_300
162	u_long ssr;
163#endif
164	u_long i, imsk;
165
166	ioasicfound = 1;
167
168	sc->sc_bst = ta->ta_memt;
169	if (bus_space_map(ta->ta_memt, ta->ta_addr,
170			0x400000, 0, &sc->sc_bsh)) {
171		printf("%s: unable to map device\n", sc->sc_dv.dv_xname);
172		return;
173	}
174	sc->sc_dmat = ta->ta_dmat;
175
176	ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
177
178#ifdef DEC_3000_300
179	if (cputype == ST_DEC_3000_300) {
180		ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
181		ssr |= IOASIC_CSR_FASTMODE;
182		bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
183		printf(": slow mode\n");
184	} else
185#endif
186		printf(": fast mode\n");
187
188	/*
189	 * Turn off all device interrupt bits.
190	 * (This does _not_ include 3000/300 TC option slot bits).
191	 */
192	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
193	for (i = 0; i < ioasic_ndevs; i++)
194		imsk &= ~ioasic_devs[i].iad_intrbits;
195	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
196
197	/*
198	 * Set up interrupt handlers.
199	 */
200	for (i = 0; i < IOASIC_NCOOKIES; i++) {
201		ioasicintrs[i].iai_func = ioasic_intrnull;
202		ioasicintrs[i].iai_arg = (void *)i;
203	}
204	tc_intr_establish(parent, ta->ta_cookie, IPL_NONE, ioasic_intr, sc,
205	    NULL);
206
207	/*
208	 * Try to configure each device.
209	 */
210	ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs);
211
212	ioasic_led_blink(NULL);
213}
214
215void
216ioasic_intr_establish(ioa, cookie, level, func, arg, name)
217	struct device *ioa;
218	void *cookie, *arg;
219	int level;
220	int (*func)(void *);
221	const char *name;
222{
223	struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
224	u_long dev, i, imsk;
225
226	dev = (u_long)cookie;
227#ifdef DIAGNOSTIC
228	/* XXX check cookie. */
229#endif
230
231	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
232		panic("ioasic_intr_establish: cookie %lu twice", dev);
233
234	ioasicintrs[dev].iai_func = func;
235	ioasicintrs[dev].iai_arg = arg;
236	evcount_attach(&ioasicintrs[dev].iai_count, name, NULL);
237
238	/* Enable interrupts for the device. */
239	for (i = 0; i < ioasic_ndevs; i++)
240		if (ioasic_devs[i].iad_cookie == cookie)
241			break;
242	if (i == ioasic_ndevs)
243		panic("ioasic_intr_establish: invalid cookie.");
244
245	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
246        imsk |= ioasic_devs[i].iad_intrbits;
247        bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
248}
249
250void
251ioasic_intr_disestablish(ioa, cookie)
252	struct device *ioa;
253	void *cookie;
254{
255	struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
256	u_long dev, i, imsk;
257
258	dev = (u_long)cookie;
259#ifdef DIAGNOSTIC
260	/* XXX check cookie. */
261#endif
262
263	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
264		panic("ioasic_intr_disestablish: cookie %lu missing intr", dev);
265
266	/* Enable interrupts for the device. */
267	for (i = 0; i < ioasic_ndevs; i++)
268		if (ioasic_devs[i].iad_cookie == cookie)
269			break;
270	if (i == ioasic_ndevs)
271		panic("ioasic_intr_disestablish: invalid cookie.");
272
273	imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
274	imsk &= ~ioasic_devs[i].iad_intrbits;
275	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
276
277	ioasicintrs[dev].iai_func = ioasic_intrnull;
278	ioasicintrs[dev].iai_arg = (void *)dev;
279	evcount_detach(&ioasicintrs[dev].iai_count);
280}
281
282int
283ioasic_intrnull(val)
284	void *val;
285{
286
287	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
288	    (u_long)val);
289}
290
291/*
292 * ASIC interrupt handler.
293 */
294int
295ioasic_intr(val)
296	void *val;
297{
298	register struct ioasic_softc *sc = val;
299	register int ifound;
300	int gifound;
301	u_int32_t sir, osir;
302
303	gifound = 0;
304	do {
305		ifound = 0;
306		tc_syncbus();
307
308		osir = sir =
309		    bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
310
311		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
312#define	CHECKINTR(slot, bits, clear)					\
313		if (sir & (bits)) {					\
314			ifound = 1;					\
315			ioasicintrs[slot].iai_count.ec_count++;		\
316			(*ioasicintrs[slot].iai_func)			\
317			    (ioasicintrs[slot].iai_arg);		\
318			if (clear)					\
319				sir &= ~(bits);				\
320		}
321		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0);
322		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0);
323		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0);
324		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD |
325		    IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1);
326
327		if (sir != osir)
328			bus_space_write_4(sc->sc_bst, sc->sc_bsh,
329			    IOASIC_INTR, sir);
330
331		gifound |= ifound;
332	} while (ifound);
333
334	return (gifound);
335}
336
337/*
338 * Blink leds
339 */
340
341struct {
342	int		patpos;
343	struct timeout	tmo;
344} led_blink_state;
345
346static const uint8_t led_pattern8[] = {
347	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
348	0x40, 0x20, 0x10, 0x08, 0x04, 0x02
349};
350
351void
352ioasic_led_blink(void *unused)
353{
354	extern int alpha_led_blink;	/* machdep.c */
355	vaddr_t rw_csr;
356	u_int32_t pattern;
357	int display_loadavg;
358
359	if (alpha_led_blink == 0) {
360		pattern = 0;	/* all clear */
361		led_blink_state.patpos = 0;
362	} else {
363#ifdef DEC_3000_300
364		if (cputype == ST_DEC_3000_300)
365			display_loadavg = 0;
366		else
367#endif
368		switch (hwrpb->rpb_variation & SV_ST_MASK) {
369		case SV_ST_FLAMINGO:
370		case SV_ST_HOTPINK:
371		case SV_ST_FLAMINGOPLUS:
372		case SV_ST_ULTRA:
373		case SV_ST_FLAMINGO45:
374			/* 500/800/900, 2 7-segment display, display loadavg */
375			display_loadavg = 1;
376			break;
377		case SV_ST_SANDPIPER:
378		case SV_ST_SANDPLUS:
379		case SV_ST_SANDPIPER45:
380		default:
381			/* 400/600/700, 8 leds, display moving pattern */
382			display_loadavg = 0;
383			break;
384		}
385
386		if (display_loadavg)
387			pattern = averunnable.ldavg[0] >> FSHIFT;
388		else {
389			pattern = led_pattern8[led_blink_state.patpos];
390			led_blink_state.patpos =
391			    (led_blink_state.patpos + 1) % sizeof(led_pattern8);
392		}
393	}
394
395	/*
396	 * The low 8 bits, controlling the leds, are read-only in the
397	 * CSR register, but read-write in its image at CSR + 4.
398	 *
399	 * On model 300, however, the internal 8 leds are at a different
400	 * address, but the (better visible) power supply led is actually
401	 * bit 5 in CSR (active low).
402	 */
403#ifdef DEC_3000_300
404	if (cputype == ST_DEC_3000_300) {
405		rw_csr = KV(0x1a0000000 + IOASIC_CSR + 4);
406
407		*(volatile uint32_t *)TC_3000_300_LED =
408		    (*(volatile uint32_t *)TC_3000_300_LED & ~(0xff << 16)) |
409		     (pattern << 16);
410		/*
411		 * Blink the power supply led 8x slower.  This relies
412		 * on led_pattern8[] being a < 16 element array.
413		 */
414		*(volatile uint32_t *)rw_csr =
415		    (*(volatile uint32_t *)rw_csr & ~(1 << 5)) ^
416		    ((led_blink_state.patpos >> 3) << 5);
417	} else
418#endif
419	{
420		rw_csr = KV(0x1e0000000 + IOASIC_CSR + 4);
421
422		*(volatile uint32_t *)rw_csr =
423		    (*(volatile uint32_t *)rw_csr & ~0xff) | pattern;
424	}
425
426	if (alpha_led_blink != 0) {
427		timeout_set(&led_blink_state.tmo, ioasic_led_blink, NULL);
428		timeout_add(&led_blink_state.tmo,
429		    (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 3)));
430	}
431}
432