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