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