1 /* $NetBSD: obio.c,v 1.56 2008/06/28 12:13:38 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 * 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.56 2008/06/28 12:13:38 tsutsui 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 (void)config_found_sm_loc(self, "obio", NULL, &oba, obio_print, 151 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