vme_pcc.c revision 1.6.24.5 1 /* $NetBSD: vme_pcc.c,v 1.6.24.5 2000/03/18 16:56:48 scw Exp $ */
2
3 /*-
4 * Copyright (c) 1996-2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe and Steve C. Woodford.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * VME support specific to the Type 1 VMEchip found on the
41 * MVME-147.
42 *
43 * For a manual on the MVME-147, call: 408.991.8634. (Yes, this
44 * is the Sunnyvale sales office.)
45 */
46
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/malloc.h>
52 #include <sys/kcore.h>
53
54 #include <machine/cpu.h>
55 #include <machine/bus.h>
56
57 #include <dev/vme/vmereg.h>
58 #include <dev/vme/vmevar.h>
59
60 #include <mvme68k/mvme68k/isr.h>
61
62 #include <mvme68k/dev/pccreg.h>
63 #include <mvme68k/dev/pccvar.h>
64 #include <mvme68k/dev/vme_pccreg.h>
65 #include <mvme68k/dev/vme_pccvar.h>
66
67
68 static int vme_pcc_match __P((struct device *, struct cfdata *, void *));
69 static void vme_pcc_attach __P((struct device *, struct device *, void *));
70
71 struct cfattach vmepcc_ca = {
72 sizeof(struct vme_pcc_softc), vme_pcc_match, vme_pcc_attach
73 };
74
75 extern struct cfdriver vmepcc_cd;
76
77 extern phys_ram_seg_t mem_clusters[];
78 static int vme_pcc_attached;
79
80 #ifdef DIAGNOSTIC
81 const char *_vme1_mod_string __P((vme_addr_t, vme_size_t,
82 vme_am_t, vme_datasize_t));
83 #endif
84
85 /*
86 * Describe the VMEbus ranges available from the MVME147
87 */
88 struct vme_pcc_range {
89 vme_am_t pr_am; /* Address Modifier for this range */
90 vme_datasize_t pr_datasize; /* Usable Data Sizes (D8, D16, D32) */
91 vme_addr_t pr_start; /* Local-bus start address of range */
92 vme_addr_t pr_end; /* Local-bus end address of range */
93 };
94
95 static struct vme_pcc_range vme_pcc_ranges[] = {
96 {VME_AM_MBO | VME_AM_A24 | VME_AM_DATA | VME_AM_SUPER,
97 VME_D32 | VME_D16 | VME_D8, VME1_A24D32_START, VME1_A24D32_END},
98 {VME_AM_MBO | VME_AM_A32 | VME_AM_DATA | VME_AM_SUPER,
99 VME_D32 | VME_D16 | VME_D8, VME1_A32D32_START, VME1_A32D32_END},
100 {VME_AM_MBO | VME_AM_A24 | VME_AM_DATA | VME_AM_SUPER,
101 VME_D16 | VME_D8, VME1_A24D16_START, VME1_A24D16_END},
102 {VME_AM_MBO | VME_AM_A32 | VME_AM_DATA | VME_AM_SUPER,
103 VME_D16 | VME_D8, VME1_A32D16_START, VME1_A32D16_END},
104 {VME_AM_MBO | VME_AM_A16 | VME_AM_DATA | VME_AM_SUPER,
105 VME_D16 | VME_D8, VME1_A16D16_START, VME1_A16D16_END}
106 };
107 #define VME1_NRANGES (sizeof(vme_pcc_ranges)/sizeof(struct vme_pcc_range))
108
109
110 static int
111 vme_pcc_match(parent, cf, aux)
112 struct device *parent;
113 struct cfdata *cf;
114 void *aux;
115 {
116 struct pcc_attach_args *pa = aux;
117
118 /* Only one VME chip, please. */
119 if (vme_pcc_attached)
120 return (0);
121
122 if (strcmp(pa->pa_name, vmepcc_cd.cd_name))
123 return (0);
124
125 return (1);
126 }
127
128 static void
129 vme_pcc_attach(parent, self, aux)
130 struct device *parent, *self;
131 void *aux;
132 {
133 struct pcc_attach_args *pa;
134 struct vme_pcc_softc *sc;
135 struct vmebus_attach_args vaa;
136 u_int8_t reg;
137 int i;
138
139 sc = (struct vme_pcc_softc *) self;
140 pa = (struct pcc_attach_args *) aux;
141
142 sc->sc_dmat = pa->pa_dmat;
143 sc->sc_bust = pa->pa_bust;
144 sc->sc_vmet = MVME68K_VME_BUS_SPACE;
145
146 bus_space_map(sc->sc_bust, pa->pa_offset, VME1REG_SIZE,0, &sc->sc_bush);
147
148 /* Initialize the chip. */
149 reg = vme1_reg_read(sc, VME1REG_SCON) & ~VME1_SCON_SYSFAIL;
150 vme1_reg_write(sc, VME1REG_SCON, reg);
151
152 printf(": Type 1 VMEchip, scon jumper %s\n",
153 (reg & VME1_SCON_SWITCH) ? "enabled" : "disabled");
154
155 sc->sc_vct.cookie = self;
156 sc->sc_vct.vct_probe = _vme_pcc_probe;
157 sc->sc_vct.vct_map = _vme_pcc_map;
158 sc->sc_vct.vct_unmap = _vme_pcc_unmap;
159 sc->sc_vct.vct_int_map = _vme_pcc_intmap;
160 sc->sc_vct.vct_int_establish = _vme_pcc_intr_establish;
161 sc->sc_vct.vct_int_disestablish = _vme_pcc_intr_disestablish;
162 sc->sc_vct.vct_dmamap_create = _vme_pcc_dmamap_create;
163 sc->sc_vct.vct_dmamap_destroy = _vme_pcc_dmamap_destroy;
164 sc->sc_vct.vct_dmamem_alloc = _vme_pcc_dmamem_alloc;
165 sc->sc_vct.vct_dmamem_free = _vme_pcc_dmamem_free;
166
167 /*
168 * Adjust the start address of the first range in vme_pcc_ranges[]
169 * according to how much onboard memory exists. Disable the first
170 * range if onboard memory >= 16Mb, and adjust the start of the
171 * second range (A32D32).
172 */
173 vme_pcc_ranges[0].pr_start = (vme_addr_t) mem_clusters[0].size;
174 if ( mem_clusters[0].size >= 0x01000000 ) {
175 vme_pcc_ranges[0].pr_am = (vme_am_t) -1;
176 vme_pcc_ranges[1].pr_start +=
177 (vme_addr_t) (mem_clusters[0].size - 0x01000000);
178 }
179
180 #ifdef DIAGNOSTIC
181 for (i = 0; i < VME1_NRANGES; i++) {
182 vme_addr_t mask;
183
184 switch ( vme_pcc_ranges[i].pr_am & VME_AM_ADRSIZEMASK ) {
185 case VME_AM_A32:
186 mask = 0xffffffffu;
187 break;
188
189 case VME_AM_A24:
190 mask = 0x00ffffffu;
191 break;
192
193 case VME_AM_A16:
194 mask = 0x0000ffffu;
195 break;
196
197 default:
198 printf("%s: Map#%d: disabled\n",
199 sc->sc_dev.dv_xname, i);
200 continue;
201 }
202
203 printf("%s: Map#%d: 0x%08x -> %s\n", sc->sc_dev.dv_xname, i,
204 vme_pcc_ranges[i].pr_start,
205 _vme1_mod_string(vme_pcc_ranges[i].pr_start & mask,
206 (vme_pcc_ranges[i].pr_end -
207 vme_pcc_ranges[i].pr_start) + 1,
208 vme_pcc_ranges[i].pr_am,
209 vme_pcc_ranges[i].pr_datasize));
210 }
211 #endif
212
213 vaa.va_vct = &(sc->sc_vct);
214 vaa.va_bdt = sc->sc_dmat;
215 vaa.va_slaveconfig = NULL;
216
217 vme_pcc_attached = 1;
218
219 /* Attach the MI VMEbus glue. */
220 config_found(self, &vaa, 0);
221 }
222
223 int
224 _vme_pcc_map(vsc, vmeaddr, len, am, datasize, swap, tag, handle, resc)
225 void *vsc;
226 vme_addr_t vmeaddr;
227 vme_size_t len;
228 vme_am_t am;
229 vme_datasize_t datasize;
230 vme_swap_t swap;
231 bus_space_tag_t *tag;
232 bus_space_handle_t *handle;
233 vme_mapresc_t *resc;
234 {
235 struct vme_pcc_softc *sc;
236 struct vme_pcc_mapresc_t *pm;
237 struct vme_pcc_range *pr;
238 vme_addr_t end, mask;
239 paddr_t paddr;
240 int rv;
241 int i;
242
243 sc = (struct vme_pcc_softc *) vsc;
244
245 end = (vmeaddr + len) - 1;
246 mask = 0;
247 paddr = 0;
248
249 switch ( am & VME_AM_ADRSIZEMASK ) {
250 case VME_AM_A32:
251 mask = 0xffffffffu;
252 break;
253
254 case VME_AM_A24:
255 mask = 0x00ffffffu;
256 break;
257
258 case VME_AM_A16:
259 mask = 0x0000ffffu;
260 break;
261
262 case VME_AM_USERDEF:
263 printf("%s: User-defined address modifiers not supported\n",
264 sc->sc_dev.dv_xname);
265 return EINVAL;
266 }
267
268 for (i = 0, pr = &vme_pcc_ranges[0]; i < VME1_NRANGES; i++, pr++) {
269 /* Ignore if range is disabled */
270 if ( pr->pr_am == (vme_am_t) -1 )
271 continue;
272
273 /*
274 * Accept the range if it matches the constraints
275 */
276 if ( am == pr->pr_am &&
277 datasize <= pr->pr_datasize &&
278 vmeaddr >= (pr->pr_start & mask) &&
279 end <= (pr->pr_end & mask) ) {
280 /*
281 * We have a match.
282 */
283 paddr = pr->pr_start + vmeaddr;
284 break;
285 }
286 }
287
288 if ( paddr == 0 ) {
289 #ifdef DIAGNOSTIC
290 printf("%s: Unable to map %s\n", sc->sc_dev.dv_xname,
291 _vme1_mod_string(vmeaddr, len, am, datasize));
292 #endif
293 return ENOMEM;
294 }
295
296 if ( (rv = bus_space_map(sc->sc_vmet, paddr, len, 0, handle)) != 0 )
297 return rv;
298
299 if ( (pm = malloc(sizeof(*pm), M_DEVBUF, M_NOWAIT)) == NULL ) {
300 bus_space_unmap(sc->sc_vmet, *handle, len);
301 return ENOMEM;
302 }
303
304 *tag = sc->sc_vmet;
305 pm->pm_am = am;
306 pm->pm_datasize = datasize;
307 pm->pm_addr = vmeaddr;
308 pm->pm_size = len;
309 pm->pm_handle = *handle;
310 *resc = (vme_mapresc_t *) pm;
311
312 return 0;
313 }
314
315 void
316 _vme_pcc_unmap(vsc, resc)
317 void *vsc;
318 vme_mapresc_t resc;
319 {
320 struct vme_pcc_softc *sc;
321 struct vme_pcc_mapresc_t *pm;
322
323 sc = (struct vme_pcc_softc *) vsc;
324 pm = (struct vme_pcc_mapresc_t *) resc;
325
326 bus_space_unmap(sc->sc_vmet, pm->pm_handle, pm->pm_size);
327
328 free(pm, M_DEVBUF);
329 }
330
331 int
332 _vme_pcc_probe(vsc, vmeaddr, len, am, datasize, callback, arg)
333 void *vsc;
334 vme_addr_t vmeaddr;
335 vme_size_t len;
336 vme_am_t am;
337 vme_datasize_t datasize;
338 int (*callback) __P((void *, bus_space_tag_t, bus_space_handle_t));
339 void *arg;
340 {
341 bus_space_tag_t tag;
342 bus_space_handle_t handle;
343 vme_mapresc_t resc;
344 int rv;
345
346 rv = _vme_pcc_map(vsc, vmeaddr, len, am, datasize,
347 0, &tag, &handle, &resc);
348 if ( rv )
349 return rv;
350
351 if ( callback )
352 rv = (*callback)(arg, tag, handle);
353 else {
354 /*
355 * FIXME: datasize is fixed by hardware, so using badaddr() in
356 * this way may cause several accesses to each VMEbus address.
357 * Also, using 'handle' in this way is a bit presumptuous...
358 */
359 rv = badaddr((caddr_t) handle, (int) len) ? EIO : 0;
360 }
361
362 _vme_pcc_unmap(vsc, resc);
363
364 return rv;
365 }
366
367 int
368 _vme_pcc_intmap(vsc, level, vector, handlep)
369 void *vsc;
370 int level, vector;
371 vme_intr_handle_t *handlep;
372 {
373 if ( level < 0x80 )
374 return EINVAL;
375
376 /* This is rather gross */
377 *handlep = (void *)(int)((level << 8) | vector);
378
379 return 0;
380 }
381
382 void *
383 _vme_pcc_intr_establish(vsc, handle, prior, func, arg)
384 void *vsc;
385 vme_intr_handle_t handle;
386 int prior;
387 int (*func) __P((void *));
388 void *arg;
389 {
390 struct vme_pcc_softc *sc;
391 int level, vector;
392
393 sc = (struct vme_pcc_softc *) vsc;
394 level = ((int)handle) >> 8;
395 vector = ((int)handle) & 0xff;
396
397 isrlink_vectored(func, arg, level, vector);
398 sc->sc_irqref[level]++;
399
400 /*
401 * There had better not be another VMEbus master responding
402 * to this interrupt level...
403 */
404 vme1_reg_write(sc, VME1REG_IRQEN,
405 vme1_reg_read(sc, VME1REG_IRQEN) | VME1_IRQ_VME(level));
406
407 return (void *) handle;
408 }
409
410 void
411 _vme_pcc_intr_disestablish(vsc, handle)
412 void *vsc;
413 vme_intr_handle_t handle;
414 {
415 struct vme_pcc_softc *sc;
416 int level, vector;
417
418 sc = (struct vme_pcc_softc *) vsc;
419 level = ((int)handle) >> 8;
420 vector = ((int)handle) & 0xff;
421
422 isrunlink_vectored(vector);
423
424 /* Disable VME IRQ if possible. */
425 switch (sc->sc_irqref[level]) {
426 case 0:
427 printf("vme_pcc_intr_disestablish: nothing using IRQ %d\n",
428 level);
429 panic("vme_pcc_intr_disestablish");
430 /* NOTREACHED */
431
432 case 1:
433 vme1_reg_write(sc, VME1REG_IRQEN,
434 vme1_reg_read(sc, VME1REG_IRQEN) & ~VME1_IRQ_VME(level));
435 /* FALLTHROUGH */
436
437 default:
438 sc->sc_irqref[level]--;
439 }
440 }
441
442 int
443 _vme_pcc_dmamap_create(vsc, len, am, datasize, swap, nsegs,
444 segsz, bound, flags, mapp)
445 void *vsc;
446 vme_size_t len;
447 vme_am_t am;
448 vme_datasize_t datasize;
449 vme_swap_t swap;
450 int nsegs;
451 vme_size_t segsz;
452 vme_addr_t bound;
453 int flags;
454 bus_dmamap_t *mapp;
455 {
456 return (EINVAL);
457 }
458
459 void
460 _vme_pcc_dmamap_destroy(vsc, map)
461 void *vsc;
462 bus_dmamap_t map;
463 {
464 }
465
466 int
467 _vme_pcc_dmamem_alloc(vsc, len, am, datasizes, swap,
468 segs, nsegs, rsegs, flags)
469 void *vsc;
470 vme_size_t len;
471 vme_am_t am;
472 vme_datasize_t datasizes;
473 vme_swap_t swap;
474 bus_dma_segment_t *segs;
475 int nsegs;
476 int *rsegs;
477 int flags;
478 {
479 return (EINVAL);
480 }
481
482 void
483 _vme_pcc_dmamem_free(vsc, segs, nsegs)
484 void *vsc;
485 bus_dma_segment_t *segs;
486 int nsegs;
487 {
488 }
489
490 #ifdef DIAGNOSTIC
491 const char *
492 _vme1_mod_string(addr, len, am, ds)
493 vme_addr_t addr;
494 vme_size_t len;
495 vme_am_t am;
496 vme_datasize_t ds;
497 {
498 static const char *mode[] = {"BLT64)", "DATA)", "PROG)", "BLT32)"};
499 static char mstring[40];
500 static char mdata[10];
501 char *fmt;
502
503 mdata[0] = '\0';
504 if ( ds & VME_D32 )
505 strcat(mdata, "D32");
506 if ( ds & VME_D16 )
507 strcat(mdata, mdata[0] == '\0' ? "D16" : "|D16");
508 if ( ds & VME_D8 )
509 strcat(mdata, mdata[0] == '\0' ? "D8" : "|D8");
510
511 switch ( am & VME_AM_ADRSIZEMASK ) {
512 case VME_AM_A32:
513 fmt = "A32%s:0x%08x-0x%08x";
514 break;
515
516 case VME_AM_A24:
517 fmt = "A24%s:0x%06x-0x%06x";
518 break;
519
520 case VME_AM_A16:
521 fmt = "A16%s:0x%04x-0x%04x";
522 break;
523
524 case VME_AM_USERDEF:
525 fmt = "USR%s:0x%08x-0x%08x";
526 break;
527 }
528
529 sprintf(mstring, fmt, mdata, addr, addr + len - 1);
530 strcat(mstring, ((am & VME_AM_PRIVMASK) == VME_AM_USER) ?
531 " (USER," : " (SUPER,");
532 strcat(mstring, mode[am & VME_AM_MODEMASK]);
533
534 return (mstring);
535 }
536 #endif
537