1*b7b2b8a3Sthorpej /* $NetBSD: ioasic.c,v 1.49 2021/05/07 16:58:34 thorpej Exp $ */
2e5e8573dSthorpej
3e5e8573dSthorpej /*-
4e5e8573dSthorpej * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5e5e8573dSthorpej * All rights reserved.
6e5e8573dSthorpej *
7e5e8573dSthorpej * This code is derived from software contributed to The NetBSD Foundation
8e5e8573dSthorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9e5e8573dSthorpej * NASA Ames Research Center.
10e5e8573dSthorpej *
11e5e8573dSthorpej * Redistribution and use in source and binary forms, with or without
12e5e8573dSthorpej * modification, are permitted provided that the following conditions
13e5e8573dSthorpej * are met:
14e5e8573dSthorpej * 1. Redistributions of source code must retain the above copyright
15e5e8573dSthorpej * notice, this list of conditions and the following disclaimer.
16e5e8573dSthorpej * 2. Redistributions in binary form must reproduce the above copyright
17e5e8573dSthorpej * notice, this list of conditions and the following disclaimer in the
18e5e8573dSthorpej * documentation and/or other materials provided with the distribution.
19e5e8573dSthorpej *
20e5e8573dSthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21e5e8573dSthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22e5e8573dSthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23e5e8573dSthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24e5e8573dSthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25e5e8573dSthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26e5e8573dSthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27e5e8573dSthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28e5e8573dSthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29e5e8573dSthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30e5e8573dSthorpej * POSSIBILITY OF SUCH DAMAGE.
31e5e8573dSthorpej */
32a5c74353Scgd
33a5c74353Scgd /*
34576c7693Scgd * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
35a5c74353Scgd * All rights reserved.
36a5c74353Scgd *
37a5c74353Scgd * Author: Keith Bostic, Chris G. Demetriou
38a5c74353Scgd *
39a5c74353Scgd * Permission to use, copy, modify and distribute this software and
40a5c74353Scgd * its documentation is hereby granted, provided that both the copyright
41a5c74353Scgd * notice and this permission notice appear in all copies of the
42a5c74353Scgd * software, derivative works or modified versions, and any portions
43a5c74353Scgd * thereof, and that both notices appear in supporting documentation.
44a5c74353Scgd *
45a5c74353Scgd * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46a5c74353Scgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
47a5c74353Scgd * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48a5c74353Scgd *
49a5c74353Scgd * Carnegie Mellon requests users of this software to return to
50a5c74353Scgd *
51a5c74353Scgd * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
52a5c74353Scgd * School of Computer Science
53a5c74353Scgd * Carnegie Mellon University
54a5c74353Scgd * Pittsburgh PA 15213-3890
55a5c74353Scgd *
56a5c74353Scgd * any improvements or extensions that they make and grant Carnegie the
57a5c74353Scgd * rights to redistribute these changes.
58a5c74353Scgd */
59a5c74353Scgd
60a4cef84aSthorpej #include "opt_dec_3000_300.h"
61a4cef84aSthorpej
6290789b53Scgd #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
6390789b53Scgd
64*b7b2b8a3Sthorpej __KERNEL_RCSID(0, "$NetBSD: ioasic.c,v 1.49 2021/05/07 16:58:34 thorpej Exp $");
65059aaeddScgd
66a5c74353Scgd #include <sys/param.h>
67a5c74353Scgd #include <sys/kernel.h>
68a5c74353Scgd #include <sys/systm.h>
69a5c74353Scgd #include <sys/device.h>
706f97a7c1Sthorpej #include <sys/kmem.h>
71a5c74353Scgd
72a5c74353Scgd #include <machine/autoconf.h>
73cf10107dSdyoung #include <sys/bus.h>
74a5c74353Scgd #include <machine/pte.h>
75a5c74353Scgd #include <machine/rpb.h>
76a5c74353Scgd
77a5c74353Scgd #include <dev/tc/tcvar.h>
78c6641d91Snisimura #include <dev/tc/ioasicreg.h>
79a5c74353Scgd #include <dev/tc/ioasicvar.h>
80a5c74353Scgd
81a5c74353Scgd /* Definition of the driver for autoconfig. */
82*b7b2b8a3Sthorpej static int ioasicmatch(device_t, cfdata_t, void *);
83*b7b2b8a3Sthorpej static void ioasicattach(device_t, device_t, void *);
8408607bc6Sthorpej
85def92600Stsutsui CFATTACH_DECL_NEW(ioasic, sizeof(struct ioasic_softc),
86b96bc0d7Sthorpej ioasicmatch, ioasicattach, NULL, NULL);
8708607bc6Sthorpej
88*b7b2b8a3Sthorpej static int ioasic_intr(void *);
89*b7b2b8a3Sthorpej static int ioasic_intrnull(void *);
90a5c74353Scgd
91a5c74353Scgd #define C(x) ((void *)(x))
92a5c74353Scgd
93a5c74353Scgd #define IOASIC_DEV_LANCE 0
94a5c74353Scgd #define IOASIC_DEV_SCC0 1
95a5c74353Scgd #define IOASIC_DEV_SCC1 2
96a5c74353Scgd #define IOASIC_DEV_ISDN 3
97a5c74353Scgd
98a5c74353Scgd #define IOASIC_DEV_BOGUS -1
99a5c74353Scgd
100a5c74353Scgd #define IOASIC_NCOOKIES 4
101a5c74353Scgd
102*b7b2b8a3Sthorpej static const struct ioasic_dev ioasic_devs[] = {
1034f051180Snisimura { "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE),
104c59c1eaeSthorpej IOASIC_INTR_LANCE, },
105c59c1eaeSthorpej { "z8530 ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0),
106c59c1eaeSthorpej IOASIC_INTR_SCC_0, },
107c59c1eaeSthorpej { "z8530 ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1),
108c59c1eaeSthorpej IOASIC_INTR_SCC_1, },
109c59c1eaeSthorpej { "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS),
110c59c1eaeSthorpej 0, },
111c59c1eaeSthorpej { "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN),
1126eb4356eSgmcgarry IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD, },
113a5c74353Scgd };
114*b7b2b8a3Sthorpej static const int ioasic_ndevs = __arraycount(ioasic_devs);
115a5c74353Scgd
116*b7b2b8a3Sthorpej static struct ioasicintr {
11702cdf4d2Sdsl int (*iai_func)(void *);
118a5c74353Scgd void *iai_arg;
119b0ce38fdSthorpej struct evcnt iai_evcnt;
120a5c74353Scgd } ioasicintrs[IOASIC_NCOOKIES];
121a5c74353Scgd
122a5c74353Scgd tc_addr_t ioasic_base; /* XXX XXX XXX */
123a5c74353Scgd
124a5c74353Scgd /* There can be only one. */
125*b7b2b8a3Sthorpej static int ioasicfound;
126a5c74353Scgd
127*b7b2b8a3Sthorpej static int
ioasicmatch(device_t parent,cfdata_t cf,void * aux)128def92600Stsutsui ioasicmatch(device_t parent, cfdata_t cf, void *aux)
129a5c74353Scgd {
130ba87ccc4Scgd struct tc_attach_args *ta = aux;
131a5c74353Scgd
132a5c74353Scgd /* Make sure that we're looking for this type of device. */
133ba87ccc4Scgd if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
134a5c74353Scgd return (0);
135a5c74353Scgd
136a5c74353Scgd /* Check that it can actually exist. */
137a5c74353Scgd if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
138a5c74353Scgd panic("ioasicmatch: how did we get here?");
139a5c74353Scgd
140a5c74353Scgd if (ioasicfound)
141a5c74353Scgd return (0);
142a5c74353Scgd
143a5c74353Scgd return (1);
144a5c74353Scgd }
145a5c74353Scgd
146*b7b2b8a3Sthorpej static void
ioasicattach(device_t parent,device_t self,void * aux)147def92600Stsutsui ioasicattach(device_t parent, device_t self, void *aux)
148a5c74353Scgd {
149def92600Stsutsui struct ioasic_softc *sc = device_private(self);
150ba87ccc4Scgd struct tc_attach_args *ta = aux;
151defe7bd1Smrg #ifdef DEC_3000_300
152defe7bd1Smrg u_long ssr;
153defe7bd1Smrg #endif
154defe7bd1Smrg u_long i, imsk;
155b0ce38fdSthorpej const struct evcnt *pevcnt;
156b0ce38fdSthorpej char *cp;
157a5c74353Scgd
158a5c74353Scgd ioasicfound = 1;
159a5c74353Scgd
160def92600Stsutsui sc->sc_dev = self;
1617fbac8b3Snisimura sc->sc_bst = ta->ta_memt;
1627fbac8b3Snisimura if (bus_space_map(ta->ta_memt, ta->ta_addr,
1637fbac8b3Snisimura 0x400000, 0, &sc->sc_bsh)) {
164def92600Stsutsui printf("%s: unable to map device\n", device_xname(self));
1657fbac8b3Snisimura return;
1667fbac8b3Snisimura }
167e5e8573dSthorpej sc->sc_dmat = ta->ta_dmat;
1687fbac8b3Snisimura
1697fbac8b3Snisimura ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
170a5c74353Scgd
171a5c74353Scgd #ifdef DEC_3000_300
172a5c74353Scgd if (cputype == ST_DEC_3000_300) {
1737fbac8b3Snisimura ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
1747fbac8b3Snisimura ssr |= IOASIC_CSR_FASTMODE;
1757fbac8b3Snisimura bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
1768d9699acSchristos printf(": slow mode\n");
177a5c74353Scgd } else
178a5c74353Scgd #endif
1798d9699acSchristos printf(": fast mode\n");
180a5c74353Scgd
181a5c74353Scgd /*
182a5c74353Scgd * Turn off all device interrupt bits.
183a5c74353Scgd * (This does _not_ include 3000/300 TC option slot bits.
184a5c74353Scgd */
1857fbac8b3Snisimura imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
186a5c74353Scgd for (i = 0; i < ioasic_ndevs; i++)
1877fbac8b3Snisimura imsk &= ~ioasic_devs[i].iad_intrbits;
1887fbac8b3Snisimura bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
189a5c74353Scgd
190a5c74353Scgd /*
191a5c74353Scgd * Set up interrupt handlers.
192a5c74353Scgd */
193b0ce38fdSthorpej pevcnt = tc_intr_evcnt(parent, ta->ta_cookie);
194a5c74353Scgd for (i = 0; i < IOASIC_NCOOKIES; i++) {
195a5c74353Scgd ioasicintrs[i].iai_func = ioasic_intrnull;
196a5c74353Scgd ioasicintrs[i].iai_arg = (void *)i;
197b0ce38fdSthorpej
1986f97a7c1Sthorpej cp = kmem_asprintf("slot %lu", i);
199b0ce38fdSthorpej evcnt_attach_dynamic(&ioasicintrs[i].iai_evcnt,
200def92600Stsutsui EVCNT_TYPE_INTR, pevcnt, device_xname(self), cp);
201a5c74353Scgd }
202220005d9Snisimura tc_intr_establish(parent, ta->ta_cookie, TC_IPL_NONE, ioasic_intr, sc);
203a5c74353Scgd
204a5c74353Scgd /*
205a5c74353Scgd * Try to configure each device.
206a5c74353Scgd */
207f476de66Snisimura ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs);
208a5c74353Scgd }
209a5c74353Scgd
210a5c74353Scgd void
ioasic_intr_establish(device_t ioa,void * cookie,tc_intrlevel_t level,int (* func)(void *),void * arg)211e0a095c7Scegger ioasic_intr_establish(device_t ioa, void *cookie, tc_intrlevel_t level,
212e0a095c7Scegger int (*func)(void *), void *arg)
213a5c74353Scgd {
214e0a095c7Scegger struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0);
2157fbac8b3Snisimura u_long dev, i, imsk;
216a5c74353Scgd
217a5c74353Scgd dev = (u_long)cookie;
218a5c74353Scgd #ifdef DIAGNOSTIC
219a5c74353Scgd /* XXX check cookie. */
220a5c74353Scgd #endif
221a5c74353Scgd
222a5c74353Scgd if (ioasicintrs[dev].iai_func != ioasic_intrnull)
2235194c207Sthorpej panic("ioasic_intr_establish: cookie %lu twice", dev);
224a5c74353Scgd
225a5c74353Scgd ioasicintrs[dev].iai_func = func;
226a5c74353Scgd ioasicintrs[dev].iai_arg = arg;
227a5c74353Scgd
228a5c74353Scgd /* Enable interrupts for the device. */
229a5c74353Scgd for (i = 0; i < ioasic_ndevs; i++)
230a5c74353Scgd if (ioasic_devs[i].iad_cookie == cookie)
231a5c74353Scgd break;
232a5c74353Scgd if (i == ioasic_ndevs)
233a5c74353Scgd panic("ioasic_intr_establish: invalid cookie.");
2347fbac8b3Snisimura
2357fbac8b3Snisimura imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
2367fbac8b3Snisimura imsk |= ioasic_devs[i].iad_intrbits;
2377fbac8b3Snisimura bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
238a5c74353Scgd }
239a5c74353Scgd
240a5c74353Scgd void
ioasic_intr_disestablish(device_t ioa,void * cookie)241e0a095c7Scegger ioasic_intr_disestablish(device_t ioa, void *cookie)
242a5c74353Scgd {
243e0a095c7Scegger struct ioasic_softc *sc = device_lookup_private(&ioasic_cd,0);
2447fbac8b3Snisimura u_long dev, i, imsk;
245a5c74353Scgd
246a5c74353Scgd dev = (u_long)cookie;
247a5c74353Scgd #ifdef DIAGNOSTIC
248a5c74353Scgd /* XXX check cookie. */
249a5c74353Scgd #endif
250a5c74353Scgd
251a5c74353Scgd if (ioasicintrs[dev].iai_func == ioasic_intrnull)
2525194c207Sthorpej panic("ioasic_intr_disestablish: cookie %lu missing intr", dev);
253a5c74353Scgd
254a5c74353Scgd /* Enable interrupts for the device. */
255a5c74353Scgd for (i = 0; i < ioasic_ndevs; i++)
256a5c74353Scgd if (ioasic_devs[i].iad_cookie == cookie)
257a5c74353Scgd break;
258a5c74353Scgd if (i == ioasic_ndevs)
259a5c74353Scgd panic("ioasic_intr_disestablish: invalid cookie.");
2607fbac8b3Snisimura
2617fbac8b3Snisimura imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
2627fbac8b3Snisimura imsk &= ~ioasic_devs[i].iad_intrbits;
2637fbac8b3Snisimura bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
264a5c74353Scgd
265a5c74353Scgd ioasicintrs[dev].iai_func = ioasic_intrnull;
266a5c74353Scgd ioasicintrs[dev].iai_arg = (void *)dev;
267a5c74353Scgd }
268a5c74353Scgd
269*b7b2b8a3Sthorpej static int
ioasic_intrnull(void * val)270454af1c0Sdsl ioasic_intrnull(void *val)
271a5c74353Scgd {
272a5c74353Scgd
2730f09ed48Sprovos panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld",
274a5c74353Scgd (u_long)val);
275a5c74353Scgd }
276a5c74353Scgd
277a5c74353Scgd /*
278a5c74353Scgd * ASIC interrupt handler.
279a5c74353Scgd */
280*b7b2b8a3Sthorpej static int
ioasic_intr(void * val)281454af1c0Sdsl ioasic_intr(void *val)
282a5c74353Scgd {
283a5c74353Scgd register struct ioasic_softc *sc = val;
2840cefc7efScgd register int ifound;
285a5c74353Scgd int gifound;
286eacc5f97Smatt uint32_t sir, osir;
287a5c74353Scgd
288a5c74353Scgd gifound = 0;
289a5c74353Scgd do {
290a5c74353Scgd ifound = 0;
291a5c74353Scgd tc_syncbus();
292a5c74353Scgd
293ea0cb4c3Sthorpej osir = sir =
294ea0cb4c3Sthorpej bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
295a5c74353Scgd
296b0ce38fdSthorpej #define INCRINTRCNT(slot) ioasicintrs[slot].iai_evcnt.ev_count++
297666c7f6fScgd
298a5c74353Scgd /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
299ea0cb4c3Sthorpej #define CHECKINTR(slot, bits, clear) \
300c7c33f17Smatt if (sir & (bits)) { \
301a5c74353Scgd ifound = 1; \
302666c7f6fScgd INCRINTRCNT(slot); \
303a5c74353Scgd (*ioasicintrs[slot].iai_func) \
304a5c74353Scgd (ioasicintrs[slot].iai_arg); \
305ea0cb4c3Sthorpej if (clear) \
306ea0cb4c3Sthorpej sir &= ~(bits); \
307a5c74353Scgd }
308ea0cb4c3Sthorpej CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0);
309ea0cb4c3Sthorpej CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0);
310ea0cb4c3Sthorpej CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0);
311ea0cb4c3Sthorpej CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD |
312ea0cb4c3Sthorpej IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1);
313ea0cb4c3Sthorpej
314ea0cb4c3Sthorpej if (sir != osir)
315ea0cb4c3Sthorpej bus_space_write_4(sc->sc_bst, sc->sc_bsh,
316ea0cb4c3Sthorpej IOASIC_INTR, sir);
317a5c74353Scgd
318a5c74353Scgd gifound |= ifound;
319a5c74353Scgd } while (ifound);
320a5c74353Scgd
321a5c74353Scgd return (gifound);
322a5c74353Scgd }
323