xref: /netbsd-src/sys/arch/sun3/sun3/obio.c (revision 7fa608457b817eca6e0977b37f758ae064f3c99c)
1 /*	$NetBSD: obio.c,v 1.53 2007/02/03 17:00:37 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 Adam Glass and 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  * 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/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: obio.c,v 1.53 2007/02/03 17:00:37 tsutsui Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 
46 #include <uvm/uvm_extern.h>
47 
48 #define _SUN68K_BUS_DMA_PRIVATE
49 #include <machine/autoconf.h>
50 #include <machine/bus.h>
51 #include <machine/dvma.h>
52 #include <machine/mon.h>
53 #include <machine/pte.h>
54 
55 #include <sun3/sun3/control.h>
56 #include <sun3/sun3/machdep.h>
57 #include <sun3/sun3/obio.h>
58 
59 static int	obio_match(struct device *, struct cfdata *, void *);
60 static void	obio_attach(struct device *, struct device *, void *);
61 static int	obio_print(void *, const char *);
62 static int	obio_submatch(struct device *, struct cfdata *,
63 			      const int *, void *);
64 
65 struct obio_softc {
66 	struct device	sc_dev;
67 	bus_space_tag_t	sc_bustag;
68 	bus_dma_tag_t	sc_dmatag;
69 };
70 
71 CFATTACH_DECL(obio, sizeof(struct obio_softc),
72     obio_match, obio_attach, NULL, NULL);
73 
74 static int obio_attached;
75 
76 static int obio_bus_map(bus_space_tag_t, bus_type_t, bus_addr_t, bus_size_t,
77     int, vaddr_t, bus_space_handle_t *);
78 static paddr_t obio_bus_mmap(bus_space_tag_t, bus_type_t, bus_addr_t,
79     off_t, int, int);
80 static int obio_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
81     struct proc *, int);
82 
83 static struct sun68k_bus_space_tag obio_space_tag = {
84 	NULL,				/* cookie */
85 	NULL,				/* parent bus space tag */
86 	obio_bus_map,			/* bus_space_map */
87 	NULL,				/* bus_space_unmap */
88 	NULL,				/* bus_space_subregion */
89 	NULL,				/* bus_space_barrier */
90 	obio_bus_mmap,			/* bus_space_mmap */
91 	NULL,				/* bus_intr_establish */
92 	NULL,				/* bus_space_peek_N */
93 	NULL				/* bus_space_poke_N */
94 };
95 
96 static struct sun68k_bus_dma_tag obio_dma_tag;
97 
98 static int
99 obio_match(struct device *parent, struct cfdata *cf, void *aux)
100 {
101 	struct confargs *ca = aux;
102 
103 	if (obio_attached)
104 		return 0;
105 
106 	if (ca->ca_bustype != BUS_OBIO)
107 		return 0;
108 
109 	if (ca->ca_name != NULL && strcmp(cf->cf_name, ca->ca_name) != 0)
110 		return 0;
111 
112 	return 1;
113 }
114 
115 /*
116  * We need control over the order of attachment on OBIO,
117  * so do "direct" style autoconfiguration with addresses
118  * tried in sequence starting at zero and incrementing
119  * by OBIO_INCR. Sun3 OBIO addresses are fixed forever.
120  */
121 #define OBIO_INCR	0x020000
122 #define OBIO_END	0x200000
123 
124 static void
125 obio_attach(struct device *parent, struct device *self, void *aux)
126 {
127 	struct confargs *ca = aux;
128 	struct obio_softc *sc = (void *)self;
129 	struct confargs oba;
130 	int addr;
131 
132 	obio_attached = 1;
133 
134 	printf("\n");
135 
136 	sc->sc_bustag = ca->ca_bustag;
137 	sc->sc_dmatag = ca->ca_dmatag;
138 
139 	obio_space_tag.cookie = sc;
140 	obio_space_tag.parent = sc->sc_bustag;
141 
142 	obio_dma_tag = *sc->sc_dmatag;
143 	obio_dma_tag._cookie = sc;
144 	obio_dma_tag._dmamap_load = obio_dmamap_load;
145 
146 	oba = *ca;
147 	oba.ca_bustag = &obio_space_tag;
148 	oba.ca_dmatag = &obio_dma_tag;
149 
150 	/* Configure these in order of address. */
151 	for (addr = 0; addr < OBIO_END; addr += OBIO_INCR) {
152 		/* Our parent set ca->ca_bustype already. */
153 		oba.ca_paddr = addr;
154 		/* These are filled-in by obio_submatch. */
155 		oba.ca_intpri = -1;
156 		oba.ca_intvec = -1;
157 		(void)config_found_sm_loc(self, "obio", NULL, &oba, obio_print,
158 		    obio_submatch);
159 	}
160 }
161 
162 /*
163  * Print out the confargs.  The (parent) name is non-NULL
164  * when there was no match found by config_found().
165  */
166 static int
167 obio_print(void *args, const char *name)
168 {
169 
170 	/* Be quiet about empty OBIO locations. */
171 	if (name)
172 		return(QUIET);
173 
174 	/* Otherwise do the usual. */
175 	return(bus_print(args, name));
176 }
177 
178 int
179 obio_submatch(struct device *parent, struct cfdata *cf,
180 	      const int *ldesc, void *aux)
181 {
182 	struct confargs *ca = aux;
183 
184 	/*
185 	 * Note that a defaulted address locator can never match
186 	 * the value of ca->ca_paddr set by the obio_attach loop.
187 	 * Without this diagnostic, any device with a defaulted
188 	 * address locator would always be silently unmatched.
189 	 * Therefore, just disallow default addresses on OBIO.
190 	 */
191 #ifdef	DIAGNOSTIC
192 	if (cf->cf_paddr == -1)
193 		panic("obio_submatch: invalid address for: %s%d",
194 			cf->cf_name, cf->cf_unit);
195 #endif
196 
197 	/*
198 	 * Note that obio_attach calls config_found_sm() with
199 	 * this function as the "submatch" and ca->ca_paddr
200 	 * set to each of the possible OBIO locations, so we
201 	 * want to reject any unmatched address here.
202 	 */
203 	if (cf->cf_paddr != ca->ca_paddr)
204 		return 0;
205 
206 	/*
207 	 * Note that the Sun3 does not really support vectored
208 	 * interrupts on OBIO, but the locator is permitted for
209 	 * consistency with the Sun3X.  Verify its absence...
210 	 */
211 #ifdef	DIAGNOSTIC
212 	if (cf->cf_intvec != -1)
213 		panic("obio_submatch: %s%d can not have a vector",
214 		    cf->cf_name, cf->cf_unit);
215 #endif
216 
217 	/*
218 	 * Copy the locators into our confargs for the child.
219 	 * Note: ca->ca_bustype was set by our parent driver
220 	 * (mainbus) and ca->ca_paddr was set by obio_attach.
221 	 */
222 	ca->ca_intpri = cf->cf_intpri;
223 	ca->ca_intvec = -1;
224 
225 	/* Now call the match function of the potential child. */
226 	return (config_match(parent, cf, aux));
227 }
228 
229 
230 /*****************************************************************/
231 
232 /*
233  * Spacing of "interesting" OBIO mappings.  We will
234  * record only those with an OBIO address that is a
235  * multiple of SAVE_INCR and below SAVE_LAST.
236  * The saved mappings are just one page each, which
237  * is good enough for all the devices that use this.
238  */
239 #define SAVE_SHIFT 17
240 #define SAVE_INCR (1<<SAVE_SHIFT)
241 #define SAVE_MASK (SAVE_INCR-1)
242 #define SAVE_SLOTS  16
243 #define SAVE_LAST (SAVE_SLOTS * SAVE_INCR)
244 
245 /*
246  * This is our record of "interesting" OBIO mappings that
247  * the PROM has left in the virtual space reserved for it.
248  * Each non-null array element holds the virtual address
249  * of an OBIO mapping where the OBIO address mapped is:
250  *     (array_index * SAVE_INCR)
251  * and the length of the mapping is one page.
252  */
253 static vaddr_t prom_mappings[SAVE_SLOTS];
254 
255 /*
256  * Find a virtual address for a device at physical address 'pa'.
257  * If one is found among the mappings already made by the PROM
258  * at power-up time, use it and return 0. Otherwise return errno
259  * as a sign that a mapping will have to be created.
260  */
261 int
262 find_prom_map(paddr_t pa, bus_type_t iospace, int sz, vaddr_t *vap)
263 {
264 	vsize_t off;
265 	vaddr_t va;
266 
267 	off = pa & PGOFSET;
268 	pa -= off;
269 	sz += off;
270 
271 	/* The saved mappings are all one page long. */
272 	if (sz > PAGE_SIZE)
273 		return EINVAL;
274 
275 	/* Within our table? */
276 	if (pa >= SAVE_LAST)
277 		return ENOENT;
278 
279 	/* Do we have this one? */
280 	va = prom_mappings[pa >> SAVE_SHIFT];
281 	if (va == 0)
282 		return ENOENT;
283 
284 	/* Found it! */
285 	*vap = va + off;
286 	return 0;
287 }
288 
289 /*
290  * This defines the permission bits to put in our PTEs.
291  * Device space is never cached, and the PROM appears to
292  * leave off the "no-cache" bit, so we can do the same.
293  */
294 #define PGBITS (PG_VALID|PG_WRITE|PG_SYSTEM)
295 
296 static void
297 save_prom_mappings(void)
298 {
299 	paddr_t pa;
300 	vaddr_t segva, pgva;
301 	int pte, sme, i;
302 
303 	segva = (vaddr_t)SUN3_MONSTART;
304 	while (segva < (vaddr_t)SUN3_MONEND) {
305 		sme = get_segmap(segva);
306 		if (sme == SEGINV) {
307 			segva += NBSG;
308 			continue;			/* next segment */
309 		}
310 		/*
311 		 * We have a valid segmap entry, so examine the
312 		 * PTEs for all the pages in this segment.
313 		 */
314 		pgva = segva;	/* starting page */
315 		segva += NBSG;	/* ending page (next seg) */
316 		while (pgva < segva) {
317 			pte = get_pte(pgva);
318 			if ((pte & (PG_VALID | PG_TYPE)) ==
319 				(PG_VALID | PGT_OBIO))
320 			{
321 				/* Have a valid OBIO mapping. */
322 				pa = PG_PA(pte);
323 				/* Is it one we want to record? */
324 				if ((pa < SAVE_LAST) &&
325 					((pa & SAVE_MASK) == 0))
326 				{
327 					i = pa >> SAVE_SHIFT;
328 					if (prom_mappings[i] == 0) {
329 						prom_mappings[i] = pgva;
330 					}
331 				}
332 				/* Make sure it has the right permissions. */
333 				if ((pte & PGBITS) != PGBITS) {
334 					pte |= PGBITS;
335 					set_pte(pgva, pte);
336 				}
337 			}
338 			pgva += PAGE_SIZE;		/* next page */
339 		}
340 	}
341 }
342 
343 /*
344  * These are all the OBIO address that are required early in
345  * the life of the kernel.  All are less than one page long.
346  */
347 static paddr_t required_mappings[] = {
348 	/* Basically the first six OBIO devices. */
349 	OBIO_ZS_KBD_MS,
350 	OBIO_ZS_TTY_AB,
351 	OBIO_EEPROM,
352 	OBIO_CLOCK,
353 	OBIO_MEMERR,
354 	OBIO_INTERREG,
355 	(paddr_t)-1,	/* end marker */
356 };
357 
358 static void
359 make_required_mappings(void)
360 {
361 	paddr_t *rmp;
362 	vaddr_t va;
363 
364 	rmp = required_mappings;
365 	while (*rmp != (paddr_t)-1) {
366 		if (find_prom_map(*rmp, PMAP_OBIO, PAGE_SIZE, &va) != 0) {
367 			/*
368 			 * XXX - Ack! Need to create one!
369 			 * I don't think this can happen, but if
370 			 * it does, we can allocate a PMEG in the
371 			 * "high segment" and add it there. -gwr
372 			 */
373 			mon_printf("obio: no mapping for 0x%x\n", *rmp);
374 			sunmon_abort();
375 		}
376 		rmp++;
377 	}
378 }
379 
380 
381 /*
382  * Find mappings for devices that are needed before autoconfiguration.
383  * We first look for and record any useful PROM mappings, then call
384  * the "init" functions for drivers that we need to use before the
385  * normal autoconfiguration calls configure().  Warning: this is
386  * called before pmap_bootstrap, so no allocation allowed!
387  */
388 void
389 obio_init(void)
390 {
391 	save_prom_mappings();
392 	make_required_mappings();
393 
394 	/*
395 	 * Find the interrupt reg mapping and turn off the
396 	 * interrupts, otherwise the PROM clock interrupt
397 	 * would poll the zs and toggle some LEDs...
398 	 */
399 	intreg_init();
400 }
401 
402 int
403 obio_bus_map(bus_space_tag_t t, bus_type_t btype, bus_addr_t paddr,
404     bus_size_t size, int flags, vaddr_t vaddr, bus_space_handle_t *hp)
405 {
406 	struct obio_softc *sc = t->cookie;
407 
408 	return bus_space_map2(sc->sc_bustag, PMAP_OBIO, paddr, size,
409 	    flags | _SUN68K_BUS_MAP_USE_PROM, vaddr, hp);
410 }
411 
412 paddr_t
413 obio_bus_mmap(bus_space_tag_t t, bus_type_t btype, bus_addr_t paddr, off_t off,
414     int prot, int flags)
415 {
416 	struct obio_softc *sc = t->cookie;
417 
418 	return bus_space_mmap2(sc->sc_bustag, PMAP_OBIO, paddr, off, prot,
419 	    flags);
420 }
421 
422 static int
423 obio_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
424     bus_size_t buflen, struct proc *p, int flags)
425 {
426 	int error;
427 
428 	error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
429 	if (error == 0)
430 		map->dm_segs[0].ds_addr &= DVMA_OBIO_SLAVE_MASK;
431 	return error;
432 }
433