1 /* $NetBSD: obio.c,v 1.59 2021/08/07 16:19:06 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.59 2021/08/07 16:19:06 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
obio_match(device_t parent,cfdata_t cf,void * aux)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
obio_attach(device_t parent,device_t self,void * aux)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 CFARGS(.submatch = obio_submatch));
152 }
153 }
154
155 /*
156 * Print out the confargs. The (parent) name is non-NULL
157 * when there was no match found by config_found().
158 */
159 static int
obio_print(void * args,const char * name)160 obio_print(void *args, const char *name)
161 {
162
163 /* Be quiet about empty OBIO locations. */
164 if (name)
165 return QUIET;
166
167 /* Otherwise do the usual. */
168 return bus_print(args, name);
169 }
170
171 int
obio_submatch(device_t parent,cfdata_t cf,const int * ldesc,void * aux)172 obio_submatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
173 {
174 struct confargs *ca = aux;
175
176 /*
177 * Note that a defaulted address locator can never match
178 * the value of ca->ca_paddr set by the obio_attach loop.
179 * Without this diagnostic, any device with a defaulted
180 * address locator would always be silently unmatched.
181 * Therefore, just disallow default addresses on OBIO.
182 */
183 #ifdef DIAGNOSTIC
184 if (cf->cf_paddr == -1)
185 panic("%s: invalid address for: %s%d",
186 __func__, cf->cf_name, cf->cf_unit);
187 #endif
188
189 /*
190 * Note that obio_attach calls config_found_sm() with
191 * this function as the "submatch" and ca->ca_paddr
192 * set to each of the possible OBIO locations, so we
193 * want to reject any unmatched address here.
194 */
195 if (cf->cf_paddr != ca->ca_paddr)
196 return 0;
197
198 /*
199 * Note that the Sun3 does not really support vectored
200 * interrupts on OBIO, but the locator is permitted for
201 * consistency with the Sun3X. Verify its absence...
202 */
203 #ifdef DIAGNOSTIC
204 if (cf->cf_intvec != -1)
205 panic("%s: %s%d can not have a vector",
206 __func__, cf->cf_name, cf->cf_unit);
207 #endif
208
209 /*
210 * Copy the locators into our confargs for the child.
211 * Note: ca->ca_bustype was set by our parent driver
212 * (mainbus) and ca->ca_paddr was set by obio_attach.
213 */
214 ca->ca_intpri = cf->cf_intpri;
215 ca->ca_intvec = -1;
216
217 /* Now call the match function of the potential child. */
218 return config_match(parent, cf, aux);
219 }
220
221
222 /*****************************************************************/
223
224 /*
225 * Spacing of "interesting" OBIO mappings. We will
226 * record only those with an OBIO address that is a
227 * multiple of SAVE_INCR and below SAVE_LAST.
228 * The saved mappings are just one page each, which
229 * is good enough for all the devices that use this.
230 */
231 #define SAVE_SHIFT 17
232 #define SAVE_INCR (1 << SAVE_SHIFT)
233 #define SAVE_MASK (SAVE_INCR - 1)
234 #define SAVE_SLOTS 16
235 #define SAVE_LAST (SAVE_SLOTS * SAVE_INCR)
236
237 /*
238 * This is our record of "interesting" OBIO mappings that
239 * the PROM has left in the virtual space reserved for it.
240 * Each non-null array element holds the virtual address
241 * of an OBIO mapping where the OBIO address mapped is:
242 * (array_index * SAVE_INCR)
243 * and the length of the mapping is one page.
244 */
245 static vaddr_t prom_mappings[SAVE_SLOTS];
246
247 /*
248 * Find a virtual address for a device at physical address 'pa'.
249 * If one is found among the mappings already made by the PROM
250 * at power-up time, use it and return 0. Otherwise return errno
251 * as a sign that a mapping will have to be created.
252 */
253 int
find_prom_map(paddr_t pa,bus_type_t iospace,int sz,vaddr_t * vap)254 find_prom_map(paddr_t pa, bus_type_t iospace, int sz, vaddr_t *vap)
255 {
256 vsize_t off;
257 vaddr_t va;
258
259 off = pa & PGOFSET;
260 pa -= off;
261 sz += off;
262
263 /* The saved mappings are all one page long. */
264 if (sz > PAGE_SIZE)
265 return EINVAL;
266
267 /* Within our table? */
268 if (pa >= SAVE_LAST)
269 return ENOENT;
270
271 /* Do we have this one? */
272 va = prom_mappings[pa >> SAVE_SHIFT];
273 if (va == 0)
274 return ENOENT;
275
276 /* Found it! */
277 *vap = va + off;
278 return 0;
279 }
280
281 /*
282 * This defines the permission bits to put in our PTEs.
283 * Device space is never cached, and the PROM appears to
284 * leave off the "no-cache" bit, so we can do the same.
285 */
286 #define PGBITS (PG_VALID|PG_WRITE|PG_SYSTEM)
287
288 static void
save_prom_mappings(void)289 save_prom_mappings(void)
290 {
291 paddr_t pa;
292 vaddr_t segva, pgva;
293 int pte, sme, i;
294
295 segva = (vaddr_t)SUN3_MONSTART;
296 while (segva < (vaddr_t)SUN3_MONEND) {
297 sme = get_segmap(segva);
298 if (sme == SEGINV) {
299 segva += NBSG;
300 continue; /* next segment */
301 }
302 /*
303 * We have a valid segmap entry, so examine the
304 * PTEs for all the pages in this segment.
305 */
306 pgva = segva; /* starting page */
307 segva += NBSG; /* ending page (next seg) */
308 while (pgva < segva) {
309 pte = get_pte(pgva);
310 if ((pte & (PG_VALID | PG_TYPE)) ==
311 (PG_VALID | PGT_OBIO)) {
312 /* Have a valid OBIO mapping. */
313 pa = PG_PA(pte);
314 /* Is it one we want to record? */
315 if ((pa < SAVE_LAST) &&
316 ((pa & SAVE_MASK) == 0)) {
317 i = pa >> SAVE_SHIFT;
318 if (prom_mappings[i] == 0) {
319 prom_mappings[i] = pgva;
320 }
321 }
322 /* Make sure it has the right permissions. */
323 if ((pte & PGBITS) != PGBITS) {
324 pte |= PGBITS;
325 set_pte(pgva, pte);
326 }
327 }
328 pgva += PAGE_SIZE; /* next page */
329 }
330 }
331 }
332
333 /*
334 * These are all the OBIO address that are required early in
335 * the life of the kernel. All are less than one page long.
336 */
337 static paddr_t required_mappings[] = {
338 /* Basically the first six OBIO devices. */
339 OBIO_ZS_KBD_MS,
340 OBIO_ZS_TTY_AB,
341 OBIO_EEPROM,
342 OBIO_CLOCK,
343 OBIO_MEMERR,
344 OBIO_INTERREG,
345 (paddr_t)-1, /* end marker */
346 };
347
348 static void
make_required_mappings(void)349 make_required_mappings(void)
350 {
351 paddr_t *rmp;
352 vaddr_t va;
353
354 rmp = required_mappings;
355 while (*rmp != (paddr_t)-1) {
356 if (find_prom_map(*rmp, PMAP_OBIO, PAGE_SIZE, &va) != 0) {
357 /*
358 * XXX - Ack! Need to create one!
359 * I don't think this can happen, but if
360 * it does, we can allocate a PMEG in the
361 * "high segment" and add it there. -gwr
362 */
363 mon_printf("obio: no mapping for 0x%x\n", *rmp);
364 sunmon_abort();
365 }
366 rmp++;
367 }
368 }
369
370
371 /*
372 * Find mappings for devices that are needed before autoconfiguration.
373 * We first look for and record any useful PROM mappings, then call
374 * the "init" functions for drivers that we need to use before the
375 * normal autoconfiguration calls configure(). Warning: this is
376 * called before pmap_bootstrap, so no allocation allowed!
377 */
378 void
obio_init(void)379 obio_init(void)
380 {
381
382 save_prom_mappings();
383 make_required_mappings();
384
385 /*
386 * Find the interrupt reg mapping and turn off the
387 * interrupts, otherwise the PROM clock interrupt
388 * would poll the zs and toggle some LEDs...
389 */
390 intreg_init();
391 }
392
393 int
obio_bus_map(bus_space_tag_t t,bus_type_t btype,bus_addr_t paddr,bus_size_t size,int flags,vaddr_t vaddr,bus_space_handle_t * hp)394 obio_bus_map(bus_space_tag_t t, bus_type_t btype, bus_addr_t paddr,
395 bus_size_t size, int flags, vaddr_t vaddr, bus_space_handle_t *hp)
396 {
397 struct obio_softc *sc = t->cookie;
398
399 return bus_space_map2(sc->sc_bustag, PMAP_OBIO, paddr, size,
400 flags | _SUN68K_BUS_MAP_USE_PROM, vaddr, hp);
401 }
402
403 paddr_t
obio_bus_mmap(bus_space_tag_t t,bus_type_t btype,bus_addr_t paddr,off_t off,int prot,int flags)404 obio_bus_mmap(bus_space_tag_t t, bus_type_t btype, bus_addr_t paddr, off_t off,
405 int prot, int flags)
406 {
407 struct obio_softc *sc = t->cookie;
408
409 return bus_space_mmap2(sc->sc_bustag, PMAP_OBIO, paddr, off, prot,
410 flags);
411 }
412
413 static int
obio_dmamap_load(bus_dma_tag_t t,bus_dmamap_t map,void * buf,bus_size_t buflen,struct proc * p,int flags)414 obio_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
415 bus_size_t buflen, struct proc *p, int flags)
416 {
417 int error;
418
419 error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
420 if (error == 0)
421 map->dm_segs[0].ds_addr &= DVMA_OBIO_SLAVE_MASK;
422 return error;
423 }
424