1 /* $NetBSD: vme_sun68k.c,v 1.2 2001/11/30 17:49:10 fredette Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg and Matthew Fredette. 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 #include <sys/param.h> 40 #include <sys/extent.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 #include <sys/malloc.h> 44 #include <sys/errno.h> 45 46 #include <sys/proc.h> 47 #include <sys/user.h> 48 #include <sys/syslog.h> 49 50 #include <uvm/uvm_extern.h> 51 52 #define _SUN68K_BUS_DMA_PRIVATE 53 #include <machine/bus.h> 54 #include <machine/autoconf.h> 55 #include <machine/pmap.h> 56 #include <machine/dvma.h> 57 58 #include <dev/vme/vmereg.h> 59 #include <dev/vme/vmevar.h> 60 61 #include <sun68k/sun68k/vme_sun68k.h> 62 63 struct sun68kvme_softc { 64 struct device sc_dev; /* base device */ 65 bus_space_tag_t sc_bustag; 66 bus_dma_tag_t sc_dmatag; 67 }; 68 struct sun68kvme_softc *sun68kvme_sc;/*XXX*/ 69 70 /* autoconfiguration driver */ 71 static int sun68kvme_match __P((struct device *, struct cfdata *, void *)); 72 static void sun68kvme_attach __P((struct device *, struct device *, void *)); 73 74 static int sun68k_vme_probe __P((void *, vme_addr_t, vme_size_t, 75 vme_am_t, vme_datasize_t, 76 int (*) __P((void *, bus_space_tag_t, bus_space_handle_t)), void *)); 77 static int sun68k_vme_map __P((void *, vme_addr_t, vme_size_t, vme_am_t, 78 vme_datasize_t, vme_swap_t, 79 bus_space_tag_t *, bus_space_handle_t *, 80 vme_mapresc_t *)); 81 static void sun68k_vme_unmap __P((void *, vme_mapresc_t)); 82 static int sun68k_vme_intr_map __P((void *, int, int, vme_intr_handle_t *)); 83 static const struct evcnt *sun68k_vme_intr_evcnt __P((void *, 84 vme_intr_handle_t)); 85 static void * sun68k_vme_intr_establish __P((void *, vme_intr_handle_t, int, 86 int (*) __P((void *)), void *)); 87 static void sun68k_vme_intr_disestablish __P((void *, void *)); 88 89 /* 90 * DMA functions. 91 */ 92 static void sun68k_vct_dmamap_destroy __P((void *, bus_dmamap_t)); 93 94 static int sun68k_vct_dmamap_create __P((void *, vme_size_t, vme_am_t, 95 vme_datasize_t, vme_swap_t, int, vme_size_t, vme_addr_t, 96 int, bus_dmamap_t *)); 97 static int sun68k_vme_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *, 98 bus_size_t, struct proc *, int)); 99 static int sun68k_vme_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t, 100 bus_dma_segment_t *, int, bus_size_t, int)); 101 102 paddr_t sun68k_vme_mmap_cookie __P((vme_addr_t, vme_am_t, bus_space_handle_t *)); 103 104 struct cfattach sun68kvme_ca = { 105 sizeof(struct sun68kvme_softc), sun68kvme_match, sun68kvme_attach 106 }; 107 108 /* 109 * The VME bus logic on sun68k machines maps DMA requests in the first MB 110 * of VME space to the last MB of DVMA space. The base bus_dma code 111 * in machdep.c manages DVMA space; all we must do is adjust the DMA 112 * addresses returned by bus_dmamap_load*() by ANDing them with 113 * DVMA_VME_SLAVE_MASK. 114 */ 115 116 struct vme_chipset_tag sun68k_vme_chipset_tag = { 117 NULL, 118 sun68k_vme_map, 119 sun68k_vme_unmap, 120 sun68k_vme_probe, 121 sun68k_vme_intr_map, 122 sun68k_vme_intr_evcnt, 123 sun68k_vme_intr_establish, 124 sun68k_vme_intr_disestablish, 125 sun68k_vct_dmamap_create, 126 sun68k_vct_dmamap_destroy 127 }; 128 129 struct sun68k_bus_dma_tag sun68k_vme_dma_tag; 130 131 /* Does this machine have a VME bus? */ 132 extern int cpu_has_vme; 133 134 /* 135 * Probe the VME bus. 136 */ 137 int 138 sun68kvme_match(parent, cf, aux) 139 struct device *parent; 140 struct cfdata *cf; 141 void *aux; 142 { 143 struct mainbus_attach_args *ma = aux; 144 145 return (cpu_has_vme && (ma->ma_name == NULL || strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0)); 146 } 147 148 /* 149 * Attach the VME bus. 150 */ 151 void 152 sun68kvme_attach(parent, self, aux) 153 struct device *parent, *self; 154 void *aux; 155 { 156 struct mainbus_attach_args *ma = aux; 157 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)self; 158 struct vmebus_attach_args vba; 159 160 if (self->dv_unit > 0) { 161 printf(" unsupported\n"); 162 return; 163 } 164 165 sun68kvme_sc = sc; 166 167 sc->sc_bustag = ma->ma_bustag; 168 sc->sc_dmatag = ma->ma_dmatag; 169 170 sun68k_vme_chipset_tag.cookie = self; 171 sun68k_vme_dma_tag = *ma->ma_dmatag; 172 sun68k_vme_dma_tag._cookie = self; 173 sun68k_vme_dma_tag._dmamap_load = sun68k_vme_dmamap_load; 174 sun68k_vme_dma_tag._dmamap_load_raw = sun68k_vme_dmamap_load_raw; 175 176 vba.va_vct = &sun68k_vme_chipset_tag; 177 vba.va_bdt = &sun68k_vme_dma_tag; 178 vba.va_slaveconfig = 0; 179 180 printf("\n"); 181 (void)config_found(self, &vba, 0); 182 } 183 184 /* 185 * Probes for a device on the VME bus. 186 * Returns zero on success. 187 */ 188 int 189 sun68k_vme_probe(cookie, addr, len, mod, datasize, callback, arg) 190 void *cookie; 191 vme_addr_t addr; 192 vme_size_t len; 193 vme_am_t mod; 194 vme_datasize_t datasize; 195 int (*callback) __P((void *, bus_space_tag_t, bus_space_handle_t)); 196 void *arg; 197 { 198 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 199 bus_type_t iospace; 200 bus_addr_t paddr; 201 bus_space_handle_t handle; 202 bus_size_t size; 203 bus_size_t off, max_off; 204 int error; 205 206 /* Map in the space. */ 207 error = vmebus_translate(mod, addr, &iospace, &paddr); 208 if (error == 0) 209 error = bus_space_map2(sc->sc_bustag, iospace, paddr, len, 210 0, NULL, &handle); 211 if (error) 212 return (error); 213 214 /* Probe the space. */ 215 size = (datasize == VME_D8 ? 1 : (datasize == VME_D16 ? 2 : 4)); 216 max_off = (callback ? size : len); 217 for (off = 0; off < max_off; off += size) { 218 error = _bus_space_peek(sc->sc_bustag, handle, off, size, NULL); 219 if (error) 220 break; 221 } 222 if (error == 0 && callback) 223 error = (*callback)(arg, sc->sc_bustag, handle); 224 225 /* Unmap the space. */ 226 bus_space_unmap(sc->sc_bustag, handle, len); 227 228 return (error); 229 } 230 231 /* 232 * Maps in a device on the VME bus. 233 */ 234 int 235 sun68k_vme_map(cookie, addr, size, mod, datasize, swap, tp, hp, rp) 236 void *cookie; 237 vme_addr_t addr; 238 vme_size_t size; 239 vme_am_t mod; 240 vme_datasize_t datasize; 241 vme_swap_t swap; 242 bus_space_tag_t *tp; 243 bus_space_handle_t *hp; 244 vme_mapresc_t *rp; 245 { 246 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 247 bus_type_t iospace; 248 bus_addr_t paddr; 249 int error; 250 251 error = vmebus_translate(mod, addr, &iospace, &paddr); 252 if (error != 0) 253 return (error); 254 255 *tp = sc->sc_bustag; 256 return (bus_space_map2(sc->sc_bustag, iospace, paddr, size, 0, 0, hp)); 257 } 258 259 /* 260 * Assists in mmap'ing a device on the VME bus. 261 */ 262 paddr_t 263 sun68k_vme_mmap_cookie(addr, mod, hp) 264 vme_addr_t addr; 265 vme_am_t mod; 266 bus_space_handle_t *hp; 267 { 268 struct sun68kvme_softc *sc = sun68kvme_sc; 269 bus_type_t iospace; 270 bus_addr_t paddr; 271 int error; 272 273 error = vmebus_translate(mod, addr, &iospace, &paddr); 274 if (error != 0) 275 return (error); 276 277 return (bus_space_mmap2(sc->sc_bustag, iospace, paddr, 0, 0, 0)); 278 } 279 280 struct sun68k_vme_intr_handle { 281 int vec; /* VME interrupt vector */ 282 int pri; /* VME interrupt priority */ 283 }; 284 285 /* 286 * This maps a VME interrupt level and vector pair into 287 * a data structure that can subsequently be used to 288 * establish an interrupt handler. 289 */ 290 int 291 sun68k_vme_intr_map(cookie, level, vec, ihp) 292 void *cookie; 293 int level; 294 int vec; 295 vme_intr_handle_t *ihp; 296 { 297 struct sun68k_vme_intr_handle *svih; 298 299 svih = (vme_intr_handle_t) 300 malloc(sizeof(struct sun68k_vme_intr_handle), M_DEVBUF, M_NOWAIT); 301 svih->pri = level; 302 svih->vec = vec; 303 *ihp = svih; 304 return (0); 305 } 306 307 const struct evcnt * 308 sun68k_vme_intr_evcnt(cookie, vih) 309 void *cookie; 310 vme_intr_handle_t vih; 311 { 312 313 /* XXX for now, no evcnt parent reported */ 314 return NULL; 315 } 316 317 /* 318 * Establish a VME bus interrupt. 319 */ 320 void * 321 sun68k_vme_intr_establish(cookie, vih, pri, func, arg) 322 void *cookie; 323 vme_intr_handle_t vih; 324 int pri; 325 int (*func) __P((void *)); 326 void *arg; 327 { 328 struct sun68k_vme_intr_handle *svih = 329 (struct sun68k_vme_intr_handle *)vih; 330 331 /* Install interrupt handler. */ 332 isr_add_vectored(func, (void *)arg, 333 svih->pri, svih->vec); 334 335 return (NULL); 336 } 337 338 void 339 sun68k_vme_unmap(cookie, resc) 340 void * cookie; 341 vme_mapresc_t resc; 342 { 343 /* Not implemented */ 344 panic("sun68k_vme_unmap"); 345 } 346 347 void 348 sun68k_vme_intr_disestablish(cookie, a) 349 void *cookie; 350 void *a; 351 { 352 /* Not implemented */ 353 panic("sun68k_vme_intr_disestablish"); 354 } 355 356 /* 357 * VME DMA functions. 358 */ 359 360 static void 361 sun68k_vct_dmamap_destroy(cookie, map) 362 void *cookie; 363 bus_dmamap_t map; 364 { 365 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 366 bus_dmamap_destroy(sc->sc_dmatag, map); 367 } 368 369 static int 370 sun68k_vct_dmamap_create(cookie, size, am, datasize, swap, nsegments, maxsegsz, 371 boundary, flags, dmamp) 372 void *cookie; 373 vme_size_t size; 374 vme_am_t am; 375 vme_datasize_t datasize; 376 vme_swap_t swap; 377 int nsegments; 378 vme_size_t maxsegsz; 379 vme_addr_t boundary; 380 int flags; 381 bus_dmamap_t *dmamp; 382 { 383 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 384 385 /* Allocate a base map through parent bus ops */ 386 return (bus_dmamap_create(sc->sc_dmatag, size, nsegments, maxsegsz, 387 boundary, flags, dmamp)); 388 } 389 390 int 391 sun68k_vme_dmamap_load(t, map, buf, buflen, p, flags) 392 bus_dma_tag_t t; 393 bus_dmamap_t map; 394 void *buf; 395 bus_size_t buflen; 396 struct proc *p; 397 int flags; 398 { 399 int error; 400 401 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 402 if (error == 0) 403 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 404 return (error); 405 } 406 407 int 408 sun68k_vme_dmamap_load_raw(t, map, segs, nsegs, size, flags) 409 bus_dma_tag_t t; 410 bus_dmamap_t map; 411 bus_dma_segment_t *segs; 412 int nsegs; 413 bus_size_t size; 414 int flags; 415 { 416 int error; 417 418 error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); 419 if (error == 0) 420 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 421 return (error); 422 } 423 424