ioasic.c revision 1.1.2.9 1 /* $NetBSD: ioasic.c,v 1.1.2.9 1999/04/06 02:32:34 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Keith Bostic, Chris G. Demetriou, Jonathan Stone
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
31
32 __KERNEL_RCSID(0, "$NetBSD: ioasic.c,v 1.1.2.9 1999/04/06 02:32:34 nisimura Exp $");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37
38 #include <machine/bus.h>
39 #include <machine/intr.h>
40
41 #include <pmax/pmax/pmaxtype.h>
42 #include <dev/tc/tcvar.h>
43 #include <dev/tc/ioasicvar.h>
44 #include <pmax/tc/ioasicreg.h>
45
46 #include "opt_dec_3min.h"
47 #include "opt_dec_maxine.h"
48 #include "opt_dec_3maxplus.h"
49
50 int ioasicmatch __P((struct device *, struct cfdata *, void *));
51 void ioasicattach __P((struct device *, struct device *, void *));
52
53 struct cfattach ioasic_ca = {
54 sizeof(struct ioasic_softc), ioasicmatch, ioasicattach,
55 };
56
57 tc_addr_t ioasic_base;
58
59 /* XXX XXX XXX */
60 #define IOASIC_INTR_SCSI 0x000e0200
61 #define IOASIC_INTR_DTOP 0x00000001
62 #define IOASIC_INTR_FDC 0x00000090
63 #define XINE_INTR_TC_0 0x00001000
64 #define XINE_INTR_TC_1 0x00000020
65 #define KN03_INTR_TC_0 0x00000800
66 #define KN03_INTR_TC_1 0x00001000
67 #define KN03_INTR_TC_2 0x00002000
68 #define KMIN_INTR_CLOCK 0x00000020
69
70 extern u_int32_t iplmask[], oldiplmask[];
71 /* XXX XXX XXX */
72
73 #define C(x) (void *)(x)
74
75 #if defined(DEC_MAXINE)
76 struct ioasic_dev xine_ioasic_devs[] = {
77 { "lance", 0x0c0000, C(SYS_DEV_LANCE), IOASIC_INTR_LANCE, },
78 { "z8530 ", 0x100000, C(SYS_DEV_SCC0), IOASIC_INTR_SCC_0, },
79 { "mc146818", 0x200000, C(SYS_DEV_BOGUS), 0, },
80 { "isdn", 0x240000, C(SYS_DEV_ISDN), IOASIC_INTR_ISDN, },
81 { "dtop", 0x280000, C(SYS_DEV_DTOP), IOASIC_INTR_DTOP, },
82 { "fdc", 0x2C0000, C(SYS_DEV_FDC), IOASIC_INTR_FDC, },
83 { "asc", 0x300000, C(SYS_DEV_SCSI), IOASIC_INTR_SCSI },
84 { "(TC0)", 0x0, C(SYS_DEV_OPT0), XINE_INTR_TC_0 },
85 { "(TC1)", 0x0, C(SYS_DEV_OPT1), XINE_INTR_TC_1 },
86 };
87 int xine_builtin_ndevs = 7;
88 int xine_ioasic_ndevs = sizeof(xine_ioasic_devs)/sizeof(xine_ioasic_devs[0]);
89 #endif
90
91 #if defined(DEC_3MIN) || defined(DEC_3MAXPLUS)
92 struct ioasic_dev kn03_ioasic_devs[] = {
93 { "lance", 0x0c0000, C(SYS_DEV_LANCE), IOASIC_INTR_LANCE, },
94 { "z8530 ", 0x100000, C(SYS_DEV_SCC0), IOASIC_INTR_SCC_0, },
95 { "z8530 ", 0x180000, C(SYS_DEV_SCC1), IOASIC_INTR_SCC_1, },
96 { "mc146818", 0x200000, C(SYS_DEV_BOGUS), KMIN_INTR_CLOCK, },
97 { "asc", 0x300000, C(SYS_DEV_SCSI), IOASIC_INTR_SCSI },
98 { "(TC0)", 0x0, C(SYS_DEV_OPT0), KN03_INTR_TC_0 },
99 { "(TC1)", 0x0, C(SYS_DEV_OPT1), KN03_INTR_TC_1 },
100 { "(TC2)", 0x0, C(SYS_DEV_OPT2), KN03_INTR_TC_2 },
101 };
102 int kn03_builtin_ndevs = 5;
103 int kn03_ioasic_ndevs = sizeof(kn03_ioasic_devs)/sizeof(kn03_ioasic_devs[0]);
104 #endif
105
106 struct ioasic_dev *ioasic_devs;
107 int ioasic_ndevs, builtin_ndevs;
108
109 int
110 ioasicmatch(parent, cfdata, aux)
111 struct device *parent;
112 struct cfdata *cfdata;
113 void *aux;
114 {
115 struct tc_attach_args *ta = aux;
116
117 /* Make sure that we're looking for this type of device. */
118 if (strncmp("IOCTL ", ta->ta_modname, TC_ROM_LLEN))
119 return (0);
120
121 if (cfdata->cf_unit > 0)
122 return (0);
123
124 switch (systype) {
125 #if defined(DEC_MAXINE)
126 case DS_MAXINE:
127 ioasic_devs = xine_ioasic_devs;
128 ioasic_ndevs = xine_ioasic_ndevs;
129 builtin_ndevs = xine_builtin_ndevs;
130 break;
131 #endif
132 #if defined(DEC_3MIN) || defined(DEC_3MAXPLUS)
133 case DS_3MIN:
134 case DS_3MAXPLUS:
135 ioasic_devs = kn03_ioasic_devs;
136 ioasic_ndevs = kn03_ioasic_ndevs;
137 builtin_ndevs = kn03_builtin_ndevs;
138 break;
139 #endif
140 default:
141 panic("ioasicmatch: how did we get here?");
142 }
143
144 return (1);
145 }
146
147 void
148 ioasicattach(parent, self, aux)
149 struct device *parent, *self;
150 void *aux;
151 {
152 struct ioasic_softc *sc = (struct ioasic_softc *)self;
153 struct tc_attach_args *ta = aux;
154 int i, imsk;
155
156 sc->sc_bst = ta->ta_memt;
157 sc->sc_dmat = ta->ta_dmat;
158 if (bus_space_map(ta->ta_memt, ta->ta_addr,
159 0x400000, 0, &sc->sc_bsh)) {
160 printf("%s: unable to map device\n", sc->sc_dv.dv_xname);
161 return;
162 }
163 sc->sc_cookie = ta->ta_cookie;
164
165 sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
166
167 printf("\n");
168
169 #if 1 /* !!! necessary? already all-0 upon booting as documented !!! */
170 /*
171 * Turn off all device interrupt bits.
172 * (This _does_ include TC option slot bits.
173 */
174 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
175 for (i = 0; i < ioasic_ndevs; i++)
176 imsk &= ~ioasic_devs[i].iad_intrbits;
177 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
178 #endif
179
180 #if 0
181 /* XXX correct if_le_ioasic.c XXX */
182 /*
183 * Set up the LANCE DMA area.
184 */
185 ioasic_lance_dma_setup(sc);
186 #endif
187
188 /*
189 * Try to configure each device.
190 */
191 ioasic_attach_devs(sc, ioasic_devs, builtin_ndevs);
192 }
193
194 void
195 ioasic_intr_establish(ioa, cookie, level, func, arg)
196 struct device *ioa;
197 void *cookie, *arg;
198 tc_intrlevel_t level;
199 int (*func) __P((void *));
200 {
201 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
202 int i, imsk, intrbits;
203
204 for (i = 0; i < ioasic_ndevs; i++) {
205 if (ioasic_devs[i].iad_cookie == cookie)
206 goto found;
207 }
208 panic("ioasic_intr_establish: invalid cookie %d", (int)cookie);
209 found:
210
211 intrtab[(int)cookie].ih_func = func;
212 intrtab[(int)cookie].ih_arg = arg;
213
214 intrbits = ioasic_devs[i].iad_intrbits;
215 iplmask[level] |= intrbits;
216 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
217 imsk |= intrbits;
218 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
219 }
220
221 void
222 ioasic_intr_disestablish(ioa, cookie)
223 struct device *ioa;
224 void *cookie;
225 {
226 printf("device %s with cookie %d: ", ioa->dv_xname, (int)cookie);
227 panic("ioasic_intr_disestablish called");
228 }
229
230 char *
231 ioasic_lance_ether_address()
232 {
233
234 return (char *)(ioasic_base + IOASIC_SLOT_2_START);
235 }
236
237 #if 0 /* Jason's new LANCE DMA region */
238 /*
239 * DMA area for IOASIC LANCE.
240 * XXX Should be done differently, but this is better than it used to be.
241 */
242 #define LE_IOASIC_MEMSIZE (128*1024)
243 #define LE_IOASIC_MEMALIGN (128*1024)
244 caddr_t le_iomem;
245
246 void ioasic_lance_dma_setup __P((struct ioasic_softc *));
247
248 void
249 ioasic_lance_dma_setup(sc)
250 struct ioasic_softc *sc;
251 {
252 bus_dma_tag_t dmat = sc->sc_dmat;
253 bus_dma_segment_t seg;
254 u_int32_t csr;
255 tc_addr_t tca;
256 int rseg;
257
258 /*
259 * Allocate a DMA area for the chip.
260 */
261 if (bus_dmamem_alloc(dmat, LE_IOASIC_MEMSIZE, LE_IOASIC_MEMALIGN,
262 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
263 printf("%s: can't allocate DMA area for LANCE\n",
264 sc->sc_dv.dv_xname);
265 return;
266 }
267 if (bus_dmamem_map(dmat, &seg, rseg, LE_IOASIC_MEMSIZE,
268 &le_iomem, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
269 printf("%s: can't map DMA area for LANCE\n",
270 sc->sc_dv.dv_xname);
271 bus_dmamem_free(dmat, &seg, rseg);
272 return;
273 }
274
275 /*
276 * Create and load the DMA map for the DMA area.
277 */
278 if (bus_dmamap_create(dmat, LE_IOASIC_MEMSIZE, 1,
279 LE_IOASIC_MEMSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_lance_dmam)) {
280 printf("%s: can't create DMA map\n", sc->sc_dv.dv_xname);
281 goto bad;
282 }
283 if (bus_dmamap_load(dmat, sc->sc_lance_dmam,
284 le_iomem, LE_IOASIC_MEMSIZE, NULL, BUS_DMA_NOWAIT)) {
285 printf("%s: can't load DMA map\n", sc->sc_dv.dv_xname);
286 goto bad;
287 }
288
289 tca = (tc_addr_t)sc->sc_lance_dmam->dm_segs[0].ds_addr;
290 if (tca != sc->sc_lance_dmam->dm_segs[0].ds_addr) {
291 printf("%s: bad LANCE DMA address\n", sc->sc_dv.dv_xname);
292 bus_dmamap_unload(dmat, sc->sc_lance_dmam);
293 goto bad;
294 }
295 bus_space_write_4(sc->sc_bst, sc->sc_bsh,
296 IOASIC_LANCE_DMAPTR,
297 ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f));
298 csr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
299 csr |= IOASIC_CSR_DMAEN_LANCE;
300 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, csr);
301 return;
302
303 bad:
304 bus_dmamem_unmap(dmat, le_iomem, LE_IOASIC_MEMSIZE);
305 bus_dmamem_free(dmat, &seg, rseg);
306 le_iomem = 0;
307 }
308 #else /* old NetBSD/pmax code */
309 void ioasic_lance_dma_setup __P((void *));
310
311 void
312 ioasic_lance_dma_setup(v)
313 void *v;
314 {
315 volatile u_int32_t *ldp;
316 tc_addr_t tca;
317
318 tca = (tc_addr_t)v;
319
320 ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
321 *ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
322 tc_wmb();
323
324 *(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
325 IOASIC_CSR_DMAEN_LANCE;
326 tc_wmb();
327 }
328 #endif
329
330 /*
331 * spl(9) for IOASIC DECstations
332 */
333
334 int _splraise_ioasic __P((int));
335 int _spllower_ioasic __P((int));
336 int _splx_ioasic __P((int));
337
338 int
339 _splraise_ioasic(lvl)
340 int lvl;
341 {
342 u_int32_t new;
343
344 new = oldiplmask[lvl] = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
345 new &= ~iplmask[lvl];
346 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = new;
347 tc_wmb();
348 return lvl | _splraise(MIPS_SOFT_INT_MASK_0|MIPS_SOFT_INT_MASK_1);
349 }
350
351 int
352 _spllower_ioasic(mask)
353 {
354 int s;
355
356 s = IPL_NONE | _spllower(mask);
357 oldiplmask[IPL_NONE] = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
358 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = iplmask[IPL_HIGH];
359 tc_wmb();
360 return s;
361 }
362
363 int
364 _splx_ioasic(lvl)
365 int lvl;
366 {
367 (void)_splset(lvl & MIPS_INT_MASK);
368 if (lvl & 0xff) {
369 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) =
370 oldiplmask[lvl & 0xff];
371 tc_wmb();
372 }
373 return 0;
374 }
375