1 /* $NetBSD: vme.c,v 1.15 2008/06/28 12:13:38 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Gordon W. Ross. 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.c,v 1.15 2008/06/28 12:13:38 tsutsui Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 39 #include <uvm/uvm_extern.h> 40 41 #define _SUN68K_BUS_DMA_PRIVATE 42 #include <machine/autoconf.h> 43 #include <machine/bus.h> 44 #include <machine/dvma.h> 45 #include <machine/pmap.h> 46 47 #include <sun3/sun3x/vme.h> 48 49 /* Does this machine have a VME bus? */ 50 extern int cpu_has_vme; 51 52 /* 53 * Convert vme unit number to bus type, 54 * but only for supported bus types. 55 * (See autoconf.h and vme.h) 56 */ 57 #define VME_UNITS 6 58 static const struct { 59 int bustype; 60 const char *name; 61 int pmtype; 62 vaddr_t base; 63 vaddr_t mask; 64 } vme_info[VME_UNITS] = { 65 { BUS_VME16D16, "A16/D16", PMAP_VME16, VME16_BASE, VME16_MASK }, 66 { BUS_VME16D32, "A16/D32", PMAP_VME32, VME16_BASE, VME16_MASK }, 67 { BUS_VME24D16, "A24/D16", PMAP_VME16, VME24_BASE, VME24_MASK }, 68 { BUS_VME24D32, "A24/D32", PMAP_VME32, VME24_BASE, VME24_MASK }, 69 { BUS_VME32D16, "A32/D16", PMAP_VME16, VME32_BASE, VME32_MASK }, 70 { BUS_VME32D32, "A32/D32", PMAP_VME32, VME32_BASE, VME32_MASK }, 71 }; 72 73 static int vme_match(struct device *, struct cfdata *, void *); 74 static void vme_attach(struct device *, struct device *, void *); 75 76 struct vme_softc { 77 device_t sc_dev; 78 bus_space_tag_t sc_bustag; 79 bus_dma_tag_t sc_dmatag; 80 int sc_bustype; 81 }; 82 83 CFATTACH_DECL_NEW(vme, sizeof(struct vme_softc), 84 vme_match, vme_attach, NULL, NULL); 85 86 static int vme_bus_map(bus_space_tag_t, bus_type_t, bus_addr_t, bus_size_t, 87 int, vaddr_t, bus_space_handle_t *); 88 static paddr_t vme_bus_mmap(bus_space_tag_t, bus_type_t, bus_addr_t, 89 off_t, int, int); 90 static int vme_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, 91 struct proc *, int); 92 93 static struct sun68k_bus_space_tag vme_space_tag = { 94 NULL, /* cookie */ 95 NULL, /* parent bus space tag */ 96 vme_bus_map, /* bus_space_map */ 97 NULL, /* bus_space_unmap */ 98 NULL, /* bus_space_subregion */ 99 NULL, /* bus_space_barrier */ 100 vme_bus_mmap, /* bus_space_mmap */ 101 NULL, /* bus_intr_establish */ 102 NULL, /* bus_space_peek_N */ 103 NULL /* bus_space_poke_N */ 104 }; 105 106 static struct sun68k_bus_dma_tag vme_dma_tag; 107 108 static int 109 vme_match(device_t parent, cfdata_t cf, void *aux) 110 { 111 struct confargs *ca = aux; 112 int unit; 113 114 if (cpu_has_vme == 0) 115 return 0; 116 117 unit = cf->cf_unit; 118 if (unit >= VME_UNITS) 119 return 0; 120 121 if (ca->ca_bustype != vme_info[unit].bustype) 122 return 0; 123 124 return 1; 125 } 126 127 static void 128 vme_attach(device_t parent, device_t self, void *args) 129 { 130 struct confargs *ca = aux; 131 struct vme_softc *sc = device_private(self); 132 struct confargs vmea; 133 int unit; 134 135 sc->sc_dev = self; 136 137 unit = device_unit(self); 138 aprint_normal(": (%s)\n", vme_info[unit].name); 139 140 sc->sc_bustag = ca->ca_bustag; 141 sc->sc_dmatag = ca->ca_dmatag; 142 sc->sc_bustype = unit; 143 144 vme_space_tag.cookie = sc; 145 vme_space_tag.parent = sc->sc_bustag; 146 147 vme_dma_tag = *sc->sc_dmatag; 148 vme_dma_tag._cookie = sc; 149 vme_dma_tag._dmamap_load = vme_dmamap_load; 150 151 vmea = *ca; 152 vmea.ca_bustag = &vme_space_tag; 153 vmea.ca_dmatag = &vme_dma_tag; 154 155 /* We know ca_bustype == BUS_VMExx */ 156 config_search_ia(bus_scan, self, "vme", args); 157 } 158 159 int 160 vme_bus_map(bus_space_tag_t t, bus_type_t btype, bus_addr_t paddr, 161 bus_size_t size, int flags, vaddr_t vaddr, bus_space_handle_t *hp) 162 { 163 struct vme_softc *sc = t->cookie; 164 paddr_t pa; 165 int bustype, pmtype; 166 167 bustype = sc->sc_bustype; 168 pa = paddr; 169 pa &= vme_info[bustype].mask; 170 pa |= vme_info[bustype].base; 171 pmtype = vme_info[bustype].pmtype; 172 173 return bus_space_map2(sc->sc_bustag, pmtype, pa, size, 174 flags | _SUN68K_BUS_MAP_USE_PROM, vaddr, hp); 175 } 176 177 paddr_t 178 vme_bus_mmap(bus_space_tag_t t, bus_type_t btype, bus_addr_t paddr, off_t off, 179 int prot, int flags) 180 { 181 struct vme_softc *sc = t->cookie; 182 paddr_t pa; 183 int bustype, pmtype; 184 185 bustype = sc->sc_bustype; 186 pa = paddr; 187 pa &= vme_info[bustype].mask; 188 pa |= vme_info[bustype].base; 189 pmtype = vme_info[bustype].pmtype; 190 191 return bus_space_mmap2(sc->sc_bustag, pmtype, pa, off, prot, flags); 192 } 193 194 static int 195 vme_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 196 bus_size_t buflen, struct proc *p, int flags) 197 { 198 int error; 199 200 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 201 if (error == 0) 202 map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK; 203 return error; 204 } 205