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