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