vme_pcc.c revision 1.9 1 /* $NetBSD: vme_pcc.c,v 1.9 2000/06/24 20:43:14 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 int vme_pcc_match __P((struct device *, struct cfdata *, void *));
69 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_locstart; /* Local-bus start address of range */
92 vme_addr_t pr_start; /* VMEbus start address of range */
93 vme_addr_t pr_end; /* VMEbus end address of range */
94 };
95
96 static struct vme_pcc_range vme_pcc_ranges[] = {
97 {VME_AM_MBO | VME_AM_A24 | VME_AM_DATA | VME_AM_SUPER,
98 VME_D32 | VME_D16 | VME_D8,
99 VME1_A24D32_LOC_START,
100 VME1_A24D32_START,
101 VME1_A24D32_END},
102
103 {VME_AM_MBO | VME_AM_A32 | VME_AM_DATA | VME_AM_SUPER,
104 VME_D32 | VME_D16 | VME_D8,
105 VME1_A32D32_LOC_START,
106 VME1_A32D32_START,
107 VME1_A32D32_END},
108
109 {VME_AM_MBO | VME_AM_A24 | VME_AM_DATA | VME_AM_SUPER,
110 VME_D16 | VME_D8,
111 VME1_A24D16_LOC_START,
112 VME1_A24D16_START,
113 VME1_A24D16_END},
114
115 {VME_AM_MBO | VME_AM_A32 | VME_AM_DATA | VME_AM_SUPER,
116 VME_D16 | VME_D8,
117 VME1_A32D16_LOC_START,
118 VME1_A32D16_START,
119 VME1_A32D16_END},
120
121 {VME_AM_MBO | VME_AM_A16 | VME_AM_DATA | VME_AM_SUPER,
122 VME_D16 | VME_D8,
123 VME1_A16D16_LOC_START,
124 VME1_A16D16_START,
125 VME1_A16D16_END}
126 };
127 #define VME1_NRANGES (sizeof(vme_pcc_ranges)/sizeof(struct vme_pcc_range))
128
129
130 /* ARGSUSED */
131 int
132 vme_pcc_match(parent, cf, aux)
133 struct device *parent;
134 struct cfdata *cf;
135 void *aux;
136 {
137 struct pcc_attach_args *pa;
138
139 pa = aux;
140
141 /* Only one VME chip, please. */
142 if (vme_pcc_attached)
143 return (0);
144
145 if (strcmp(pa->pa_name, vmepcc_cd.cd_name))
146 return (0);
147
148 return (1);
149 }
150
151 void
152 vme_pcc_attach(parent, self, aux)
153 struct device *parent;
154 struct device *self;
155 void *aux;
156 {
157 struct pcc_attach_args *pa;
158 struct vme_pcc_softc *sc;
159 struct vmebus_attach_args vaa;
160 u_int8_t reg;
161
162 sc = (struct vme_pcc_softc *) self;
163 pa = aux;
164
165 sc->sc_dmat = pa->pa_dmat;
166 sc->sc_bust = pa->pa_bust;
167 sc->sc_vmet = MVME68K_VME_BUS_SPACE;
168
169 bus_space_map(sc->sc_bust, pa->pa_offset, VME1REG_SIZE, 0,
170 &sc->sc_bush);
171
172 /* Initialize the chip. */
173 reg = vme1_reg_read(sc, VME1REG_SCON) & ~VME1_SCON_SYSFAIL;
174 vme1_reg_write(sc, VME1REG_SCON, reg);
175
176 printf(": Type 1 VMEchip, scon jumper %s\n",
177 (reg & VME1_SCON_SWITCH) ? "enabled" : "disabled");
178
179 sc->sc_vct.cookie = self;
180 sc->sc_vct.vct_probe = _vme_pcc_probe;
181 sc->sc_vct.vct_map = _vme_pcc_map;
182 sc->sc_vct.vct_unmap = _vme_pcc_unmap;
183 sc->sc_vct.vct_int_map = _vme_pcc_intmap;
184 sc->sc_vct.vct_int_evcnt = _vme_pcc_intr_evcnt;
185 sc->sc_vct.vct_int_establish = _vme_pcc_intr_establish;
186 sc->sc_vct.vct_int_disestablish = _vme_pcc_intr_disestablish;
187 sc->sc_vct.vct_dmamap_create = _vme_pcc_dmamap_create;
188 sc->sc_vct.vct_dmamap_destroy = _vme_pcc_dmamap_destroy;
189 sc->sc_vct.vct_dmamem_alloc = _vme_pcc_dmamem_alloc;
190 sc->sc_vct.vct_dmamem_free = _vme_pcc_dmamem_free;
191
192 /*
193 * Adjust the start address of the first range in vme_pcc_ranges[]
194 * according to how much onboard memory exists. Disable the first
195 * range if onboard memory >= 16Mb, and adjust the start of the
196 * second range (A32D32).
197 */
198 vme_pcc_ranges[0].pr_start = (vme_addr_t) mem_clusters[0].size;
199 if (mem_clusters[0].size >= 0x01000000) {
200 vme_pcc_ranges[0].pr_am = (vme_am_t) - 1;
201 vme_pcc_ranges[1].pr_start +=
202 (vme_addr_t) (mem_clusters[0].size - 0x01000000);
203 }
204
205 #ifdef DIAGNOSTIC
206 {
207 int i;
208 for (i = 0; i < VME1_NRANGES; i++) {
209 vme_addr_t mask;
210
211 switch (vme_pcc_ranges[i].pr_am & VME_AM_ADRSIZEMASK) {
212 case VME_AM_A32:
213 mask = 0xffffffffu;
214 break;
215
216 case VME_AM_A24:
217 mask = 0x00ffffffu;
218 break;
219
220 case VME_AM_A16:
221 mask = 0x0000ffffu;
222 break;
223
224 default:
225 printf("%s: Map#%d: disabled\n",
226 sc->sc_dev.dv_xname, i);
227 continue;
228 }
229
230 printf("%s: Map#%d: 0x%08x -> %s\n", sc->sc_dev.dv_xname, i,
231 vme_pcc_ranges[i].pr_locstart + vme_pcc_ranges[i].pr_start,
232 _vme1_mod_string(vme_pcc_ranges[i].pr_start & mask,
233 (vme_pcc_ranges[i].pr_end -
234 vme_pcc_ranges[i].pr_start) + 1,
235 vme_pcc_ranges[i].pr_am,
236 vme_pcc_ranges[i].pr_datasize));
237 }
238 }
239 #endif
240
241 vaa.va_vct = &(sc->sc_vct);
242 vaa.va_bdt = sc->sc_dmat;
243 vaa.va_slaveconfig = NULL;
244
245 vme_pcc_attached = 1;
246
247 /* Attach the MI VMEbus glue. */
248 config_found(self, &vaa, 0);
249 }
250
251 /* ARGSUSED */
252 int
253 _vme_pcc_map(vsc, vmeaddr, len, am, datasize, swap, tag, handle, resc)
254 void *vsc;
255 vme_addr_t vmeaddr;
256 vme_size_t len;
257 vme_am_t am;
258 vme_datasize_t datasize;
259 vme_swap_t swap;
260 bus_space_tag_t *tag;
261 bus_space_handle_t *handle;
262 vme_mapresc_t *resc;
263 {
264 struct vme_pcc_softc *sc;
265 struct vme_pcc_mapresc_t *pm;
266 struct vme_pcc_range *pr;
267 vme_addr_t end;
268 paddr_t paddr;
269 int rv;
270 int i;
271
272 sc = vsc;
273 end = (vmeaddr + len) - 1;
274 paddr = 0;
275
276 for (i = 0, pr = &vme_pcc_ranges[0]; i < VME1_NRANGES; i++, pr++) {
277 /* Ignore if range is disabled */
278 if (pr->pr_am == (vme_am_t) - 1)
279 continue;
280
281 /*
282 * Accept the range if it matches the constraints
283 */
284 if (am == pr->pr_am &&
285 datasize <= pr->pr_datasize &&
286 vmeaddr >= pr->pr_start && end <= pr->pr_end) {
287 /*
288 * We have a match.
289 */
290 paddr = pr->pr_locstart + vmeaddr;
291 break;
292 }
293 }
294
295 if (paddr == 0) {
296 #ifdef DIAGNOSTIC
297 printf("%s: Unable to map %s\n", sc->sc_dev.dv_xname,
298 _vme1_mod_string(vmeaddr, len, am, datasize));
299 #endif
300 return (ENOMEM);
301 }
302 if ((rv = bus_space_map(sc->sc_vmet, paddr, len, 0, handle)) != 0)
303 return (rv);
304
305 if ((pm = malloc(sizeof(*pm), M_DEVBUF, M_NOWAIT)) == NULL) {
306 bus_space_unmap(sc->sc_vmet, *handle, len);
307 return (ENOMEM);
308 }
309 *tag = sc->sc_vmet;
310 pm->pm_am = am;
311 pm->pm_datasize = datasize;
312 pm->pm_addr = vmeaddr;
313 pm->pm_size = len;
314 pm->pm_handle = *handle;
315 *resc = (vme_mapresc_t *) pm;
316
317 return (0);
318 }
319
320 void
321 _vme_pcc_unmap(vsc, resc)
322 void *vsc;
323 vme_mapresc_t resc;
324 {
325 struct vme_pcc_softc *sc;
326 struct vme_pcc_mapresc_t *pm;
327
328 sc = (struct vme_pcc_softc *) vsc;
329 pm = (struct vme_pcc_mapresc_t *) resc;
330
331 bus_space_unmap(sc->sc_vmet, pm->pm_handle, pm->pm_size);
332
333 free(pm, M_DEVBUF);
334 }
335
336 int
337 _vme_pcc_probe(vsc, vmeaddr, len, am, datasize, callback, arg)
338 void *vsc;
339 vme_addr_t vmeaddr;
340 vme_size_t len;
341 vme_am_t am;
342 vme_datasize_t datasize;
343 int (*callback) __P((void *, bus_space_tag_t, bus_space_handle_t));
344 void *arg;
345 {
346 bus_space_tag_t tag;
347 bus_space_handle_t handle;
348 vme_mapresc_t resc;
349 int rv;
350
351 rv = _vme_pcc_map(vsc, vmeaddr, len, am, datasize,
352 0, &tag, &handle, &resc);
353 if (rv)
354 return (rv);
355
356 if (callback)
357 rv = (*callback) (arg, tag, handle);
358 else {
359 /*
360 * FIXME: datasize is fixed by hardware, so using badaddr() in
361 * this way may cause several accesses to each VMEbus address.
362 * Also, using 'handle' in this way is a bit presumptuous...
363 */
364 rv = badaddr((caddr_t) handle, (int) len) ? EIO : 0;
365 }
366
367 _vme_pcc_unmap(vsc, resc);
368
369 return (rv);
370 }
371
372 /* ARGSUSED */
373 int
374 _vme_pcc_intmap(vsc, level, vector, handlep)
375 void *vsc;
376 int level, vector;
377 vme_intr_handle_t *handlep;
378 {
379
380 if (level < 1 || level > 7 || vector < 0x80 || vector > 0xff)
381 return (EINVAL);
382
383 /* This is rather gross */
384 *handlep = (void *) (int) ((level << 8) | vector);
385
386 return (0);
387 }
388
389 const struct evcnt *
390 _vme_pcc_intr_evcnt(vsc, handle)
391 void *vsc;
392 vme_intr_handle_t handle;
393 {
394
395 /* XXX for now, no evcnt parent reported */
396 return NULL;
397 }
398
399 void *
400 _vme_pcc_intr_establish(vsc, handle, prior, func, arg)
401 void *vsc;
402 vme_intr_handle_t handle;
403 int prior;
404 int (*func) __P((void *));
405 void *arg;
406 {
407 struct vme_pcc_softc *sc;
408 int level, vector;
409
410 sc = vsc;
411 level = ((int) handle) >> 8;
412 vector = ((int) handle) & 0xff;
413
414 isrlink_vectored(func, arg, level, vector);
415 sc->sc_irqref[level]++;
416
417 /*
418 * There had better not be another VMEbus master responding
419 * to this interrupt level...
420 */
421 vme1_reg_write(sc, VME1REG_IRQEN,
422 vme1_reg_read(sc, VME1REG_IRQEN) | VME1_IRQ_VME(level));
423
424 return ((void *) handle);
425 }
426
427 void
428 _vme_pcc_intr_disestablish(vsc, handle)
429 void *vsc;
430 vme_intr_handle_t handle;
431 {
432 struct vme_pcc_softc *sc;
433 int level, vector;
434
435 sc = (struct vme_pcc_softc *) vsc;
436 level = ((int) handle) >> 8;
437 vector = ((int) handle) & 0xff;
438
439 isrunlink_vectored(vector);
440
441 /* Disable VME IRQ if possible. */
442 switch (sc->sc_irqref[level]) {
443 case 0:
444 printf("vme_pcc_intr_disestablish: nothing using IRQ %d\n",
445 level);
446 panic("vme_pcc_intr_disestablish");
447 /* NOTREACHED */
448
449 case 1:
450 vme1_reg_write(sc, VME1REG_IRQEN,
451 vme1_reg_read(sc, VME1REG_IRQEN) & ~VME1_IRQ_VME(level));
452 /* FALLTHROUGH */
453
454 default:
455 sc->sc_irqref[level]--;
456 }
457 }
458
459 /* ARGSUSED */
460 int
461 _vme_pcc_dmamap_create(vsc, len, am, datasize, swap, nsegs,
462 segsz, bound, flags, mapp)
463 void *vsc;
464 vme_size_t len;
465 vme_am_t am;
466 vme_datasize_t datasize;
467 vme_swap_t swap;
468 int nsegs;
469 vme_size_t segsz;
470 vme_addr_t bound;
471 int flags;
472 bus_dmamap_t *mapp;
473 {
474
475 return (EINVAL);
476 }
477
478 /* ARGSUSED */
479 void
480 _vme_pcc_dmamap_destroy(vsc, map)
481 void *vsc;
482 bus_dmamap_t map;
483 {
484 }
485
486 /* ARGSUSED */
487 int
488 _vme_pcc_dmamem_alloc(vsc, len, am, datasizes, swap,
489 segs, nsegs, rsegs, flags)
490 void *vsc;
491 vme_size_t len;
492 vme_am_t am;
493 vme_datasize_t datasizes;
494 vme_swap_t swap;
495 bus_dma_segment_t *segs;
496 int nsegs;
497 int *rsegs;
498 int flags;
499 {
500
501 return (EINVAL);
502 }
503
504 /* ARGSUSED */
505 void
506 _vme_pcc_dmamem_free(vsc, segs, nsegs)
507 void *vsc;
508 bus_dma_segment_t *segs;
509 int nsegs;
510 {
511 }
512
513 #ifdef DIAGNOSTIC
514 const char *
515 _vme1_mod_string(addr, len, am, ds)
516 vme_addr_t addr;
517 vme_size_t len;
518 vme_am_t am;
519 vme_datasize_t ds;
520 {
521 static const char *mode[] = {"BLT64)", "DATA)", "PROG)", "BLT32)"};
522 static const char *dsiz[] = {"(", "(D8,", "(D16,", "(D16-D8,",
523 "(D32,", "(D32,D8,", "(D32-D16,", "(D32-D8,"};
524 static char mstring[40];
525 char *fmt;
526
527 switch (am & VME_AM_ADRSIZEMASK) {
528 case VME_AM_A32:
529 fmt = "A32:%08x-%08x ";
530 break;
531
532 case VME_AM_A24:
533 fmt = "A24:%06x-%06x ";
534 break;
535
536 case VME_AM_A16:
537 fmt = "A16:%04x-%04x ";
538 break;
539
540 case VME_AM_USERDEF:
541 fmt = "USR:%08x-%08x ";
542 break;
543 }
544
545 sprintf(mstring, fmt, addr, addr + len - 1);
546 strcat(mstring, dsiz[ds & 0x7]);
547 strcat(mstring, ((am & VME_AM_PRIVMASK) == VME_AM_USER) ?
548 "USER," : "SUPER,");
549 strcat(mstring, mode[am & VME_AM_MODEMASK]);
550
551 return (mstring);
552 }
553 #endif
554