1 /* $NetBSD: sbus.c,v 1.16 1997/04/08 20:08:21 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 56 #include <machine/autoconf.h> 57 58 #include <sparc/dev/sbusreg.h> 59 #include <sparc/dev/sbusvar.h> 60 61 int sbus_print __P((void *, const char *)); 62 void sbusreset __P((int)); 63 64 /* autoconfiguration driver */ 65 void sbus_attach __P((struct device *, struct device *, void *)); 66 int sbus_match __P((struct device *, struct cfdata *, void *)); 67 68 struct cfattach sbus_ca = { 69 sizeof(struct sbus_softc), sbus_match, sbus_attach 70 }; 71 72 struct cfdriver sbus_cd = { 73 NULL, "sbus", DV_DULL 74 }; 75 76 /* 77 * Print the location of some sbus-attached device (called just 78 * before attaching that device). If `sbus' is not NULL, the 79 * device was found but not configured; print the sbus as well. 80 * Return UNCONF (config_find ignores this if the device was configured). 81 */ 82 int 83 sbus_print(args, sbus) 84 void *args; 85 const char *sbus; 86 { 87 register struct confargs *ca = args; 88 89 if (sbus) 90 printf("%s at %s", ca->ca_ra.ra_name, sbus); 91 printf(" slot %d offset 0x%x", ca->ca_slot, ca->ca_offset); 92 return (UNCONF); 93 } 94 95 int 96 sbus_match(parent, cf, aux) 97 struct device *parent; 98 struct cfdata *cf; 99 void *aux; 100 { 101 register struct confargs *ca = aux; 102 register struct romaux *ra = &ca->ca_ra; 103 104 if (CPU_ISSUN4) 105 return (0); 106 107 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 108 } 109 110 /* 111 * Attach an Sbus. 112 */ 113 void 114 sbus_attach(parent, self, aux) 115 struct device *parent; 116 struct device *self; 117 void *aux; 118 { 119 register struct sbus_softc *sc = (struct sbus_softc *)self; 120 struct confargs *ca = aux; 121 register struct romaux *ra = &ca->ca_ra; 122 register int node; 123 register char *name; 124 struct confargs oca; 125 int rlen; 126 127 /* 128 * XXX there is only one Sbus, for now -- do not know how to 129 * address children on others 130 */ 131 if (sc->sc_dev.dv_unit > 0) { 132 printf(" unsupported\n"); 133 return; 134 } 135 136 /* 137 * Record clock frequency for synchronous SCSI. 138 * IS THIS THE CORRECT DEFAULT?? 139 */ 140 node = ra->ra_node; 141 sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000); 142 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); 143 144 /* 145 * Get the SBus burst transfer size if burst transfers are supported 146 */ 147 sc->sc_burst = getpropint(node, "burst-sizes", 0); 148 149 if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "sbus") == 0) 150 oca.ca_ra.ra_bp = ra->ra_bp + 1; 151 else 152 oca.ca_ra.ra_bp = NULL; 153 154 rlen = getproplen(node, "ranges"); 155 if (rlen > 0) { 156 sc->sc_nrange = rlen / sizeof(struct rom_range); 157 sc->sc_range = 158 (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT); 159 if (sc->sc_range == 0) 160 panic("sbus: PROM ranges too large: %d", rlen); 161 (void)getprop(node, "ranges", sc->sc_range, rlen); 162 } 163 164 /* 165 * Loop through ROM children, fixing any relative addresses 166 * and then configuring each device. 167 */ 168 for (node = firstchild(node); node; node = nextsibling(node)) { 169 name = getpropstring(node, "name"); 170 if (!romprop(&oca.ca_ra, name, node)) 171 continue; 172 173 sbus_translate(self, &oca); 174 oca.ca_bustype = BUS_SBUS; 175 (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print); 176 } 177 } 178 179 void 180 sbus_translate(dev, ca) 181 struct device *dev; 182 struct confargs *ca; 183 { 184 struct sbus_softc *sc = (struct sbus_softc *)dev; 185 register int base, slot; 186 register int i; 187 188 if (sc->sc_nrange == 0) { 189 /* Old-style Sbus configuration */ 190 base = (int)ca->ca_ra.ra_paddr; 191 if (SBUS_ABS(base)) { 192 ca->ca_slot = SBUS_ABS_TO_SLOT(base); 193 ca->ca_offset = SBUS_ABS_TO_OFFSET(base); 194 } else { 195 ca->ca_slot = slot = ca->ca_ra.ra_iospace; 196 ca->ca_offset = base; 197 ca->ca_ra.ra_paddr = 198 (void *)SBUS_ADDR(slot, base); 199 /* Fix any remaining register banks */ 200 for (i = 1; i < ca->ca_ra.ra_nreg; i++) { 201 base = (int)ca->ca_ra.ra_reg[i].rr_paddr; 202 ca->ca_ra.ra_reg[i].rr_paddr = 203 (void *)SBUS_ADDR(slot, base); 204 } 205 } 206 207 } else { 208 209 ca->ca_slot = ca->ca_ra.ra_iospace; 210 ca->ca_offset = (int)ca->ca_ra.ra_paddr; 211 212 /* Translate into parent address spaces */ 213 for (i = 0; i < ca->ca_ra.ra_nreg; i++) { 214 int j, cspace = ca->ca_ra.ra_reg[i].rr_iospace; 215 216 for (j = 0; j < sc->sc_nrange; j++) { 217 if (sc->sc_range[j].cspace == cspace) { 218 (int)ca->ca_ra.ra_reg[i].rr_paddr += 219 sc->sc_range[j].poffset; 220 (int)ca->ca_ra.ra_reg[i].rr_iospace = 221 sc->sc_range[j].pspace; 222 break; 223 } 224 } 225 } 226 } 227 } 228 229 /* 230 * Each attached device calls sbus_establish after it initializes 231 * its sbusdev portion. 232 */ 233 void 234 sbus_establish(sd, dev) 235 register struct sbusdev *sd; 236 register struct device *dev; 237 { 238 register struct sbus_softc *sc; 239 register struct device *curdev; 240 241 /* 242 * We have to look for the sbus by name, since it is not necessarily 243 * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp) 244 * We don't just use the device structure of the above-attached 245 * sbus, since we might (in the future) support multiple sbus's. 246 */ 247 for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) { 248 if (!curdev || !curdev->dv_xname) 249 panic("sbus_establish: can't find sbus parent for %s", 250 sd->sd_dev->dv_xname 251 ? sd->sd_dev->dv_xname 252 : "<unknown>" ); 253 254 if (strncmp(curdev->dv_xname, "sbus", 4) == 0) 255 break; 256 } 257 sc = (struct sbus_softc *) curdev; 258 259 sd->sd_dev = dev; 260 sd->sd_bchain = sc->sc_sbdev; 261 sc->sc_sbdev = sd; 262 } 263 264 /* 265 * Reset the given sbus. (???) 266 */ 267 void 268 sbusreset(sbus) 269 int sbus; 270 { 271 register struct sbusdev *sd; 272 struct sbus_softc *sc = sbus_cd.cd_devs[sbus]; 273 struct device *dev; 274 275 printf("reset %s:", sc->sc_dev.dv_xname); 276 for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) { 277 if (sd->sd_reset) { 278 dev = sd->sd_dev; 279 (*sd->sd_reset)(dev); 280 printf(" %s", dev->dv_xname); 281 } 282 } 283 } 284