Handling when MPU crashes, eg. CTRL-C on MPU side.
[ivimm/ipumm.git] / src / ti / framework / dce / dce.c
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/fc/global/FCSettings.h>
48 #include <ti/sdo/fc/utils/fcutils.h>
49 #include <ti/sysbios/BIOS.h>
50 #include <ti/sysbios/hal/Cache.h>
51 #include <ti/sysbios/knl/Task.h>
52 #include <ti/sysbios/knl/Semaphore.h>
53 #include <ti/sysbios/posix/pthread.h>
54 #include <xdc/cfg/global.h>
55 #include <xdc/runtime/System.h>
56 #include <xdc/runtime/Diags.h>
57 #include <xdc/runtime/Memory.h>
58 #include <xdc/runtime/IHeap.h>
59 #include <xdc/runtime/knl/Thread.h>
60 #include <xdc/std.h>
62 #include "dce_priv.h"
63 #include "dce_rpc.h"
64 #include "ti/utils/profile.h"
66 static uint32_t    suspend_initialised = 0;
67 uint32_t           dce_debug = DCE_DEBUG_LEVEL;
69 #define SERVER_NAME "rpmsg-dce"
70 #define CALLBACK_SERVER_NAME "dce-callback"
72 #define MEMORYSTATS_DEBUG
73 /* Each client is based on a unique id from MmServiceMgr which is the connect identity */
74 /*   created by IPC per MmRpc_create instances                                         */
75 #define NUM_CLIENTS 10
76 /* Each client can have NUM_INSTANCE of ENGINE, DECODE_CODEC, and ENCODE_CODEC handle */
77 /* Commonly one ENGINE is associated with one DECODE_CODEC or one ENCODE_CODEC handle */
78 #define NUM_INSTANCE 5
80 #define MmRpc_NUM_PARAMETERS(size) \
81     (size / sizeof(MmType_Param))
83 /* dce_inv, dce_clean needs to be modified to expect buffers */
84 /* without headers (relevant for GLP)                        */
85 static void dce_inv(void *ptr)
86 {
87     if( ptr ) {
88         Cache_inv(ptr, P2H(ptr)->size, Cache_Type_ALL, TRUE);
89     }
90 }
92 static void dce_clean(void *ptr)
93 {
94     if( ptr ) {
95         Cache_wbInv(ptr, P2H(ptr)->size, Cache_Type_ALL, TRUE);
96     }
97 }
99 typedef void * (*CreateFxn)(Engine_Handle, String, void *);
100 typedef Int32 (*ControlFxn)(void *, int, void *, void *);
101 typedef Int32 (*ProcessFxn)(void *, void *, void *, void *, void *);
102 typedef Int32 (*RelocFxn)(void *, uint8_t *ptr, uint32_t len);
103 typedef void (*DeleteFxn)(void *);
105 /* DCE Server static function declarations */
106 static Int32 engine_open(UInt32 size, UInt32 *data);
107 static Int32 engine_close(UInt32 size, UInt32 *data);
109 /* Encoder Server static function declarations */
110 static VIDENC2_Handle videnc2_create(Engine_Handle engine, String name, VIDENC2_Params *params);
111 static XDAS_Int32 videnc2_control(VIDENC2_Handle codec, VIDENC2_Cmd id, VIDENC2_DynamicParams *dynParams, VIDENC2_Status *status);
112 static int videnc2_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len);
114 /* Decoder Server static function declarations */
115 static VIDDEC3_Handle viddec3_create(Engine_Handle engine, String name, VIDDEC3_Params *params);
116 static XDAS_Int32 viddec3_control(VIDDEC3_Handle codec,VIDDEC3_Cmd id,VIDDEC3_DynamicParams * dynParams,VIDDEC3_Status * status);
117 static int viddec3_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len);
119 static pthread_mutex_t sync_process_mutex;
121 typedef struct {
122     XDM_DataSyncHandle dataSyncHandle;
123     XDM_DataSyncDesc *dataSyncDesc;
124     pthread_mutex_t callback_mutex;
125     pthread_cond_t synch_callback;
126     Uint32 row_mode;
127     Uint32 getdata_ready;
128     Uint32 codec_request;
129     Uint32 putdata_ready;
130     Uint32 mpu_crash_indication;
131 } Callback_data;
133 typedef struct {
134     Uint32 mm_serv_id;  /* value of zero means unused */
135     Int refs;           /* reference count on number of engine */
136     Engine_Handle engines[NUM_INSTANCE];
137     VIDDEC3_Handle decode_codec[NUM_INSTANCE];
138     VIDENC2_Handle encode_codec[NUM_INSTANCE];
139     Uint32 codec_id;
140     Callback_data decode_callback[NUM_INSTANCE];
141     Callback_data encode_callback[NUM_INSTANCE];
142 } Client;
143 static Client clients[NUM_CLIENTS] = {0};
145 static inline Client * get_client(Uint32 mm_serv_id)
147     int i;
148     for (i = 0; i < DIM(clients); i++) {
149         if (clients[i].mm_serv_id == mm_serv_id) {
150             return &clients[i];
151         }
152     }
153     return NULL;
156 static inline Client * get_client_instance(Uint32 codec)
158     int i, j;
160     for (i = 0; i < DIM(clients); i++) {
161         for (j = 0; j < DIM(clients[i].decode_codec); j++) {
162             if (clients[i].decode_codec[j] == (VIDDEC3_Handle) codec) {
163                 DEBUG("Found VIDDEC3 clients[%d] = 0x%x, &clients[%d] = 0x%x", i, clients[i], i, &clients[i]);
164                 return &clients[i];
165             }
166             if (clients[i].encode_codec[j] == (VIDENC2_Handle) codec) {
167                 DEBUG("Found VIDENC2 clients[%d] = 0x%x, &clients[%d] = 0x%x", i, clients[i], i, &clients[i]);
168                 return &clients[i];
169             }
170         }
171     }
172     return NULL;
175 static struct {
176     CreateFxn  create;
177     ControlFxn control;
178     ProcessFxn process;
179     DeleteFxn  delete;
180     RelocFxn   reloc;   /* handle buffer relocation table */
181 } codec_fxns[] =
183     [OMAP_DCE_VIDENC2] =
184     {
185         (CreateFxn)videnc2_create,   (ControlFxn)videnc2_control,
186         (ProcessFxn)VIDENC2_process, (DeleteFxn)VIDENC2_delete,
187         (RelocFxn)videnc2_reloc,
188     },
189     [OMAP_DCE_VIDDEC3] =
190     {
191         (CreateFxn)viddec3_create,   (ControlFxn)viddec3_control,
192         (ProcessFxn)VIDDEC3_process, (DeleteFxn)VIDDEC3_delete,
193         (RelocFxn)viddec3_reloc,
194     },
195 };
198 /* Static version string buffer.
199  * Note: codec version can be large. For example, h264vdec needs more than
200  * 58 characters, or the query will fail. */
201 #define VERSION_SIZE 128
202 static char    version_buffer[VERSION_SIZE];
204 /* the following callbacks are needed for suspend/resume
205  * on the linux side.
206  * - FC_suspend() waits for all algorithms to get deactivated and
207  * and takes care of the resources acquired.
208  * - FC_resume() does nothing for now, but we add it just in case
209  * it gets populated in the future versions of framework components.
210  *
211  * Forced off mode during video decode/encode is not supported. */
212 static void dce_suspend()
214     INFO("Preparing for suspend...");
215     FC_suspend();
218 static void dce_resume()
220     INFO("Restoring after suspend...");
221     FC_resume();
224 static void get_videnc2_version(VIDENC2_Handle h, char *buffer, unsigned size)
226     VIDENC2_DynamicParams    params =
227     {
228         .size = sizeof(VIDENC2_DynamicParams),
229     };
231     VIDENC2_Status    status =
232     {
233         .size = sizeof(VIDENC2_Status),
234         .data =
235         {
236             .buf = (XDAS_Int8 *)buffer,
237             .bufSize = (XDAS_Int32)size,
238         },
239     };
241     XDAS_Int32    s;
243     memset(buffer, 0, size);
244     s = VIDENC2_control(h, XDM_GETVERSION, &params, &status);
246     if( s != VIDENC2_EOK ) {
247         ERROR("Unknown version Error = %d:: buffer = %p size = %d", s, buffer, size);
248     }
251 // VIDENC2_create wrapper, to display version string in the trace.
252 static VIDENC2_Handle videnc2_create(Engine_Handle engine, String name, VIDENC2_Params *params)
254     VIDENC2_Handle    h;
256     h = VIDENC2_create(engine, name, params);
258     if( h ) {
259         get_videnc2_version(h, version_buffer, VERSION_SIZE);
260         INFO("Created videnc2 %s: version %s", name, version_buffer);
261     }
263     return (h);
266 static XDAS_Int32 getBufferFxnStub(XDM_DataSyncHandle handle, XDM_DataSyncDesc *desc)
268     return (0);
271 static XDAS_Int32 videnc2_control(VIDENC2_Handle codec, VIDENC2_Cmd id,
272                                   VIDENC2_DynamicParams *dynParams, VIDENC2_Status *status)
274     Client* c;
276     c = get_client_instance((Uint32) codec);
277     if (c) {
278         int i;
279         for (i = 0; i < DIM(c->encode_codec); i++) {
280             if (c->encode_codec[i] == codec) {
281                 if (c->encode_callback[i].row_mode) {
282                     c->encode_callback[i].dataSyncHandle = codec;
283                     c->encode_callback[i].mpu_crash_indication = FALSE;
284                     dynParams->getDataFxn = (XDM_DataSyncGetFxn) H264E_GetDataFxn;
285                     dynParams->getDataHandle = codec;
286                 }
287             }
288         }
289     }
291     dynParams->getBufferFxn = getBufferFxnStub;
292     return (VIDENC2_control(codec, id, dynParams, status));
295 static void get_viddec3_version(VIDDEC3_Handle h, char *buffer, unsigned size)
297     VIDDEC3_DynamicParams    params =
298     {
299         .size = sizeof(VIDDEC3_DynamicParams),
300     };
302     VIDDEC3_Status    status =
303     {
304         .size = sizeof(VIDDEC3_Status),
305         .data =
306         {
307             .buf = (XDAS_Int8 *)buffer,
308             .bufSize = (XDAS_Int32)size,
309         },
310     };
312     XDAS_Int32    s;
314     memset(buffer, 0, size);
315     s = VIDDEC3_control(h, XDM_GETVERSION, &params, &status);
317     if( s != VIDDEC3_EOK ) {
318         ERROR("Unknown version Error = %d:: buffer = %p size = %d", s, buffer, size);
319     }
322 // VIDDEC3_create wrapper, to display version string in the trace.
323 static VIDDEC3_Handle viddec3_create(Engine_Handle engine, String name, VIDDEC3_Params *params)
325     VIDDEC3_Handle    h;
327     DEBUG(">> engine=%08x, name=%s, params=%p", engine, name, params);
328     DEBUG(">> max_height %d max_width %d frame_rate %d", params->maxHeight, params->maxWidth, params->maxFrameRate);
330     h = VIDDEC3_create(engine, name, params);
332     if( h ) {
333         get_viddec3_version(h, version_buffer, VERSION_SIZE);
334         INFO("Created viddec3 %s: version %s", name, version_buffer);
335     }
337     return (h);
340 static XDAS_Int32 viddec3_control(VIDDEC3_Handle codec,VIDDEC3_Cmd id,VIDDEC3_DynamicParams * dynParams,VIDDEC3_Status * status)
342     Client* c;
344     c = get_client_instance((Uint32) codec);
345     if (c) {
346         int i;
347         for (i = 0; i < DIM(c->decode_codec); i++) {
348             if (c->decode_codec[i] == codec) {
349                 if (c->decode_callback[i].row_mode) {
350                     DEBUG("Check codec 0x%x", codec);
351                     c->decode_callback[i].dataSyncHandle = codec;
352                     c->decode_callback[i].mpu_crash_indication = FALSE;
353                     dynParams->putDataFxn = (XDM_DataSyncPutFxn) H264D_PutDataFxn;
354                     dynParams->putDataHandle = codec;
355                 }
356             }
357         }
358     }
360     //dynParams->putBufferFxn = putBufferFxnStub;
361     return (VIDDEC3_control(codec, id, dynParams, status));
364 static int videnc2_reloc(VIDENC2_Handle handle, uint8_t *ptr, uint32_t len)
366     return (-1); // Not implemented
369 /* Only valid if XDM_MOVEBUFS added in XDC tools */
370 static int viddec3_reloc(VIDDEC3_Handle handle, uint8_t *ptr, uint32_t len)
372     return (-1); // Not implemented
373 #if 0
374     static VIDDEC3_DynamicParams    params =
375     {
376         .size = sizeof(VIDDEC3_DynamicParams),
377     };
378     VIDDEC3_Status    status =
379     {
380         .size = sizeof(VIDDEC3_Status),
381         .data =
382         {
383             .buf = (XDAS_Int8 *)ptr,
384             .bufSize = (XDAS_Int32)len,
385         },
386     };
387     INFO("status.size=%d", status.size);
388     return (VIDDEC3_control(handle, XDM_MOVEBUFS, &params, &status));
389 #endif
392 /*
393  * RPC message handlers
394  */
395 static int connect(void *msg)
397     dce_connect   *req = msg;
399     DEBUG(">> chipset_id=0x%x, debug=%d", req->chipset_id, req->debug);
401     if( dce_debug >= MAX_DEBUG_LEVEL ) {
402         DEBUG("Enable FC, CE and IPC traces");
404         FCSettings_init();
405         Diags_setMask(FCSETTINGS_MODNAME "+12345678LEXAIZFS");
406         CESettings_init();
407         Diags_setMask(CESETTINGS_MODNAME "+12345678LEXAIZFS");
409         /*
410             * Enable use of runtime Diags_setMask per module:
411             *
412             * Codes: E = ENTRY, X = EXIT, L = LIFECYCLE, F = INFO, S = STATUS
413             */
414         Diags_setMask("ti.ipc.rpmsg.RPMessage=EXLFS");
415         Diags_setMask("ti.ipc.rpmsg.VirtQueue=EXLFS");
416     }
418     ivahd_init(req->chipset_id);
420     if( !suspend_initialised ) {
422         /* registering sysbios-rpmsg callbacks for suspend/resume */
423         IpcPower_registerCallback(IpcPower_Event_SUSPEND, (IpcPower_CallbackFuncPtr)dce_suspend, 0);
424         IpcPower_registerCallback(IpcPower_Event_RESUME, (IpcPower_CallbackFuncPtr)dce_resume, 0);
425         suspend_initialised++;
426     }
428     DEBUG("<<");
430     return (0);
433 static Int32 dce_register_engine(Uint32 mm_serv_id, Engine_Handle engine)
435     Int32  ret = 0;
436     Uint32 clientIndex = 0;
437     Client *c;
439     c = get_client(mm_serv_id);
440     if( c ) {
441         int i;
442         DEBUG("found mem client: %p refs=%d", c, c->refs);
443         c->refs++;
444         for (i = 0; i < DIM(c->engines); i++) {
445             if (c->engines[i] == NULL) {
446                 c->engines[i] = engine;
447                 clientIndex = i;
448                 DEBUG("registered engine: mm_serv_id=%x engine=%p", mm_serv_id, engine);
449                 break;
450             }
451         }
453         //If clientIndex is equal to 0 and it is not the register engine, then we know that no more
454         //empty spot since clientIndex not getting set in the for loop.
455         if( (clientIndex == 0) && (c->engines[clientIndex]) != engine ){
456             ERROR("No more empty space for engine");
457             ret = -1;
458             goto out;
459         }
460     }else {
461         c = get_client(0);
462         if (!c) {
463             ERROR("too many clients");
464             ret = -1;
465             goto out;
466         }
467         DEBUG("new client: %p refs=%d", c, c->refs);
469         c->mm_serv_id = mm_serv_id;
470         c->refs = 1;
471         c->engines[0] = engine;
472     }
473 out:
474     if ((ret != 0) && (c)){
475         c->mm_serv_id = NULL;
476         c->refs--;
477         c->engines[0] = NULL;
478     }
479     return ret;
482 static void dce_unregister_engine(Uint32 mm_serv_id, Engine_Handle engine)
484     Client *c;
486     c = get_client(mm_serv_id);
487     if( c ) {
488         int i;
489         DEBUG("found mem client: %p refs=%d", c, c->refs);
491         for( i = 0; i < DIM(c->engines); i++ ) {
492             if( c->engines[i] == engine ) {
493                 c->engines[i] = NULL;
494                 DEBUG("unregistered engine: mm_serv_id=0x%x engine=%p", mm_serv_id, engine);
495                 break;
496             }
497         }
499         //If i is equal to the size of Array, then it means it has search the whole array.
500         if( i == DIM(c->engines) ) {
501             ERROR("Unknown engine received on dce_unregister_engine");
502             return;
503         }
505         DEBUG("dce_unregister_engine: %p refs=%d", c, c->refs);
506         c->refs--;
508         if( !c->refs ) {
509             c->mm_serv_id = NULL;
510         }
511     }
514 static Int32 dce_register_codec(Uint32 type, Uint32 mm_serv_id, Uint32 codec)
516     Client *c;
517     Int32 ret = 0;
518     Uint32 clientIndex = 0;
520     c = get_client(mm_serv_id);
521     if( c ) {
522         int i;
523         DEBUG("found mem client: %p refs=%d", c, c->refs);
525         if( type == OMAP_DCE_VIDDEC3 ) {
526             for( i = 0; i < DIM(c->decode_codec); i++ ) {
527                 if( c->decode_codec[i] == NULL ) {
528                     c->decode_codec[i] = (VIDDEC3_Handle) codec;
529                     c->codec_id = type;
530                     clientIndex = i;
531                     DEBUG("registering codec: decode_codec[%d] codec=%p", i, codec);
532                     break;
533                 }
534             }
536             //If clientIndex is equal to 0 and it's not the register codec, then we know that no more
537             //empty spot since clientIndex not getting set in the for loop.
538             if( (clientIndex == 0) && (c->decode_codec[clientIndex]) != (VIDDEC3_Handle) codec ) {
539                 ERROR("No more empty space for codecs");
540                 ret = -1;
541                 goto out;
542             }
543         }
544         else if( type == OMAP_DCE_VIDENC2 ) {
545             for( i = 0; i < DIM(c->encode_codec); i++ ) {
546                 if( c->encode_codec[i] == NULL ) {
547                     c->encode_codec[i] = (VIDENC2_Handle) codec;
548                     c->codec_id = type;
549                     clientIndex = i;
550                     DEBUG("registering codec: encode_codec[%d] codec=%p", i, codec);
551                     break;
552                 }
553             }
555             //If clientIndex is equal to 0 and it's not the register codec, then we know that no more
556             //empty spot since clientIndex not getting set in the for loop.
557             if( (clientIndex == 0) && (c->encode_codec[clientIndex]) != (VIDENC2_Handle) codec ) {
558                 ERROR("No more empty space for codecs");
559                 ret = -1;
560                 goto out;
561             }
562         }
563     }
565 out:
566     return ret;
569 static void dce_unregister_codec(Uint32 type, Uint32 mm_serv_id, Uint32 codec)
571     Client *c;
573     c = get_client(mm_serv_id);
574     if (c) {
575         int i;
576         DEBUG("found mem client: %p refs=%d", c, c->refs);
578         if( type == OMAP_DCE_VIDDEC3 ) {
579             for( i = 0; i < DIM(c->decode_codec); i++ ) {
580                 if( c->decode_codec[i] == (VIDDEC3_Handle) codec ) {
581                     c->decode_codec[i] = NULL;
582                     DEBUG("unregistered decode_codec[%d] type Decoder codec=%p", i, codec);
583                     break;
584                 }
585             }
586         }
587         else if( type == OMAP_DCE_VIDENC2 ) {
588             for( i = 0; i < DIM(c->encode_codec); i++ ) {
589                 if( c->encode_codec[i] == (VIDENC2_Handle) codec ) {
590                     c->encode_codec[i] = NULL;
591                     DEBUG("unregistered encode_codec[%d] type Encoder codec=%p", i, codec);
592                     break;
593                 }
594             }
595         }
596     }
599 /*
600  * Engine_open:
601  */
602 static Int32 engine_open(UInt32 size, UInt32 *data)
604     MmType_Param      *payload = (MmType_Param *)data;
605     dce_engine_open   *engine_open_msg = (dce_engine_open *)payload[0].data;
606     Uint32             mm_serv_id = 0;
607     Engine_Handle      eng_handle = NULL;
608     Uint32             num_params = MmRpc_NUM_PARAMETERS(size);
609     Int32              ret = 0;
611     DEBUG(">> engine_open");
613     if( num_params != 1 ) {
614         ERROR("Invalid number of params sent");
615         return (-1);
616     }
618     dce_inv(engine_open_msg);
620     eng_handle = Engine_open(engine_open_msg->name, engine_open_msg->engine_attrs, &engine_open_msg->error_code);
621     DEBUG("<< engine=%08x, ec=%d", eng_handle, engine_open_msg->error_code);
623     mm_serv_id = MmServiceMgr_getId();
624     DEBUG("engine_open mm_serv_id 0x%x", mm_serv_id);
626     ret = dce_register_engine(mm_serv_id, eng_handle);
627     if( ret < 0 ) {
628         Engine_close(eng_handle);
629         eng_handle = NULL;
630     }
631     dce_clean(engine_open_msg);
633     return ((Int32)eng_handle);
636 /*
637  * Engine_close:
638  */
639 static Int32 engine_close(UInt32 size, UInt32 *data)
641     MmType_Param    *payload = (MmType_Param *)data;
642     Engine_Handle    eng_handle = (Engine_Handle)payload[0].data;
643     Uint32           mm_serv_id = 0;
644     Uint32           num_params = MmRpc_NUM_PARAMETERS(size);
646     if( num_params != 1 ) {
647         ERROR("invalid number of params sent");
648         return (-1);
649     }
651     mm_serv_id = MmServiceMgr_getId();
652     DEBUG("engine_close mm_serv_id 0x%x", mm_serv_id);
654     dce_unregister_engine(mm_serv_id, eng_handle);
656     Engine_close(eng_handle);
657     DEBUG("<<");
659     return (0);
662 /*
663   * codec_create
664   */
665 static Int32 codec_create(UInt32 size, UInt32 *data)
667     MmType_Param    *payload = (MmType_Param *)data;
668     Uint32           codec_id      = (Uint32)payload[0].data;
669     Engine_Handle    engine = (Engine_Handle)payload[1].data;
670     char            *codec_name    = (char *)payload[2].data;
671     void            *static_params = (void *)payload[3].data;
672     Uint32           mm_serv_id = 0;
673     Uint32           num_params = MmRpc_NUM_PARAMETERS(size);
674     void            *codec_handle;
675     Int32            ret = 0;
676     Client*          c;
678 #ifdef MEMORYSTATS_DEBUG
679     Memory_Stats    stats;
680 #endif
681     DEBUG(">> codec_create");
683     if( num_params != 4 ) {
684         ERROR("invalid number of params sent");
685         return (-1);
686     }
688     dce_inv(codec_name);
689     dce_inv(static_params);
691     /* The next source code statement shouldn't get executed in real world as the client should send */
692     /* the correct width and height for the video resolution to be decoded.                          */
693     /* It is coded to test the Error Recovery when IPUMM on IPU2 is crashing                         */
694     /* by simulating the condition where A15 will send maxHeight as zero                             */
695     if( ((VIDDEC3_Params*)static_params)->maxHeight == 0 ) {
696         DEBUG("IPC RECOVERY will be performed due to maxHeight is zero which will cause exception!!!!");
697         num_params = num_params / ((VIDDEC3_Params*)static_params)->maxHeight;
698         System_printf("Crashing the IPU2 after divided by zero num_params %d", num_params);
699     }
701     ivahd_acquire();
703     codec_handle = (void *)codec_fxns[codec_id].create(engine, codec_name, static_params);
704     ivahd_release();
706     mm_serv_id = MmServiceMgr_getId();
707     DEBUG("codec_create codec_handle 0x%x mm_serv_id 0x%x", codec_handle, mm_serv_id);
709     ret = dce_register_codec(codec_id, mm_serv_id, (Uint32) codec_handle);
710     if( ret < 0 ) {
711         codec_fxns[codec_id].delete((void *)codec_handle);
712         codec_handle = NULL;
713     }
715     if ( codec_id == OMAP_DCE_VIDDEC3 ) {
716         DEBUG("codec_create for VIDDEC3 codec_handle 0x%x", codec_handle);
717         if ( ((VIDDEC3_Params*)static_params)->outputDataMode == IVIDEO_NUMROWS ) {
718             c = get_client_instance((Uint32) codec_handle);
719             int i;
720             for (i = 0; i < DIM(c->decode_codec); i++ ) {
721                 if (c->decode_codec[i] == codec_handle) {
722                     c->decode_callback[i].row_mode = 1;
723                     pthread_mutex_init(&(c->decode_callback[i].callback_mutex), NULL);
724                     pthread_cond_init(&(c->decode_callback[i].synch_callback), NULL);
725                     DEBUG("codec_create client 0x%x c->decode_callback[%d].callback_mutex 0x%x c->decode_callback[%d].row_mode %d",
726                         c, i, c->decode_callback[i].callback_mutex, i, c->decode_callback[i].row_mode);
727                 }
728             }
729         }
730     } else if ( codec_id == OMAP_DCE_VIDENC2 ) {
731         DEBUG("codec_create for VIDENC2 codec_handle 0x%x", codec_handle);
732         if ( ((VIDENC2_Params*)static_params)->inputDataMode == IVIDEO_NUMROWS ) {
733             c = get_client_instance((Uint32) codec_handle);
734             int i;
735             for (i = 0; i < DIM(c->encode_codec); i++ ) {
736                 if (c->encode_codec[i] == codec_handle) {
737                     c->encode_callback[i].row_mode = 1;
738                     pthread_mutex_init(&(c->encode_callback[i].callback_mutex), NULL);
739                     pthread_cond_init(&(c->encode_callback[i].synch_callback), NULL);
740                     DEBUG("codec_create client 0x%x c->encode_callback[%d].callback_mutex 0x%x c->encode_callback[%d].row_mode %d",
741                         c, i, c->encode_callback[i].callback_mutex, i, c->encode_callback[i].row_mode);
742                 }
743             }
744         }
745     }
747     DEBUG("<< codec_handle=%08x", codec_handle);
749     dce_clean(static_params);
750     dce_clean(codec_name);
752 #ifdef MEMORYSTATS_DEBUG
753     Memory_getStats(NULL, &stats);
754     INFO("Total: %d\tFree: %d\tLargest: %d", stats.totalSize,
755          stats.totalFreeSize, stats.largestFreeSize);
756 #endif
757 #ifdef PSI_KPI
758         kpi_comp_init(codec_handle);
759 #endif /*PSI_KPI*/
760     return ((Int32)codec_handle);
763 /*
764   * codec_control
765   */
766 static int codec_control(UInt32 size, UInt32 *data)
768     MmType_Param   *payload = (MmType_Param *)data;
769     Uint32          codec_id            = (Uint32)payload[0].data;
770     void           *codec_handle = (Engine_Handle)payload[1].data;
771     uint32_t        cmd_id              = (Uint32)payload[2].data;
772     void           *dyn_params          = (void *)payload[3].data;
773     void           *status              = (void *)payload[4].data;
774     Uint32          num_params = MmRpc_NUM_PARAMETERS(size);
775     Int32           ret = 0;
778     DEBUG(">> codec_control");
780     if( num_params != 5 ) {
781         ERROR("invalid number of params sent");
782         return (-1);
783     }
785     dce_inv(dyn_params);
786     dce_inv(status);
788     /* Only for cmd_id == XDM_FLUSH/XDM_MOVEBUF ? */
789     ivahd_acquire();
791     ret = (uint32_t) codec_fxns[codec_id].control(codec_handle, cmd_id, dyn_params, status);
792     ivahd_release();
794     DEBUG("<< result=%d", ret);
796     dce_clean(dyn_params);
797     dce_clean(status);
799     return (ret);
802 /*
803   * codec get version
804   */
805 static int codec_get_version(UInt32 size, UInt32 *data)
807     MmType_Param   *payload = (MmType_Param *)data;
808     Uint32          codec_id            = (Uint32)payload[0].data;
809     void           *codec_handle = (Engine_Handle)payload[1].data;
810     void           *dyn_params          = (void *)payload[2].data;
811     void           *status              = (void *)payload[3].data;
812     Uint32          num_params = MmRpc_NUM_PARAMETERS(size);
813     void           *version_buf = NULL;
814     Int32           ret = 0;
816     DEBUG(">> codec_get_version");
818     if( num_params != 4 ) {
819         ERROR("invalid number of params sent");
820         return (-1);
821     }
822     if( codec_id == OMAP_DCE_VIDDEC3 ) {
823         version_buf = (void *)(H2P((MemHeader *)((IVIDDEC3_Status *)status)->data.buf));
824     } else if( codec_id == OMAP_DCE_VIDENC2 ) {
825         version_buf = (void *)(H2P((MemHeader *)((IVIDENC2_Status *)status)->data.buf));
826     }
828     dce_inv(dyn_params);
829     dce_inv(status);
830     dce_inv(version_buf);
832     ivahd_acquire();
833     ret = (uint32_t) codec_fxns[codec_id].control(codec_handle, XDM_GETVERSION, dyn_params, status);
834     ivahd_release();
836     DEBUG("<< result=%d", ret);
838     dce_clean(dyn_params);
839     dce_clean(status);
840     dce_clean(version_buf);
842     return (ret);
845 /* Notes about serialization of process command:
846  *
847  * Since codec_process code on kernel side is doing buffer mapping/unmapping,
848  * and keeping track of codec's locked buffers, it is necessary for it to
849  * look into the contents of some of the parameter structs, and in some cases
850  * re-write them.  For this reason inArgs/outBufs/inBufs are serialized within
851  * the rpmsg rather than just passed by pointer.
853 XDAS_Int32 VIDDEC3_process(VIDDEC3_Handle handle, XDM2_BufDesc *inBufs,
854     XDM2_BufDesc *outBufs, VIDDEC3_InArgs *inArgs, VIDDEC3_OutArgs *outArgs);
856   REQ:
857     struct dce_rpc_hdr hdr   -> 4
858     codec_id                 -> 4
859     codec                    -> 4
860     reloc length             -> 1   (length/4)
861     inArgs length            -> 1   (length/4)
862     outBufs length           -> 1   (length/4)
863     inBufs length            -> 1   (length/4)
864     VIDDEC3_OutArgs *outArgs -> 4   (pass by pointer)
865     reloc table              -> 12 * nreloc (typically <= 16)
866     VIDDEC3_InArgs   inArgs  -> 12  (need inputID from userspace)
867     XDM2_BufDesc     outBufs -> 44  (4 + 2 * 20)
868     XDM2_BufDesc     inBufs  -> 24  (4 + 1 * 20)
869     -------------------------------
870                                99
872   RSP
873     struct dce_rpc_hdr hdr   -> 4
874     result                   -> 4
875     inBufs length            -> 1   (length/4)
876     XDAS_Int32 freeBufID[]   -> 4*n (n typically 0 or 2, but could be up to 20)
877     -------------------------------
878                                9-89
879     Note: freeBufID[] duplicates what is returned in outArgs, but avoids
880     needing to create kernel mappings of these objects which are to big
881     to copy inline.  Also it avoids differences between VIDDEC3/VIDDENC2.
884 XDAS_Int32 VIDENC2_process(VIDENC2_Handle handle, IVIDEO2_BufDesc *inBufs,
885     XDM2_BufDesc *outBufs, IVIDENC2_InArgs *inArgs, IVIDENC2_OutArgs *outArgs);
887   REQ:
888     struct dce_rpc_hdr hdr   -> 4
889     codec_id                 -> 4
890     codec                    -> 4
891     reloc length             -> 1   (length/4)
892     inArgs length            -> 1   (length/4)
893     outBufs length           -> 1   (length/4)
894     inBufs length            -> 1   (length/4)
895     VIDENC2_OutArgs *outArgs -> 4   (pass by pointer)
896     reloc table              -> ???
897     VIDENC2_InArgs   inArgs  -> 12  (need inputID from userspace)
898     XDM2_BufDesc     outBufs -> 24  (4 + 1 * 20)
899     IVIDEO2_BufDesc  inBufs  -> 252
900     -------------------------------
901                               307
903   RSP
904     struct dce_rpc_hdr hdr   -> 4
905     result                   -> 4
906     inBufs length            -> 1   (length/4)
907     XDAS_Int32 freeBufID[]   -> 4*n (n typically 0 or 2, but could be up to 20)
908     -------------------------------
909                                9-89
910  */
912 static int codec_process(UInt32 size, UInt32 *data)
914     MmType_Param   *payload = (MmType_Param *)data;
915     Uint32          num_params = MmRpc_NUM_PARAMETERS(size);
916     Uint32          codec_id = (Uint32) payload[0].data;
917     Uint32          codec    = (Uint32) payload[1].data;
918     void           *inBufs   = (void *) payload[2].data;
919     void           *outBufs  = (void *) payload[3].data;
920     void           *inArgs   = (void *) payload[4].data;
921     void           *outArgs  = (void *) payload[5].data;
922     Int32           ret = 0;
924     DEBUG(">> codec_process");
926     if( num_params != 6 ) {
927         ERROR("invalid number of params sent");
928         return (-1);
929     }
931     pthread_mutex_lock(&sync_process_mutex);
933     dce_inv(inBufs);
934     dce_inv(outBufs);
935     dce_inv(inArgs);
936     dce_inv(outArgs);
939     DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p codec_id=%d LOCK sync_process_mutex 0x%x",
940           codec, inBufs, outBufs, inArgs, outArgs, codec_id, sync_process_mutex);
942 #ifdef PSI_KPI
943         kpi_before_codec();
944 #endif /*PSI_KPI*/
945     ivahd_acquire();
946     // do a reloc()
947     ret = codec_fxns[codec_id].process((void *)codec, inBufs, outBufs, inArgs, outArgs);
949     ivahd_release();
951 #ifdef PSI_KPI
952         kpi_after_codec();
953 #endif /*PSI_KPI*/
954     DEBUG("<< ret=%d extendedError=%08x", ret, ((VIDDEC3_OutArgs *)outArgs)->extendedError);
956     dce_clean(inBufs);
957     dce_clean(outBufs);
958     dce_clean(inArgs);
959     dce_clean(outArgs);
961     DEBUG("codec_process codec=%p UNLOCK sync_process_mutex 0x%x", codec, sync_process_mutex);
962     pthread_mutex_unlock(&sync_process_mutex);
964     return ((Int32)ret);
967 /*
968   * codec delete
969   */
971 static int codec_delete(UInt32 size, UInt32 *data)
973     MmType_Param   *payload = (MmType_Param *)data;
974     Uint32          num_params = MmRpc_NUM_PARAMETERS(size);
975     Uint32          codec_id = (Uint32) payload[0].data;
976     Uint32          codec    = (Uint32) payload[1].data;
977     Uint32          mm_serv_id = 0;
978     Client*          c;
980 #ifdef MEMORYSTATS_DEBUG
981     Memory_Stats    stats;
982 #endif
984     DEBUG(">> codec_delete on codec 0x%x", codec);
986     if( num_params != 2 ) {
987         ERROR("invalid number of params sent");
988         return (-1);
989     }
991     if ( codec_id == OMAP_DCE_VIDDEC3 ) {
992         DEBUG("codec_delete for VIDDEC3 codec_handle 0x%x", codec);
993         c = get_client_instance((Uint32) codec);
994         int i;
995         for (i = 0; i < DIM(c->decode_codec); i++ ) {
996             if (c->decode_codec[i] == (VIDDEC3_Handle) codec) {
997                 if (c->decode_callback[i].row_mode) {
998                     c->decode_callback[i].row_mode = 0;
999                     pthread_mutex_destroy(&(c->decode_callback[i].callback_mutex));
1000                     pthread_cond_destroy(&(c->decode_callback[i].synch_callback));
1001                 }
1002                 DEBUG("codec_delete client 0x%x c->decode_callback[%d].callback_mutex 0x%x", c, i, c->decode_callback[i].callback_mutex);
1003             }
1004         }
1005     } else if ( codec_id == OMAP_DCE_VIDENC2 ) {
1006         DEBUG("codec_delete for VIDENC2 codec_handle 0x%x", codec);
1007         c = get_client_instance((Uint32) codec);
1008         int i;
1009         for (i = 0; i < DIM(c->encode_codec); i++ ) {
1010             if (c->encode_codec[i] == (VIDENC2_Handle) codec) {
1011                 if (c->encode_callback[i].row_mode) {
1012                     c->encode_callback[i].row_mode = 0;
1013                     pthread_mutex_destroy(&(c->encode_callback[i].callback_mutex));
1014                     pthread_cond_destroy(&(c->encode_callback[i].synch_callback));
1015                 }
1016                 DEBUG("codec_delete client 0x%x c->encode_callback[%d].callback_mutex 0x%x", c, i, c->encode_callback[i].callback_mutex);
1017             }
1018         }
1019     }
1021     codec_fxns[codec_id].delete((void *)codec);
1023     mm_serv_id = MmServiceMgr_getId();
1024     DEBUG("codec_delete mm_serv_id 0x%x", mm_serv_id);
1025     dce_unregister_codec(codec_id, mm_serv_id, codec);
1027 #ifdef MEMORYSTATS_DEBUG
1028     Memory_getStats(NULL, &stats);
1029     INFO("Total: %d\tFree: %d\tLargest: %d", stats.totalSize,
1030          stats.totalFreeSize, stats.largestFreeSize);
1031 #endif
1033     DEBUG("<<");
1035 #ifdef PSI_KPI
1036         kpi_comp_deinit((void*)codec);
1037 #endif /*PSI_KPI*/
1038     return (0);
1041 /*
1042  * get_DataFxn : Sync/transfer the input data information from MPU side to DCE Server.
1043  * DCE Server will pass the information through the IVA-HD callback function:
1044  * H264E_GetDataFxn.
1045  */
1046 static int get_DataFxn(UInt32 size, UInt32 *data)
1048     MmType_Param   *payload = (MmType_Param *)data;
1049     Uint32          num_params = MmRpc_NUM_PARAMETERS(size);
1050     XDM_DataSyncHandle          dataSyncHandle = (XDM_DataSyncHandle) payload[0].data;
1051     XDM_DataSyncDesc            *dataSyncDesc    = (void *) payload[1].data;
1052     Client* c;
1054     DEBUG(">> get_DataFxn dataSyncHandle 0x%x", dataSyncHandle);
1056     if( num_params != 2 ) {
1057         ERROR("invalid number of params sent");
1058         return (-1);
1059     }
1061     dce_inv(dataSyncDesc);
1063     c = get_client_instance((Uint32) dataSyncHandle);
1064     if (c) {
1065         int i;
1066         for (i = 0; i < DIM(c->encode_codec); i++) {
1067             if (c->encode_codec[i] == dataSyncHandle) {
1068                 pthread_mutex_lock(&(c->encode_callback[i].callback_mutex));
1069                 c->encode_callback[i].dataSyncHandle = dataSyncHandle;
1070                 c->encode_callback[i].dataSyncDesc = dataSyncDesc;
1072                 if (c->encode_callback[i].codec_request) {
1073                     DEBUG("Case#1 get_DataFxn is received while codec has requested first. Signal the H264E_GetDataFxn to continue.");
1074                     pthread_cond_signal(&(c->encode_callback[i].synch_callback));
1075                 } else {
1076                     // We received get_DataFxn from libdce/client, need to hold it until the data
1077                     // is consumed by codec through H264E_GetDataFxn before continuing. Otherwise
1078                     // we will receive another one since MPU side thinks that the data has been
1079                     // consumed by the codec.
1080                     c->encode_callback[i].getdata_ready = 1;
1081                     DEBUG("Case#2 get_DataFxn is received but codec has not request H264E_GetDataFxn. Wait conditionally.");
1082                     pthread_cond_wait(&(c->encode_callback[i].synch_callback), &(c->encode_callback[i].callback_mutex));
1083                     DEBUG("Case#2 get_DataFxn finally gets H264E_GetDataFxn, and the data has been consumed, continue.");
1084                     c->encode_callback[i].getdata_ready = 0;
1085                 }
1086                 pthread_mutex_unlock(&(c->encode_callback[i].callback_mutex));
1087             }
1088         }
1089     }
1091     dce_clean(dataSyncDesc);
1092     return (0);
1095 /*
1096  * put_DataFxn : Sync/transfer the output data information from DCE Server to MPU side.
1097  * DCE Server will pass the information from the IVA-HD callback function:
1098  * H264D_PutDataFxn to MPU side.
1099  */
1100 static int put_DataFxn(UInt32 size, UInt32 *data)
1102     MmType_Param   *payload = (MmType_Param *)data;
1103     Uint32          num_params = MmRpc_NUM_PARAMETERS(size);
1104     XDM_DataSyncHandle          dataSyncHandle = (XDM_DataSyncHandle) payload[0].data;
1105     XDM_DataSyncDesc            *dataSyncDesc    = (void *) payload[1].data;
1106     Client* c;
1108     DEBUG(">> put_DataFxn dataSyncHandle 0x%x dataSyncDesc 0x%x", dataSyncHandle, dataSyncDesc);
1110     if( num_params != 2 ) {
1111         ERROR("invalid number of params sent");
1112         return (-1);
1113     }
1115     dce_inv(dataSyncDesc);
1117     c = get_client_instance((Uint32) dataSyncHandle);
1118     if (c) {
1119         int i;
1120         for (i = 0; i < DIM(c->decode_codec); i++) {
1121             if (c->decode_codec[i] == dataSyncHandle) {
1122                 pthread_mutex_lock(&(c->decode_callback[i].callback_mutex));
1123                 // Found the corresponding entry, check if IVA-HD has already called the callback (codec_request == 1).
1124                 if (c->decode_callback[i].codec_request) {
1125                     DEBUG("Case#1 put_DataFxn is received while codec has requested first. c->decode_callback[%d].callback_mutex 0x%x",
1126                         i, c->decode_callback[i].callback_mutex);
1127                     DEBUG("Case#1 c->decode_callback[i].dataSyncDesc 0x%x dataSyncDesc 0x%x", c->decode_callback[i].dataSyncDesc, dataSyncDesc);
1128                     // Copy the local structure as H264D_PutDataFxn has already stored codec partial decoded data.
1129                     dataSyncDesc->size = (c->decode_callback[i].dataSyncDesc)->size;
1130                     dataSyncDesc->scatteredBlocksFlag = (c->decode_callback[i].dataSyncDesc)->scatteredBlocksFlag;
1131                     dataSyncDesc->baseAddr = (c->decode_callback[i].dataSyncDesc)->baseAddr;
1132                     dataSyncDesc->numBlocks = (c->decode_callback[i].dataSyncDesc)->numBlocks;
1133                     dataSyncDesc->varBlockSizesFlag = (c->decode_callback[i].dataSyncDesc)->varBlockSizesFlag;
1134                     dataSyncDesc->blockSizes = (c->decode_callback[i].dataSyncDesc)->blockSizes;
1136                     DEBUG("signal the other thread H264D_PutDataFxn to continue");
1137                     pthread_cond_signal(&(c->decode_callback[i].synch_callback));
1138                 } else {
1139                     // We received put_DataFxn from libdce/client, need to hold it until the data
1140                     // is provided by codec through H264D_PutDataFxn before continuing.
1141                     c->decode_callback[i].putdata_ready = 1;
1142                     DEBUG("Case#2 put_DataFxn is received but codec has not requested H264D_PutDataFxn. Wait cond. c->decode_callback[%d].callback_mutex 0x%x", i, c->decode_callback[i].callback_mutex);
1143                     DEBUG("Case#2 c->decode_callback[i].dataSyncDesc 0x%x dataSyncDesc 0x%x", c->decode_callback[i].dataSyncDesc, dataSyncDesc);
1144                     pthread_cond_wait(&(c->decode_callback[i].synch_callback), &(c->decode_callback[i].callback_mutex));
1145                     DEBUG("put_DataFxn FINALLY gets H264D_PutDataFxn, and the data has been provided, continue.");
1146                     // Copy the local structure as H264D_PutDataFxn has already stored codec partial decoded data to be sent to MPU side.
1147                     dataSyncDesc->size = (c->decode_callback[i].dataSyncDesc)->size;
1148                     dataSyncDesc->scatteredBlocksFlag = (c->decode_callback[i].dataSyncDesc)->scatteredBlocksFlag;
1149                     dataSyncDesc->baseAddr = (c->decode_callback[i].dataSyncDesc)->baseAddr;
1150                     dataSyncDesc->numBlocks = (c->decode_callback[i].dataSyncDesc)->numBlocks;
1151                     dataSyncDesc->varBlockSizesFlag = (c->decode_callback[i].dataSyncDesc)->varBlockSizesFlag;
1152                     dataSyncDesc->blockSizes = (c->decode_callback[i].dataSyncDesc)->blockSizes;
1154                     c->decode_callback[i].putdata_ready = 0;
1155                     // After resetting putdata_ready to 0, this function will return to MPU; we can let the codec callback to continue for more data.
1156                     DEBUG("From client dataSyncDesc->size %d ", dataSyncDesc->size);
1157                     DEBUG("From client dataSyncDesc->scatteredBlocksFlag %d ", dataSyncDesc->scatteredBlocksFlag);
1158                     DEBUG("From client dataSyncDesc->baseAddr %d ", dataSyncDesc->baseAddr);
1159                     DEBUG("From client dataSyncDesc->numBlocks %d ", dataSyncDesc->numBlocks);
1160                     DEBUG("From client dataSyncDesc->varBlockSizesFlag %d ", dataSyncDesc->varBlockSizesFlag);
1161                     DEBUG("From client dataSyncDesc->blockSizes %d ", dataSyncDesc->blockSizes);
1162                 }
1163                 pthread_mutex_unlock(&(c->decode_callback[i].callback_mutex));
1164             }
1165         }
1166     }
1168     dce_clean(dataSyncDesc);
1169     return (0);
1172 static int get_BufferFxn(UInt32 size, UInt32 *data)
1174     return (0);
1178 /* the server create parameters, must be in persistent memory */
1179 static RcmServer_Params    rpc_Params;
1181 /* DCE Server skel function array */
1182 static RcmServer_FxnDesc    DCEServerFxnAry[] =
1184     { "engine_open",     (RcmServer_MsgFxn) engine_open },
1185     { "engine_close",    (RcmServer_MsgFxn) engine_close },
1186     { "codec_create",    (RcmServer_MsgFxn) codec_create },
1187     { "codec_control",    (RcmServer_MsgFxn) codec_control },
1188     { "codec_get_version",    (RcmServer_MsgFxn) codec_get_version },
1189     { "codec_process",   (RcmServer_MsgFxn) codec_process },
1190     { "codec_delete",    (RcmServer_MsgFxn) codec_delete }
1191 };
1193 /* DCE Server skel function table */
1194 #define DCEServerFxnAryLen (sizeof(DCEServerFxnAry) / sizeof(DCEServerFxnAry[0]))
1196 static const RcmServer_FxnDescAry    DCEServer_fxnTab =
1198     DCEServerFxnAryLen,
1199     DCEServerFxnAry
1200 };
1202 static MmType_FxnSig    DCEServer_sigAry[] =
1204     { "engine_open", 2,
1205       {
1206           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1207           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
1208       } },
1209     { "engine_close", 2,
1210       {
1211           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1212           { MmType_Dir_In, MmType_Param_U32, 1 }
1213       } },
1214     { "codec_create", 5,
1215       {
1216           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1217           { MmType_Dir_In, MmType_Param_U32, 1 },
1218           { MmType_Dir_In, MmType_Param_U32, 1 },
1219           { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 },
1220           { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 }
1221       } },
1222     { "codec_control", 6,
1223       {
1224           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1225           { MmType_Dir_In, MmType_Param_U32, 1 },
1226           { MmType_Dir_In, MmType_Param_U32, 1 },
1227           { MmType_Dir_In, MmType_Param_U32, 1 },
1228           { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 },
1229           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
1230       } },
1231     { "codec_get_version", 5,
1232       {
1233           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1234           { MmType_Dir_In, MmType_Param_U32, 1 },
1235           { MmType_Dir_In, MmType_Param_U32, 1 },
1236           { MmType_Dir_In, MmType_PtrType(MmType_Param_VOID), 1 },
1237           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
1238       } },
1239     { "codec_process", 7,
1240       {
1241           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1242           { MmType_Dir_In, MmType_Param_U32, 1 },
1243           { MmType_Dir_In, MmType_Param_U32, 1 },
1244           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 },
1245           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 },
1246           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 },
1247           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
1248       } },
1249     { "codec_delete", 3,
1250       {
1251           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1252           { MmType_Dir_In, MmType_Param_U32, 1 },
1253           { MmType_Dir_In, MmType_Param_U32, 1 }
1254       } }
1255 };
1257 static MmType_FxnSigTab    dce_fxnSigTab =
1259     MmType_NumElem(DCEServer_sigAry), DCEServer_sigAry
1260 };
1262 /* DCE Callback Server skel function array */
1263 static RcmServer_FxnDesc    DCECallbackServerFxnAry[] =
1265     { "get_DataFxn",     (RcmServer_MsgFxn) get_DataFxn },
1266     { "put_DataFxn",     (RcmServer_MsgFxn) put_DataFxn },
1267     { "get_BufferFxn",   (RcmServer_MsgFxn) get_BufferFxn }
1268 };
1270 #define DCECallbackServerFxnAryLen (sizeof(DCECallbackServerFxnAry) / sizeof(DCECallbackServerFxnAry[0]))
1272 static const RcmServer_FxnDescAry    DCECallbackServer_fxnTab =
1274     DCECallbackServerFxnAryLen,
1275     DCECallbackServerFxnAry
1276 };
1278 static MmType_FxnSig    DCECallbackServer_sigAry[] =
1280     { "get_DataFxn", 3,
1281       {
1282           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1283           { MmType_Dir_In, MmType_Param_U32, 1 },
1284           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
1285       } },
1286     { "put_DataFxn", 3,
1287       {
1288           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1289           { MmType_Dir_In, MmType_Param_U32, 1 },
1290           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
1291       } },
1292     { "get_BufferFxn", 3,
1293       {
1294           { MmType_Dir_Out, MmType_Param_S32, 1 }, // return
1295           { MmType_Dir_In, MmType_Param_U32, 1 },
1296           { MmType_Dir_Bi, MmType_PtrType(MmType_Param_VOID), 1 }
1297       } }
1298 };
1300 static MmType_FxnSigTab    dce_callback_fxnSigTab =
1302     MmType_NumElem(DCECallbackServer_sigAry), DCECallbackServer_sigAry
1303 };
1305 Void dce_SrvDelNotification(Void)
1307     Client *c;
1308     int i;
1309     uint32_t mm_serv_id = 0;
1311     DEBUG("dce_SrvDelNotification: cleanup existing codec and engine\n");
1313     mm_serv_id = MmServiceMgr_getId();
1314     DEBUG("cleanup: mm_serv_id=0x%x", mm_serv_id);
1316     c = get_client(mm_serv_id);
1317     if( c ) {
1318         DEBUG("cleanup: mm_serv_id=0x%x c=%p c->refs=%d", mm_serv_id, c, c->refs);
1320         /* For low latency instance, need to trigger the flag to callback function so that it will return full numblock*/
1321         for( i = 0; i < DIM(c->decode_codec); i++ ) {
1322             //DEBUG("c->decode_callback[%d].row_mode %d", i, c->decode_callback[i].row_mode);
1323             if (c->decode_callback[i].row_mode) {
1324                 DEBUG("Setting c->decode_callback[%d].mpu_crash_indication = TRUE c->decode_codec[%d].callback_mutex 0x%x", i, i, c->decode_callback[i].callback_mutex);
1325                 c->decode_callback[i].mpu_crash_indication = TRUE;
1326                 pthread_cond_signal(&(c->decode_callback[i].synch_callback));
1327             }
1328         }
1330         for( i = 0; i < DIM(c->encode_codec); i++ ) {
1331             //DEBUG("c->encode_callback[%d].row_mode %d", i, c->encode_callback[i].row_mode);
1332             if (c->encode_callback[i].row_mode) {
1333                 DEBUG("Setting c->encode_callback[%d].mpu_crash_indication = TRUE c->encode_codec[%d].callback_mutex 0x%x", i, i, c->encode_callback[i].callback_mutex);
1334                 c->encode_callback[i].mpu_crash_indication = TRUE;
1335                 pthread_cond_signal(&(c->encode_callback[i].synch_callback));
1336             }
1337         }
1339         /* Make sure IVAHD and SL2 are idle before proceeding */
1340         ivahd_idle_check();
1342         /* delete all codecs first */
1343         for( i = 0; i < DIM(c->decode_codec); i++ ) {
1344             DEBUG("dce_SrvDelNotification: test c->decode_codec[%d] 0x%x", i, c->decode_codec[i]);
1345             if( c->decode_codec[i] ) {
1346                 DEBUG("dce_SrvDelNotification: delete decoder codec handle 0x%x c->decode_callback[i] 0x%x c->decode_callback[i].row_mode %d\n",
1347                     c->decode_codec[i], c->decode_callback[i], c->decode_callback[i].row_mode);
1348                 if (c->decode_callback[i].row_mode) {
1349                     pthread_mutex_destroy(&(c->decode_callback[i].callback_mutex));
1350                     pthread_cond_destroy(&(c->decode_callback[i].synch_callback));
1351                     c->decode_callback[i].row_mode = 0;
1352                     c->decode_callback[i].mpu_crash_indication = FALSE;
1353                 }
1354                 codec_fxns[OMAP_DCE_VIDDEC3].delete((void *)c->decode_codec[i]);
1355                 c->decode_codec[i] = NULL;
1356             }
1357         }
1359         for( i = 0; i < DIM(c->encode_codec); i++ ) {
1360             DEBUG("dce_SrvDelNotification: test c->encode_codec[%d] 0x%x", i, c->encode_codec[i]);
1361             if( c->encode_codec[i] ) {
1362                 DEBUG("dce_SrvDelNotification: delete encoder codec handle 0x%x c->encode_callback[i] 0x%x \n",
1363                     c->encode_codec[i], c->encode_callback[i]);
1364                 if (c->encode_callback[i].row_mode) {
1365                     pthread_mutex_destroy(&(c->encode_callback[i].callback_mutex));
1366                     pthread_cond_destroy(&(c->encode_callback[i].synch_callback));
1367                     c->encode_callback[i].row_mode = 0;
1368                     c->encode_callback[i].mpu_crash_indication = FALSE;
1369                 }
1370                 codec_fxns[OMAP_DCE_VIDENC2].delete((void *)c->encode_codec[i]);
1371                 c->encode_codec[i] = NULL;
1372             }
1373         }
1375         /* and lastly close all engines */
1376         for( i = 0; i < DIM(c->engines); i++ ) {
1377             if( c->engines[i] ) {
1378                 DEBUG("dce_SrvDelNotification: delete Engine handle 0x%x\n", c->engines[i]);
1379                 Engine_close(c->engines[i]);
1380                 c->engines[i] = NULL;
1381                 DEBUG("dce_SrvDelNotification engine_close: %p refs=%d", c, c->refs);
1382                 c->refs--;
1383             }
1384         }
1386         if( !c->refs ) {
1387             c->mm_serv_id = NULL;
1388         }
1389     }
1390     DEBUG("dce_SrvDelNotification: COMPLETE exit function \n");
1393 Void dceCallback_SrvDelNotification(Void)
1395     System_printf("dceCallback_SrvDelNotification - call dce_SrvDelNotification to clean up\n");
1398 /*
1399  * dce_main : main function for dce-server thread.
1400  * Registering to MmServiceMgr.
1401  */
1402 static void dce_main(uint32_t arg0, uint32_t arg1)
1404     int            err = 0;
1405     dce_connect    dce_connect_msg;
1407     /* Read the register for ID_CODE to figure out the correct configuration: */
1408     /* CONTROL_STD_FUSE_ID_CODE[31:0] ID_CODE STD_FUSE_IDCODE */
1409     /* physical address: 0x4A00 2204 Address offset: 0x204                       */
1410 #ifdef OMAP5430_ES10
1411     dce_connect_msg.chipset_id = 0x5430;
1412 #elif OMAP5432_ES20
1413     dce_connect_msg.chipset_id = 0x5432;
1414 #elif VAYU_ES10
1415     dce_connect_msg.chipset_id = 0x5436;
1416 #endif
1417     dce_connect_msg.debug = dce_debug;
1418     connect(&dce_connect_msg);
1420     err = MmServiceMgr_init();  // MmServiceMgr_init() will always return MmServiceMgr_S_SUCCESS.
1422     // setup the RCM Server create params
1423     RcmServer_Params_init(&rpc_Params);
1424     rpc_Params.priority = Thread_Priority_ABOVE_NORMAL;
1425     rpc_Params.stackSize = 0x1000;
1426     rpc_Params.fxns.length = DCEServer_fxnTab.length;
1427     rpc_Params.fxns.elem = DCEServer_fxnTab.elem;
1429     DEBUG("REGISTER %s\n", SERVER_NAME);
1431     // Get the Service Manager handle
1432     err = MmServiceMgr_register(SERVER_NAME, &rpc_Params, &dce_fxnSigTab, dce_SrvDelNotification);
1433     if( err < 0 ) {
1434         DEBUG("failed to start " SERVER_NAME " \n");
1435     } else {
1436         DEBUG(SERVER_NAME " running through MmServiceMgr");
1437     }
1439     MmServiceMgr_exit();
1441     DEBUG("deleted " SERVER_NAME);
1443     return;
1446 /*
1447  * dce_callback_main : main function for dce-callback-server thread.
1448  * Registering to MmServiceMgr.
1449  */
1451 static void dce_callback_main(uint32_t arg0, uint32_t arg1)
1453     int            err = 0;
1455     err = MmServiceMgr_init();  // MmServiceMgr_init() will always return MmServiceMgr_S_SUCCESS.
1457     // setup the RCM Server create params
1458     RcmServer_Params_init(&rpc_Params);
1459     rpc_Params.priority = Thread_Priority_ABOVE_NORMAL;
1460     rpc_Params.stackSize = 0x1000;
1461     rpc_Params.fxns.length = DCECallbackServer_fxnTab.length;
1462     rpc_Params.fxns.elem = DCECallbackServer_fxnTab.elem;
1464     DEBUG("REGISTER %s\n", CALLBACK_SERVER_NAME);
1466     // Get the Service Manager handle
1467     err = MmServiceMgr_register(CALLBACK_SERVER_NAME, &rpc_Params, &dce_callback_fxnSigTab, dceCallback_SrvDelNotification);
1468     if( err < 0 ) {
1469         DEBUG("failed to start " CALLBACK_SERVER_NAME " \n");
1470     } else {
1471         DEBUG(CALLBACK_SERVER_NAME " running through MmServiceMgr");
1472     }
1474     MmServiceMgr_exit();
1476     DEBUG("deleted " CALLBACK_SERVER_NAME);
1478     return;
1482 /*
1483   * dce init : Startup Function
1484   */
1485 Bool dce_init(void)
1487     Task_Params    params;
1488     Task_Params    callback_params;
1490     INFO("Creating DCE server and DCE callbabk server thread...");
1492     /* Create DCE task. */
1493     Task_Params_init(&params);
1494     params.instance->name = "dce-server";
1495     params.priority = Thread_Priority_ABOVE_NORMAL;
1496     Task_create(dce_main, &params, NULL);
1498     /* Create DCE callback task. */
1499     Task_Params_init(&callback_params);
1500     callback_params.instance->name = "dce-callback-server";
1501     callback_params.priority = Thread_Priority_ABOVE_NORMAL;
1502     Task_create(dce_callback_main, &callback_params, NULL);
1504     pthread_mutex_init(&sync_process_mutex, NULL);
1506     return (TRUE);
1509 /*
1510   * dce deinit
1511   */
1513 void dce_deinit(void)
1515     DEBUG("dce_deinit");
1517     pthread_mutex_destroy(&sync_process_mutex);
1520 /*
1521  * H264E_GetDataFxn
1522  * This is callback function provided for IVA-HD codec to callback for more input data.
1523  * This function syncs with get_DataFxn which handles the required data from the MPU side.
1524  * It will continue if DCE Server has received get_DataFxn from MPU side otherwise it will
1525  * wait until DCE server receive get_DataFxn.
1526  */
1527 XDM_DataSyncGetFxn H264E_GetDataFxn(XDM_DataSyncHandle dataSyncHandle,
1528     XDM_DataSyncDesc *dataSyncDesc)
1530     Client* c;
1532     dce_inv(dataSyncDesc);
1534     DEBUG("********************H264E_GetDataFxn START*************************** dataSyncHandle 0x%x",
1535         dataSyncHandle);
1536     c = get_client_instance((Uint32) dataSyncHandle);
1537     if (c) {
1538         int i;
1539         for (i = 0; i < DIM(c->encode_codec); i++) {
1540             if (c->encode_codec[i] == dataSyncHandle) {
1541                 pthread_mutex_lock(&(c->encode_callback[i].callback_mutex));
1542                 DEBUG("H264E_GetDataFxn dataSyncHandle 0x%x c->encode_callback[%d].callback_mutex 0x%x", dataSyncHandle, i, c->encode_callback[i].callback_mutex);
1543                 // Check if H264E_GetDataFxn from codec and get_DataFxn from MPU side. Which comes first.
1544                 // Check if MPU has crashed c->encode_callback[i].mpu_crash_indication, if it is then send the highest numBlock to codec so that VIDENC2_process will be returned and IVA back to IDLE.
1545                 if (c->encode_callback[i].mpu_crash_indication) {
1546                     // Since MPU has crashed, need to send the numBlocks to codec so that VIDENC2_process can be returned and IVA back to IDLE.
1547                     // Send the numBlocks as expected max value or add functionality to count up to proper numBlocks to be returned to codec.
1548                     // Current implementation will send arbitrary value 100 numBlocks (height resolution 1600) which will let codec return the process call and move IVA into IDLE state.
1549                     DEBUG("MPU has crashed, send arbitrary numBlocks 100 so that VIDENC2_process will be returned");
1550                     dataSyncDesc->size = sizeof(XDM_DataSyncDesc);
1551                     dataSyncDesc->scatteredBlocksFlag = 0;
1552                     dataSyncDesc->baseAddr = 0;
1553                     dataSyncDesc->numBlocks = 100;
1554                     dataSyncDesc->varBlockSizesFlag = 0;
1555                     dataSyncDesc->blockSizes = 0;
1556                 } else {
1557                     if (c->encode_callback[i].getdata_ready) {
1558                         // Already have data to be passed to codec
1559                         DEBUG("H264E_GetDataFxn Case#2 c->encode_callback[%d].dataSyncHandle 0x%x c->encode_callback[%d].dataSyncDesc 0x%x",
1560                             i, c->encode_callback[i].dataSyncHandle, i, c->encode_callback[i].dataSyncDesc);
1561                         if (dataSyncHandle == c->encode_callback[i].dataSyncHandle) {
1562                             dataSyncDesc->size = (c->encode_callback[i].dataSyncDesc)->size;
1563                             dataSyncDesc->scatteredBlocksFlag = (c->encode_callback[i].dataSyncDesc)->scatteredBlocksFlag;
1564                             dataSyncDesc->baseAddr = (c->encode_callback[i].dataSyncDesc)->baseAddr;
1565                             dataSyncDesc->numBlocks = (c->encode_callback[i].dataSyncDesc)->numBlocks;
1566                             dataSyncDesc->varBlockSizesFlag = (c->encode_callback[i].dataSyncDesc)->varBlockSizesFlag;
1567                             dataSyncDesc->blockSizes = (c->encode_callback[i].dataSyncDesc)->blockSizes;
1568                         }
1570                         // Order get_DataFxn to continue request to MPU client side for more data as it is currently pending.
1571                         pthread_cond_signal(&(c->encode_callback[i].synch_callback));
1572                     } else {
1573                         c->encode_callback[i].codec_request = 1;
1575                         // Wait until get_DataFxn is received from MPU client side. Need the information to be passed to codec as currently not available.
1576                         pthread_cond_wait(&(c->encode_callback[i].synch_callback), &(c->encode_callback[i].callback_mutex));
1578                         // Once get_DataFxn is received from MPU side continue by providing it to IVA-HD codec.
1579                         DEBUG("H264E_GetDataFxn Case#1 c->encode_callback[%d].dataSyncHandle 0x%x c->encode_callback[%d].dataSyncDesc 0x%x",
1580                             i, c->encode_callback[i].dataSyncHandle, i, c->encode_callback[i].dataSyncDesc);
1581                         if (dataSyncHandle == c->encode_callback[i].dataSyncHandle) {
1582                             dataSyncDesc->size = (c->encode_callback[i].dataSyncDesc)->size;
1583                             dataSyncDesc->scatteredBlocksFlag = (c->encode_callback[i].dataSyncDesc)->scatteredBlocksFlag;
1584                             dataSyncDesc->baseAddr = (c->encode_callback[i].dataSyncDesc)->baseAddr;
1585                             dataSyncDesc->numBlocks = (c->encode_callback[i].dataSyncDesc)->numBlocks;
1586                             dataSyncDesc->varBlockSizesFlag = (c->encode_callback[i].dataSyncDesc)->varBlockSizesFlag;
1587                             dataSyncDesc->blockSizes = (c->encode_callback[i].dataSyncDesc)->blockSizes;
1588                         }
1589                         c->encode_callback[i].codec_request = 0;
1590                     }
1591                 }
1592                 pthread_mutex_unlock(&(c->encode_callback[i].callback_mutex));
1593             }
1594         }
1595     }
1597     DEBUG("********************H264E_GetDataFxn END*************************** dataSyncHandle 0x%x", dataSyncHandle);
1598     dce_clean(dataSyncDesc);
1599     return (0);
1602 /*
1603  * H264D_PutDataFxn
1604  * This is callback function provided for IVA-HD codec to callback for notifying client on partial decoded output.
1605  * This function syncs with put_DataFxn which handles passing the data from codec to the MPU side.
1606  * Once this callback is received from IVA-HD codec, it will save the codec partial decoded data into local structure
1607  * for put_DataFxn to pick up.
1608  * If DCE server has already receive put_DataFxn (putdata_ready == 1), then it notifies through semaphore_post to continue.
1609  * If DCE server is waiting for put_DataFxn, then it will set codec_request = 1, and wait through semaphore_pend.
1610  */
1611 XDM_DataSyncPutFxn H264D_PutDataFxn(XDM_DataSyncHandle dataSyncHandle,
1612     XDM_DataSyncDesc *dataSyncDesc)
1614     Client* c;
1616     dce_inv(dataSyncDesc);
1617     DEBUG("********************H264D_PutDataFxn START*************************** dataSyncHandle 0x%x dataSyncDesc->numBlocks %d",
1618         dataSyncHandle, dataSyncDesc->numBlocks);
1620     c = get_client_instance((Uint32) dataSyncHandle);
1621     if (c) {
1622         int i;
1623         for (i = 0; i < DIM(c->decode_codec); i++) {
1624             if (c->decode_codec[i] == dataSyncHandle) {
1625                 pthread_mutex_lock(&(c->decode_callback[i].callback_mutex));
1626                 DEBUG("H264D_PutDataFxn dataSyncHandle 0x%x c->decode_codec[%d].callback_mutex 0x%x", dataSyncHandle, i, c->decode_callback[i].callback_mutex);
1627                 // Should be okay to save the data from IVA-HD codec into local structure for put_DataFxn to pick up.
1628                 if (dataSyncHandle == c->decode_callback[i].dataSyncHandle) {
1629                     (c->decode_callback[i].dataSyncDesc)->size = dataSyncDesc->size;
1630                     (c->decode_callback[i].dataSyncDesc)->scatteredBlocksFlag = dataSyncDesc->scatteredBlocksFlag;
1631                     (c->decode_callback[i].dataSyncDesc)->baseAddr = dataSyncDesc->baseAddr;
1632                     (c->decode_callback[i].dataSyncDesc)->numBlocks = dataSyncDesc->numBlocks;
1633                     (c->decode_callback[i].dataSyncDesc)->varBlockSizesFlag = dataSyncDesc->varBlockSizesFlag;
1634                     (c->decode_callback[i].dataSyncDesc)->blockSizes = dataSyncDesc->blockSizes;
1635                     DEBUG("From Codec (c->decode_callback[%d].dataSyncDesc)->size %d ", i, (c->decode_callback[i].dataSyncDesc)->size);
1636                     DEBUG("From Codec (c->decode_callback[%d].dataSyncDesc)->scatteredBlocksFlag %d ", i, (c->decode_callback[i].dataSyncDesc)->scatteredBlocksFlag);
1637                     DEBUG("From Codec (c->decode_callback[%d].dataSyncDesc)->baseAddr %d ", i, (c->decode_callback[i].dataSyncDesc)->baseAddr);
1638                     DEBUG("From Codec (c->decode_callback[%d].dataSyncDesc)->numBlocks %d ", i, (c->decode_callback[i].dataSyncDesc)->numBlocks);
1639                     DEBUG("From Codec (c->decode_callback[%d].dataSyncDesc)->varBlockSizesFlag %d ", i, (c->decode_callback[i].dataSyncDesc)->varBlockSizesFlag);
1640                     DEBUG("From Codec (c->decode_callback[%d].dataSyncDesc)->blockSizes %d ", i, (c->decode_callback[i].dataSyncDesc)->blockSizes);
1641                 }
1643                 // If MPU has crashed, there is no way MPU will respond after this. Let codec thinking that MPU has received the numblock. Don't wait, just returned.
1644                 if (!(c->decode_callback[i].mpu_crash_indication)) {
1645                     // MPU is alive. Wait until the put_DataFxn is received from MPU side. Codec has callback with partial decoded data but put_DataFxn is not received yet.
1646                     // Check if put_DataFxn from MPU side has come before H264D_PutDataFxn.
1647                     if (c->decode_callback[i].putdata_ready) {
1648                         // Already receive request from client for partial decoded output information from codec.
1649                         // Order put_DataFxn to continue sending codec partial decoded data in the local structure to MPU side.
1650                         DEBUG("H264D_PutDataFxn Case#2 c->decode_callback[%d].dataSyncHandle 0x%x c->decode_callback[%d].dataSyncDesc 0x%x",
1651                             i, c->decode_callback[i].dataSyncHandle, i, c->decode_callback[i].dataSyncDesc);
1653                         // After storing the data from codec, send thread signal conditional for put_DataFxn to continue passing the codec data to MPU.
1654                         pthread_cond_signal(&(c->decode_callback[i].synch_callback));
1655                     } else {
1656                         c->decode_callback[i].codec_request = 1;
1657                         DEBUG("H264D_PutDataFxn Case#1 wait on pthread_cond_wait c->decode_codec[%d].callback_mutex 0x%x", i, c->decode_callback[i].callback_mutex);
1658                         pthread_cond_wait(&(c->decode_callback[i].synch_callback), &(c->decode_callback[i].callback_mutex));
1659                         c->decode_callback[i].codec_request = 0;
1660                     }
1661                 }
1662                 pthread_mutex_unlock(&(c->decode_callback[i].callback_mutex));
1663             }
1664         }
1665     }
1667     DEBUG("********************H264D_PutDataFxn END*************************** dataSyncHandle 0x%x", dataSyncHandle);
1668     dce_clean(dataSyncDesc);
1669     return (0);