Home | History | Annotate | Line # | Download | only in mac68k
      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
     66 iop_read1(IOPHW *ioph, u_long iopbase)
     67 {
     68 	IOP_LOADADDR(ioph, iopbase);
     69 	return ioph->data;
     70 }
     71 
     72 static inline void
     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
     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
     90 default_listener(IOP *iop, struct iop_msg *msg)
     91 {
     92 	printf("unsolicited message on channel %d.\n", msg->channel);
     93 }
     94 
     95 void
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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