1 /* $NetBSD: sbus.c,v 1.17 1997/06/01 22:10:39 pk Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)sbus.c 8.1 (Berkeley) 6/11/93 45 */ 46 47 /* 48 * Sbus stuff. 49 */ 50 51 #include <sys/param.h> 52 #include <sys/malloc.h> 53 #include <sys/systm.h> 54 #include <sys/device.h> 55 #include <vm/vm.h> 56 57 #include <machine/autoconf.h> 58 59 #include <sparc/dev/sbusreg.h> 60 #include <sparc/dev/sbusvar.h> 61 62 int sbus_print __P((void *, const char *)); 63 void sbusreset __P((int)); 64 65 /* autoconfiguration driver */ 66 void sbus_attach __P((struct device *, struct device *, void *)); 67 int sbus_match __P((struct device *, struct cfdata *, void *)); 68 69 struct cfattach sbus_ca = { 70 sizeof(struct sbus_softc), sbus_match, sbus_attach 71 }; 72 73 struct cfdriver sbus_cd = { 74 NULL, "sbus", DV_DULL 75 }; 76 77 /* 78 * Print the location of some sbus-attached device (called just 79 * before attaching that device). If `sbus' is not NULL, the 80 * device was found but not configured; print the sbus as well. 81 * Return UNCONF (config_find ignores this if the device was configured). 82 */ 83 int 84 sbus_print(args, sbus) 85 void *args; 86 const char *sbus; 87 { 88 register struct confargs *ca = args; 89 90 if (sbus) 91 printf("%s at %s", ca->ca_ra.ra_name, sbus); 92 printf(" slot %d offset 0x%x", ca->ca_slot, ca->ca_offset); 93 return (UNCONF); 94 } 95 96 int 97 sbus_match(parent, cf, aux) 98 struct device *parent; 99 struct cfdata *cf; 100 void *aux; 101 { 102 register struct confargs *ca = aux; 103 register struct romaux *ra = &ca->ca_ra; 104 105 if (CPU_ISSUN4) 106 return (0); 107 108 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 109 } 110 111 /* 112 * Attach an Sbus. 113 */ 114 void 115 sbus_attach(parent, self, aux) 116 struct device *parent; 117 struct device *self; 118 void *aux; 119 { 120 register struct sbus_softc *sc = (struct sbus_softc *)self; 121 struct confargs *ca = aux; 122 register struct romaux *ra = &ca->ca_ra; 123 register int node; 124 register char *name; 125 struct confargs oca; 126 int rlen; 127 128 /* 129 * XXX there is only one Sbus, for now -- do not know how to 130 * address children on others 131 */ 132 if (sc->sc_dev.dv_unit > 0) { 133 printf(" unsupported\n"); 134 return; 135 } 136 137 /* 138 * Record clock frequency for synchronous SCSI. 139 * IS THIS THE CORRECT DEFAULT?? 140 */ 141 node = ra->ra_node; 142 sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000); 143 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 144 145 /* 146 * Get the SBus burst transfer size if burst transfers are supported 147 */ 148 sc->sc_burst = getpropint(node, "burst-sizes", 0); 149 150 if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "sbus") == 0) 151 oca.ca_ra.ra_bp = ra->ra_bp + 1; 152 else 153 oca.ca_ra.ra_bp = NULL; 154 155 rlen = getproplen(node, "ranges"); 156 if (rlen > 0) { 157 sc->sc_nrange = rlen / sizeof(struct rom_range); 158 sc->sc_range = 159 (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT); 160 if (sc->sc_range == 0) 161 panic("sbus: PROM ranges too large: %d", rlen); 162 (void)getprop(node, "ranges", sc->sc_range, rlen); 163 } 164 165 /* 166 * Loop through ROM children, fixing any relative addresses 167 * and then configuring each device. 168 */ 169 for (node = firstchild(node); node; node = nextsibling(node)) { 170 name = getpropstring(node, "name"); 171 if (!romprop(&oca.ca_ra, name, node)) 172 continue; 173 174 sbus_translate(self, &oca); 175 oca.ca_bustype = BUS_SBUS; 176 (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print); 177 } 178 } 179 180 void 181 sbus_translate(dev, ca) 182 struct device *dev; 183 struct confargs *ca; 184 { 185 struct sbus_softc *sc = (struct sbus_softc *)dev; 186 register int base, slot; 187 register int i; 188 189 if (sc->sc_nrange == 0) { 190 /* Old-style Sbus configuration */ 191 base = (int)ca->ca_ra.ra_paddr; 192 if (SBUS_ABS(base)) { 193 ca->ca_slot = SBUS_ABS_TO_SLOT(base); 194 ca->ca_offset = SBUS_ABS_TO_OFFSET(base); 195 } else { 196 if (!CPU_ISSUN4C) 197 panic("relative sbus addressing not supported"); 198 ca->ca_slot = slot = ca->ca_ra.ra_iospace; 199 ca->ca_offset = base; 200 ca->ca_ra.ra_paddr = (void *)SBUS_ADDR(slot, base); 201 ca->ca_ra.ra_iospace = PMAP_OBIO; 202 203 /* Fix any remaining register banks */ 204 for (i = 1; i < ca->ca_ra.ra_nreg; i++) { 205 base = (int)ca->ca_ra.ra_reg[i].rr_paddr; 206 ca->ca_ra.ra_reg[i].rr_paddr = 207 (void *)SBUS_ADDR(slot, base); 208 ca->ca_ra.ra_reg[i].rr_iospace = PMAP_OBIO; 209 } 210 } 211 212 } else { 213 214 ca->ca_slot = ca->ca_ra.ra_iospace; 215 ca->ca_offset = (int)ca->ca_ra.ra_paddr; 216 217 /* Translate into parent address spaces */ 218 for (i = 0; i < ca->ca_ra.ra_nreg; i++) { 219 int j, cspace = ca->ca_ra.ra_reg[i].rr_iospace; 220 221 for (j = 0; j < sc->sc_nrange; j++) { 222 if (sc->sc_range[j].cspace == cspace) { 223 (int)ca->ca_ra.ra_reg[i].rr_paddr += 224 sc->sc_range[j].poffset; 225 (int)ca->ca_ra.ra_reg[i].rr_iospace = 226 sc->sc_range[j].pspace; 227 break; 228 } 229 } 230 } 231 } 232 } 233 234 /* 235 * Each attached device calls sbus_establish after it initializes 236 * its sbusdev portion. 237 */ 238 void 239 sbus_establish(sd, dev) 240 register struct sbusdev *sd; 241 register struct device *dev; 242 { 243 register struct sbus_softc *sc; 244 register struct device *curdev; 245 246 /* 247 * We have to look for the sbus by name, since it is not necessarily 248 * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp) 249 * We don't just use the device structure of the above-attached 250 * sbus, since we might (in the future) support multiple sbus's. 251 */ 252 for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) { 253 if (!curdev || !curdev->dv_xname) 254 panic("sbus_establish: can't find sbus parent for %s", 255 sd->sd_dev->dv_xname 256 ? sd->sd_dev->dv_xname 257 : "<unknown>" ); 258 259 if (strncmp(curdev->dv_xname, "sbus", 4) == 0) 260 break; 261 } 262 sc = (struct sbus_softc *) curdev; 263 264 sd->sd_dev = dev; 265 sd->sd_bchain = sc->sc_sbdev; 266 sc->sc_sbdev = sd; 267 } 268 269 /* 270 * Reset the given sbus. (???) 271 */ 272 void 273 sbusreset(sbus) 274 int sbus; 275 { 276 register struct sbusdev *sd; 277 struct sbus_softc *sc = sbus_cd.cd_devs[sbus]; 278 struct device *dev; 279 280 printf("reset %s:", sc->sc_dev.dv_xname); 281 for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) { 282 if (sd->sd_reset) { 283 dev = sd->sd_dev; 284 (*sd->sd_reset)(dev); 285 printf(" %s", dev->dv_xname); 286 } 287 } 288 } 289