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