sbus.c revision 1.17 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