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