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