xref: /netbsd/sys/arch/sun68k/sun68k/vme_sun68k.c (revision c4a72b64)
1 /*	$NetBSD: vme_sun68k.c,v 1.6 2002/10/02 16:02:31 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  * 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 CFATTACH_DECL(sun68kvme, sizeof(struct sun68kvme_softc),
105     sun68kvme_match, sun68kvme_attach, NULL, NULL);
106 
107 /*
108  * The VME bus logic on sun68k machines maps DMA requests in the first MB
109  * of VME space to the last MB of DVMA space.  The base bus_dma code
110  * in machdep.c manages DVMA space; all we must do is adjust the DMA
111  * addresses returned by bus_dmamap_load*() by ANDing them with
112  * DVMA_VME_SLAVE_MASK.
113  */
114 
115 struct vme_chipset_tag sun68k_vme_chipset_tag = {
116 	NULL,
117 	sun68k_vme_map,
118 	sun68k_vme_unmap,
119 	sun68k_vme_probe,
120 	sun68k_vme_intr_map,
121 	sun68k_vme_intr_evcnt,
122 	sun68k_vme_intr_establish,
123 	sun68k_vme_intr_disestablish,
124 	sun68k_vct_dmamap_create,
125 	sun68k_vct_dmamap_destroy
126 };
127 
128 struct sun68k_bus_dma_tag sun68k_vme_dma_tag;
129 
130 /* Does this machine have a VME bus? */
131 extern int cpu_has_vme;
132 
133 /*
134  * Probe the VME bus.
135  */
136 int
137 sun68kvme_match(parent, cf, aux)
138 	struct device *parent;
139 	struct cfdata *cf;
140 	void *aux;
141 {
142         struct mainbus_attach_args *ma = aux;
143 
144         return (cpu_has_vme && (ma->ma_name == NULL || strcmp(cf->cf_name, ma->ma_name) == 0));
145 }
146 
147 /*
148  * Attach the VME bus.
149  */
150 void
151 sun68kvme_attach(parent, self, aux)
152 	struct device *parent, *self;
153 	void *aux;
154 {
155 	struct mainbus_attach_args *ma = aux;
156 	struct sun68kvme_softc *sc = (struct sun68kvme_softc *)self;
157 	struct vmebus_attach_args vba;
158 
159 	if (self->dv_unit > 0) {
160 		printf(" unsupported\n");
161 		return;
162 	}
163 
164 	sun68kvme_sc = sc;
165 
166 	sc->sc_bustag = ma->ma_bustag;
167 	sc->sc_dmatag = ma->ma_dmatag;
168 
169 	sun68k_vme_chipset_tag.cookie = self;
170 	sun68k_vme_dma_tag = *ma->ma_dmatag;
171 	sun68k_vme_dma_tag._cookie = self;
172 	sun68k_vme_dma_tag._dmamap_load = sun68k_vme_dmamap_load;
173 	sun68k_vme_dma_tag._dmamap_load_raw = sun68k_vme_dmamap_load_raw;
174 
175 	vba.va_vct = &sun68k_vme_chipset_tag;
176 	vba.va_bdt = &sun68k_vme_dma_tag;
177 	vba.va_slaveconfig = 0;
178 
179 	printf("\n");
180 	(void)config_found(self, &vba, 0);
181 }
182 
183 /*
184  * Probes for a device on the VME bus.
185  * Returns zero on success.
186  */
187 int
188 sun68k_vme_probe(cookie, addr, len, mod, datasize, callback, arg)
189 	void *cookie;
190 	vme_addr_t addr;
191 	vme_size_t len;
192 	vme_am_t mod;
193 	vme_datasize_t datasize;
194 	int (*callback) __P((void *, bus_space_tag_t, bus_space_handle_t));
195 	void *arg;
196 {
197 	struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie;
198 	bus_type_t iospace;
199 	bus_addr_t paddr;
200 	bus_space_handle_t handle;
201 	bus_size_t size;
202 	bus_size_t off, max_off;
203 	int error;
204 
205 	/* Map in the space. */
206 	error = vmebus_translate(mod, addr, &iospace, &paddr);
207 	if (error == 0)
208 		error = bus_space_map2(sc->sc_bustag, iospace, paddr, len,
209 			0, NULL, &handle);
210 	if (error)
211 		return (error);
212 
213 	/* Probe the space. */
214 	size = (datasize == VME_D8 ? 1 : (datasize == VME_D16 ? 2 : 4));
215 	max_off = (callback ? size : len);
216 	for (off = 0; off < max_off; off += size) {
217 		error = _bus_space_peek(sc->sc_bustag, handle, off, size, NULL);
218 		if (error)
219 			break;
220 	}
221 	if (error == 0 && callback)
222 		error = (*callback)(arg, sc->sc_bustag, handle);
223 
224 	/* Unmap the space. */
225 	bus_space_unmap(sc->sc_bustag, handle, len);
226 
227 	return (error);
228 }
229 
230 /*
231  * Maps in a device on the VME bus.
232  */
233 int
234 sun68k_vme_map(cookie, addr, size, mod, datasize, swap, tp, hp, rp)
235 	void *cookie;
236 	vme_addr_t addr;
237 	vme_size_t size;
238 	vme_am_t mod;
239 	vme_datasize_t datasize;
240 	vme_swap_t swap;
241 	bus_space_tag_t *tp;
242 	bus_space_handle_t *hp;
243 	vme_mapresc_t *rp;
244 {
245 	struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie;
246 	bus_type_t iospace;
247 	bus_addr_t paddr;
248 	int error;
249 
250 	error = vmebus_translate(mod, addr, &iospace, &paddr);
251 	if (error != 0)
252 		return (error);
253 
254 	*tp = sc->sc_bustag;
255 	return (bus_space_map2(sc->sc_bustag, iospace, paddr, size, 0, 0, hp));
256 }
257 
258 /*
259  * Assists in mmap'ing a device on the VME bus.
260  */
261 paddr_t
262 sun68k_vme_mmap_cookie(addr, mod, hp)
263 	vme_addr_t addr;
264 	vme_am_t mod;
265 	bus_space_handle_t *hp;
266 {
267 	struct sun68kvme_softc *sc = sun68kvme_sc;
268 	bus_type_t iospace;
269 	bus_addr_t paddr;
270 	int error;
271 
272 	error = vmebus_translate(mod, addr, &iospace, &paddr);
273 	if (error != 0)
274 		return (error);
275 
276 	return (bus_space_mmap2(sc->sc_bustag, iospace, paddr, 0, 0, 0));
277 }
278 
279 struct sun68k_vme_intr_handle {
280 	int	vec;		/* VME interrupt vector */
281 	int	pri;		/* VME interrupt priority */
282 };
283 
284 /*
285  * This maps a VME interrupt level and vector pair into
286  * a data structure that can subsequently be used to
287  * establish an interrupt handler.
288  */
289 int
290 sun68k_vme_intr_map(cookie, level, vec, ihp)
291 	void *cookie;
292 	int level;
293 	int vec;
294 	vme_intr_handle_t *ihp;
295 {
296 	struct sun68k_vme_intr_handle *svih;
297 
298 	svih = (vme_intr_handle_t)
299 	    malloc(sizeof(struct sun68k_vme_intr_handle), M_DEVBUF, M_NOWAIT);
300 	svih->pri = level;
301 	svih->vec = vec;
302 	*ihp = svih;
303 	return (0);
304 }
305 
306 const struct evcnt *
307 sun68k_vme_intr_evcnt(cookie, vih)
308 	void *cookie;
309 	vme_intr_handle_t vih;
310 {
311 
312 	/* XXX for now, no evcnt parent reported */
313 	return NULL;
314 }
315 
316 /*
317  * Establish a VME bus interrupt.
318  */
319 void *
320 sun68k_vme_intr_establish(cookie, vih, pri, func, arg)
321 	void *cookie;
322 	vme_intr_handle_t vih;
323 	int pri;
324 	int (*func) __P((void *));
325 	void *arg;
326 {
327 	struct sun68k_vme_intr_handle *svih =
328 			(struct sun68k_vme_intr_handle *)vih;
329 
330 	/* Install interrupt handler. */
331 	isr_add_vectored(func, (void *)arg,
332 		svih->pri, svih->vec);
333 
334 	return (NULL);
335 }
336 
337 void
338 sun68k_vme_unmap(cookie, resc)
339 	void * cookie;
340 	vme_mapresc_t resc;
341 {
342 	/* Not implemented */
343 	panic("sun68k_vme_unmap");
344 }
345 
346 void
347 sun68k_vme_intr_disestablish(cookie, a)
348 	void *cookie;
349 	void *a;
350 {
351 	/* Not implemented */
352 	panic("sun68k_vme_intr_disestablish");
353 }
354 
355 /*
356  * VME DMA functions.
357  */
358 
359 static void
360 sun68k_vct_dmamap_destroy(cookie, map)
361 	void *cookie;
362 	bus_dmamap_t map;
363 {
364 	struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie;
365 	bus_dmamap_destroy(sc->sc_dmatag, map);
366 }
367 
368 static int
369 sun68k_vct_dmamap_create(cookie, size, am, datasize, swap, nsegments, maxsegsz,
370 			  boundary, flags, dmamp)
371 	void *cookie;
372 	vme_size_t size;
373 	vme_am_t am;
374 	vme_datasize_t datasize;
375 	vme_swap_t swap;
376 	int nsegments;
377 	vme_size_t maxsegsz;
378 	vme_addr_t boundary;
379 	int flags;
380 	bus_dmamap_t *dmamp;
381 {
382 	struct sun68kvme_softc *sc = (struct sun68kvme_softc *)cookie;
383 
384 	/* Allocate a base map through parent bus ops */
385 	return (bus_dmamap_create(sc->sc_dmatag, size, nsegments, maxsegsz,
386 				  boundary, flags, dmamp));
387 }
388 
389 int
390 sun68k_vme_dmamap_load(t, map, buf, buflen, p, flags)
391 	bus_dma_tag_t t;
392 	bus_dmamap_t map;
393 	void *buf;
394 	bus_size_t buflen;
395 	struct proc *p;
396 	int flags;
397 {
398 	int error;
399 
400 	error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
401 	if (error == 0)
402 		map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK;
403 	return (error);
404 }
405 
406 int
407 sun68k_vme_dmamap_load_raw(t, map, segs, nsegs, size, flags)
408 	bus_dma_tag_t t;
409 	bus_dmamap_t map;
410 	bus_dma_segment_t *segs;
411 	int nsegs;
412 	bus_size_t size;
413 	int flags;
414 {
415 	int error;
416 
417 	error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags);
418 	if (error == 0)
419 		map->dm_segs[0].ds_addr &= DVMA_VME_SLAVE_MASK;
420 	return (error);
421 }
422 
423