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