xref: /netbsd/sys/arch/mac68k/mac68k/iop.c (revision bf9ec67e)
1 /*	$NetBSD: iop.c,v 1.4 2002/03/08 20:48:31 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 Allen Briggs.
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. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  *	This code handles VIA, RBV, and OSS functionality.
32  */
33 
34 #include "opt_mac68k.h"
35 
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/pool.h>
40 #include <sys/queue.h>
41 #include <sys/systm.h>
42 
43 #include <machine/cpu.h>
44 #include <machine/frame.h>
45 
46 #include <machine/iopreg.h>
47 #include <machine/viareg.h>
48 
49 static IOP	mac68k_iops[2];
50 
51 static void	iopism_hand __P((void *arg));
52 static void	load_msg_to_iop __P((IOPHW *ioph, struct iop_msg *msg));
53 static void	iop_message_sent __P((IOP *iop, int chan));
54 static void	receive_iop_message __P((IOP *iop, int chan));
55 static void	default_listener __P((IOP *iop, struct iop_msg *msg));
56 
57 static __inline__ int iop_alive __P((IOPHW *ioph));
58 static __inline__ int iop_read1 __P((IOPHW *ioph, u_long addr));
59 static __inline__ void iop_write1 __P((IOPHW *ioph, u_long addr, u_char data));
60 static __inline__ void _iop_upload __P((IOPHW *, u_char *, u_long, u_long));
61 static __inline__ void _iop_download __P((IOPHW *, u_char *, u_long, u_long));
62 
63 static __inline__ int
64 iop_read1(ioph, iopbase)
65 	IOPHW	*ioph;
66 	u_long	iopbase;
67 {
68 	IOP_LOADADDR(ioph, iopbase);
69 	return ioph->data;
70 }
71 
72 static __inline__ void
73 iop_write1(ioph, iopbase, data)
74 	IOPHW	*ioph;
75 	u_long	iopbase;
76 	u_char	data;
77 {
78 	IOP_LOADADDR(ioph, iopbase);
79 	ioph->data = data;
80 }
81 
82 static __inline__ int
83 iop_alive(ioph)
84 	IOPHW	*ioph;
85 {
86 	int	alive;
87 
88 	alive = iop_read1(ioph, IOP_ADDR_ALIVE);
89 	iop_write1(ioph, IOP_ADDR_ALIVE, 0);
90 	return alive;
91 }
92 
93 static void
94 default_listener(iop, msg)
95 	IOP *iop;
96 	struct iop_msg *msg;
97 {
98 	printf("unsolicited message on channel %d.\n", msg->channel);
99 }
100 
101 void
102 iop_init(fullinit)
103 	int	fullinit;
104 {
105 	IOPHW	*ioph;
106 	IOP	*iop;
107 	int	i, ii;
108 
109 	switch (current_mac_model->machineid) {
110 	default:
111 		return;
112 	case MACH_MACQ900:
113 	case MACH_MACQ950:
114 		mac68k_iops[SCC_IOP].iop = (IOPHW *)
115 						 ((u_char *)IOBase +  0xc000);
116 		mac68k_iops[ISM_IOP].iop = (IOPHW *)
117 						 ((u_char *)IOBase + 0x1e000);
118 		break;
119 	case MACH_MACIIFX:
120 		mac68k_iops[SCC_IOP].iop = (IOPHW *)
121 						 ((u_char *)IOBase +  0x4000);
122 		mac68k_iops[ISM_IOP].iop = (IOPHW *)
123 						 ((u_char *)IOBase + 0x12000);
124 		break;
125 	}
126 
127 	if (!fullinit) {
128 		ioph = mac68k_iops[SCC_IOP].iop;
129 		ioph->control_status = 0;		/* Reset */
130 		ioph->control_status = IOP_BYPASS;	/* Set to bypass */
131 
132 		ioph = mac68k_iops[ISM_IOP].iop;
133 		ioph->control_status = 0;		/* Reset */
134 
135 		return;
136 	}
137 
138 	for (ii = 0 ; ii < 2 ; ii++) {
139 		iop = &mac68k_iops[ii];
140 		ioph = iop->iop;
141 		for (i = 0; i < IOP_MAXCHAN; i++) {
142 			SIMPLEQ_INIT(&iop->sendq[i]);
143 			SIMPLEQ_INIT(&iop->recvq[i]);
144 			iop->listeners[i] = default_listener;
145 			iop->listener_data[i] = NULL;
146 		}
147 /*		IOP_LOADADDR(ioph, 0x200);
148 		for (i = 0x200; i > 0; i--) {
149 			ioph->data = 0;
150 		}*/
151 	}
152 
153 	switch (current_mac_model->machineid) {
154 	default:
155 		return;
156 	case MACH_MACQ900:
157 	case MACH_MACQ950:
158 #ifdef notyet_maybe_not_ever
159 		iop = &mac68k_iops[SCC_IOP];
160 		intr_establish(iopscc_hand, iop, 4);
161 #endif
162 		iop = &mac68k_iops[ISM_IOP];
163 		via2_register_irq(0, iopism_hand, iop);
164 		via_reg(VIA2, vIER) = 0x81;
165 		via_reg(VIA2, vIFR) = 0x01;
166 		break;
167 	case MACH_MACIIFX:
168 		/* oss_register_irq(2, iopism_hand, &ioph); */
169 		break;
170 	}
171 
172 	iop = &mac68k_iops[SCC_IOP];
173 	ioph = iop->iop;
174 	printf("SCC IOP base: 0x%x\n", (unsigned) ioph);
175 	pool_init(&iop->pool, sizeof(struct iop_msg), 0, 0, 0, "mac68k_iop1",
176 		  NULL);
177 	ioph->control_status = IOP_BYPASS;
178 
179 	iop = &mac68k_iops[ISM_IOP];
180 	ioph = iop->iop;
181 	printf("ISM IOP base: 0x%x, alive %x\n", (unsigned) ioph,
182 	(unsigned) iop_alive(ioph));
183 	pool_init(&iop->pool, sizeof(struct iop_msg), 0, 0, 0, "mac68k_iop2",
184 		  NULL);
185 	iop_write1(ioph, IOP_ADDR_ALIVE, 0);
186 
187 /*
188  * XXX  The problem here seems to be that the IOP wants to go back into
189  *	BYPASS mode.  The state should be 0x86 after we're done with it
190  *	here.  It switches to 0x7 almost immediately.
191  *	This means one of a couple of things to me--
192  *		1. We're doing something wrong
193  *		2. MacOS is really shutting down the IOP
194  *	Most likely, it's the first.
195  */
196 	printf("OLD cs0: 0x%x\n", (unsigned) ioph->control_status);
197 
198 	ioph->control_status = IOP_CS_RUN | IOP_CS_AUTOINC;
199 {unsigned cs, c2;
200 	cs = (unsigned) ioph->control_status;
201 	printf("OLD cs1: 0x%x\n", cs);
202 	cs = 0;
203 	do { c2 = iop_read1(ioph, IOP_ADDR_ALIVE); cs++; } while (c2 != 0xff);
204 	printf("OLD cs2: 0x%x (i = %d)\n", (unsigned) ioph->control_status, cs);
205 }
206 }
207 
208 static __inline__ void
209 _iop_upload(ioph, mem, nb, iopbase)
210 	IOPHW	*ioph;
211 	u_char	*mem;
212 	u_long	nb, iopbase;
213 {
214 	IOP_LOADADDR(ioph, iopbase);
215 	while (nb--) {
216 		ioph->data = *mem++;
217 	}
218 }
219 
220 void
221 iop_upload(iopn, mem, nb, iopbase)
222 	int	iopn;
223 	u_char	*mem;
224 	u_long	nb, iopbase;
225 {
226 	IOPHW	*ioph;
227 
228 	if (iopn & ~1) return;
229 	ioph = mac68k_iops[iopn].iop;
230 	if (!ioph) return;
231 
232 	_iop_upload(ioph, mem, nb, iopbase);
233 }
234 
235 static __inline__ void
236 _iop_download(ioph, mem, nb, iopbase)
237 	IOPHW	*ioph;
238 	u_char	*mem;
239 	u_long	nb, iopbase;
240 {
241 	IOP_LOADADDR(ioph, iopbase);
242 	while (nb--) {
243 		*mem++ = ioph->data;
244 	}
245 }
246 
247 void
248 iop_download(iopn, mem, nb, iopbase)
249 	int	iopn;
250 	u_char	*mem;
251 	u_long	nb, iopbase;
252 {
253 	IOPHW	*ioph;
254 
255 	if (iopn & ~1) return;
256 	ioph = mac68k_iops[iopn].iop;
257 	if (!ioph) return;
258 
259 	_iop_download(ioph, mem, nb, iopbase);
260 }
261 
262 static void
263 iopism_hand(arg)
264 	void	*arg;
265 {
266 	IOP	*iop;
267 	IOPHW	*ioph;
268 	u_char	cs;
269 	u_char	m, s;
270 	int	i;
271 
272 	iop = (IOP *) arg;
273 	ioph = iop->iop;
274 	cs = ioph->control_status;
275 
276 printf("iopism_hand.\n");
277 
278 #if DIAGNOSTIC
279 	if ((cs & IOP_INTERRUPT) == 0) {
280 		printf("IOP_ISM interrupt--no interrupt!? (cs 0x%x)\n",
281 			(u_int) cs);
282 	}
283 #endif
284 
285 	/*
286 	 * Scan send queues for complete messages.
287 	 */
288 	if (cs & IOP_CS_INT0) {
289 		ioph->control_status |= IOP_CS_INT0;
290 		m = iop_read1(ioph, IOP_ADDR_MAX_SEND_CHAN);
291 		for (i = 0; i < m; i++) {
292 			s = iop_read1(ioph, IOP_ADDR_SEND_STATE + i);
293 			if (s == IOP_MSG_COMPLETE) {
294 				iop_message_sent(iop, i);
295 			}
296 		}
297 	}
298 
299 	/*
300 	 * Scan receive queue for new messages.
301 	 */
302 	if (cs & IOP_CS_INT1) {
303 		ioph->control_status |= IOP_CS_INT1;
304 		m = iop_read1(ioph, IOP_ADDR_MAX_RECV_CHAN);
305 		for (i = 0; i < m; i++) {
306 			s = iop_read1(ioph, IOP_ADDR_RECV_STATE + i);
307 			if (s == IOP_MSG_NEW) {
308 				receive_iop_message(iop, i);
309 			}
310 		}
311 	}
312 }
313 
314 static void
315 load_msg_to_iop(ioph, msg)
316 	IOPHW		*ioph;
317 	struct iop_msg	*msg;
318 {
319 	int		offset;
320 
321 	msg->status = IOP_MSGSTAT_SENDING;
322 	offset = IOP_ADDR_SEND_MSG + msg->channel * IOP_MSGLEN;
323 	_iop_upload(ioph, msg->msg, IOP_MSGLEN, offset);
324 	iop_write1(ioph, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW);
325 
326 	/* ioph->control_status |= IOP_CS_IRQ; */
327 	ioph->control_status = (ioph->control_status & 0xfe) | IOP_CS_IRQ;
328 }
329 
330 static void
331 iop_message_sent(iop, chan)
332 	IOP	*iop;
333 	int	chan;
334 {
335 	IOPHW		*ioph;
336 	struct iop_msg	*msg;
337 
338 	ioph = iop->iop;
339 
340 	msg = SIMPLEQ_FIRST(&iop->sendq[chan]);
341 	msg->status = IOP_MSGSTAT_SENT;
342 	SIMPLEQ_REMOVE_HEAD(&iop->sendq[chan], msg, iopm);
343 
344 	msg->handler(iop, msg);
345 
346 	pool_put(&iop->pool, msg);
347 
348 	if (!(msg = SIMPLEQ_FIRST(&iop->sendq[chan]))) {
349 		iop_write1(ioph, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE);
350 	} else {
351 		load_msg_to_iop(ioph, msg);
352 	}
353 }
354 
355 static void
356 receive_iop_message(iop, chan)
357 	IOP	*iop;
358 	int	chan;
359 {
360 	IOPHW		*ioph;
361 	struct iop_msg	*msg;
362 	int		offset;
363 
364 	msg = SIMPLEQ_FIRST(&iop->recvq[chan]);
365 	if (msg) {
366 		SIMPLEQ_REMOVE_HEAD(&iop->recvq[chan], msg, iopm);
367 	} else {
368 		msg = &iop->unsolicited_msg;
369 		msg->channel = chan;
370 		msg->handler = iop->listeners[chan];
371 		msg->user_data = iop->listener_data[chan];
372 	}
373 
374 	offset = IOP_ADDR_RECV_MSG + chan * IOP_MSGLEN;
375 	_iop_download(ioph, msg->msg, IOP_MSGLEN, offset);
376 	msg->status = IOP_MSGSTAT_RECEIVED;
377 
378 	msg->handler(iop, msg);
379 
380 	if (msg != &iop->unsolicited_msg)
381 		pool_put(&iop->pool, msg);
382 
383 	iop_write1(ioph, IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE);
384 	ioph->control_status |= IOP_CS_IRQ;
385 
386 	if ((msg = SIMPLEQ_FIRST(&iop->recvq[chan])) != NULL) {
387 		msg->status = IOP_MSGSTAT_RECEIVING;
388 	}
389 }
390 
391 int
392 iop_send_msg(iopn, chan, mesg, msglen, handler, user_data)
393 	int		iopn, chan, msglen;
394 	u_char		*mesg;
395 	iop_msg_handler	handler;
396 	void		*user_data;
397 {
398 	struct iop_msg	*msg;
399 	IOP		*iop;
400 	int		s;
401 
402 	if (iopn & ~1) return -1;
403 	iop = &mac68k_iops[iopn];
404 	if (!iop) return -1;
405 	if (msglen > IOP_MSGLEN) return -1;
406 
407 	msg = (struct iop_msg *) pool_get(&iop->pool, PR_WAITOK);
408 	if (msg == NULL) return -1;
409 printf("have msg buffer for IOP: %#x\n", (unsigned) iop->iop);
410 	msg->channel = chan;
411 	if (msglen < IOP_MSGLEN) memset(msg->msg, '\0', IOP_MSGLEN);
412 	memcpy(msg->msg, mesg, msglen);
413 	msg->handler = handler;
414 	msg->user_data = user_data;
415 
416 	msg->status = IOP_MSGSTAT_QUEUED;
417 
418 	s = splhigh();
419 	SIMPLEQ_INSERT_TAIL(&iop->sendq[chan], msg, iopm);
420 	if (msg == SIMPLEQ_FIRST(&iop->sendq[chan])) {
421 		msg->status = IOP_MSGSTAT_SENDING;
422 printf("loading msg to iop: cs: 0x%x V1-%x- ", (unsigned) iop->iop->control_status, (unsigned)via_reg(VIA1, vIFR));
423 		load_msg_to_iop(iop->iop, msg);
424 printf("msg loaded to iop: cs: 0x%x V1-%x- ", (unsigned) iop->iop->control_status, (unsigned)via_reg(VIA1, vIFR));
425 	}
426 
427 {int i; for (i=0;i<16;i++) {
428 printf(" cs: 0x%x V1-%x- ", (unsigned) iop->iop->control_status, (unsigned)via_reg(VIA1, vIFR));
429 delay(1000);
430 }}
431 	splx(s);
432 
433 	return 0;
434 }
435 
436 int
437 iop_queue_receipt(iopn, chan, handler, user_data)
438 	int		iopn, chan;
439 	iop_msg_handler	handler;
440 	void		*user_data;
441 {
442 	struct iop_msg	*msg;
443 	IOP		*iop;
444 	int		s;
445 
446 	if (iopn & ~1) return -1;
447 	iop = &mac68k_iops[iopn];
448 	if (!iop) return -1;
449 
450 	msg = (struct iop_msg *) pool_get(&iop->pool, PR_WAITOK);
451 	if (msg == NULL) return -1;
452 	msg->channel = chan;
453 	msg->handler = handler;
454 	msg->user_data = user_data;
455 
456 	msg->status = IOP_MSGSTAT_QUEUED;
457 
458 	s = splhigh();
459 	SIMPLEQ_INSERT_TAIL(&iop->recvq[chan], msg, iopm);
460 	if (msg == SIMPLEQ_FIRST(&iop->recvq[chan])) {
461 		msg->status = IOP_MSGSTAT_RECEIVING;
462 	}
463 	splx(s);
464 
465 	return 0;
466 }
467 
468 int
469 iop_register_listener(iopn, chan, handler, user_data)
470 	int		iopn, chan;
471 	iop_msg_handler	handler;
472 	void		*user_data;
473 {
474 	IOP		*iop;
475 	int		s;
476 
477 	if (iopn & ~1) return -1;
478 	iop = &mac68k_iops[iopn];
479 	if (!iop) return -1;
480 
481 	s = splhigh();
482 	iop->listeners[chan] = handler;
483 	iop->listener_data[chan] = user_data;
484 	splx(s);
485 
486 	return 0;
487 }
488