1 /* $NetBSD: vme_sun68k.c,v 1.14 2008/07/01 15:15:34 tsutsui 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: vme_sun68k.c,v 1.14 2008/07/01 15:15:34 tsutsui Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/extent.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/errno.h> 41 42 #include <sys/proc.h> 43 #include <sys/user.h> 44 #include <sys/syslog.h> 45 46 #include <uvm/uvm_extern.h> 47 48 #define _SUN68K_BUS_DMA_PRIVATE 49 #include <machine/bus.h> 50 #include <machine/autoconf.h> 51 #include <machine/pmap.h> 52 #include <machine/dvma.h> 53 54 #include <dev/vme/vmereg.h> 55 #include <dev/vme/vmevar.h> 56 57 #include <sun68k/sun68k/vme_sun68k.h> 58 59 struct sun68kvme_softc { 60 device_t sc_dev; /* base device */ 61 bus_space_tag_t sc_bustag; 62 bus_dma_tag_t sc_dmatag; 63 }; 64 struct sun68kvme_softc *sun68kvme_sc;/*XXX*/ 65 66 /* autoconfiguration driver */ 67 static int sun68kvme_match(device_t, cfdata_t, void *); 68 static void sun68kvme_attach(device_t, device_t, void *); 69 70 static int sun68k_vme_probe(void *, vme_addr_t, vme_size_t, vme_am_t, 71 vme_datasize_t, 72 int (*)(void *, bus_space_tag_t, bus_space_handle_t), void *); 73 static int sun68k_vme_map(void *, vme_addr_t, vme_size_t, vme_am_t, 74 vme_datasize_t, vme_swap_t, bus_space_tag_t *, bus_space_handle_t *, 75 vme_mapresc_t *); 76 static void sun68k_vme_unmap(void *, vme_mapresc_t); 77 static int sun68k_vme_intr_map(void *, int, int, vme_intr_handle_t *); 78 static const struct evcnt *sun68k_vme_intr_evcnt(void *, vme_intr_handle_t); 79 static void * sun68k_vme_intr_establish(void *, vme_intr_handle_t, int, 80 int (*)(void *), void *); 81 static void sun68k_vme_intr_disestablish(void *, void *); 82 83 /* 84 * DMA functions. 85 */ 86 static void sun68k_vct_dmamap_destroy(void *, bus_dmamap_t); 87 88 static int sun68k_vct_dmamap_create(void *, vme_size_t, vme_am_t, 89 vme_datasize_t, vme_swap_t, int, vme_size_t, vme_addr_t, 90 int, bus_dmamap_t *); 91 static int sun68k_vme_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, 92 bus_size_t, struct proc *, int); 93 static int sun68k_vme_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, 94 bus_dma_segment_t *, int, bus_size_t, int); 95 96 paddr_t sun68k_vme_mmap_cookie(vme_addr_t, vme_am_t, bus_space_handle_t *); 97 98 CFATTACH_DECL_NEW(sun68kvme, sizeof(struct sun68kvme_softc), 99 sun68kvme_match, sun68kvme_attach, NULL, NULL); 100 101 static int sun68kvme_attached; 102 103 /* 104 * The VME bus logic on sun68k machines maps DMA requests in the first MB 105 * of VME space to the last MB of DVMA space. The base bus_dma code 106 * in machdep.c manages DVMA space; all we must do is adjust the DMA 107 * addresses returned by bus_dmamap_load*() by ANDing them with 108 * DVMA_VME_SLAVE_MASK. 109 */ 110 111 struct vme_chipset_tag sun68k_vme_chipset_tag = { 112 NULL, 113 sun68k_vme_map, 114 sun68k_vme_unmap, 115 sun68k_vme_probe, 116 sun68k_vme_intr_map, 117 sun68k_vme_intr_evcnt, 118 sun68k_vme_intr_establish, 119 sun68k_vme_intr_disestablish, 120 sun68k_vct_dmamap_create, 121 sun68k_vct_dmamap_destroy 122 }; 123 124 struct sun68k_bus_dma_tag sun68k_vme_dma_tag; 125 126 /* Does this machine have a VME bus? */ 127 extern int cpu_has_vme; 128 129 /* 130 * Probe the VME bus. 131 */ 132 int 133 sun68kvme_match(device_t parent, cfdata_t cf, void *aux) 134 { 135 struct mainbus_attach_args *ma = aux; 136 137 if (sun68kvme_attached) 138 return 0; 139 140 return cpu_has_vme && 141 (ma->ma_name == NULL || strcmp(cf->cf_name, ma->ma_name) == 0); 142 } 143 144 /* 145 * Attach the VME bus. 146 */ 147 void 148 sun68kvme_attach(device_t parent, device_t self, void *aux) 149 { 150 struct mainbus_attach_args *ma = aux; 151 struct sun68kvme_softc *sc = device_private(self); 152 struct vmebus_attach_args vba; 153 154 sun68kvme_attached = 1; 155 156 sun68kvme_sc = sc; 157 158 sc->sc_dev = self; 159 sc->sc_bustag = ma->ma_bustag; 160 sc->sc_dmatag = ma->ma_dmatag; 161 162 sun68k_vme_chipset_tag.cookie = sc; 163 sun68k_vme_dma_tag = *ma->ma_dmatag; 164 sun68k_vme_dma_tag._cookie = sc; 165 sun68k_vme_dma_tag._dmamap_load = sun68k_vme_dmamap_load; 166 sun68k_vme_dma_tag._dmamap_load_raw = sun68k_vme_dmamap_load_raw; 167 168 vba.va_vct = &sun68k_vme_chipset_tag; 169 vba.va_bdt = &sun68k_vme_dma_tag; 170 vba.va_slaveconfig = 0; 171 172 aprint_normal("\n"); 173 (void)config_found(self, &vba, 0); 174 } 175 176 /* 177 * Probes for a device on the VME bus. 178 * Returns zero on success. 179 */ 180 int 181 sun68k_vme_probe(void *cookie, vme_addr_t addr, vme_size_t len, vme_am_t mod, 182 vme_datasize_t datasize, 183 int (*callback)(void *, bus_space_tag_t, bus_space_handle_t), void *arg) 184 { 185 struct sun68kvme_softc *sc = cookie; 186 bus_type_t iospace; 187 bus_addr_t paddr; 188 bus_space_handle_t handle; 189 bus_size_t size; 190 bus_size_t off, max_off; 191 int error; 192 193 /* Map in the space. */ 194 error = vmebus_translate(mod, addr, &iospace, &paddr); 195 if (error == 0) 196 error = bus_space_map2(sc->sc_bustag, iospace, paddr, len, 197 0, 0, &handle); 198 if (error) 199 return error; 200 201 /* Probe the space. */ 202 size = (datasize == VME_D8 ? 1 : (datasize == VME_D16 ? 2 : 4)); 203 max_off = (callback ? size : len); 204 for (off = 0; off < max_off; off += size) { 205 error = _bus_space_peek(sc->sc_bustag, handle, off, size, NULL); 206 if (error) 207 break; 208 } 209 if (error == 0 && callback) 210 error = (*callback)(arg, sc->sc_bustag, handle); 211 212 /* Unmap the space. */ 213 bus_space_unmap(sc->sc_bustag, handle, len); 214 215 return error; 216 } 217 218 /* 219 * Maps in a device on the VME bus. 220 */ 221 int 222 sun68k_vme_map(void *cookie, vme_addr_t addr, vme_size_t size, vme_am_t mod, 223 vme_datasize_t datasize, vme_swap_t swap, bus_space_tag_t *tp, 224 bus_space_handle_t *hp, vme_mapresc_t *rp) 225 { 226 struct sun68kvme_softc *sc = cookie; 227 bus_type_t iospace; 228 bus_addr_t paddr; 229 int error; 230 231 error = vmebus_translate(mod, addr, &iospace, &paddr); 232 if (error != 0) 233 return error; 234 235 *tp = sc->sc_bustag; 236 return bus_space_map2(sc->sc_bustag, iospace, paddr, size, 0, 0, hp); 237 } 238 239 /* 240 * Assists in mmap'ing a device on the VME bus. 241 */ 242 paddr_t 243 sun68k_vme_mmap_cookie(vme_addr_t addr, vme_am_t mod, bus_space_handle_t *hp) 244 { 245 struct sun68kvme_softc *sc = sun68kvme_sc; 246 bus_type_t iospace; 247 bus_addr_t paddr; 248 int error; 249 250 error = vmebus_translate(mod, addr, &iospace, &paddr); 251 if (error != 0) 252 return error; 253 254 return bus_space_mmap2(sc->sc_bustag, iospace, paddr, 0, 0, 0); 255 } 256 257 struct sun68k_vme_intr_handle { 258 int vec; /* VME interrupt vector */ 259 int pri; /* VME interrupt priority */ 260 }; 261 262 /* 263 * This maps a VME interrupt level and vector pair into 264 * a data structure that can subsequently be used to 265 * establish an interrupt handler. 266 */ 267 int 268 sun68k_vme_intr_map(void *cookie, int level, int vec, vme_intr_handle_t *ihp) 269 { 270 struct sun68k_vme_intr_handle *svih; 271 272 svih = malloc(sizeof(struct sun68k_vme_intr_handle), 273 M_DEVBUF, M_NOWAIT); 274 svih->pri = level; 275 svih->vec = vec; 276 *ihp = svih; 277 return 0; 278 } 279 280 const struct evcnt * 281 sun68k_vme_intr_evcnt(void *cookie, vme_intr_handle_t vih) 282 { 283 284 /* XXX for now, no evcnt parent reported */ 285 return NULL; 286 } 287 288 /* 289 * Establish a VME bus interrupt. 290 */ 291 void * 292 sun68k_vme_intr_establish(void *cookie, vme_intr_handle_t vih, int pri, 293 int (*func)(void *), void *arg) 294 { 295 struct sun68k_vme_intr_handle *svih = 296 (struct sun68k_vme_intr_handle *)vih; 297 298 /* Install interrupt handler. */ 299 isr_add_vectored(func, arg, svih->pri, svih->vec); 300 301 return NULL; 302 } 303 304 void 305 sun68k_vme_unmap(void *cookie, vme_mapresc_t resc) 306 { 307 308 /* Not implemented */ 309 panic("%s: not implemented", __func__); 310 } 311 312 void 313 sun68k_vme_intr_disestablish(void *cookie, void *a) 314 { 315 316 /* Not implemented */ 317 panic("%s: not implemented", __func__); 318 } 319 320 /* 321 * VME DMA functions. 322 */ 323 324 static void 325 sun68k_vct_dmamap_destroy(void *cookie, bus_dmamap_t map) 326 { 327 struct sun68kvme_softc *sc = cookie; 328 329 bus_dmamap_destroy(sc->sc_dmatag, map); 330 } 331 332 static int 333 sun68k_vct_dmamap_create(void *cookie, vme_size_t size, vme_am_t am, 334 vme_datasize_t datasize, vme_swap_t swap, int nsegments, 335 vme_size_t maxsegsz, vme_addr_t boundary, int flags, bus_dmamap_t *dmamp) 336 { 337 struct sun68kvme_softc *sc = cookie; 338 339 /* Allocate a base map through parent bus ops */ 340 return bus_dmamap_create(sc->sc_dmatag, size, nsegments, maxsegsz, 341 boundary, flags, dmamp); 342 } 343 344 int 345 sun68k_vme_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 346 bus_size_t buflen, struct proc *p, int flags) 347 { 348 int error; 349 350 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 351 if (error == 0) 352 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 353 return error; 354 } 355 356 int 357 sun68k_vme_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 358 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 359 { 360 int error; 361 362 error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); 363 if (error == 0) 364 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 365 return error; 366 } 367