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