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