1 /*
2 * Copyright (c) 2011, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <ti/grcm/RcmServer.h>
38 #include <ti/grcm/RcmTypes.h>
39 #include <ti/ipc/mm/MmServiceMgr.h>
40 #include <ti/ipc/mm/MmRpc.h>
41 #include <ti/ipc/MultiProc.h>
42 #include <ti/ipc/rpmsg/RPMessage.h>
43 #include <ti/ipc/rpmsg/NameMap.h>
44 #include <ti/pm/IpcPower.h>
45 #include <ti/sdo/ce/global/CESettings.h>
46 #include <ti/sdo/ce/Engine.h>
47 #include <ti/sdo/ce/video3/viddec3.h>
48 #include <ti/sdo/ce/video2/videnc2.h>
49 #include <ti/sdo/fc/global/FCSettings.h>
50 #include <ti/sdo/fc/utils/fcutils.h>
51 #include <ti/sysbios/BIOS.h>
52 #include <ti/sysbios/hal/Cache.h>
53 #include <ti/sysbios/knl/Task.h>
54 #include <ti/xdais/dm/xdm.h>
55 #include <xdc/cfg/global.h>
56 #include <xdc/runtime/System.h>
57 #include <xdc/runtime/Diags.h>
58 #include <xdc/runtime/Memory.h>
59 #include <xdc/runtime/IHeap.h>
60 #include <xdc/runtime/knl/Thread.h>
61 #include <xdc/std.h>
63 #include "dce_priv.h"
64 #include "dce_rpc.h"
65 #include "ti/utils/profile.h"
67 static uint32_t suspend_initialised = 0;
68 uint32_t dce_debug = DCE_DEBUG_LEVEL;
70 #define SERVER_NAME "rpmsg-dce"
71 #define MEMORYSTATS_DEBUG
72 /* Each client is based on a unique id from MmServiceMgr which is the connect identity */
73 /* created by IPC per MmRpc_create instances */
74 #define NUM_CLIENTS 10
75 /* Each client can have NUM_INSTANCE of ENGINE, DECODE_CODEC, and ENCODE_CODEC handle */
76 /* Commonly one ENGINE is associated with one DECODE_CODEC or one ENCODE_CODEC handle */
77 #define NUM_INSTANCE 5
79 #define MmRpc_NUM_PARAMETERS(size) \
80 (size / sizeof(MmType_Param))
82 /* dce_inv, dce_clean needs to be modified to expect buffers */
83 /* without headers (relevant for GLP) */
84 static void dce_inv(void *ptr)
85 {
86 if( ptr ) {
87 Cache_inv(ptr, P2H(ptr)->size, Cache_Type_ALL, TRUE);
88 }
89 }
91 static void dce_clean(void *ptr)
92 {
93 if( ptr ) {
94 Cache_wbInv(ptr, P2H(ptr)->size, Cache_Type_ALL, TRUE);
95 }
96 }
98 typedef void * (*CreateFxn)(Engine_Handle, String, void *);
99 typedef Int32 (*ControlFxn)(void *, int, void *, void *);
100 typedef Int32 (*ProcessFxn)(void *, void *, void *, void *, void *);
101 typedef Int32 (*RelocFxn)(void *, uint8_t *ptr, uint32_t len);
102 typedef void (*DeleteFxn)(void *);
104 /* DCE Server static function declarations */
105 static Int32 engine_open(UInt32 size, UInt32 *data);
106 static Int32 engine_close(UInt32 size, UInt32 *data);
108 /* Encoder Server static function declarations */
109 static VIDENC2_Handle videnc2_create(Engine_Handle engine, String name, VIDENC2_Params *params);
110 static XDAS_Int32 videnc2_control(VIDENC2_Handle codec, VIDENC2_Cmd id, VIDENC2_DynamicParams *dynParams, VIDENC2_Status *status);
111 static int videnc2_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len);
113 /* Decoder Server static function declarations */
114 static VIDDEC3_Handle viddec3_create(Engine_Handle engine, String name, VIDDEC3_Params *params);
115 static int viddec3_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len);
118 typedef struct {
119 Uint32 mm_serv_id; /* value of zero means unused */
120 Int refs; /* reference count on number of engine */
121 Engine_Handle engines[NUM_INSTANCE];
122 VIDDEC3_Handle decode_codec[NUM_INSTANCE];
123 VIDENC2_Handle encode_codec[NUM_INSTANCE];
124 } Client;
125 static Client clients[NUM_CLIENTS] = {0};
127 static inline Client * get_client(Uint32 mm_serv_id)
128 {
129 int i;
130 for (i = 0; i < DIM(clients); i++) {
131 if (clients[i].mm_serv_id == mm_serv_id) {
132 return &clients[i];
133 }
134 }
135 return NULL;
136 }
138 static struct {
139 CreateFxn create;
140 ControlFxn control;
141 ProcessFxn process;
142 DeleteFxn delete;
143 RelocFxn reloc; /* handle buffer relocation table */
144 } codec_fxns[] =
145 {
146 [OMAP_DCE_VIDENC2] =
147 {
148 (CreateFxn)videnc2_create, (ControlFxn)videnc2_control,
149 (ProcessFxn)VIDENC2_process, (DeleteFxn)VIDENC2_delete,
150 (RelocFxn)videnc2_reloc,
151 },
152 [OMAP_DCE_VIDDEC3] =
153 {
154 (CreateFxn)viddec3_create, (ControlFxn)VIDDEC3_control,
155 (ProcessFxn)VIDDEC3_process, (DeleteFxn)VIDDEC3_delete,
156 (RelocFxn)viddec3_reloc,
157 },
158 };
161 /* Static version string buffer.
162 * Note: codec version can be large. For example, h264vdec needs more than
163 * 58 characters, or the query will fail. */
164 #define VERSION_SIZE 128
165 static char version_buffer[VERSION_SIZE];
167 /* the following callbacks are needed for suspend/resume
168 * on the linux side.
169 * - FC_suspend() waits for all algorithms to get deactivated and
170 * and takes care of the resources acquired.
171 * - FC_resume() does nothing for now, but we add it just in case
172 * it gets populated in the future versions of framework components.
173 *
174 * Forced off mode during video decode/encode is not supported. */
175 static void dce_suspend()
176 {
177 INFO("Preparing for suspend...");
178 FC_suspend();
179 }
181 static void dce_resume()
182 {
183 INFO("Restoring after suspend...");
184 FC_resume();
185 }
187 static void get_videnc2_version(VIDENC2_Handle h, char *buffer, unsigned size)
188 {
189 VIDENC2_DynamicParams params =
190 {
191 .size = sizeof(VIDENC2_DynamicParams),
192 };
194 VIDENC2_Status status =
195 {
196 .size = sizeof(VIDENC2_Status),
197 .data =
198 {
199 .buf = (XDAS_Int8 *)buffer,
200 .bufSize = (XDAS_Int32)size,
201 },
202 };
204 XDAS_Int32 s;
206 memset(buffer, 0, size);
207 s = VIDENC2_control(h, XDM_GETVERSION, ¶ms, &status);
209 if( s != VIDENC2_EOK ) {
210 ERROR("Unknown version Error = %d:: buffer = %p size = %d", s, buffer, size);
211 }
212 }
214 // VIDENC2_create wrapper, to display version string in the trace.
215 static VIDENC2_Handle videnc2_create(Engine_Handle engine, String name, VIDENC2_Params *params)
216 {
217 VIDENC2_Handle h;
219 h = VIDENC2_create(engine, name, params);
221 if( h ) {
222 get_videnc2_version(h, version_buffer, VERSION_SIZE);
223 INFO("Created videnc2 %s: version %s", name, version_buffer);
224 }
226 return (h);
227 }
229 static XDAS_Int32 getBufferFxnStub(XDM_DataSyncHandle handle, XDM_DataSyncDesc *desc)
230 {
231 return (0);
232 }
234 static XDAS_Int32 videnc2_control(VIDENC2_Handle codec, VIDENC2_Cmd id,
235 VIDENC2_DynamicParams *dynParams, VIDENC2_Status *status)
236 {
237 dynParams->getBufferFxn = getBufferFxnStub;
238 return (VIDENC2_control(codec, id, dynParams, status));
239 }
241 static void get_viddec3_version(VIDDEC3_Handle h, char *buffer, unsigned size)
242 {
243 VIDDEC3_DynamicParams params =
244 {
245 .size = sizeof(VIDDEC3_DynamicParams),
246 };
248 VIDDEC3_Status status =
249 {
250 .size = sizeof(VIDDEC3_Status),
251 .data =
252 {
253 .buf = (XDAS_Int8 *)buffer,
254 .bufSize = (XDAS_Int32)size,
255 },
256 };
258 XDAS_Int32 s;
260 memset(buffer, 0, size);
261 s = VIDDEC3_control(h, XDM_GETVERSION, ¶ms, &status);
263 if( s != VIDDEC3_EOK ) {
264 ERROR("Unknown version Error = %d:: buffer = %p size = %d", s, buffer, size);
265 }
266 }
268 // VIDDEC3_create wrapper, to display version string in the trace.
269 static VIDDEC3_Handle viddec3_create(Engine_Handle engine, String name, VIDDEC3_Params *params)
270 {
271 VIDDEC3_Handle h;
273 DEBUG(">> engine=%08x, name=%s, params=%p", engine, name, params);
274 DEBUG(">> max_height %d max_width %d frame_rate %d", params->maxHeight, params->maxWidth, params->maxFrameRate);
276 h = VIDDEC3_create(engine, name, params);
278 if( h ) {
279 get_viddec3_version(h, version_buffer, VERSION_SIZE);
280 INFO("Created viddec3 %s: version %s", name, version_buffer);
281 }
283 return (h);
284 }
286 static int videnc2_reloc(VIDENC2_Handle handle, uint8_t *ptr, uint32_t len)
287 {
288 return (-1); // Not implemented
289 }
291 /* needs to be updated when XDM_MOVEBUFS added in XDC tools */
292 static int viddec3_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len)
293 {
294 return (-1); // Not implemented
295 #if 0
296 static VIDDEC3_DynamicParams params =
297 {
298 .size = sizeof(VIDDEC3_DynamicParams),
299 };
300 VIDDEC3_Status status =
301 {
302 .size = sizeof(VIDDEC3_Status),
303 .data =
304 {
305 .buf = (XDAS_Int8 *)ptr,
306 .bufSize = (XDAS_Int32)len,
307 },
308 };
309 INFO("status.size=%d", status.size);
310 return (VIDDEC3_control(handle, XDM_MOVEBUFS, ¶ms, &status));
311 #endif
312 }
314 /*
315 * RPC message handlers
316 */
317 static int connect(void *msg)
318 {
319 dce_connect *req = msg;
321 DEBUG(">> chipset_id=0x%x, debug=%d", req->chipset_id, req->debug);
323 if( dce_debug >= MAX_DEBUG_LEVEL ) {
324 DEBUG("Enable FC, CE and IPC traces");
326 FCSettings_init();
327 Diags_setMask(FCSETTINGS_MODNAME "+12345678LEXAIZFS");
328 CESettings_init();
329 Diags_setMask(CESETTINGS_MODNAME "+12345678LEXAIZFS");
331 /*
332 * Enable use of runtime Diags_setMask per module:
333 *
334 * Codes: E = ENTRY, X = EXIT, L = LIFECYCLE, F = INFO, S = STATUS
335 */
336 Diags_setMask("ti.ipc.rpmsg.RPMessage=EXLFS");
337 Diags_setMask("ti.ipc.rpmsg.VirtQueue=EXLFS");
338 }
340 ivahd_init(req->chipset_id);
342 if( !suspend_initialised ) {
344 /* registering sysbios-rpmsg callbacks for suspend/resume */
345 IpcPower_registerCallback(IpcPower_Event_SUSPEND, (IpcPower_CallbackFuncPtr)dce_suspend, 0);
346 IpcPower_registerCallback(IpcPower_Event_RESUME, (IpcPower_CallbackFuncPtr)dce_resume, 0);
347 suspend_initialised++;
348 }
350 DEBUG("<<");
352 return (0);
353 }
355 static Int32 dce_register_engine(Uint32 mm_serv_id, Engine_Handle engine)
356 {
357 Int32 ret = 0;
358 Uint32 clientIndex = 0;
359 Client *c;
361 c = get_client(mm_serv_id);
362 if( c ) {
363 int i;
364 DEBUG("found mem client: %p refs=%d", c, c->refs);
365 c->refs++;
366 for (i = 0; i < DIM(c->engines); i++) {
367 if (c->engines[i] == NULL) {
368 c->engines[i] = engine;
369 clientIndex = i;
370 DEBUG("registered engine: mm_serv_id=%x engine=%p", mm_serv_id, engine);
371 break;
372 }
373 }
375 //If clientIndex is equal to 0 and it is not the register engine, then we know that no more
376 //empty spot since clientIndex not getting set in the for loop.
377 if( (clientIndex == 0) && (c->engines[clientIndex]) != engine ){
378 ERROR("No more empty space for engine");
379 ret = -1;
380 goto out;
381 }
382 }else {
383 c = get_client(0);
384 if (!c) {
385 ERROR("too many clients");
386 ret = -1;
387 goto out;
388 }
389 DEBUG("new client: %p refs=%d", c, c->refs);
391 c->mm_serv_id = mm_serv_id;
392 c->refs = 1;
393 c->engines[0] = engine;
394 }
395 out:
396 if ((ret != 0) && (c)){
397 c->mm_serv_id = NULL;
398 c->refs--;
399 c->engines[0] = NULL;
400 }
401 return ret;
402 }
404 static void dce_unregister_engine(Uint32 mm_serv_id, Engine_Handle engine)
405 {
406 Client *c;
408 c = get_client(mm_serv_id);
409 if( c ) {
410 int i;
411 DEBUG("found mem client: %p refs=%d", c, c->refs);
413 for( i = 0; i < DIM(c->engines); i++ ) {
414 if( c->engines[i] == engine ) {
415 c->engines[i] = NULL;
416 DEBUG("unregistered engine: mm_serv_id=0x%x engine=%p", mm_serv_id, engine);
417 break;
418 }
419 }
421 //If i is equal to the size of Array, then it means it has search the whole array.
422 if( i == DIM(c->engines) ) {
423 ERROR("Unknown engine received on dce_unregister_engine");
424 return;
425 }
427 DEBUG("dce_unregister_engine: %p refs=%d", c, c->refs);
428 c->refs--;
430 if( !c->refs ) {
431 c->mm_serv_id = NULL;
432 }
433 }
434 }
436 static Int32 dce_register_codec(Uint32 type, Uint32 mm_serv_id, Uint32 codec)
437 {
438 Client *c;
439 Int32 ret = 0;
440 Uint32 clientIndex = 0;
442 c = get_client(mm_serv_id);
443 if( c ) {
444 int i;
445 DEBUG("found mem client: %p refs=%d", c, c->refs);
447 if( type == OMAP_DCE_VIDDEC3 ) {
448 for( i = 0; i < DIM(c->decode_codec); i++ ) {
449 if( c->decode_codec[i] == NULL ) {
450 c->decode_codec[i] = (VIDDEC3_Handle) codec;
451 clientIndex = i;
452 DEBUG("registering codec: decode_codec[%d] codec=%p", i, codec);
453 break;
454 }
455 }
457 //If clientIndex is equal to 0 and it's not the register codec, then we know that no more
458 //empty spot since clientIndex not getting set in the for loop.
459 if( (clientIndex == 0) && (c->decode_codec[clientIndex]) != (VIDDEC3_Handle) codec ) {
460 ERROR("No more empty space for codecs");
461 ret = -1;
462 goto out;
463 }
464 }
465 else if( type == OMAP_DCE_VIDENC2 ) {
466 for( i = 0; i < DIM(c->encode_codec); i++ ) {
467 if( c->encode_codec[i] == NULL ) {
468 c->encode_codec[i] = (VIDENC2_Handle) codec;
469 clientIndex = i;
470 DEBUG("registering codec: encode_codec[%d] codec=%p", i, codec);
471 break;
472 }
473 }
475 //If clientIndex is equal to 0 and it's not the register codec, then we know that no more
476 //empty spot since clientIndex not getting set in the for loop.
477 if( (clientIndex == 0) && (c->encode_codec[clientIndex]) != (VIDENC2_Handle) codec ) {
478 ERROR("No more empty space for codecs");
479 ret = -1;
480 goto out;
481 }
482 }
483 }
485 out:
486 return ret;
487 }
489 static void dce_unregister_codec(Uint32 type, Uint32 mm_serv_id, Uint32 codec)
490 {
491 Client *c;
493 c = get_client(mm_serv_id);
494 if (c) {
495 int i;
496 DEBUG("found mem client: %p refs=%d", c, c->refs);
498 if( type == OMAP_DCE_VIDDEC3 ) {
499 for( i = 0; i < DIM(c->decode_codec); i++ ) {
500 if( c->decode_codec[i] == (VIDDEC3_Handle) codec ) {
501 c->decode_codec[i] = NULL;
502 DEBUG("unregistered decode_codec[%d] type Decoder codec=%p", i, codec);
503 break;
504 }
505 }
506 }
507 else if( type == OMAP_DCE_VIDENC2 ) {
508 for( i = 0; i < DIM(c->encode_codec); i++ ) {
509 if( c->encode_codec[i] == (VIDENC2_Handle) codec ) {
510 c->encode_codec[i] = NULL;
511 DEBUG("unregistered encode_codec[%d] type Encoder codec=%p", i, codec);
512 break;
513 }
514 }
515 }
516 }
517 }
519 /*
520 * Engine_open:
521 */
522 static Int32 engine_open(UInt32 size, UInt32 *data)
523 {
524 MmType_Param *payload = (MmType_Param *)data;
525 dce_engine_open *engine_open_msg = (dce_engine_open *)payload[0].data;
526 Uint32 mm_serv_id = 0;
527 Engine_Handle eng_handle = NULL;
528 Uint32 num_params = MmRpc_NUM_PARAMETERS(size);
529 Int32 ret = 0;
531 DEBUG(">> engine_open");
533 if( num_params != 1 ) {
534 ERROR("Invalid number of params sent");
535 return (-1);
536 }
538 dce_inv(engine_open_msg);
540 eng_handle = Engine_open(engine_open_msg->name, engine_open_msg->engine_attrs, &engine_open_msg->error_code);
541 DEBUG("<< engine=%08x, ec=%d", eng_handle, engine_open_msg->error_code);
543 mm_serv_id = MmServiceMgr_getId();
544 DEBUG("engine_open mm_serv_id 0x%x", mm_serv_id);
546 ret = dce_register_engine(mm_serv_id, eng_handle);
547 if( ret < 0 ) {
548 Engine_close(eng_handle);
549 eng_handle = NULL;
550 }
551 dce_clean(engine_open_msg);
553 return ((Int32)eng_handle);
554 }
556 /*
557 * Engine_close:
558 */
559 static Int32 engine_close(UInt32 size, UInt32 *data)
560 {
561 MmType_Param *payload = (MmType_Param *)data;
562 Engine_Handle eng_handle = (Engine_Handle)payload[0].data;
563 Uint32 mm_serv_id = 0;
564 Uint32 num_params = MmRpc_NUM_PARAMETERS(size);
566 if( num_params != 1 ) {
567 ERROR("invalid number of params sent");
568 return (-1);
569 }
571 mm_serv_id = MmServiceMgr_getId();
572 DEBUG("engine_close mm_serv_id 0x%x", mm_serv_id);
574 dce_unregister_engine(mm_serv_id, eng_handle);
576 Engine_close(eng_handle);
577 DEBUG("<<");
579 return (0);
580 }
582 /*
583 * codec_create
584 */
585 static Int32 codec_create(UInt32 size, UInt32 *data)
586 {
587 MmType_Param *payload = (MmType_Param *)data;
588 Uint32 codec_id = (Uint32)payload[0].data;
589 Engine_Handle engine = (Engine_Handle)payload[1].data;
590 char *codec_name = (char *)payload[2].data;
591 void *static_params = (void *)payload[3].data;
592 Uint32 mm_serv_id = 0;
593 Uint32 num_params = MmRpc_NUM_PARAMETERS(size);
594 void *codec_handle;
595 Int32 ret = 0;
597 #ifdef MEMORYSTATS_DEBUG
598 Memory_Stats stats;
599 #endif
600 DEBUG(">> codec_create");
602 if( num_params != 4 ) {
603 ERROR("invalid number of params sent");
604 return (-1);
605 }
607 dce_inv(codec_name);
608 dce_inv(static_params);
610 /* The next source code statement shouldn't get executed in real world as the client should send */
611 /* the correct width and height for the video resolution to be decoded. */
612 /* It is coded to test the Error Recovery when IPUMM on IPU2 is crashing */
613 /* by simulating the condition where A15 will send maxHeight as zero */
614 if( ((VIDDEC3_Params*)static_params)->maxHeight == 0 ) {
615 DEBUG("IPC RECOVERY will be performed due to maxHeight is zero which will cause exception!!!!");
616 num_params = num_params / ((VIDDEC3_Params*)static_params)->maxHeight;
617 System_printf("Crashing the IPU2 after divided by zero num_params %d", num_params);
618 }
620 ivahd_acquire();
622 codec_handle = (void *)codec_fxns[codec_id].create(engine, codec_name, static_params);
623 ivahd_release();
625 mm_serv_id = MmServiceMgr_getId();
626 DEBUG("codec_create mm_serv_id 0x%x", mm_serv_id);
628 ret = dce_register_codec(codec_id, mm_serv_id, (Uint32) codec_handle);
629 if( ret < 0 ) {
630 codec_fxns[codec_id].delete((void *)codec_handle);
631 codec_handle = NULL;
632 }
634 DEBUG("<< codec_handle=%08x", codec_handle);
636 dce_clean(static_params);
637 dce_clean(codec_name);
639 #ifdef MEMORYSTATS_DEBUG
640 Memory_getStats(NULL, &stats);
641 INFO("Total: %d\tFree: %d\tLargest: %d", stats.totalSize,
642 stats.totalFreeSize, stats.largestFreeSize);
643 #endif
644 #ifdef PSI_KPI
645 kpi_comp_init(codec_handle);
646 #endif /*PSI_KPI*/
647 return ((Int32)codec_handle);
648 }
650 /*
651 * codec_control
652 */
653 static int codec_control(UInt32 size, UInt32 *data)
654 {
655 MmType_Param *payload = (MmType_Param *)data;
656 Uint32 codec_id = (Uint32)payload[0].data;
657 void *codec_handle = (Engine_Handle)payload[1].data;
658 uint32_t cmd_id = (Uint32)payload[2].data;
659 void *dyn_params = (void *)payload[3].data;
660 void *status = (void *)payload[4].data;
661 Uint32 num_params = MmRpc_NUM_PARAMETERS(size);
662 Int32 ret = 0;
665 DEBUG(">> codec_control");
667 if( num_params != 5 ) {
668 ERROR("invalid number of params sent");
669 return (-1);
670 }
672 dce_inv(dyn_params);
673 dce_inv(status);
675 /* Only for cmd_id == XDM_FLUSH/XDM_MOVEBUF ? */
676 ivahd_acquire();
678 ret = (uint32_t) codec_fxns[codec_id].control(codec_handle, cmd_id, dyn_params, status);
679 ivahd_release();
681 DEBUG("<< result=%d", ret);
683 dce_clean(dyn_params);
684 dce_clean(status);
686 return (ret);
687 }
689 /*
690 * codec get version
691 */
692 static int codec_get_version(UInt32 size, UInt32 *data)
693 {
694 MmType_Param *payload = (MmType_Param *)data;
695 Uint32 codec_id = (Uint32)payload[0].data;
696 void *codec_handle = (Engine_Handle)payload[1].data;
697 void *dyn_params = (void *)payload[2].data;
698 void *status = (void *)payload[3].data;
699 Uint32 num_params = MmRpc_NUM_PARAMETERS(size);
700 void *version_buf = NULL;
701 Int32 ret = 0;
703 DEBUG(">> codec_get_version");
705 if( num_params != 4 ) {
706 ERROR("invalid number of params sent");
707 return (-1);
708 }
709 if( codec_id == OMAP_DCE_VIDDEC3 ) {
710 version_buf = (void *)(H2P((MemHeader *)((IVIDDEC3_Status *)status)->data.buf));
711 } else if( codec_id == OMAP_DCE_VIDENC2 ) {
712 version_buf = (void *)(H2P((MemHeader *)((IVIDENC2_Status *)status)->data.buf));
713 }
715 dce_inv(dyn_params);
716 dce_inv(status);
717 dce_inv(version_buf);
719 ivahd_acquire();
720 ret = (uint32_t) codec_fxns[codec_id].control(codec_handle, XDM_GETVERSION, dyn_params, status);
721 ivahd_release();
723 DEBUG("<< result=%d", ret);
725 dce_clean(dyn_params);
726 dce_clean(status);
727 dce_clean(version_buf);
729 return (ret);
730 }
732 /* Notes about serialization of process command:
733 *
734 * Since codec_process code on kernel side is doing buffer mapping/unmapping,
735 * and keeping track of codec's locked buffers, it is necessary for it to
736 * look into the contents of some of the parameter structs, and in some cases
737 * re-write them. For this reason inArgs/outBufs/inBufs are serialized within
738 * the rpmsg rather than just passed by pointer.
740 XDAS_Int32 VIDDEC3_process(VIDDEC3_Handle handle, XDM2_BufDesc *inBufs,
741 XDM2_BufDesc *outBufs, VIDDEC3_InArgs *inArgs, VIDDEC3_OutArgs *outArgs);
743 REQ:
744 struct dce_rpc_hdr hdr -> 4
745 codec_id -> 4
746 codec -> 4
747 reloc length -> 1 (length/4)
748 inArgs length -> 1 (length/4)
749 outBufs length -> 1 (length/4)
750 inBufs length -> 1 (length/4)
751 VIDDEC3_OutArgs *outArgs -> 4 (pass by pointer)
752 reloc table -> 12 * nreloc (typically <= 16)
753 VIDDEC3_InArgs inArgs -> 12 (need inputID from userspace)
754 XDM2_BufDesc outBufs -> 44 (4 + 2 * 20)
755 XDM2_BufDesc inBufs -> 24 (4 + 1 * 20)
756 -------------------------------
757 99
759 RSP
760 struct dce_rpc_hdr hdr -> 4
761 result -> 4
762 inBufs length -> 1 (length/4)
763 XDAS_Int32 freeBufID[] -> 4*n (n typically 0 or 2, but could be up to 20)
764 -------------------------------
765 9-89
766 Note: freeBufID[] duplicates what is returned in outArgs, but avoids
767 needing to create kernel mappings of these objects which are to big
768 to copy inline. Also it avoids differences between VIDDEC3/VIDDENC2.
771 XDAS_Int32 VIDENC2_process(VIDENC2_Handle handle, IVIDEO2_BufDesc *inBufs,
772 XDM2_BufDesc *outBufs, IVIDENC2_InArgs *inArgs, IVIDENC2_OutArgs *outArgs);
774 REQ:
775 struct dce_rpc_hdr hdr -> 4
776 codec_id -> 4
777 codec -> 4
778 reloc length -> 1 (length/4)
779 inArgs length -> 1 (length/4)
780 outBufs length -> 1 (length/4)
781 inBufs length -> 1 (length/4)
782 VIDENC2_OutArgs *outArgs -> 4 (pass by pointer)
783 reloc table -> ???
784 VIDENC2_InArgs inArgs -> 12 (need inputID from userspace)
785 XDM2_BufDesc outBufs -> 24 (4 + 1 * 20)
786 IVIDEO2_BufDesc inBufs -> 252
787 -------------------------------
788 307
790 RSP
791 struct dce_rpc_hdr hdr -> 4
792 result -> 4
793 inBufs length -> 1 (length/4)
794 XDAS_Int32 freeBufID[] -> 4*n (n typically 0 or 2, but could be up to 20)
795 -------------------------------
796 9-89
797 */
799 static int codec_process(UInt32 size, UInt32 *data)
800 {
801 MmType_Param *payload = (MmType_Param *)data;
802 Uint32 num_params = MmRpc_NUM_PARAMETERS(size);
803 Uint32 codec_id = (Uint32) payload[0].data;
804 Uint32 codec = (Uint32) payload[1].data;
805 void *inBufs = (void *) payload[2].data;
806 void *outBufs = (void *) payload[3].data;
807 void *inArgs = (void *) payload[4].data;
808 void *outArgs = (void *) payload[5].data;
809 Int32 ret = 0;
811 DEBUG(">> codec_process");
813 if( num_params != 6 ) {
814 ERROR("invalid number of params sent");
815 return (-1);
816 }
818 dce_inv(inBufs);
819 dce_inv(outBufs);
820 dce_inv(inArgs);
821 dce_inv(outArgs);
824 DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p codec_id=%d",
825 codec, inBufs, outBufs, inArgs, outArgs, codec_id);
827 #ifdef PSI_KPI
828 kpi_before_codec();
829 #endif /*PSI_KPI*/
830 ivahd_acquire();
831 // do a reloc()
832 ret = codec_fxns[codec_id].process((void *)codec, inBufs, outBufs, inArgs, outArgs);
834 ivahd_release();
836 #ifdef PSI_KPI
837 kpi_after_codec();
838 #endif /*PSI_KPI*/
839 DEBUG("<< ret=%d extendedError=%08x", ret, ((VIDDEC3_OutArgs *)outArgs)->extendedError);
841 dce_clean(inBufs);
842 dce_clean(outBufs);
843 dce_clean(inArgs);
844 dce_clean(outArgs);
846 return ((Int32)ret);
847 }
849 /*
850 * codec delete
851 */
853 static int codec_delete(UInt32 size, UInt32 *data)
854 {
855 MmType_Param *payload = (MmType_Param *)data;
856 Uint32 num_params = MmRpc_NUM_PARAMETERS(size);
857 Uint32 codec_id = (Uint32) payload[0].data;
858 Uint32 codec = (Uint32) payload[1].data;
859 Uint32 mm_serv_id = 0;
861 #ifdef MEMORYSTATS_DEBUG
862 Memory_Stats stats;
863 #endif
865 DEBUG(">> codec_delete");
867 if( num_params != 2 ) {
868 ERROR("invalid number of params sent");
869 return (-1);
870 }
872 codec_fxns[codec_id].delete((void *)codec);
874 mm_serv_id = MmServiceMgr_getId();
875 DEBUG("codec_delete mm_serv_id 0x%x", mm_serv_id);
876 dce_unregister_codec(codec_id, mm_serv_id, codec);
878 #ifdef MEMORYSTATS_DEBUG
879 Memory_getStats(NULL, &stats);
880 INFO("Total: %d\tFree: %d\tLargest: %d", stats.totalSize,
881 stats.totalFreeSize, stats.largestFreeSize);
882 #endif
884 DEBUG("<<");
886 #ifdef PSI_KPI
887 kpi_comp_deinit((void*)codec);
888 #endif /*PSI_KPI*/
889 return (0);
890 }
892 /* the server create parameters, must be in persistent memory */
893 static RcmServer_Params rpc_Params;
895 /* DCE Server skel function array */
896 static RcmServer_FxnDesc DCEServerFxnAry[] =
897 {
898 { "engine_open", (RcmServer_MsgFxn) engine_open },
899 { "engine_close", (RcmServer_MsgFxn) engine_close },
900 { "codec_create", (RcmServer_MsgFxn) codec_create },
901 { "codec_control", (RcmServer_MsgFxn) codec_control },
902 { "codec_get_version", (RcmServer_MsgFxn) codec_get_version },
903 { "codec_process", (RcmServer_MsgFxn) codec_process },
904 { "codec_delete", (RcmServer_MsgFxn) codec_delete }
905 };
907 /* DCE Server skel function table */
908 #define DCEServerFxnAryLen (sizeof(DCEServerFxnAry) / sizeof(DCEServerFxnAry[0]))
910 static const RcmServer_FxnDescAry DCEServer_fxnTab =
911 {
912 DCEServerFxnAryLen,
913 DCEServerFxnAry
914 };
916 static MmType_FxnSig DCEServer_sigAry[] =
917 {
918 { "engine_open", 2,
919 {
920 { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
921 { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
922 } },
923 { "engine_close", 2,
924 {
925 { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
926 { MmType_Dir_In, MmType_Param_U32, 1 }
927 } },
928 { "codec_create", 5,
929 {
930 { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
931 { MmType_Dir_In, MmType_Param_U32, 1 },
932 { MmType_Dir_In, MmType_Param_U32, 1 },
933 { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 },
934 { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 }
935 } },
936 { "codec_control", 6,
937 {
938 { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
939 { MmType_Dir_In, MmType_Param_U32, 1 },
940 { MmType_Dir_In, MmType_Param_U32, 1 },
941 { MmType_Dir_In, MmType_Param_U32, 1 },
942 { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 },
943 { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
944 } },
945 { "codec_get_version", 5,
946 {
947 { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
948 { MmType_Dir_In, MmType_Param_U32, 1 },
949 { MmType_Dir_In, MmType_Param_U32, 1 },
950 { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 },
951 { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
952 } },
953 { "codec_process", 7,
954 {
955 { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
956 { MmType_Dir_In, MmType_Param_U32, 1 },
957 { MmType_Dir_In, MmType_Param_U32, 1 },
958 { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 },
959 { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 },
960 { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 },
961 { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
962 } },
963 { "codec_delete", 3,
964 {
965 { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
966 { MmType_Dir_In, MmType_Param_U32, 1 },
967 { MmType_Dir_In, MmType_Param_U32, 1 }
968 } }
969 };
971 static MmType_FxnSigTab dce_fxnSigTab =
972 {
973 MmType_NumElem(DCEServer_sigAry), DCEServer_sigAry
974 };
976 Void dce_SrvDelNotification(Void)
977 {
978 Client *c;
979 int i;
980 uint32_t mm_serv_id = 0;
982 DEBUG("dce_SrvDelNotification: cleanup existing codec and engine\n");
984 mm_serv_id = MmServiceMgr_getId();
985 DEBUG("cleanup: mm_serv_id=0x%x", mm_serv_id);
987 c = get_client(mm_serv_id);
988 if( c ) {
989 DEBUG("cleanup: mm_serv_id=0x%x c=%p c->refs=%d", mm_serv_id, c, c->refs);
991 /* Make sure IVAHD and SL2 are idle before proceeding */
992 ivahd_idle_check();
994 /* delete all codecs first */
995 for( i = 0; i < DIM(c->decode_codec); i++ ) {
996 if( c->decode_codec[i] ) {
997 // Do we need to check if IVAHD is used or not before deleting the codec?
998 DEBUG("dce_SrvDelNotification: delete decoder codec handle 0x%x\n", c->decode_codec[i]);
999 codec_fxns[OMAP_DCE_VIDDEC3].delete((void *)c->decode_codec[i]);
1000 c->decode_codec[i] = NULL;
1001 }
1002 }
1004 for( i = 0; i < DIM(c->encode_codec); i++ ) {
1005 if( c->encode_codec[i] ) {
1006 DEBUG("dce_SrvDelNotification: delete encoder codec handle 0x%x\n", c->encode_codec[i]);
1007 codec_fxns[OMAP_DCE_VIDENC2].delete((void *)c->encode_codec[i]);
1008 c->encode_codec[i] = NULL;
1009 }
1010 }
1012 /* and lastly close all engines */
1013 for( i = 0; i < DIM(c->engines); i++ ) {
1014 if( c->engines[i] ) {
1015 DEBUG("dce_SrvDelNotification: delete Engine handle 0x%x\n", c->engines[i]);
1016 Engine_close(c->engines[i]);
1017 c->engines[i] = NULL;
1018 DEBUG("dce_SrvDelNotification engine_close: %p refs=%d", c, c->refs);
1019 c->refs--;
1020 }
1021 }
1023 if( !c->refs ) {
1024 c->mm_serv_id = NULL;
1025 }
1026 }
1027 DEBUG("dce_SrvDelNotification: COMPLETE exit function \n");
1028 }
1030 static void dce_main(uint32_t arg0, uint32_t arg1)
1031 {
1032 int err = 0;
1033 dce_connect dce_connect_msg;
1035 /* Read the register for ID_CODE to figure out the correct configuration: */
1036 /* CONTROL_STD_FUSE_ID_CODE[31:0] ID_CODE STD_FUSE_IDCODE */
1037 /* physical address: 0x4A00 2204 Address offset: 0x204 */
1038 #ifdef OMAP5430_ES10
1039 dce_connect_msg.chipset_id = 0x5430;
1040 #elif OMAP5432_ES20
1041 dce_connect_msg.chipset_id = 0x5432;
1042 #elif VAYU_ES10
1043 dce_connect_msg.chipset_id = 0x5436;
1044 #endif
1045 dce_connect_msg.debug = dce_debug;
1046 connect(&dce_connect_msg);
1048 err = MmServiceMgr_init(); // MmServiceMgr_init() will always return MmServiceMgr_S_SUCCESS.
1050 // setup the RCM Server create params
1051 RcmServer_Params_init(&rpc_Params);
1052 rpc_Params.priority = Thread_Priority_ABOVE_NORMAL;
1053 rpc_Params.stackSize = 0x1000;
1054 rpc_Params.fxns.length = DCEServer_fxnTab.length;
1055 rpc_Params.fxns.elem = DCEServer_fxnTab.elem;
1057 DEBUG("REGISTER %s\n", SERVER_NAME);
1059 // Get the Service Manager handle
1060 err = MmServiceMgr_register(SERVER_NAME, &rpc_Params, &dce_fxnSigTab, dce_SrvDelNotification);
1061 if( err < 0 ) {
1062 DEBUG("failed to start " SERVER_NAME " \n");
1063 //err = -1;
1064 } else {
1065 DEBUG(SERVER_NAME " running through MmServiceMgr");
1066 }
1068 MmServiceMgr_exit();
1070 DEBUG("deleted " SERVER_NAME);
1072 return;
1073 }
1075 /*
1076 * dce init : Startup Function
1077 */
1078 Bool dce_init(void)
1079 {
1080 Task_Params params;
1082 INFO("Creating DCE server thread...");
1085 /* Create DCE task. */
1086 Task_Params_init(¶ms);
1087 params.instance->name = "dce-server";
1088 params.priority = Thread_Priority_ABOVE_NORMAL;
1089 Task_create(dce_main, ¶ms, NULL);
1091 return (TRUE);
1092 }
1094 /*
1095 * dce deinit
1096 */
1098 void dce_deinit(void)
1099 {
1100 DEBUG("dce_deinit");
1101 }