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