1 /* $NetBSD: vme_sun68k.c,v 1.13 2008/04/28 20:23:39 martin 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.13 2008/04/28 20:23:39 martin 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 struct device 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(struct device *, struct cfdata *, void *); 68 static void sun68kvme_attach(struct device *, struct device *, 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(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(struct device *parent, struct cfdata *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(struct device *parent, struct device *self, void *aux) 149 { 150 struct mainbus_attach_args *ma = aux; 151 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)self; 152 struct vmebus_attach_args vba; 153 154 sun68kvme_attached = 1; 155 156 sun68kvme_sc = sc; 157 158 sc->sc_bustag = ma->ma_bustag; 159 sc->sc_dmatag = ma->ma_dmatag; 160 161 sun68k_vme_chipset_tag.cookie = self; 162 sun68k_vme_dma_tag = *ma->ma_dmatag; 163 sun68k_vme_dma_tag._cookie = self; 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 printf("\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 = (struct sun68kvme_softc *)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 = (struct sun68kvme_softc *)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 = (vme_intr_handle_t) 272 malloc(sizeof(struct sun68k_vme_intr_handle), 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, (void *)arg, 299 svih->pri, svih->vec); 300 301 return (NULL); 302 } 303 304 void 305 sun68k_vme_unmap(void *cookie, vme_mapresc_t resc) 306 { 307 /* Not implemented */ 308 panic("sun68k_vme_unmap"); 309 } 310 311 void 312 sun68k_vme_intr_disestablish(void *cookie, void *a) 313 { 314 /* Not implemented */ 315 panic("sun68k_vme_intr_disestablish"); 316 } 317 318 /* 319 * VME DMA functions. 320 */ 321 322 static void 323 sun68k_vct_dmamap_destroy(void *cookie, bus_dmamap_t map) 324 { 325 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 326 bus_dmamap_destroy(sc->sc_dmatag, map); 327 } 328 329 static int 330 sun68k_vct_dmamap_create(void *cookie, vme_size_t size, vme_am_t am, 331 vme_datasize_t datasize, vme_swap_t swap, int nsegments, 332 vme_size_t maxsegsz, vme_addr_t boundary, int flags, bus_dmamap_t *dmamp) 333 { 334 struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie; 335 336 /* Allocate a base map through parent bus ops */ 337 return (bus_dmamap_create(sc->sc_dmatag, size, nsegments, maxsegsz, 338 boundary, flags, dmamp)); 339 } 340 341 int 342 sun68k_vme_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 343 bus_size_t buflen, struct proc *p, int flags) 344 { 345 int error; 346 347 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 348 if (error == 0) 349 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 350 return (error); 351 } 352 353 int 354 sun68k_vme_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 355 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 356 { 357 int error; 358 359 error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); 360 if (error == 0) 361 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 362 return (error); 363 } 364 365