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