ioasic.c revision 1.1.2.6 1 /* $NetBSD: ioasic.c,v 1.1.2.6 1999/03/30 07:09:42 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.6 1999/03/30 07:09:42 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(DS_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;
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 /* XXX XXX XXX */
166 sc->sc_base = ta->ta_addr;
167
168 printf("\n");
169
170 #if 1 /* !!! necessary? already all-0 upon booting as documented !!! */
171 /*
172 * Turn off all device interrupt bits.
173 * (This _does_ include TC option slot bits.
174 */
175 for (i = 0; i < ioasic_ndevs; i++)
176 *(volatile u_int32_t *)(sc->sc_base + IOASIC_IMSK)
177 &= ~ioasic_devs[i].iad_intrbits;
178 tc_wmb();
179 #endif
180
181 #if 0
182 /* XXX correct if_le_ioasic.c XXX */
183 /*
184 * Set up the LANCE DMA area.
185 */
186 ioasic_lance_dma_setup(sc);
187 #endif
188
189 /*
190 * Try to configure each device.
191 */
192 ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs);
193 }
194
195 void
196 ioasic_intr_establish(ioa, cookie, level, func, arg)
197 struct device *ioa;
198 void *cookie, *arg;
199 tc_intrlevel_t level;
200 int (*func) __P((void *));
201 {
202 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
203 u_int dev, i, intrbits;
204
205 dev = (u_long)cookie;
206
207 for (i = 0; i < ioasic_ndevs; i++) {
208 if (ioasic_devs[i].iad_cookie == cookie)
209 goto found;
210 }
211 panic("ioasic_intr_establish: invalid cookie %d", dev);
212 found:
213
214 intrtab[dev].ih_func = func;
215 intrtab[dev].ih_arg = arg;
216
217 intrbits = ioasic_devs[i].iad_intrbits;
218 iplmask[level] |= intrbits;
219 *(volatile u_int32_t *)(sc->sc_base + IOASIC_IMSK) |= intrbits;
220 tc_wmb();
221 }
222
223 void
224 ioasic_intr_disestablish(ioa, cookie)
225 struct device *ioa;
226 void *cookie;
227 {
228 printf("device %s with cookie %d: ", ioa->dv_xname, (int)cookie);
229 panic("ioasic_intr_disestablish called");
230 }
231
232 char *
233 ioasic_lance_ether_address()
234 {
235
236 return (char *)(ioasic_base + IOASIC_SLOT_2_START);
237 }
238
239 #if 0 /* Jason's new LANCE DMA region */
240 /*
241 * DMA area for IOASIC LANCE.
242 * XXX Should be done differently, but this is better than it used to be.
243 */
244 #define LE_IOASIC_MEMSIZE (128*1024)
245 #define LE_IOASIC_MEMALIGN (128*1024)
246 caddr_t le_iomem;
247
248 void ioasic_lance_dma_setup __P((struct ioasic_softc *));
249
250 void
251 ioasic_lance_dma_setup(sc)
252 struct ioasic_softc *sc;
253 {
254 bus_dma_tag_t dmat = sc->sc_dmat;
255 bus_dma_segment_t seg;
256 u_int32_t csr;
257 tc_addr_t tca;
258 int rseg;
259
260 /*
261 * Allocate a DMA area for the chip.
262 */
263 if (bus_dmamem_alloc(dmat, LE_IOASIC_MEMSIZE, LE_IOASIC_MEMALIGN,
264 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
265 printf("%s: can't allocate DMA area for LANCE\n",
266 sc->sc_dv.dv_xname);
267 return;
268 }
269 if (bus_dmamem_map(dmat, &seg, rseg, LE_IOASIC_MEMSIZE,
270 &le_iomem, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
271 printf("%s: can't map DMA area for LANCE\n",
272 sc->sc_dv.dv_xname);
273 bus_dmamem_free(dmat, &seg, rseg);
274 return;
275 }
276
277 /*
278 * Create and load the DMA map for the DMA area.
279 */
280 if (bus_dmamap_create(dmat, LE_IOASIC_MEMSIZE, 1,
281 LE_IOASIC_MEMSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_lance_dmam)) {
282 printf("%s: can't create DMA map\n", sc->sc_dv.dv_xname);
283 goto bad;
284 }
285 if (bus_dmamap_load(dmat, sc->sc_lance_dmam,
286 le_iomem, LE_IOASIC_MEMSIZE, NULL, BUS_DMA_NOWAIT)) {
287 printf("%s: can't load DMA map\n", sc->sc_dv.dv_xname);
288 goto bad;
289 }
290
291 tca = (tc_addr_t)sc->sc_lance_dmam->dm_segs[0].ds_addr;
292 if (tca != sc->sc_lance_dmam->dm_segs[0].ds_addr) {
293 printf("%s: bad LANCE DMA address\n", sc->sc_dv.dv_xname);
294 bus_dmamap_unload(dmat, sc->sc_lance_dmam);
295 goto bad;
296 }
297 bus_space_write_4(sc->sc_bst, sc->sc_bsh,
298 IOASIC_LANCE_DMAPTR,
299 ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f));
300 csr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
301 csr |= IOASIC_CSR_DMAEN_LANCE;
302 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, csr);
303 return;
304
305 bad:
306 bus_dmamem_unmap(dmat, le_iomem, LE_IOASIC_MEMSIZE);
307 bus_dmamem_free(dmat, &seg, rseg);
308 le_iomem = 0;
309 }
310 #else /* old NetBSD/pmax code */
311 void ioasic_lance_dma_setup __P((void *));
312
313 void
314 ioasic_lance_dma_setup(v)
315 void *v;
316 {
317 volatile u_int32_t *ldp;
318 tc_addr_t tca;
319
320 tca = (tc_addr_t)v;
321
322 ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
323 *ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
324 tc_wmb();
325
326 *(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
327 IOASIC_CSR_DMAEN_LANCE;
328 tc_wmb();
329 }
330 #endif
331
332 /*
333 * spl(9) for IOASIC DECstations
334 */
335
336 int _splraise_ioasic __P((int));
337 int _spllower_ioasic __P((int));
338 int _splx_ioasic __P((int));
339
340 int
341 _splraise_ioasic(lvl)
342 int lvl;
343 {
344 u_int32_t new;
345
346 new = oldiplmask[lvl] = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
347 new &= ~iplmask[lvl];
348 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = new;
349 tc_wmb();
350 return lvl | _splraise(MIPS_SOFT_INT_MASK_0|MIPS_SOFT_INT_MASK_1);
351 }
352
353 int
354 _spllower_ioasic(mask)
355 {
356 int s;
357
358 s = IPL_NONE | _spllower(mask);
359 oldiplmask[IPL_NONE] = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
360 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) = iplmask[IPL_HIGH];
361 tc_wmb();
362 return s;
363 }
364
365 int
366 _splx_ioasic(lvl)
367 int lvl;
368 {
369 (void)_splset(lvl & MIPS_INT_MASK);
370 if (lvl & 0xff) {
371 *(u_int32_t *)(ioasic_base + IOASIC_IMSK) =
372 oldiplmask[lvl & 0xff];
373 tc_wmb();
374 }
375 return 0;
376 }
377