xref: /netbsd-src/sys/arch/hp300/dev/dio.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: dio.c,v 1.10 1997/10/09 09:06:49 jtc Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Autoconfiguration and mapping support for the DIO bus.
41  */
42 
43 #define	_HP300_INTR_H_PRIVATE
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/device.h>
49 
50 #include <machine/autoconf.h>
51 #include <machine/cpu.h>
52 #include <machine/hp300spu.h>
53 
54 #include <hp300/dev/dmavar.h>
55 
56 #include <hp300/dev/dioreg.h>
57 #include <hp300/dev/diovar.h>
58 
59 #include <hp300/dev/diodevs.h>
60 #include <hp300/dev/diodevs_data.h>
61 
62 extern	caddr_t internalhpib;
63 
64 int	dio_scodesize __P((struct dio_attach_args *));
65 char	*dio_devinfo __P((struct dio_attach_args *, char *, size_t));
66 
67 int	diomatch __P((struct device *, struct cfdata *, void *));
68 void	dioattach __P((struct device *, struct device *, void *));
69 int	dioprint __P((void *, const char *));
70 int	diosubmatch __P((struct device *, struct cfdata *, void *));
71 
72 struct cfattach dio_ca = {
73 	sizeof(struct device), diomatch, dioattach
74 };
75 
76 struct cfdriver dio_cd = {
77 	NULL, "dio", DV_DULL
78 };
79 
80 int
81 diomatch(parent, match, aux)
82 	struct device *parent;
83 	struct cfdata *match;
84 	void *aux;
85 {
86 	static int dio_matched = 0;
87 
88 	/* Allow only one instance. */
89 	if (dio_matched)
90 		return (0);
91 
92 	dio_matched = 1;
93 	return (1);
94 }
95 
96 void
97 dioattach(parent, self, aux)
98 	struct device *parent, *self;
99 	void *aux;
100 {
101 	struct dio_attach_args da;
102 	caddr_t pa, va;
103 	int scode, scmax, didmap, scodesize;
104 
105 	scmax = DIO_SCMAX(machineid);
106 	printf(": ");
107 	dmainit();
108 
109 	for (scode = 0; scode < scmax; ) {
110 		if (DIO_INHOLE(scode)) {
111 			scode++;
112 			continue;
113 		}
114 
115 		didmap = 0;
116 
117 		/*
118 		 * Temporarily map the space corresponding to
119 		 * the current select code unless:
120 		 *	- this is the internal hpib select code,
121 		 *	- this is the console select code.
122 		 */
123 		pa = dio_scodetopa(scode);
124 		if (scode == conscode)
125 			va = conaddr;
126 		else if ((scode == 7) && internalhpib)
127 			va = internalhpib = (caddr_t)IIOV(pa);
128 		else {
129 			va = iomap(pa, NBPG);
130 			if (va == NULL) {
131 				printf("%s: can't map scode %d\n",
132 				    self->dv_xname, scode);
133 				scode++;
134 				continue;
135 			}
136 			didmap = 1;
137 		}
138 
139 		/* Check for hardware. */
140 		if (badaddr(va)) {
141 			if (didmap)
142 				iounmap(va, NBPG);
143 			scode++;
144 			continue;
145 		}
146 
147 		/* Fill out attach args. */
148 		bzero(&da, sizeof(da));
149 		da.da_scode = scode;
150 		da.da_id = DIO_ID(va);
151 
152 		if (DIO_ISFRAMEBUFFER(da.da_id))
153 			da.da_secid = DIO_SECID(va);
154 
155 		da.da_size = DIO_SIZE(scode, va);
156 		scodesize = dio_scodesize(&da);
157 		if (DIO_ISDIO(scode))
158 			da.da_size *= scodesize;
159 
160 		/* No longer need the device to be mapped. */
161 		if (didmap)
162 			iounmap(va, NBPG);
163 
164 		/* Attach matching device. */
165 		config_found_sm(self, &da, dioprint, diosubmatch);
166 		scode += scodesize;
167 	}
168 }
169 
170 int
171 diosubmatch(parent, cf, aux)
172 	struct device *parent;
173 	struct cfdata *cf;
174 	void *aux;
175 {
176 	struct dio_attach_args *da = aux;
177 
178 	if (cf->diocf_scode != DIOCF_SCODE_DEFAULT &&
179 	    cf->diocf_scode != da->da_scode)
180 		return (0);
181 
182 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
183 }
184 
185 int
186 dioprint(aux, pnp)
187 	void *aux;
188 	const char *pnp;
189 {
190 	struct dio_attach_args *da = aux;
191 	char buf[128];
192 
193 	if (pnp)
194 		printf("%s at %s", dio_devinfo(da, buf, sizeof(buf)), pnp);
195 	printf(" scode %d", da->da_scode);
196 	return (UNCONF);
197 }
198 
199 /*
200  * Convert a select code to a system physical address.
201  */
202 void *
203 dio_scodetopa(scode)
204 	int scode;
205 {
206 	u_long rval;
207 
208 	if (scode == 7 && internalhpib)
209 		rval = DIO_IHPIBADDR;
210 	else if (DIO_ISDIO(scode))
211 		rval = DIO_BASE + (scode * DIO_DEVSIZE);
212 	else if (DIO_ISDIOII(scode))
213 		rval = DIOII_BASE + ((scode - DIOII_SCBASE) * DIOII_DEVSIZE);
214 	else
215 		rval = 0;
216 
217 	return ((void *)rval);
218 }
219 
220 /*
221  * Return the select code size for this device, defaulting to 1
222  * if we don't know what kind of device we have.
223  */
224 int
225 dio_scodesize(da)
226 	struct dio_attach_args *da;
227 {
228 	int i;
229 
230 	/*
231 	 * Deal with lame internal HP-IB controllers which don't have
232 	 * consistent/reliable device ids.
233 	 */
234 	if (da->da_scode == 7 && internalhpib)
235 		return (1);
236 
237 	/*
238 	 * Find the dio_devdata matchind the primary id.
239 	 * If we're a framebuffer, we also check the secondary id.
240 	 */
241 	for (i = 0; i < DIO_NDEVICES; i++) {
242 		if (da->da_id == dio_devdatas[i].dd_id) {
243 			if (DIO_ISFRAMEBUFFER(da->da_id)) {
244 				if (da->da_secid == dio_devdatas[i].dd_secid) {
245 					goto foundit;
246 				}
247 			} else {
248 			foundit:
249 				return (dio_devdatas[i].dd_nscode);
250 			}
251 		}
252 	}
253 
254 	/*
255 	 * Device is unknown.  Print a warning and assume a default.
256 	 */
257 	printf("WARNING: select code size unknown for id = 0x%x secid = 0x%x\n",
258 	    da->da_id, da->da_secid);
259 	return (1);
260 }
261 
262 /*
263  * Return a reasonable description of a DIO device.
264  */
265 char *
266 dio_devinfo(da, buf, buflen)
267 	struct dio_attach_args *da;
268 	char *buf;
269 	size_t buflen;
270 {
271 #ifdef DIOVERBOSE
272 	int i;
273 #endif
274 
275 	bzero(buf, buflen);
276 
277 	/*
278 	 * Deal with lame internal HP-IB controllers which don't have
279 	 * consistent/reliable device ids.
280 	 */
281 	if (da->da_scode == 7 && internalhpib) {
282 		sprintf(buf, DIO_DEVICE_DESC_IHPIB);
283 		return (buf);
284 	}
285 
286 #ifdef DIOVERBOSE
287 	/*
288 	 * Find the description matching our primary id.
289 	 * If we're a framebuffer, we also check the secondary id.
290 	 */
291 	for (i = 0; i < DIO_NDEVICES; i++) {
292 		if (da->da_id == dio_devdescs[i].dd_id) {
293 			if (DIO_ISFRAMEBUFFER(da->da_id)) {
294 				if (da->da_secid == dio_devdescs[i].dd_secid) {
295 					goto foundit;
296 				}
297 			} else {
298 			foundit:
299 				sprintf(buf, "%s", dio_devdescs[i].dd_desc);
300 				return (buf);
301 			}
302 		}
303 	}
304 #endif /* DIOVERBOSE */
305 
306 	/*
307 	 * Device is unknown.  Construct something reasonable.
308 	 */
309 	sprintf(buf, "device id = 0x%x secid = 0x%x",
310 	    da->da_id, da->da_secid);
311 	return (buf);
312 }
313 
314 /*
315  * Establish an interrupt handler for a DIO device.
316  */
317 void *
318 dio_intr_establish(func, arg, ipl, priority)
319 	int (*func) __P((void *));
320 	void *arg;
321 	int ipl;
322 	int priority;
323 {
324 	void *ih;
325 
326 	ih = intr_establish(func, arg, ipl, priority);
327 
328 	if (priority == IPL_BIO)
329 		dmacomputeipl();
330 
331 	return (ih);
332 }
333 
334 /*
335  * Remove an interrupt handler for a DIO device.
336  */
337 void
338 dio_intr_disestablish(arg)
339 	void *arg;
340 {
341 	struct isr *isr = arg;
342 	int priority = isr->isr_priority;
343 
344 	intr_disestablish(arg);
345 
346 	if (priority == IPL_BIO)
347 		dmacomputeipl();
348 }
349