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