dio.c revision 1.12 1 /* $NetBSD: dio.c,v 1.12 1998/01/12 18:30:49 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1996, 1997, 1998 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 int
77 diomatch(parent, match, aux)
78 struct device *parent;
79 struct cfdata *match;
80 void *aux;
81 {
82 static int dio_matched = 0;
83
84 /* Allow only one instance. */
85 if (dio_matched)
86 return (0);
87
88 dio_matched = 1;
89 return (1);
90 }
91
92 void
93 dioattach(parent, self, aux)
94 struct device *parent, *self;
95 void *aux;
96 {
97 struct dio_attach_args da;
98 caddr_t pa, va;
99 int scode, scmax, didmap, scodesize;
100
101 scmax = DIO_SCMAX(machineid);
102 printf(": ");
103 dmainit();
104
105 for (scode = 0; scode < scmax; ) {
106 if (DIO_INHOLE(scode)) {
107 scode++;
108 continue;
109 }
110
111 didmap = 0;
112
113 /*
114 * Temporarily map the space corresponding to
115 * the current select code unless:
116 * - this is the internal hpib select code,
117 * - this is the console select code.
118 */
119 pa = dio_scodetopa(scode);
120 if (scode == conscode)
121 va = conaddr;
122 else if ((scode == 7) && internalhpib)
123 va = internalhpib = (caddr_t)IIOV(pa);
124 else {
125 va = iomap(pa, NBPG);
126 if (va == NULL) {
127 printf("%s: can't map scode %d\n",
128 self->dv_xname, scode);
129 scode++;
130 continue;
131 }
132 didmap = 1;
133 }
134
135 /* Check for hardware. */
136 if (badaddr(va)) {
137 if (didmap)
138 iounmap(va, NBPG);
139 scode++;
140 continue;
141 }
142
143 /* Fill out attach args. */
144 bzero(&da, sizeof(da));
145 da.da_bst = HP300_BUS_SPACE_DIO;
146 da.da_scode = scode;
147 da.da_id = DIO_ID(va);
148
149 if (DIO_ISFRAMEBUFFER(da.da_id))
150 da.da_secid = DIO_SECID(va);
151
152 da.da_size = DIO_SIZE(scode, va);
153 scodesize = dio_scodesize(&da);
154 if (DIO_ISDIO(scode))
155 da.da_size *= scodesize;
156
157 /* No longer need the device to be mapped. */
158 if (didmap)
159 iounmap(va, NBPG);
160
161 /* Attach matching device. */
162 config_found_sm(self, &da, dioprint, diosubmatch);
163 scode += scodesize;
164 }
165 }
166
167 int
168 diosubmatch(parent, cf, aux)
169 struct device *parent;
170 struct cfdata *cf;
171 void *aux;
172 {
173 struct dio_attach_args *da = aux;
174
175 if (cf->diocf_scode != DIOCF_SCODE_DEFAULT &&
176 cf->diocf_scode != da->da_scode)
177 return (0);
178
179 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
180 }
181
182 int
183 dioprint(aux, pnp)
184 void *aux;
185 const char *pnp;
186 {
187 struct dio_attach_args *da = aux;
188 char buf[128];
189
190 if (pnp)
191 printf("%s at %s", dio_devinfo(da, buf, sizeof(buf)), pnp);
192 printf(" scode %d", da->da_scode);
193 return (UNCONF);
194 }
195
196 /*
197 * Convert a select code to a system physical address.
198 */
199 void *
200 dio_scodetopa(scode)
201 int scode;
202 {
203 u_long rval;
204
205 if (scode == 7 && internalhpib)
206 rval = DIO_IHPIBADDR;
207 else if (DIO_ISDIO(scode))
208 rval = DIO_BASE + (scode * DIO_DEVSIZE);
209 else if (DIO_ISDIOII(scode))
210 rval = DIOII_BASE + ((scode - DIOII_SCBASE) * DIOII_DEVSIZE);
211 else
212 rval = 0;
213
214 return ((void *)rval);
215 }
216
217 /*
218 * Return the select code size for this device, defaulting to 1
219 * if we don't know what kind of device we have.
220 */
221 int
222 dio_scodesize(da)
223 struct dio_attach_args *da;
224 {
225 int i;
226
227 /*
228 * Deal with lame internal HP-IB controllers which don't have
229 * consistent/reliable device ids.
230 */
231 if (da->da_scode == 7 && internalhpib)
232 return (1);
233
234 /*
235 * Find the dio_devdata matchind the primary id.
236 * If we're a framebuffer, we also check the secondary id.
237 */
238 for (i = 0; i < DIO_NDEVICES; i++) {
239 if (da->da_id == dio_devdatas[i].dd_id) {
240 if (DIO_ISFRAMEBUFFER(da->da_id)) {
241 if (da->da_secid == dio_devdatas[i].dd_secid) {
242 goto foundit;
243 }
244 } else {
245 foundit:
246 return (dio_devdatas[i].dd_nscode);
247 }
248 }
249 }
250
251 /*
252 * Device is unknown. Print a warning and assume a default.
253 */
254 printf("WARNING: select code size unknown for id = 0x%x secid = 0x%x\n",
255 da->da_id, da->da_secid);
256 return (1);
257 }
258
259 /*
260 * Return a reasonable description of a DIO device.
261 */
262 char *
263 dio_devinfo(da, buf, buflen)
264 struct dio_attach_args *da;
265 char *buf;
266 size_t buflen;
267 {
268 #ifdef DIOVERBOSE
269 int i;
270 #endif
271
272 bzero(buf, buflen);
273
274 /*
275 * Deal with lame internal HP-IB controllers which don't have
276 * consistent/reliable device ids.
277 */
278 if (da->da_scode == 7 && internalhpib) {
279 sprintf(buf, DIO_DEVICE_DESC_IHPIB);
280 return (buf);
281 }
282
283 #ifdef DIOVERBOSE
284 /*
285 * Find the description matching our primary id.
286 * If we're a framebuffer, we also check the secondary id.
287 */
288 for (i = 0; i < DIO_NDEVICES; i++) {
289 if (da->da_id == dio_devdescs[i].dd_id) {
290 if (DIO_ISFRAMEBUFFER(da->da_id)) {
291 if (da->da_secid == dio_devdescs[i].dd_secid) {
292 goto foundit;
293 }
294 } else {
295 foundit:
296 sprintf(buf, "%s", dio_devdescs[i].dd_desc);
297 return (buf);
298 }
299 }
300 }
301 #endif /* DIOVERBOSE */
302
303 /*
304 * Device is unknown. Construct something reasonable.
305 */
306 sprintf(buf, "device id = 0x%x secid = 0x%x",
307 da->da_id, da->da_secid);
308 return (buf);
309 }
310
311 /*
312 * Establish an interrupt handler for a DIO device.
313 */
314 void *
315 dio_intr_establish(func, arg, ipl, priority)
316 int (*func) __P((void *));
317 void *arg;
318 int ipl;
319 int priority;
320 {
321 void *ih;
322
323 ih = intr_establish(func, arg, ipl, priority);
324
325 if (priority == IPL_BIO)
326 dmacomputeipl();
327
328 return (ih);
329 }
330
331 /*
332 * Remove an interrupt handler for a DIO device.
333 */
334 void
335 dio_intr_disestablish(arg)
336 void *arg;
337 {
338 struct isr *isr = arg;
339 int priority = isr->isr_priority;
340
341 intr_disestablish(arg);
342
343 if (priority == IPL_BIO)
344 dmacomputeipl();
345 }
346