Home | History | Annotate | Line # | Download | only in playstation2
      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