intio.c revision 1.1.2.2 1 /* $NetBSD: intio.c,v 1.1.2.2 1998/12/27 14:13:04 minoura Exp $ */
2
3 /*
4 *
5 * Copyright (c) 1998 NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor and
19 * Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * NetBSD/x68k internal I/O virtual bus.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/extent.h>
44
45 #include <machine/bus.h>
46 #include <machine/cpu.h>
47 #include <machine/frame.h>
48
49 #include <arch/x68k/dev/intiovar.h>
50 #include <arch/x68k/dev/mfp.h>
51
52
53 /*
54 * bus_space(9) interface
55 */
56 static int intio_bus_space_map __P((bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *));
57 static void intio_bus_space_unmap __P((bus_space_tag_t, bus_space_handle_t, bus_size_t));
58 static int intio_bus_space_subregion __P((bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *));
59
60 static struct x68k_bus_space intio_bus = {
61 #if 0
62 X68K_INTIO_BUS,
63 #endif
64 intio_bus_space_map, intio_bus_space_unmap, intio_bus_space_subregion,
65 x68k_bus_space_alloc, x68k_bus_space_free,
66 #if 0
67 x68k_bus_space_barrier,
68 #endif
69 x68k_bus_space_read_1, x68k_bus_space_read_2, x68k_bus_space_read_4,
70 x68k_bus_space_read_multi_1, x68k_bus_space_read_multi_2,
71 x68k_bus_space_read_multi_4,
72 x68k_bus_space_read_region_1, x68k_bus_space_read_region_2,
73 x68k_bus_space_read_region_4,
74
75 x68k_bus_space_write_1, x68k_bus_space_write_2, x68k_bus_space_write_4,
76 x68k_bus_space_write_multi_1, x68k_bus_space_write_multi_2,
77 x68k_bus_space_write_multi_4,
78 x68k_bus_space_write_region_1, x68k_bus_space_write_region_2,
79 x68k_bus_space_write_region_4,
80
81 x68k_bus_space_set_region_1, x68k_bus_space_set_region_2,
82 x68k_bus_space_set_region_4,
83 x68k_bus_space_copy_region_1, x68k_bus_space_copy_region_2,
84 x68k_bus_space_copy_region_4,
85
86 0
87 };
88
89
90 /*
91 * autoconf stuff
92 */
93 static int intio_match __P((struct device *, struct cfdata *, void *));
94 static void intio_attach __P((struct device *, struct device *, void *));
95 static int intio_search __P((struct device *, struct cfdata *cf, void *));
96 static int intio_print __P((void *, const char *));
97 static void intio_alloc_system_ports __P((struct intio_softc*));
98
99 struct cfattach intio_ca = {
100 sizeof(struct intio_softc), intio_match, intio_attach
101 };
102
103 static struct intio_interrupt_vector {
104 intio_intr_handler_t iiv_handler;
105 void *iiv_arg;
106 } iiv[256] = {0,};
107
108 extern struct cfdriver intio_cd;
109
110 /* used in console initialization */
111 extern int x68k_realconfig;
112 int x68k_config_found __P((struct cfdata *, struct device *,
113 void *, cfprint_t));
114 static struct cfdata *cfdata_intiobus = NULL;
115
116 static int
117 intio_match(parent, cf, aux)
118 struct device *parent;
119 struct cfdata *cf;
120 void *aux; /* NULL */
121 {
122 if (strcmp(aux, intio_cd.cd_name) != 0)
123 return (0);
124 if (cf->cf_unit != 0)
125 return (0);
126 if (x68k_realconfig == 0)
127 cfdata_intiobus = cf; /* XXX */
128
129 return (1);
130 }
131
132
133 /* used in console initialization: configure only MFP */
134 static struct intio_attach_args initial_ia = {
135 &intio_bus,
136 0/*XXX*/,
137
138 "mfp", /* ia_name */
139 MFP_ADDR, /* ia_addr */
140 MFP_INTR, /* ia_intr */
141 -1, /* ia_errintr */
142 -1 /* ia_dma */
143 };
144
145 static void
146 intio_attach(parent, self, aux)
147 struct device *parent, *self;
148 void *aux; /* NULL */
149 {
150 struct intio_softc *sc = (struct intio_softc *)self;
151 struct intio_attach_args ia;
152
153 if (self == NULL) {
154 /* console only init */
155 x68k_config_found(cfdata_intiobus, NULL, &initial_ia, NULL);
156 return;
157 }
158
159 printf (" mapped at 0x%08p\n", intiobase);
160
161 sc->sc_map = extent_create("intiomap",
162 PHYS_INTIODEV,
163 PHYS_INTIODEV + 0x400000,
164 M_DEVBUF, NULL, NULL, EX_NOWAIT);
165 intio_alloc_system_ports (sc);
166
167 sc->sc_bst = &intio_bus;
168 sc->sc_bst->x68k_bus_device = self;
169 #if 0
170 sc->sc_dmat = &intio_dma;
171 #endif
172 bzero(iiv, sizeof (struct intio_interrupt_vector) * 256);
173
174 ia.ia_bst = sc->sc_bst;
175 ia.ia_dmat = sc->sc_dmat;
176
177 config_search (intio_search, self, &ia);
178 }
179
180 static int
181 intio_search(parent, cf, aux)
182 struct device *parent;
183 struct cfdata *cf;
184 void *aux;
185 {
186 struct intio_attach_args *ia = aux;
187 struct intio_softc *sc = (struct intio_softc *)parent;
188
189 ia->ia_bst = sc->sc_bst;
190 ia->ia_dmat = sc->sc_dmat;
191 ia->ia_name = cf->cf_driver->cd_name;
192 ia->ia_addr = cf->cf_addr;
193 ia->ia_intr = cf->cf_intr;
194 ia->ia_errintr = cf->cf_errintr;
195 ia->ia_dma = cf->cf_dma;
196
197 if ((*cf->cf_attach->ca_match)(parent, cf, ia) > 0)
198 config_attach(parent, cf, ia, intio_print);
199
200 return (0);
201 }
202
203 static int
204 intio_print(aux, name)
205 void *aux;
206 const char *name;
207 {
208 struct intio_attach_args *ia = aux;
209
210 /* if (ia->ia_addr > 0) */
211 printf (" addr 0x%06x", ia->ia_addr);
212 if (ia->ia_intr > 0) {
213 printf (" interrupting at 0x%02x", ia->ia_intr);
214 if (ia->ia_errintr > 0)
215 printf (" and 0x%02x", ia->ia_errintr);
216 }
217 if (ia->ia_dma >= 0)
218 printf (" using DMA ch%d", ia->ia_dma);
219
220 return (QUIET);
221 }
222
223 /*
224 * intio memory map manager
225 */
226
227 int
228 intio_map_allocate_region(parent, ia, flag)
229 struct device *parent;
230 struct intio_attach_args *ia;
231 enum intio_map_flag flag; /* INTIO_MAP_TESTONLY or INTIO_MAP_ALLOCATE */
232 {
233 struct intio_softc *sc = (struct intio_softc*) parent;
234 struct extent *map = sc->sc_map;
235 int r;
236
237 r = extent_alloc_region (map, ia->ia_addr, ia->ia_size, 0);
238 #ifdef DEBUG
239 extent_print (map);
240 #endif
241 if (r == 0) {
242 if (flag != INTIO_MAP_ALLOCATE)
243 extent_free (map, ia->ia_addr, ia->ia_size, 0);
244 return 0;
245 }
246
247 return -1;
248 }
249
250 int
251 intio_map_free_region(parent, ia)
252 struct device *parent;
253 struct intio_attach_args *ia;
254 {
255 struct intio_softc *sc = (struct intio_softc*) parent;
256 struct extent *map = sc->sc_map;
257
258 extent_free (map, ia->ia_addr, ia->ia_size, 0);
259 #ifdef DEBUG
260 extent_print (map);
261 #endif
262 return 0;
263 }
264
265 void
266 intio_alloc_system_ports(sc)
267 struct intio_softc *sc;
268 {
269 extent_alloc_region (sc->sc_map, INTIO_SYSPORT, 16, 0);
270 }
271
272
273 /*
274 * intio bus space stuff.
275 */
276 static int
277 intio_bus_space_map(t, bpa, size, flags, bshp)
278 bus_space_tag_t t;
279 bus_addr_t bpa;
280 bus_size_t size;
281 int flags;
282 bus_space_handle_t *bshp;
283 {
284 /*
285 * Intio bus is mapped permanently.
286 */
287 *bshp = (bus_space_handle_t)
288 ((u_int) bpa - PHYS_INTIODEV + intiobase);
289
290 return (0);
291 }
292
293 static void
294 intio_bus_space_unmap(t, bsh, size)
295 bus_space_tag_t t;
296 bus_space_handle_t bsh;
297 bus_size_t size;
298 {
299 return;
300 }
301
302 static int
303 intio_bus_space_subregion(t, bsh, offset, size, nbshp)
304 bus_space_tag_t t;
305 bus_space_handle_t bsh;
306 bus_size_t offset, size;
307 bus_space_handle_t *nbshp;
308 {
309
310 *nbshp = bsh + offset;
311 return (0);
312 }
313
314
315 /*
316 * interrupt handler
317 */
318 int
319 intio_intr_establish (vector, name, handler, arg)
320 int vector;
321 const char *name; /* XXX */
322 intio_intr_handler_t handler;
323 void *arg;
324 {
325 if (vector < 16)
326 panic ("Invalid interrupt vector");
327 if (iiv[vector].iiv_handler)
328 return EBUSY;
329 iiv[vector].iiv_handler = handler;
330 iiv[vector].iiv_arg = arg;
331
332 return 0;
333 }
334
335 int
336 intio_intr_disestablish (vector, arg)
337 int vector;
338 void *arg;
339 {
340 if (iiv[vector].iiv_handler == 0 || iiv[vector].iiv_arg != arg)
341 return EINVAL;
342 iiv[vector].iiv_handler = 0;
343 iiv[vector].iiv_arg = 0;
344
345 return 0;
346 }
347
348 int
349 intio_intr (frame)
350 struct frame *frame;
351 {
352 int vector = frame->f_vector / 4;
353
354 /* CAUTION: HERE WE ARE IN SPLHIGH() */
355 /* LOWER TO APPROPRIATE IPL AT VERY FIRST IN THE HANDLER!! */
356
357 if (iiv[vector].iiv_handler == 0) {
358 printf ("Stray interrupt: %d type %x\n", vector, frame->f_format);
359 return 0;
360 }
361
362 return (*(iiv[vector].iiv_handler)) (iiv[vector].iiv_arg);
363 }
364