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