intio.c revision 1.1.2.1 1 /* $NetBSD: intio.c,v 1.1.2.1 1998/12/23 16:47:29 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_ADDR, /* ia_addr */
139 MFP_INTR, /* ia_intr */
140 -1, /* ia_errintr */
141 -1 /* ia_dma */
142 };
143
144 static void
145 intio_attach(parent, self, aux)
146 struct device *parent, *self;
147 void *aux; /* NULL */
148 {
149 struct intio_softc *sc = (struct intio_softc *)self;
150 struct intio_attach_args ia;
151
152 if (self == NULL) {
153 /* console only init */
154 x68k_config_found(cfdata_intiobus, NULL, &initial_ia, NULL);
155 return;
156 }
157
158 printf (" mapped at 0x%08p\n", intiobase);
159
160 sc->sc_map = extent_create("intiomap",
161 PHYS_INTIODEV,
162 PHYS_INTIODEV + 0x400000,
163 M_DEVBUF, NULL, NULL, EX_NOWAIT);
164 intio_alloc_system_ports (sc);
165
166 sc->sc_bst = &intio_bus;
167 sc->sc_bst->x68k_bus_device = self;
168 #if 0
169 sc->sc_dmat = &intio_dma;
170 #endif
171 bzero(iiv, sizeof (struct intio_interrupt_vector) * 256);
172
173 ia.ia_bst = sc->sc_bst;
174 ia.ia_dmat = sc->sc_dmat;
175
176 config_search (intio_search, self, &ia);
177 }
178
179 static int
180 intio_search(parent, cf, aux)
181 struct device *parent;
182 struct cfdata *cf;
183 void *aux;
184 {
185 struct intio_attach_args *ia = aux;
186 struct intio_softc *sc = (struct intio_softc *)parent;
187
188 ia->ia_bst = sc->sc_bst;
189 ia->ia_dmat = sc->sc_dmat;
190 ia->ia_addr = cf->cf_addr;
191 ia->ia_intr = cf->cf_intr;
192 ia->ia_errintr = cf->cf_errintr;
193 ia->ia_dma = cf->cf_dma;
194
195 if ((*cf->cf_attach->ca_match)(parent, cf, ia) > 0)
196 config_attach(parent, cf, ia, intio_print);
197
198 return (0);
199 }
200
201 static int
202 intio_print(aux, name)
203 void *aux;
204 const char *name;
205 {
206 struct intio_attach_args *ia = aux;
207
208 /* if (ia->ia_addr > 0) */
209 printf (" addr 0x%06x", ia->ia_addr);
210 if (ia->ia_intr > 0) {
211 printf (" interrupting at 0x%02x", ia->ia_intr);
212 if (ia->ia_errintr > 0)
213 printf (" and 0x%02x", ia->ia_errintr);
214 }
215 if (ia->ia_dma >= 0)
216 printf (" using DMA ch%d", ia->ia_dma);
217
218 return (QUIET);
219 }
220
221 /*
222 * intio memory map manager
223 */
224
225 int
226 intio_map_allocate_region(parent, ia, flag)
227 struct device *parent;
228 struct intio_attach_args *ia;
229 enum intio_map_flag flag; /* INTIO_MAP_TESTONLY or INTIO_MAP_ALLOCATE */
230 {
231 struct intio_softc *sc = (struct intio_softc*) parent;
232 struct extent *map = sc->sc_map;
233 int r;
234
235 r = extent_alloc_region (map, ia->ia_addr, ia->ia_size, 0);
236 #ifdef DEBUG
237 extent_print (map);
238 #endif
239 if (r == 0) {
240 if (flag != INTIO_MAP_ALLOCATE)
241 extent_free (map, ia->ia_addr, ia->ia_size, 0);
242 return 0;
243 }
244
245 return -1;
246 }
247
248 int
249 intio_map_free_region(parent, ia)
250 struct device *parent;
251 struct intio_attach_args *ia;
252 {
253 struct intio_softc *sc = (struct intio_softc*) parent;
254 struct extent *map = sc->sc_map;
255
256 extent_free (map, ia->ia_addr, ia->ia_size, 0);
257 #ifdef DEBUG
258 extent_print (map);
259 #endif
260 return 0;
261 }
262
263 void
264 intio_alloc_system_ports(sc)
265 struct intio_softc *sc;
266 {
267 extent_alloc_region (sc->sc_map, INTIO_SYSPORT, 16, 0);
268 }
269
270
271 /*
272 * intio bus space stuff.
273 */
274 static int
275 intio_bus_space_map(t, bpa, size, flags, bshp)
276 bus_space_tag_t t;
277 bus_addr_t bpa;
278 bus_size_t size;
279 int flags;
280 bus_space_handle_t *bshp;
281 {
282 /*
283 * Intio bus is mapped permanently.
284 */
285 *bshp = (bus_space_handle_t)
286 ((u_int) bpa - PHYS_INTIODEV + intiobase);
287
288 return (0);
289 }
290
291 static void
292 intio_bus_space_unmap(t, bsh, size)
293 bus_space_tag_t t;
294 bus_space_handle_t bsh;
295 bus_size_t size;
296 {
297 return;
298 }
299
300 static int
301 intio_bus_space_subregion(t, bsh, offset, size, nbshp)
302 bus_space_tag_t t;
303 bus_space_handle_t bsh;
304 bus_size_t offset, size;
305 bus_space_handle_t *nbshp;
306 {
307
308 *nbshp = bsh + offset;
309 return (0);
310 }
311
312
313 /*
314 * interrupt handler
315 */
316 int
317 intio_intr_establish (vector, name, handler, arg)
318 int vector;
319 const char *name; /* XXX */
320 intio_intr_handler_t handler;
321 void *arg;
322 {
323 if (vector < 16)
324 panic ("Invalid interrupt vector");
325 if (iiv[vector].iiv_handler)
326 return EBUSY;
327 iiv[vector].iiv_handler = handler;
328 iiv[vector].iiv_arg = arg;
329
330 return 0;
331 }
332
333 int
334 intio_intr_disestablish (vector, arg)
335 int vector;
336 void *arg;
337 {
338 if (iiv[vector].iiv_handler == 0 || iiv[vector].iiv_arg != arg)
339 return EINVAL;
340 iiv[vector].iiv_handler = 0;
341 iiv[vector].iiv_arg = 0;
342
343 return 0;
344 }
345
346 int
347 intio_intr (frame)
348 struct frame *frame;
349 {
350 int vector = frame->f_vector / 4;
351
352 /* CAUTION: HERE WE ARE IN SPLHIGH() */
353 /* LOWER TO APPROPRIATE IPL AT VERY FIRST IN THE HANDLER!! */
354
355 if (iiv[vector].iiv_handler == 0) {
356 printf ("Stray interrupt: %d type %x\n", vector, frame->f_format);
357 return 0;
358 }
359
360 return (*(iiv[vector].iiv_handler)) (iiv[vector].iiv_arg);
361 }
362