Home | History | Annotate | Line # | Download | only in sun3
      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
     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 		    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
    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
    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
    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
    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
    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
    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
    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
    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
    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