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