maple.c revision 1.1 1 /* $NetBSD: maple.c,v 1.1 2001/01/16 00:32:42 marcus Exp $ */
2
3 /*
4 * Copyright (c) 2001 Marcus Comstedt
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Bradley A. Grantham.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34 #include <sys/param.h>
35 #include <sys/device.h>
36 #include <sys/fcntl.h>
37 #include <sys/poll.h>
38 #include <sys/select.h>
39 #include <sys/proc.h>
40 #include <sys/signalvar.h>
41 #include <sys/systm.h>
42
43 #include <uvm/uvm_extern.h>
44
45 #include <machine/cpu.h>
46 #include <machine/bus.h>
47 #include <sh3/shbvar.h>
48 #include <sh3/pmap.h>
49
50
51 #include <dreamcast/dev/maple/maple.h>
52 #include <dreamcast/dev/maple/mapleconf.h>
53 #include <dreamcast/dev/maple/maplevar.h>
54 #include <dreamcast/dev/maple/maplereg.h>
55
56
57 #define MAPLE_CALLOUT_TICKS 1
58
59 /*
60 * Function declarations.
61 */
62 static int maplematch __P((struct device *, struct cfdata *, void *));
63 static void mapleattach __P((struct device *, struct device *, void *));
64 static int mapleprint __P((void *, const char *));
65 static void maple_attach_dev __P((struct maple_softc *, int, int));
66 static void maple_begin_txbuf __P((struct maple_softc *));
67 static int maple_end_txbuf __P((struct maple_softc *));
68 static void maple_write_command __P((struct maple_softc *, int, int,
69 int, int, void *));
70 static void maple_scanbus __P((struct maple_softc *));
71 static void maple_callout __P((void *));
72 static void maple_send_commands __P((struct maple_softc *));
73 static void maple_check_responses __P((struct maple_softc *));
74
75
76 /*
77 * Global variables.
78 */
79 int maple_polling = 0; /* Are we polling? (Debugger mode) */
80
81 /*
82 * Driver definition.
83 */
84 struct cfattach maple_ca = {
85 sizeof(struct maple_softc), maplematch, mapleattach
86 };
87
88 int maplesearch __P((struct device *, struct cfdata *, void *));
89
90 static int
91 maplematch(parent, cf, aux)
92 struct device *parent;
93 struct cfdata *cf;
94 void *aux;
95 {
96 struct shb_attach_args *sa = aux;
97
98 if (strcmp("maple", cf->cf_driver->cd_name))
99 return (0);
100
101 sa->ia_iosize = 0 /* 0x100 */;
102 return (1);
103 }
104
105
106 static void
107 maple_attach_dev(sc, port, subunit)
108 struct maple_softc *sc;
109 int port;
110 int subunit;
111 {
112 struct maple_attach_args ma;
113 ma.ma_port = port;
114 ma.ma_subunit = subunit;
115 ma.ma_devinfo = &sc->sc_unit[port][subunit].devinfo;
116 config_search(maplesearch, &sc->sc_dev, &ma);
117 }
118
119 static void
120 maple_begin_txbuf(sc)
121 struct maple_softc *sc;
122 {
123 sc->sc_txlink = sc->sc_txpos = sc->sc_txbuf;
124 }
125
126 static int
127 maple_end_txbuf(sc)
128 struct maple_softc *sc;
129 {
130 /* if no frame have been written, we can't mark the
131 list end, and so the DMA must not be activated */
132 if (sc->sc_txpos == sc->sc_txbuf)
133 return (0);
134
135 *sc->sc_txlink |= 0x80000000;
136
137 return (1);
138 }
139
140 static int8_t subunit_code[] = { 0x20, 0x01, 0x02, 0x04, 0x08, 0x10 };
141
142 static void
143 maple_write_command(sc, port, subunit, command, datalen, dataaddr)
144 struct maple_softc *sc;
145 int port;
146 int subunit;
147 int command;
148 int datalen;
149 void *dataaddr;
150 {
151 int to, from;
152 u_int32_t *p = sc->sc_txpos;
153
154 if ((port & ~(MAPLE_PORTS-1)) != 0 ||
155 subunit < 0 || subunit >= MAPLE_SUBUNITS)
156 return;
157
158 /* Compute sender and recipient address */
159 from = port << 6;
160 to = from | subunit_code[subunit];
161
162 /* Max data length = 255 longs = 1020 bytes */
163 if(datalen > 255)
164 datalen = 255;
165 else if(datalen < 0)
166 datalen = 0;
167
168 sc->sc_txlink = p;
169
170 /* Set length of packet and destination port (A-D) */
171 *p++ = datalen | (port << 16);
172
173 /* Write address to receive buffer where the response
174 frame should be put */
175 *p++ = sc->sc_rxbuf_phys[port][subunit];
176
177 /* Create the frame header. The fields are assembled "backwards"
178 because of the Maple Bus big-endianness. */
179 *p++ = (command & 0xff) | (to << 8) | (from << 16) | (datalen << 24);
180
181 /* Copy parameter data, if any */
182 if (datalen > 0) {
183 u_int32_t *param = dataaddr;
184 int i;
185 for (i = 0; i < datalen; i++)
186 *p++ = *param++;
187 }
188
189 sc->sc_txpos = p;
190 }
191
192 static void
193 maple_scanbus(sc)
194 struct maple_softc *sc;
195 {
196 int p;
197
198 maple_polling = 1;
199
200 maple_begin_txbuf(sc);
201
202 for (p = 0; p < MAPLE_PORTS; p++) {
203 maple_write_command(sc, p, 0, MAPLE_COMMAND_DEVINFO, 0, NULL);
204 }
205
206 if (maple_end_txbuf(sc)) {
207
208 MAPLE_DMAADDR = sc->sc_txbuf_phys;
209 MAPLE_STATE = 1;
210 while (MAPLE_STATE != 0)
211 ;
212
213 for (p = 0; p < MAPLE_PORTS; p++)
214 if ((sc->sc_rxbuf[p][0][0] & 0xff) == MAPLE_RESPONSE_DEVINFO) {
215
216 u_int32_t *to_swap;
217 int i;
218
219 bcopy(sc->sc_rxbuf[p][0]+1,
220 (to_swap = &sc->sc_unit[p][0].devinfo.di_func),
221 sizeof(struct maple_devinfo));
222
223 for (i = 0; i < 4; i++, to_swap++)
224 *to_swap = ntohl(*to_swap);
225
226 maple_attach_dev(sc, p, 0);
227 }
228
229 }
230
231 maple_polling = 0;
232
233 }
234
235 static void
236 maple_send_commands(sc)
237 struct maple_softc *sc;
238 {
239 int p;
240
241 if (sc->maple_commands_pending || MAPLE_STATE != 0)
242 return;
243
244 maple_begin_txbuf(sc);
245
246 for (p = 0; p < MAPLE_PORTS; p++) {
247
248 if (sc->sc_unit[p][0].getcond_callback != NULL) {
249
250 u_int32_t func = ntohl(sc->sc_unit[p][0].getcond_func);
251
252 maple_write_command(sc, p, 0, MAPLE_COMMAND_GETCOND, 1, &func);
253
254 }
255
256 }
257
258 if (!maple_end_txbuf(sc))
259 return;
260
261 MAPLE_DMAADDR = sc->sc_txbuf_phys;
262 MAPLE_STATE = 1;
263
264 sc->maple_commands_pending = 1;
265 }
266
267 static void
268 maple_check_responses(sc)
269 struct maple_softc *sc;
270 {
271 int p;
272
273 if (!sc->maple_commands_pending || MAPLE_STATE != 0)
274 return;
275
276 for (p = 0; p < MAPLE_PORTS; p++) {
277 struct maple_unit * u = &sc->sc_unit[p][0];
278 if (u->getcond_callback != NULL &&
279 (sc->sc_rxbuf[p][0][0] & 0xff) == MAPLE_RESPONSE_DATATRF &&
280 (sc->sc_rxbuf[p][0][0]>>24) >= 1 &&
281 htonl(sc->sc_rxbuf[p][0][1]) == u->getcond_func) {
282 (*u->getcond_callback)(u->getcond_data,
283 (void *)(sc->sc_rxbuf[p][0]+2),
284 ((sc->sc_rxbuf[p][0][0]>>22)&1020)-4);
285 }
286 }
287
288 sc->maple_commands_pending = 0;
289 }
290
291 void
292 maple_run_polling(dev)
293 struct device *dev;
294 {
295 struct maple_softc *sc;
296
297 sc = (struct maple_softc *)dev;
298
299 if (MAPLE_STATE != 0)
300 return;
301
302 maple_send_commands(sc);
303
304 while (MAPLE_STATE != 0)
305 ;
306
307 maple_check_responses(sc);
308 }
309
310 void
311 maple_set_condition_callback(dev, port, subunit, func, callback, data)
312 struct device *dev;
313 int port;
314 int subunit;
315 u_int32_t func;
316 void (*callback)(void *, void *, int);
317 void *data;
318 {
319 struct maple_softc *sc;
320
321 sc = (struct maple_softc *)dev;
322
323 if ((port & ~(MAPLE_PORTS-1)) != 0 ||
324 subunit < 0 || subunit >= MAPLE_SUBUNITS)
325 return;
326
327 sc->sc_unit[port][subunit].getcond_func = func;
328 sc->sc_unit[port][subunit].getcond_callback = callback;
329 sc->sc_unit[port][subunit].getcond_data = data;
330 }
331
332 static void
333 maple_callout(ctx)
334 void *ctx;
335 {
336 struct maple_softc *sc = ctx;
337
338 if(!maple_polling) {
339
340 maple_check_responses(sc);
341
342 maple_send_commands(sc);
343
344 }
345
346 callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
347 (void *)maple_callout, sc);
348 }
349
350 static void
351 mapleattach(parent, self, aux)
352 struct device *parent, *self;
353 void *aux;
354 {
355 struct maple_softc *sc;
356 vaddr_t dmabuffer;
357 u_int32_t *p;
358 int i, j;
359
360 sc = (struct maple_softc *)self;
361
362 printf("\n");
363
364 dmabuffer = uvm_km_alloc(phys_map, MAPLE_DMABUF_SIZE);
365
366 p = (u_int32_t *) vtophys(dmabuffer);
367
368 for (i = 0; i < MAPLE_PORTS; i++)
369 for (j = 0; j < MAPLE_SUBUNITS; j++) {
370
371 sc->sc_rxbuf[i][j] = p;
372 sc->sc_rxbuf_phys[i][j] = SH3_P2SEG_TO_PHYS(p);
373 p += 256;
374
375 }
376
377 sc->sc_txbuf = p;
378 sc->sc_txbuf_phys = SH3_P2SEG_TO_PHYS(p);
379
380 sc->maple_commands_pending = 0;
381
382 MAPLE_RESET = RESET_MAGIC;
383 MAPLE_RESET2 = 0;
384
385 MAPLE_SPEED = SPEED_2MBPS | TIMEOUT(50000);
386
387 MAPLE_ENABLE = 1;
388
389 maple_scanbus(sc);
390
391 bzero(&sc->maple_callout_ch, sizeof(sc->maple_callout_ch));
392
393 callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
394 (void *)maple_callout, sc);
395 }
396
397 int
398 mapleprint(aux, pnp)
399 void *aux;
400 const char *pnp;
401 {
402 struct maple_attach_args *ma = aux;
403
404 if (pnp != NULL)
405 printf("%s", pnp);
406
407 printf(" port %c", ma->ma_port+'A');
408
409 if (ma->ma_subunit != 0)
410 printf("%d", ma->ma_subunit);
411
412 return (UNCONF);
413 }
414
415 int
416 maplesearch(parent, cf, aux)
417 struct device *parent;
418 struct cfdata *cf;
419 void *aux;
420 {
421 if ((*cf->cf_attach->ca_match)(parent, cf, aux) > 0)
422 config_attach(parent, cf, aux, mapleprint);
423
424 return (0);
425 }
426
427 u_int32_t
428 maple_get_function_data(devinfo, function_code)
429 struct maple_devinfo *devinfo;
430 u_int32_t function_code;
431 {
432 int i, p = 0;
433
434 for (i = 31; i >= 0; --i)
435 if (devinfo->di_func & (1U<<i))
436 if (function_code & (1U<<i))
437 return devinfo->di_function_data[p];
438 else
439 if (++p >= 3)
440 break;
441 return (0);
442 }
443
444