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