1 /* $NetBSD: sifbios.c,v 1.11 2014/03/31 11:25:49 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * PlayStation 2 SIF BIOS Version 2.0 interface. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: sifbios.c,v 1.11 2014/03/31 11:25:49 martin Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 42 #include <playstation2/playstation2/sifbios.h> 43 #include <playstation2/playstation2/interrupt.h> 44 45 #ifdef DEBUG 46 #define STATIC 47 #else 48 #define STATIC static 49 #endif 50 51 #define SIFBIOS_ENTRY_PTR MIPS_PHYS_TO_KSEG0(0x00001000) 52 #define SIFBIOS_SIGNATURE_PTR MIPS_PHYS_TO_KSEG1(0x00001004) 53 #define SIFBIOS_SIGNATURE (('P' << 0)|('S' << 8)|('2' << 16)|('b' << 24)) 54 55 STATIC int (*__sifbios_call)(int, void *); 56 #define CALL(t, n, a) ((t)(*__sifbios_call)((n), (void *)(a))) 57 58 STATIC void sifbios_rpc_callback(void *, int); 59 STATIC int sifbios_rpc_call(int, void *, int *); 60 61 void 62 sifbios_init(void) 63 { 64 /* check BIOS exits */ 65 if (*(u_int32_t *)SIFBIOS_SIGNATURE_PTR != SIFBIOS_SIGNATURE) 66 panic("SIFBIOS not found"); 67 68 __sifbios_call = *((int (**)(int, void*))SIFBIOS_ENTRY_PTR); 69 } 70 71 int 72 sifbios_rpc_call(int callno, void *arg, int *result) 73 { 74 volatile int done = 0; 75 int retry; 76 struct { 77 int result; 78 void *arg; 79 void (*callback)(void *, int); 80 volatile void *callback_arg; 81 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 82 arg: arg, 83 callback: sifbios_rpc_callback, 84 callback_arg: (volatile void *)&done, 85 }; 86 87 /* call SIF BIOS */ 88 retry = 100; 89 while (CALL(int, callno, &sifbios_arg) != 0 && --retry > 0) 90 delay(20000); /* .02 sec. for slow IOP */ 91 92 if (retry == 0) { 93 printf("SIF BIOS call %d failed\n", callno); 94 goto error; 95 } 96 97 /* wait IOP response (1 sec.) */ 98 _sif_call_start(); 99 retry = 10000; 100 while (!done && --retry > 0) 101 delay(100); 102 _sif_call_end(); 103 104 if (retry == 0) { 105 printf("IOP not respond (callno = %d)\n", callno); 106 goto error; 107 } 108 109 *result = sifbios_arg.result; 110 111 return (0); 112 113 error: 114 return (-1); 115 } 116 117 void 118 sifbios_rpc_callback(void *arg, int result) 119 { 120 int *done = (int *)arg; 121 122 *done = 1; 123 } 124 125 /* 126 * System misc. 127 */ 128 int 129 sifbios_getver(void) 130 { 131 132 return CALL(int, 0, 0); 133 } 134 135 void 136 sifbios_halt(int mode) 137 { 138 int sifbios_arg = mode; 139 140 CALL(void, 1, &sifbios_arg); 141 } 142 143 void 144 sifbios_setdve(int mode) 145 { 146 int sifbios_arg = mode; 147 148 CALL(void, 2, &sifbios_arg); 149 } 150 151 void 152 sifbios_putchar(int c) 153 { 154 int sifbios_arg = c; 155 156 CALL(void, 3, &sifbios_arg); 157 } 158 159 int 160 sifbios_getchar(void) 161 { 162 163 return CALL(int, 4, 0); 164 } 165 166 /* 167 * SIF DMA 168 */ 169 int 170 sifdma_init(void) 171 { 172 173 return CALL(int, 16, 0); 174 } 175 176 void 177 sifdma_exit(void) 178 { 179 180 CALL(void, 17, 0); 181 } 182 183 /* queue DMA request to SIFBIOS. returns queue identifier. */ 184 sifdma_id_t 185 sifdma_queue(struct sifdma_transfer *arg, int n) 186 { 187 struct { 188 void *arg; /* pointer to sifdma_transfer array */ 189 int n; /* # of elements */ 190 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 191 arg: arg, 192 n: n 193 }; 194 195 return CALL(sifdma_id_t, 18, &sifbios_arg); 196 } 197 198 /* 199 * status of DMA 200 * >0 ... queued. not kicked. 201 * 0 ... DMA executing. 202 * <0 ... DMA done. 203 */ 204 int 205 sifdma_stat(sifdma_id_t id) 206 { 207 u_int32_t sifbios_arg = id; 208 209 return CALL(int, 19, &sifbios_arg); 210 } 211 212 /* reset DMA channel */ 213 void 214 sifdma_reset(void) 215 { 216 217 CALL(void, 20, 0); 218 } 219 220 /* 221 * SIF CMD 222 */ 223 int 224 sifcmd_init(void) 225 { 226 227 return CALL(int, 32, 0); 228 } 229 230 void 231 sifcmd_exit(void) 232 { 233 234 CALL(void, 33, 0); 235 } 236 237 sifdma_id_t 238 sifcmd_queue(sifcmd_sw_t sw, vaddr_t cmd_pkt_addr, size_t cmd_pkt_sz, 239 vaddr_t src_addr, vaddr_t dst_addr, vsize_t buf_sz) 240 { 241 struct { 242 sifcmd_sw_t sw; 243 vaddr_t cmd_pkt_addr; /* command buffer */ 244 size_t cmd_pkt_sz; 245 vaddr_t src_addr; /* data buffer */ 246 vaddr_t dst_addr; 247 vsize_t buf_sz; 248 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 249 sw: sw, 250 cmd_pkt_addr: cmd_pkt_addr, 251 cmd_pkt_sz: cmd_pkt_sz, 252 src_addr: src_addr, 253 dst_addr: dst_addr, 254 buf_sz: buf_sz, 255 }; 256 257 return CALL(sifdma_id_t, 34, &sifbios_arg); 258 } 259 260 /* interrupt handler of DMAC channel 5 (SIF0) */ 261 int 262 sifcmd_intr(void *arg) 263 { 264 265 CALL(void, 35, 0); 266 267 return (1); 268 } 269 270 void 271 sifcmd_establish(sifcmd_sw_t sw, struct sifcmd_callback_holder *holder) 272 { 273 struct { 274 sifcmd_sw_t sw; 275 sifcmd_callback_t func; 276 void *arg; 277 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 278 sw: sw, 279 func: holder->func, 280 arg: holder->arg, 281 }; 282 283 CALL(void, 36, &sifbios_arg); 284 } 285 286 void 287 sifcmd_disestablish(sifcmd_sw_t sw) 288 { 289 u_int32_t sifbios_arg = sw; 290 291 CALL(void, 37, &sifbios_arg); 292 } 293 294 struct sifcmd_callback_holder * 295 sifcmd_handler_init(struct sifcmd_callback_holder *holder, int n) 296 { 297 struct { 298 void *holder; 299 int n; /* # of slot */ 300 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 301 holder: holder, 302 n: n, 303 }; 304 305 /* returns old holder */ 306 return CALL(struct sifcmd_callback_holder *, 38, &sifbios_arg); 307 } 308 309 /* 310 * SIF RPC 311 */ 312 int 313 sifrpc_init(void) 314 { 315 316 return CALL(int, 48, 0); 317 } 318 319 void 320 sifrpc_exit(void) 321 { 322 323 CALL(void, 49, 0); 324 } 325 326 int 327 sifrpc_receive_buffer(struct sifrpc_receive *_cookie, void *src_iop, 328 void *dst_ee, size_t sz, u_int32_t rpc_mode, void (*end_func)(void *), 329 void *end_arg) 330 { 331 struct { 332 void *_cookie; 333 void *src_iop; 334 void *dst_ee; 335 size_t sz; 336 u_int32_t rpc_mode; 337 sifrpc_endfunc_t end_func; 338 void *end_arg; 339 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 340 _cookie: _cookie, 341 src_iop: src_iop, 342 dst_ee: dst_ee, 343 sz: sz, 344 rpc_mode: rpc_mode, 345 end_func: end_func, 346 end_arg: end_arg, 347 }; 348 349 return CALL(int, 50, &sifbios_arg); 350 } 351 352 int 353 sifrpc_bind(struct sifrpc_client *_cookie, sifrpc_id_t rpc_id, 354 u_int32_t rpc_mode, void (*end_func)(void *), void *end_arg) 355 { 356 struct { 357 void *_cookie; /* filled by this call */ 358 sifrpc_id_t rpc_id; /* specify server RPC id */ 359 u_int32_t rpc_mode; 360 sifrpc_endfunc_t end_func; 361 void *end_arg; 362 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 363 _cookie: _cookie, 364 rpc_id: rpc_id, 365 rpc_mode: rpc_mode, 366 end_func: end_func, 367 end_arg: end_arg, 368 }; 369 370 return CALL(int, 51, &sifbios_arg); 371 } 372 373 int 374 sifrpc_call(struct sifrpc_client *_cookie, sifrpc_callno_t call_no, 375 u_int32_t rpc_mode, void *sendbuf, size_t sendbuf_sz, void *recvbuf, 376 size_t recvbuf_sz, void (*end_func)(void *), void *end_arg) 377 { 378 struct { 379 struct sifrpc_client *_cookie; /* binded client cookie */ 380 sifrpc_callno_t call_no; /* passed to service function arg. */ 381 u_int32_t rpc_mode; 382 void *sendbuf; 383 size_t sendbuf_sz; 384 void *recvbuf; 385 size_t recvbuf_sz; 386 sifrpc_endfunc_t end_func; 387 void *end_arg; 388 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 389 _cookie: _cookie, 390 call_no: call_no, 391 rpc_mode: rpc_mode, 392 sendbuf: sendbuf, 393 sendbuf_sz: sendbuf_sz, 394 recvbuf: recvbuf, 395 recvbuf_sz: recvbuf_sz, 396 end_func: end_func, 397 end_arg: end_arg, 398 }; 399 400 return CALL(int, 52, &sifbios_arg); 401 } 402 403 int 404 sifrpc_stat(struct sifrpc_header *_cookie) 405 { 406 void *sifbios_arg = _cookie; 407 408 return CALL(int, 53, &sifbios_arg); 409 } 410 411 void 412 sifrpc_establish(struct sifrpc_server_system *queue, void (*end_func)(void *), 413 void *end_arg) 414 { 415 struct { 416 struct sifrpc_server_system *queue; 417 sifrpc_endfunc_t end_func; 418 void *end_arg; 419 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 420 queue: queue, 421 end_func: end_func, 422 end_arg: end_arg, 423 }; 424 425 CALL(void, 54, &sifbios_arg); 426 } 427 428 void 429 sifrpc_register_service(struct sifrpc_server_system *queue, 430 struct sifrpc_server *server, sifrpc_id_t rpc_id, 431 void *(*service_func)(sifrpc_callno_t, void *, size_t), void *service_arg, 432 void *(*cancel_func)(sifrpc_callno_t, void *, size_t), void *cancel_arg) 433 { 434 struct { 435 void *server; 436 sifrpc_id_t rpc_id; 437 sifrpc_rpcfunc_t service_func; 438 void *service_arg; 439 sifrpc_rpcfunc_t cancel_func; 440 void *cancel_arg; 441 void *receive_queue; 442 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 443 server: server, 444 rpc_id: rpc_id, 445 service_func: service_func, 446 service_arg: service_arg, 447 cancel_func: cancel_func, 448 cancel_arg: cancel_arg, 449 receive_queue: queue, 450 }; 451 452 CALL(void, 55, &sifbios_arg); 453 } 454 455 void 456 sifrpc_unregister_service(struct sifrpc_server_system *queue, 457 struct sifrpc_server *server) 458 { 459 struct { 460 void *server; 461 void *receive_queue; 462 } __attribute__((__packed__, __aligned__(4))) sifbios_arg = { 463 server: server, 464 receive_queue: queue, 465 }; 466 467 CALL(void, 56, &sifbios_arg); 468 } 469 470 void 471 sifrpc_disestablish(struct sifrpc_server_system *queue) 472 { 473 void *sifbios_arg = queue; 474 475 CALL(void, 57, &sifbios_arg); 476 } 477 478 struct sifrpc_server * 479 sifrpc_dequeue(struct sifrpc_server_system *queue) 480 { 481 void *sifbios_arg = queue; 482 483 return CALL(struct sifrpc_server *, 58, &sifbios_arg); 484 } 485 486 void 487 sifrpc_dispatch_service(struct sifrpc_server *server) 488 { 489 void *sifbios_arg = server; 490 491 CALL(void, 59, &sifbios_arg); 492 } 493 494 /* 495 * IOP memory 496 */ 497 int 498 iopmem_init(void) 499 { 500 int result; 501 502 sifbios_rpc_call(64, 0, &result); 503 504 return (0); 505 } 506 507 paddr_t 508 iopmem_alloc(psize_t sz) 509 { 510 int result, sifbios_arg = sz; 511 512 if (sifbios_rpc_call(65, (void *)&sifbios_arg, &result) < 0) 513 return (paddr_t)0; 514 /* returns allocated IOP physical addr */ 515 return (paddr_t)result; 516 } 517 518 int 519 iopmem_free(paddr_t addr) 520 { 521 int result, sifbios_arg = addr; 522 523 sifbios_rpc_call(66, (void *)&sifbios_arg, &result); 524 525 return (result); 526 } 527