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
sifbios_init(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
sifbios_rpc_call(int callno,void * arg,int * result)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
sifbios_rpc_callback(void * arg,int result)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
sifbios_getver(void)129 sifbios_getver(void)
130 {
131
132 return CALL(int, 0, 0);
133 }
134
135 void
sifbios_halt(int mode)136 sifbios_halt(int mode)
137 {
138 int sifbios_arg = mode;
139
140 CALL(void, 1, &sifbios_arg);
141 }
142
143 void
sifbios_setdve(int mode)144 sifbios_setdve(int mode)
145 {
146 int sifbios_arg = mode;
147
148 CALL(void, 2, &sifbios_arg);
149 }
150
151 void
sifbios_putchar(int c)152 sifbios_putchar(int c)
153 {
154 int sifbios_arg = c;
155
156 CALL(void, 3, &sifbios_arg);
157 }
158
159 int
sifbios_getchar(void)160 sifbios_getchar(void)
161 {
162
163 return CALL(int, 4, 0);
164 }
165
166 /*
167 * SIF DMA
168 */
169 int
sifdma_init(void)170 sifdma_init(void)
171 {
172
173 return CALL(int, 16, 0);
174 }
175
176 void
sifdma_exit(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
sifdma_queue(struct sifdma_transfer * arg,int n)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
sifdma_stat(sifdma_id_t id)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
sifdma_reset(void)214 sifdma_reset(void)
215 {
216
217 CALL(void, 20, 0);
218 }
219
220 /*
221 * SIF CMD
222 */
223 int
sifcmd_init(void)224 sifcmd_init(void)
225 {
226
227 return CALL(int, 32, 0);
228 }
229
230 void
sifcmd_exit(void)231 sifcmd_exit(void)
232 {
233
234 CALL(void, 33, 0);
235 }
236
237 sifdma_id_t
sifcmd_queue(sifcmd_sw_t sw,vaddr_t cmd_pkt_addr,size_t cmd_pkt_sz,vaddr_t src_addr,vaddr_t dst_addr,vsize_t buf_sz)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
sifcmd_intr(void * arg)262 sifcmd_intr(void *arg)
263 {
264
265 CALL(void, 35, 0);
266
267 return (1);
268 }
269
270 void
sifcmd_establish(sifcmd_sw_t sw,struct sifcmd_callback_holder * holder)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
sifcmd_disestablish(sifcmd_sw_t sw)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 *
sifcmd_handler_init(struct sifcmd_callback_holder * holder,int n)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
sifrpc_init(void)313 sifrpc_init(void)
314 {
315
316 return CALL(int, 48, 0);
317 }
318
319 void
sifrpc_exit(void)320 sifrpc_exit(void)
321 {
322
323 CALL(void, 49, 0);
324 }
325
326 int
sifrpc_receive_buffer(struct sifrpc_receive * _cookie,void * src_iop,void * dst_ee,size_t sz,u_int32_t rpc_mode,void (* end_func)(void *),void * end_arg)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
sifrpc_bind(struct sifrpc_client * _cookie,sifrpc_id_t rpc_id,u_int32_t rpc_mode,void (* end_func)(void *),void * end_arg)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
sifrpc_call(struct sifrpc_client * _cookie,sifrpc_callno_t call_no,u_int32_t rpc_mode,void * sendbuf,size_t sendbuf_sz,void * recvbuf,size_t recvbuf_sz,void (* end_func)(void *),void * end_arg)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
sifrpc_stat(struct sifrpc_header * _cookie)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
sifrpc_establish(struct sifrpc_server_system * queue,void (* end_func)(void *),void * end_arg)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
sifrpc_register_service(struct sifrpc_server_system * queue,struct sifrpc_server * server,sifrpc_id_t rpc_id,void * (* service_func)(sifrpc_callno_t,void *,size_t),void * service_arg,void * (* cancel_func)(sifrpc_callno_t,void *,size_t),void * cancel_arg)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
sifrpc_unregister_service(struct sifrpc_server_system * queue,struct sifrpc_server * server)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
sifrpc_disestablish(struct sifrpc_server_system * queue)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 *
sifrpc_dequeue(struct sifrpc_server_system * queue)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
sifrpc_dispatch_service(struct sifrpc_server * server)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
iopmem_init(void)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
iopmem_alloc(psize_t sz)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
iopmem_free(paddr_t addr)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