ioasic.c revision 1.1.2.10 1 /* $NetBSD: ioasic.c,v 1.1.2.10 1999/05/11 06:43:14 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.10 1999/05/11 06:43:14 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 XINE_INTR_FDC 0x00000090
62 #define XINE_INTR_VINT 0x00000008
63 #define XINE_INTR_DTOP 0x00000001
64 #define XINE_INTR_TC_0 0x00001000
65 #define XINE_INTR_TC_1 0x00000020
66 #define KN03_INTR_TC_0 0x00000800
67 #define KN03_INTR_TC_1 0x00001000
68 #define KN03_INTR_TC_2 0x00002000
69 #define KMIN_INTR_CLOCK 0x00000020
70
71 extern u_int32_t iplmask[], oldiplmask[];
72 /* XXX XXX XXX */
73
74 #define C(x) (void *)(x)
75
76 #if defined(DEC_MAXINE)
77 struct ioasic_dev xine_ioasic_devs[] = {
78 { "lance", 0x0c0000, C(SYS_DEV_LANCE), IOASIC_INTR_LANCE, },
79 { "z8530 ", 0x100000, C(SYS_DEV_SCC0), IOASIC_INTR_SCC_0, },
80 { "mc146818", 0x200000, C(SYS_DEV_BOGUS), 0, },
81 { "isdn", 0x240000, C(SYS_DEV_ISDN), IOASIC_INTR_ISDN, },
82 { "dtop", 0x280000, C(SYS_DEV_DTOP), XINE_INTR_DTOP, },
83 { "fdc", 0x2C0000, C(SYS_DEV_FDC), XINE_INTR_FDC, },
84 { "asc", 0x300000, C(SYS_DEV_SCSI), IOASIC_INTR_SCSI },
85 { "(TC0)", 0x0, C(SYS_DEV_OPT0), XINE_INTR_TC_0 },
86 { "(TC1)", 0x0, C(SYS_DEV_OPT1), XINE_INTR_TC_1 },
87 { "(TC2)", 0x0, C(SYS_DEV_OPT2), XINE_INTR_VINT },
88 };
89 int xine_builtin_ndevs = 7;
90 int xine_ioasic_ndevs = sizeof(xine_ioasic_devs)/sizeof(xine_ioasic_devs[0]);
91 #endif
92
93 #if defined(DEC_3MIN) || defined(DEC_3MAXPLUS)
94 struct ioasic_dev kn03_ioasic_devs[] = {
95 { "lance", 0x0c0000, C(SYS_DEV_LANCE), IOASIC_INTR_LANCE, },
96 { "z8530 ", 0x100000, C(SYS_DEV_SCC0), IOASIC_INTR_SCC_0, },
97 { "z8530 ", 0x180000, C(SYS_DEV_SCC1), IOASIC_INTR_SCC_1, },
98 { "mc146818", 0x200000, C(SYS_DEV_BOGUS), KMIN_INTR_CLOCK, },
99 { "asc", 0x300000, C(SYS_DEV_SCSI), IOASIC_INTR_SCSI },
100 { "(TC0)", 0x0, C(SYS_DEV_OPT0), KN03_INTR_TC_0 },
101 { "(TC1)", 0x0, C(SYS_DEV_OPT1), KN03_INTR_TC_1 },
102 { "(TC2)", 0x0, C(SYS_DEV_OPT2), KN03_INTR_TC_2 },
103 };
104 int kn03_builtin_ndevs = 5;
105 int kn03_ioasic_ndevs = sizeof(kn03_ioasic_devs)/sizeof(kn03_ioasic_devs[0]);
106 #endif
107
108 struct ioasic_dev *ioasic_devs;
109 int ioasic_ndevs, builtin_ndevs;
110
111 int
112 ioasicmatch(parent, cfdata, aux)
113 struct device *parent;
114 struct cfdata *cfdata;
115 void *aux;
116 {
117 struct tc_attach_args *ta = aux;
118
119 /* Make sure that we're looking for this type of device. */
120 if (strncmp("IOCTL ", ta->ta_modname, TC_ROM_LLEN))
121 return (0);
122
123 if (cfdata->cf_unit > 0)
124 return (0);
125
126 switch (systype) {
127 #if defined(DEC_MAXINE)
128 case DS_MAXINE:
129 ioasic_devs = xine_ioasic_devs;
130 ioasic_ndevs = xine_ioasic_ndevs;
131 builtin_ndevs = xine_builtin_ndevs;
132 break;
133 #endif
134 #if defined(DEC_3MIN) || defined(DEC_3MAXPLUS)
135 case DS_3MIN:
136 case DS_3MAXPLUS:
137 ioasic_devs = kn03_ioasic_devs;
138 ioasic_ndevs = kn03_ioasic_ndevs;
139 builtin_ndevs = kn03_builtin_ndevs;
140 break;
141 #endif
142 default:
143 panic("ioasicmatch: how did we get here?");
144 }
145
146 return (1);
147 }
148
149 void
150 ioasicattach(parent, self, aux)
151 struct device *parent, *self;
152 void *aux;
153 {
154 struct ioasic_softc *sc = (struct ioasic_softc *)self;
155 struct tc_attach_args *ta = aux;
156 int i, imsk;
157
158 sc->sc_bst = ta->ta_memt;
159 if (bus_space_map(ta->ta_memt, ta->ta_addr,
160 0x400000, 0, &sc->sc_bsh)) {
161 printf("%s: unable to map device\n", sc->sc_dv.dv_xname);
162 return;
163 }
164 sc->sc_dmat = ta->ta_dmat;
165 sc->sc_cookie = ta->ta_cookie;
166
167 sc->sc_base = ta->ta_addr; /* XXX XXX XXX */
168
169 printf("\n");
170
171 /*
172 * Turn off all device interrupt bits.
173 * (This _does_ include TC option slot bits.
174 */
175 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
176 for (i = 0; i < ioasic_ndevs; i++)
177 imsk &= ~ioasic_devs[i].iad_intrbits;
178 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk);
179
180 #if 0
181 (void)ioasic_lance_dma_setup(sc);
182 #endif
183
184 /*
185 * Try to configure each device.
186 */
187 ioasic_attach_devs(sc, ioasic_devs, builtin_ndevs);
188 }
189
190 void
191 ioasic_intr_establish(ioa, cookie, level, func, arg)
192 struct device *ioa;
193 void *cookie, *arg;
194 tc_intrlevel_t level;
195 int (*func) __P((void *));
196 {
197 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
198 int i, intrbits;
199
200 for (i = 0; i < ioasic_ndevs; i++) {
201 if (ioasic_devs[i].iad_cookie == cookie)
202 goto found;
203 }
204 panic("ioasic_intr_establish: invalid cookie %d", (int)cookie);
205 found:
206
207 intrtab[(int)cookie].ih_func = func;
208 intrtab[(int)cookie].ih_arg = arg;
209
210 intrbits = ioasic_devs[i].iad_intrbits;
211 i = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK);
212 i |= intrbits;
213 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, i);
214 iplmask[level] |= intrbits;
215 }
216
217 void
218 ioasic_intr_disestablish(ioa, cookie)
219 struct device *ioa;
220 void *cookie;
221 {
222 printf("device %s with cookie %d: ", ioa->dv_xname, (int)cookie);
223 panic("ioasic_intr_disestablish called");
224 }
225
226 char *
227 ioasic_lance_ether_address()
228 {
229
230 return (char *)(ioasic_base + IOASIC_SLOT_2_START);
231 }
232
233 #if 0 /* Jason's new LANCE DMA region */
234 /*
235 * DMA area for IOASIC LANCE.
236 * XXX Should be done differently, but this is better than it used to be.
237 */
238 #define LE_IOASIC_MEMSIZE (128*1024)
239 #define LE_IOASIC_MEMALIGN (128*1024)
240 caddr_t le_iomem;
241
242 int
243 ioasic_lance_dma_setup(sc)
244 struct ioasic_softc *sc;
245 {
246 bus_dma_tag_t dmat = sc->sc_dmat;
247 bus_dmamap_t le_dmam;
248 bus_dma_segment_t seg;
249 caddr_t le_mem;
250 u_int32_t csr;
251 tc_addr_t tca;
252 int rseg;
253
254 /*
255 * Allocate a DMA area for the chip.
256 */
257 if (bus_dmamem_alloc(dmat, LE_IOASIC_MEMSIZE, LE_IOASIC_MEMALIGN,
258 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
259 printf("%s: can't allocate DMA area for LANCE\n",
260 sc->sc_dv.dv_xname);
261 return 0;
262 }
263 if (bus_dmamem_map(dmat, &seg, rseg, LE_IOASIC_MEMSIZE,
264 &le_mem, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
265 printf("%s: can't map DMA area for LANCE\n",
266 sc->sc_dv.dv_xname);
267 bus_dmamem_free(dmat, &seg, rseg);
268 return 0;
269 }
270
271 /*
272 * Create and load the DMA map for the DMA area.
273 */
274 if (bus_dmamap_create(dmat, LE_IOASIC_MEMSIZE, 1,
275 LE_IOASIC_MEMSIZE, 0, BUS_DMA_NOWAIT, &le_dmam)) {
276 printf("%s: can't create DMA map\n", sc->sc_dv.dv_xname);
277 goto bad;
278 }
279 if (bus_dmamap_load(dmat, le_dmam,
280 &le_iomem, LE_IOASIC_MEMSIZE, NULL, BUS_DMA_NOWAIT)) {
281 printf("%s: can't load DMA map\n", sc->sc_dv.dv_xname);
282 goto bad;
283 }
284 tca = (tc_addr_t)le_dmam->dm_segs[0].ds_addr;
285 #if 0
286 if (tca != le_dmam->dm_segs[0].ds_addr) {
287 printf("%s: bad LANCE DMA address\n", sc->sc_dv.dv_xname);
288 bus_dmamap_unload(dmat, le_dmam);
289 goto bad;
290 }
291 #endif
292 bus_space_write_4(sc->sc_bst, sc->sc_bsh,
293 IOASIC_LANCE_DMAPTR,
294 ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f));
295 csr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
296 csr |= IOASIC_CSR_DMAEN_LANCE;
297 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, csr);
298 return tca;
299
300 bad:
301 bus_dmamem_unmap(dmat, le_iomem, LE_IOASIC_MEMSIZE);
302 bus_dmamem_free(dmat, &seg, rseg);
303 return tca;
304 }
305 #else /* old NetBSD/pmax code */
306 void ioasic_lance_dma_setup __P((void *));
307
308 void
309 ioasic_lance_dma_setup(v)
310 void *v;
311 {
312 volatile u_int32_t *ldp;
313 tc_addr_t tca;
314
315 tca = (tc_addr_t)v;
316
317 ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
318 *ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
319 tc_wmb();
320
321 *(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
322 IOASIC_CSR_DMAEN_LANCE;
323 tc_wmb();
324 }
325 #endif
326
327 /*
328 * spl(9) for IOASIC DECstations
329 */
330
331 int _splraise_ioasic __P((int));
332 int _spllower_ioasic __P((int));
333 int _splx_ioasic __P((int));
334
335 int
336 _splraise_ioasic(lvl)
337 int lvl;
338 {
339 u_int32_t new;
340
341 new = oldiplmask[lvl] = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
342 new &= ~iplmask[lvl];
343 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = new;
344 tc_wmb();
345 return lvl | _splraise(MIPS_SOFT_INT_MASK_0|MIPS_SOFT_INT_MASK_1);
346 }
347
348 int
349 _spllower_ioasic(mask)
350 {
351 int s;
352
353 s = IPL_NONE | _spllower(mask);
354 oldiplmask[IPL_NONE] = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
355 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = iplmask[IPL_HIGH];
356 tc_wmb();
357 return s;
358 }
359
360 int
361 _splx_ioasic(lvl)
362 int lvl;
363 {
364 (void)_splset(lvl & MIPS_INT_MASK);
365 if (lvl & 0xff) {
366 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) =
367 oldiplmask[lvl & 0xff];
368 tc_wmb();
369 }
370 return 0;
371 }
372