1 /* $NetBSD: obio.c,v 1.48 2000/06/29 07:40:07 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 1997,1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 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 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 #include <sys/malloc.h> 44 45 #ifdef DEBUG 46 #include <sys/proc.h> 47 #include <sys/syslog.h> 48 #endif 49 50 #include <uvm/uvm_extern.h> 51 52 #include <machine/bus.h> 53 #include <sparc/dev/sbusvar.h> 54 #include <machine/autoconf.h> 55 #include <machine/oldmon.h> 56 #include <machine/cpu.h> 57 #include <machine/ctlreg.h> 58 #include <sparc/sparc/asm.h> 59 #include <sparc/sparc/vaddrs.h> 60 #include <sparc/sparc/cpuvar.h> 61 62 struct obio4_softc { 63 struct device sc_dev; /* base device */ 64 bus_space_tag_t sc_bustag; /* parent bus tag */ 65 bus_dma_tag_t sc_dmatag; /* parent bus dma tag */ 66 }; 67 68 union obio_softc { 69 struct device sc_dev; /* base device */ 70 struct obio4_softc sc_obio; /* sun4 obio */ 71 struct sbus_softc sc_sbus; /* sun4m obio is another sbus slot */ 72 }; 73 74 75 /* autoconfiguration driver */ 76 static int obiomatch __P((struct device *, struct cfdata *, void *)); 77 static void obioattach __P((struct device *, struct device *, void *)); 78 79 struct cfattach obio_ca = { 80 sizeof(union obio_softc), obiomatch, obioattach 81 }; 82 83 84 /* 85 * This `obio4_busattachargs' data structure only exists to pass down 86 * to obiosearch() the name of a device that must be configured early. 87 */ 88 struct obio4_busattachargs { 89 struct mainbus_attach_args *ma; 90 const char *name; 91 }; 92 93 #if defined(SUN4) 94 static int obioprint __P((void *, const char *)); 95 static int obiosearch __P((struct device *, struct cfdata *, void *)); 96 static int obio_bus_mmap __P((bus_space_tag_t, bus_type_t, bus_addr_t, 97 int, bus_space_handle_t *)); 98 static int _obio_bus_map __P((bus_space_tag_t, bus_type_t, bus_addr_t, 99 bus_size_t, int, 100 vaddr_t, bus_space_handle_t *)); 101 102 static struct sparc_bus_space_tag obio_space_tag = { 103 NULL, /* cookie */ 104 NULL, /* parent bus tag */ 105 _obio_bus_map, /* bus_space_map */ 106 NULL, /* bus_space_unmap */ 107 NULL, /* bus_space_subregion */ 108 NULL, /* bus_space_barrier */ 109 obio_bus_mmap, /* bus_space_mmap */ 110 NULL /* bus_intr_establish */ 111 }; 112 #endif 113 114 /* 115 * Translate obio `interrupts' property value to processor IPL (see sbus.c) 116 * Apparently, the `interrupts' property on obio devices is just 117 * the processor IPL. 118 */ 119 static int intr_obio2ipl[] = { 120 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 121 }; 122 123 int 124 obiomatch(parent, cf, aux) 125 struct device *parent; 126 struct cfdata *cf; 127 void *aux; 128 { 129 struct mainbus_attach_args *ma = aux; 130 131 return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0); 132 } 133 134 void 135 obioattach(parent, self, aux) 136 struct device *parent, *self; 137 void *aux; 138 { 139 struct mainbus_attach_args *ma = aux; 140 141 /* 142 * There is only one obio bus 143 */ 144 if (self->dv_unit > 0) { 145 printf(" unsupported\n"); 146 return; 147 } 148 printf("\n"); 149 150 if (CPU_ISSUN4) { 151 #if defined(SUN4) 152 struct obio4_softc *sc = &((union obio_softc *)self)->sc_obio; 153 struct obio4_busattachargs oa; 154 const char *const *cpp; 155 static const char *const special4[] = { 156 /* find these first */ 157 "timer", 158 NULL 159 }; 160 161 sc->sc_bustag = ma->ma_bustag; 162 sc->sc_dmatag = ma->ma_dmatag; 163 164 obio_space_tag.cookie = sc; 165 obio_space_tag.parent = sc->sc_bustag; 166 167 oa.ma = ma; 168 169 /* Find all `early' obio devices */ 170 for (cpp = special4; *cpp != NULL; cpp++) { 171 oa.name = *cpp; 172 (void)config_search(obiosearch, self, &oa); 173 } 174 175 /* Find all other obio devices */ 176 oa.name = NULL; 177 (void)config_search(obiosearch, self, &oa); 178 #endif 179 return; 180 } else if (CPU_ISSUN4M) { 181 /* 182 * Attach the on-board I/O bus at on a sun4m. 183 * In this case we treat the obio bus as another sbus slot. 184 */ 185 struct sbus_softc *sc = &((union obio_softc *)self)->sc_sbus; 186 187 static const char *const special4m[] = { 188 /* find these first */ 189 "eeprom", 190 "counter", 191 #if 0 /* Not all sun4m's have an `auxio' */ 192 "auxio", 193 #endif 194 "", 195 /* place device to ignore here */ 196 "interrupt", 197 NULL 198 }; 199 200 sc->sc_bustag = ma->ma_bustag; 201 sc->sc_dmatag = ma->ma_dmatag; 202 sc->sc_intr2ipl = intr_obio2ipl; 203 204 sbus_attach_common(sc, "obio", ma->ma_node, special4m); 205 } else { 206 printf("obio on this machine?\n"); 207 } 208 } 209 210 #if defined(SUN4) 211 int 212 obioprint(args, busname) 213 void *args; 214 const char *busname; 215 { 216 union obio_attach_args *uoba = args; 217 struct obio4_attach_args *oba = &uoba->uoba_oba4; 218 219 printf(" addr 0x%lx", (long)oba->oba_paddr); 220 if (oba->oba_pri != -1) 221 printf(" level %d", oba->oba_pri); 222 223 return (UNCONF); 224 } 225 226 int 227 _obio_bus_map(t, btype, paddr, size, flags, vaddr, hp) 228 bus_space_tag_t t; 229 bus_type_t btype; 230 bus_addr_t paddr; 231 bus_size_t size; 232 int flags; 233 vaddr_t vaddr; 234 bus_space_handle_t *hp; 235 { 236 struct obio4_softc *sc = t->cookie; 237 238 if ((flags & OBIO_BUS_MAP_USE_ROM) != 0 && 239 obio_find_rom_map(paddr, PMAP_OBIO, size, hp) == 0) 240 return (0); 241 242 return (bus_space_map2(sc->sc_bustag, PMAP_OBIO, paddr, 243 size, flags, vaddr, hp)); 244 } 245 246 int 247 obio_bus_mmap(t, btype, paddr, flags, hp) 248 bus_space_tag_t t; 249 bus_type_t btype; 250 bus_addr_t paddr; 251 int flags; 252 bus_space_handle_t *hp; 253 { 254 struct obio4_softc *sc = t->cookie; 255 256 return (bus_space_mmap(sc->sc_bustag, PMAP_OBIO, paddr, flags, hp)); 257 } 258 259 int 260 obiosearch(parent, cf, aux) 261 struct device *parent; 262 struct cfdata *cf; 263 void *aux; 264 { 265 struct obio4_busattachargs *oap = aux; 266 union obio_attach_args uoba; 267 struct obio4_attach_args *oba = &uoba.uoba_oba4; 268 269 /* Check whether we're looking for a specifically named device */ 270 if (oap->name != NULL && strcmp(oap->name, cf->cf_driver->cd_name) != 0) 271 return (0); 272 273 /* 274 * Avoid sun4m entries which don't have valid PAs. 275 * no point in even probing them. 276 */ 277 if (cf->cf_loc[0] == -1) 278 return (0); 279 280 /* 281 * On the 4/100 obio addresses must be mapped at 282 * 0x0YYYYYYY, but alias higher up (we avoid the 283 * alias condition because it causes pmap difficulties) 284 * XXX: We also assume that 4/[23]00 obio addresses 285 * must be 0xZYYYYYYY, where (Z != 0) 286 */ 287 if (cpuinfo.cpu_type == CPUTYP_4_100 && (cf->cf_loc[0] & 0xf0000000)) 288 return (0); 289 if (cpuinfo.cpu_type != CPUTYP_4_100 && !(cf->cf_loc[0] & 0xf0000000)) 290 return (0); 291 292 uoba.uoba_isobio4 = 1; 293 oba->oba_bustag = &obio_space_tag; 294 oba->oba_dmatag = oap->ma->ma_dmatag; 295 oba->oba_paddr = cf->cf_loc[0]; 296 oba->oba_pri = cf->cf_loc[1]; 297 298 if ((*cf->cf_attach->ca_match)(parent, cf, &uoba) == 0) 299 return (0); 300 301 config_attach(parent, cf, &uoba, obioprint); 302 return (1); 303 } 304 305 306 /* 307 * If we can find a mapping that was established by the rom, use it. 308 * Else, create a new mapping. 309 */ 310 int 311 obio_find_rom_map(pa, iospace, len, hp) 312 bus_addr_t pa; 313 bus_type_t iospace; 314 int len; 315 bus_space_handle_t *hp; 316 { 317 #define getpte(va) lda(va, ASI_PTE) 318 319 u_long pf; 320 int pgtype; 321 u_long va, pte; 322 323 if (len > NBPG) 324 return (EINVAL); 325 326 pf = pa >> PGSHIFT; 327 pgtype = PMAP_T2PTE_4(iospace); 328 329 for (va = OLDMON_STARTVADDR; va < OLDMON_ENDVADDR; va += NBPG) { 330 pte = getpte(va); 331 if ((pte & PG_V) == 0 || (pte & PG_TYPE) != pgtype || 332 (pte & PG_PFNUM) != pf) 333 continue; 334 335 /* 336 * Found entry in PROM's pagetable 337 * note: preserve page offset 338 */ 339 *hp = (bus_space_handle_t)(va | ((u_long)pa & PGOFSET)); 340 return (0); 341 } 342 343 return (ENOENT); 344 } 345 #endif /* SUN4 */ 346