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