/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License 
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public 
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/
#include <config.h>

#include <pthread.h>

#include <sys/ioctl.h>
#include <sys/mman.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include <asm/types.h>

#include <directfb.h>

#include <direct/mem.h>
#include <direct/memcpy.h>
#include <direct/messages.h>
#include <direct/system.h>
#include <direct/util.h>

#include <fusion/arena.h>
#include <fusion/fusion.h>
#include <fusion/reactor.h>
#include <fusion/shmalloc.h>

#include <core/core.h>
#include <core/layers.h>
#include <core/gfxcard.h>
#include <core/screens.h>
#include <core/surface_pool.h>

#include <misc/conf.h>
#include <misc/util.h>

#include "mt53.h"


#include <core/core_system.h>

DFB_CORE_SYSTEM( mt53sys )

MT53 *dfb_mt53 = NULL;

int dfb_fb = 0;

#ifdef CC_B2R44K2K_SUPPORT
int _B2RBufNum = 0;
unsigned int _B2RBufPhyAddr[10];
unsigned int _B2RBufVirAddr[10];
unsigned int _B2RBufCPhyAddr[10];
#endif
/**********************************************************************************************************************/


void system_mmap_dfb_addr(void)
{
    if(ioctl( dfb_mt53->fd, FBIOGET_FSCREENINFO, &dfb_mt53->fix ) < 0) 
    {
        D_PERROR( "DirectFB/MT53: FBIOGET_FSCREENINFO failed!\n" );
        return ;
    }
#ifdef CC_GFX_RM_FIX_MAPPING
    dfb_mt53->mem = mmap( (void*)NULL,
                                dfb_mt53->fix.smem_len,
                                PROT_READ | PROT_WRITE,
                                MAP_SHARED ,
                                dfb_mt53->fd,
                                0x0);
#else
    dfb_mt53->mem = mmap( (void*)dfb_mt53->fix.smem_start,
                                dfb_mt53->fix.smem_len,
                                PROT_READ | PROT_WRITE,
                                MAP_SHARED | MAP_FIXED,
                                dfb_mt53->fd,
                                0x0);
#endif
    if(dfb_mt53->mem == MAP_FAILED)
    {
        D_PERROR( "DirectFB/MT53: Could not mmap the DFB  buffer!\n");
    }
    else
    {
        //memset(dfb_mt53->mem,0x0,dfb_mt53->fix.smem_len);
        D_INFO( "DirectFB/MT53: DFB[vir=0x%x,phy=0x%x,size=0x%x]\n",
            (int)dfb_mt53->mem,dfb_mt53->fix.smem_start,dfb_mt53->fix.smem_len);
    }

    return;
}

void system_mmap_crsr_addr(void)
{
    if(ioctl( dfb_mt53->fd, FBIO_CRSR_INFO, &dfb_mt53->t_crsr ) < 0)
    {
        D_PERROR( "DirectFB/MT53: FBIO_CRSR_INFO failed!\n" );
        return;
    }
#ifdef CC_GFX_RM_FIX_MAPPING
    dfb_mt53->t_crsr.u4VirtAddr = (unsigned int)mmap(
                         (void*)NULL,
                         dfb_mt53->t_crsr.u4Size,
                         PROT_READ | PROT_WRITE,
                         MAP_SHARED,
                         dfb_mt53->fd,
                         dfb_mt53->t_crsr.u4PhyAddr);
#else
    dfb_mt53->t_crsr.u4VirtAddr = (unsigned int)mmap(
                         (void*)dfb_mt53->t_crsr.u4PhyAddr,
                         dfb_mt53->t_crsr.u4Size,
                         PROT_READ | PROT_WRITE,
                         MAP_SHARED | MAP_FIXED,
                         dfb_mt53->fd,
                         dfb_mt53->t_crsr.u4PhyAddr);
#endif
    if(dfb_mt53->t_crsr.u4VirtAddr == (unsigned int)MAP_FAILED)
    {
        D_PERROR( "DirectFB/MT53: Could not mmap the t_crsr  buffer!\n");
    }
    else
    {
        //memset(dfb_mt53->t_crsr.u4VirtAddr,0x0,dfb_mt53->t_crsr.u4Size);
        D_INFO( "DirectFB/MT53: t_crsr[vir=0x%x,phy=0x%x,size=0x%x]\n",
        dfb_mt53->t_crsr.u4VirtAddr,dfb_mt53->t_crsr.u4PhyAddr,dfb_mt53->t_crsr.u4Size);
    }

    return ;
}

void system_munmap_imagebuf_addr(void)
{
    int ret=0;
    // D_INFO("%s[0x%x]\n",__FUNCTION__,dfb_mt53->imagebuf.u4VirtAddr);
    
    if(dfb_mt53->imagebuf.u4VirtAddr)
    {
        if(dfb_mt53->shared->manager_fbm->avail >= dfb_mt53->shared->manager_fbm->length)
        {
            ret = munmap((void *)dfb_mt53->imagebuf.u4VirtAddr,dfb_mt53->imagebuf.u4Size);
            
            D_INFO( "DirectFB/MT53: munmap imagebuf[pid=%d][vir=0x%x,phy=0x%x,size=0x%x][%d]\n",getpid(),
            dfb_mt53->imagebuf.u4VirtAddr,dfb_mt53->imagebuf.u4PhyAddr,dfb_mt53->imagebuf.u4Size,ret);

            dfb_mt53->imagebuf.u4VirtAddr =0x0;
        }
    }

    return;
}

void system_mmap_imagebuf_addr(void)
{
    if (ioctl( dfb_mt53->fd, FBIO_GETIMAGEBUFFER, &dfb_mt53->imagebuf ) < 0) 
    {
        D_PERROR( "DirectFB/MT53: FBIO_CRSR_INFO failed!\n" );
       return ;
    }
    
    dfb_mt53->imagebuf.u4VirtAddr = (unsigned int)mmap( 
                         NULL, 
                         dfb_mt53->imagebuf.u4Size, 
                         PROT_READ | PROT_WRITE, 
                         MAP_SHARED, 
                         dfb_mt53->fd, 
                         dfb_mt53->imagebuf.u4PhyAddr
                         );
 
    if(dfb_mt53->imagebuf.u4VirtAddr == (unsigned int)MAP_FAILED) 
    {
        D_PERROR( "DirectFB/MT53: Could not mmap the imagebuf  buffer!\n");
    }
    else
    {
        //memset(dfb_mt53->imagebuf.u4VirtAddr,0x00,dfb_mt53->imagebuf.u4Size);
        D_INFO( "DirectFB/MT53: imagebuf[vir=0x%x,phy=0x%x,size=0x%x]\n",
        dfb_mt53->imagebuf.u4VirtAddr,dfb_mt53->imagebuf.u4PhyAddr,dfb_mt53->imagebuf.u4Size);
    }

    return ;
}

void system_munmap_vdpbuf_addr(void)
{
    //D_INFO("%s[%d][0x%x]\n",__FUNCTION__,getpid(),dfb_mt53->vdpbuf.u4VirtAddr);
    int ret=0;
    
    if(dfb_mt53->vdpbuf.u4VirtAddr)
    {
        if(dfb_mt53->shared->manager_vdp->avail >= dfb_mt53->shared->manager_vdp->length)
        {
            ret = munmap((void *)dfb_mt53->vdpbuf.u4VirtAddr,dfb_mt53->vdpbuf.u4Size);

            if(ret)
            {
                D_ERROR( "DirectFB/MT53 ERROR: munmap vdpbuf[pid=%d][vir=0x%x,phy=0x%x,size=0x%x] ret[%d]\n",getpid(),
                dfb_mt53->vdpbuf.u4VirtAddr,dfb_mt53->vdpbuf.u4PhyAddr,dfb_mt53->vdpbuf.u4Size,ret);
            }
            else
            {
                D_INFO( "DirectFB/MT53: munmap vdpbuf[pid=%d][vir=0x%x,phy=0x%x,size=0x%x] ret[%d]\n",getpid(),
                dfb_mt53->vdpbuf.u4VirtAddr,dfb_mt53->vdpbuf.u4PhyAddr,dfb_mt53->vdpbuf.u4Size,ret);
            }

            dfb_mt53->vdpbuf.u4VirtAddr =0x0;
        }
    }

    return;
}


void system_mmap_vdpbuf_addr(void)
{
    if(ioctl( dfb_mt53->fd, FBIO_VDP_GETBUFFER, &dfb_mt53->vdpbuf ) < 0) 
    {
        D_PERROR( "DirectFB/MT53: FBIO_CRSR_INFO failed!\n" );
        return ;
    }
        
    dfb_mt53->vdpbuf.u4VirtAddr = (unsigned int)mmap( 
                         NULL, 
                         dfb_mt53->vdpbuf.u4Size, 
                         PROT_READ | PROT_WRITE, 
                         MAP_SHARED, 
                         dfb_mt53->fd, 
                         dfb_mt53->vdpbuf.u4PhyAddr);

    if(dfb_mt53->vdpbuf.u4VirtAddr == (unsigned int)MAP_FAILED) 
    {
        D_PERROR( "DirectFB/MT53: Could not mmap the vdpbuf  buffer!\n");
    }
    else
    {
        memset((void *)(dfb_mt53->vdpbuf.u4VirtAddr),0x0,dfb_mt53->vdpbuf.u4Size);
        D_INFO( "DirectFB/MT53: vdpbuf[pid=%d][vir=0x%x,phy=0x%x,size=0x%x]\n",getpid(),
        dfb_mt53->vdpbuf.u4VirtAddr,dfb_mt53->vdpbuf.u4PhyAddr,dfb_mt53->vdpbuf.u4Size);
    }

    return ;
}


void system_munmap_imagebuf2_addr(void)
{
    //D_INFO("%s[0x%x]\n",__FUNCTION__,dfb_mt53->imagebuf2.u4VirtAddr);
    
    if(dfb_mt53->imagebuf2.u4VirtAddr)
    {
        if(dfb_mt53->shared->manager_3dmm->avail >= dfb_mt53->shared->manager_3dmm->length)
        {
            munmap((void *)dfb_mt53->imagebuf2.u4VirtAddr,dfb_mt53->imagebuf2.u4Size);
            D_INFO( "DirectFB/MT53: munmap imagebuf2[vir=0x%x,phy=0x%x,size=0x%x]\n",
            dfb_mt53->imagebuf2.u4VirtAddr,dfb_mt53->imagebuf2.u4PhyAddr,dfb_mt53->imagebuf2.u4Size);

            dfb_mt53->imagebuf2.u4VirtAddr =0x0;
        }
    }

    return ;
}

void system_mmap_imagebuf2_addr(void)
{
    if (ioctl( dfb_mt53->fd, FBIO_GETIMAGEBUFFER2, &dfb_mt53->imagebuf2 ) < 0) 
    {
        D_PERROR( "DirectFB/MT53: FBIO_CRSR_INFO failed!\n" );
       return ;
    }

    dfb_mt53->imagebuf2.u4VirtAddr = (unsigned int)mmap( 
                         NULL, 
                         dfb_mt53->imagebuf2.u4Size, 
                         PROT_READ | PROT_WRITE, 
                         MAP_SHARED, 
                         dfb_mt53->fd, 
                         dfb_mt53->imagebuf2.u4PhyAddr
                         );
 
    if(dfb_mt53->imagebuf2.u4VirtAddr == (unsigned int)MAP_FAILED) 
    {
        D_PERROR( "DirectFB/MT53: Could not mmap the imagebuf2  buffer!\n");
    }
    else
    {
        //memset(dfb_mt53->imagebuf2.u4VirtAddr,0x00,dfb_mt53->imagebuf2.u4Size);
        D_INFO( "DirectFB/MT53: imagebuf2[vir=0x%x,phy=0x%x,size=0x%x]\n",
        dfb_mt53->imagebuf2.u4VirtAddr,dfb_mt53->imagebuf2.u4PhyAddr,dfb_mt53->imagebuf2.u4Size);
    }

    return ;
}


#ifdef CC_B2R44K2K_SUPPORT
void system_mmap_b2r44K2Kbuf_addr(void)
{
    int n;
    if (ioctl( dfb_mt53->fd, FBIO_B2R44K2K_GETBUFFER, dfb_mt53->m_B2RSysBuf) < 0) {
         D_PERROR( "DirectFB/MT53: FBIO_VDP_GETBUFFER failed!\n" );
         return;
    }

    for(n = 0; n < B2R_BUFFER_NUM; n++)
    {
        dfb_mt53->m_B2RDfbBuf[n].u4PhyAddr = dfb_mt53->m_B2RSysBuf[n].m_YAddr;
        dfb_mt53->m_B2RDfbBuf[n].u4Size = dfb_mt53->m_B2RSysBuf[n].m_Size;
    }

    for(n = 0; n < B2R_BUFFER_NUM; n++)
    {
        dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr = (unsigned int)mmap( 
                  NULL,
                  dfb_mt53->m_B2RDfbBuf[n].u4Size, 
                  PROT_READ | PROT_WRITE, MAP_SHARED, 
                  dfb_mt53->fd, 
                  dfb_mt53->m_B2RDfbBuf[n].u4PhyAddr
                  );
 
        if (dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr == (unsigned int)MAP_FAILED) {
                   D_PERROR( "DirectFB/MT53: Could not mmap the MPEG2[%d] OSD buffer For 4k2k!\n", n);
                   dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr = 0;
        }
        else
        {
            //memset((void *)(dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr),0x0,dfb_mt53->m_B2RDfbBuf[n].u4Size);
        }
        _B2RBufVirAddr[n] = dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr;
        _B2RBufPhyAddr[n] = dfb_mt53->m_B2RDfbBuf[n].u4PhyAddr;
        _B2RBufCPhyAddr[n] = dfb_mt53->m_B2RSysBuf[n].m_CAddr;

        D_INFO("##########dfb_mt53->mpegbuf[%d] [0x%x,0x%x] [%d] \n", n,dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr, dfb_mt53->m_B2RDfbBuf[n].u4PhyAddr, dfb_mt53->m_B2RDfbBuf[n].u4Size);
        
    }   

    _B2RBufNum = B2R_BUFFER_NUM;
}


void system_munmap_b2r44K2Kbuf_addr(void)
{
    int ret=0;
    int n;

    if(!((dfb_mt53->shared->m_B2R44K2KFlags&0xf)==0xf))
    {
        return;
    }
    
    for(n = 0; n < B2R_BUFFER_NUM; n++)
    {
        if(dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr)
        {
            ret=munmap((void *)dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr,dfb_mt53->m_B2RDfbBuf[n].u4Size);
            if(ret)
            {
                D_INFO( "DirectFB/MT53: munmap b2r44K2Kbuf fail[pid=%d,ret=%d][vir=0x%x,phy=0x%x,size=0x%x]\n",getpid(),ret,
                        dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr,
                        dfb_mt53->m_B2RDfbBuf[n].u4PhyAddr,dfb_mt53->m_B2RDfbBuf[n].u4Size);
            }
            else
            {
                D_INFO( "DirectFB/MT53: munmap b2r44K2Kbuf ok[pid=%d,ret=%d][vir=0x%x,phy=0x%x,size=0x%x]\n",getpid(),ret,
                        dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr,
                        dfb_mt53->m_B2RDfbBuf[n].u4PhyAddr,dfb_mt53->m_B2RDfbBuf[n].u4Size);

                dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr =0x0;
                _B2RBufNum = 0x0;
            }
        }
    }  
}

#endif

void system_fb_mmap(void)
{
    int n=0x0;
    
    system_mmap_dfb_addr();
    system_mmap_crsr_addr();

    if (ioctl( dfb_mt53->fd, FBIO_GETIMAGEBUFFER, &dfb_mt53->imagebuf ) < 0) 
    {
        D_PERROR( "DirectFB/MT53: FBIO_CRSR_INFO failed!\n" );
       return ;
    }
    dfb_mt53->imagebuf.u4VirtAddr   = 0x0;

    if(ioctl( dfb_mt53->fd, FBIO_VDP_GETBUFFER, &dfb_mt53->vdpbuf ) < 0) 
    {
        D_PERROR( "DirectFB/MT53: FBIO_CRSR_INFO failed!\n" );
        return ;
    }
    dfb_mt53->vdpbuf.u4VirtAddr     = 0x0;


    if (ioctl( dfb_mt53->fd, FBIO_GETIMAGEBUFFER2, &dfb_mt53->imagebuf2 ) < 0) 
    {
        D_PERROR( "DirectFB/MT53: FBIO_CRSR_INFO failed!\n" );
       return ;
    }
    dfb_mt53->imagebuf2.u4VirtAddr= 0x0;
    
    #ifdef CC_B2R44K2K_SUPPORT
    if (ioctl( dfb_mt53->fd, FBIO_B2R44K2K_GETBUFFER, dfb_mt53->m_B2RSysBuf) < 0) 
    {
         D_PERROR( "DirectFB/MT53: FBIO_VDP_GETBUFFER failed!\n" );
         return;
    }
    for(n = 0; n < B2R_BUFFER_NUM; n++)
    {
        dfb_mt53->m_B2RDfbBuf[n].u4PhyAddr = dfb_mt53->m_B2RSysBuf[n].m_YAddr;
        dfb_mt53->m_B2RDfbBuf[n].u4Size    = dfb_mt53->m_B2RSysBuf[n].m_Size;
        dfb_mt53->m_B2RDfbBuf[n].u4VirtAddr=0x0;
    }
    #endif
    
    return;
}
#ifdef DFB_INPUT_FILER_EN

static FusionCallHandlerResult
call_handler( int           caller,
              int           call_arg,
              void         *call_ptr,
              void         *ctx,
              unsigned int  serial,
              int          *ret_val )
{
     bool ret = false;
     MT53Shared *shared;
     
     //D_INFO("mt53 system pid=%d recieve event \n", getpid());

     D_ASSERT((dfb_mt53 != NULL));
     D_ASSERT((dfb_mt53->shared != NULL));

     shared = dfb_mt53->shared;
     
     if(dfb_mt53->input_filter != NULL)
     {
         ret = dfb_mt53->input_filter((const DFBInputEvent *)&shared->input_event);
     }

     //D_INFO("event [%d][%d] \n", shared->input_event.key_symbol, shared->input_event.type);
     
     *ret_val = (int) ret;

     return FCHR_RETURN;
}


static void
system_participant_init(MT53Shared *shared)
{
    int i;
    D_ASSERT((shared != NULL));

    for(i = 0; i < MT53_MAX_PARTICIPANTS; i++)
    {
        shared->participants[i].mark = false;
    }

    shared->participant_number = 1;
}

static void
system_participant_attend(MT53Shared *shared)
{
    int i;
    DirectResult ret;
    mt53_participant_t *participant = NULL; 
    D_ASSERT((shared != NULL));

    //get idle participant
    for(i = 0; i < MT53_MAX_PARTICIPANTS; i++)
    {
        if(shared->participants[i].mark == false)
        {
            participant = &shared->participants[i];
        }
    }

    if(participant != NULL)
    {
        ret = fusion_call_init(&participant->call, call_handler, shared, dfb_core_world(dfb_mt53->core));
        if(ret < 0)
        {
            return;
        }
        
        participant->mark = true;
        participant->inputfilter = false;
        participant->pid = (int)getpid();
        shared->participant_number++;
    }
}

static void
system_participant_leave(MT53Shared *shared)
{
    int i, pid;
    mt53_participant_t *participant = NULL; 
    D_ASSERT((shared != NULL));

    pid = getpid();
    //get remove participant
    for(i = 0; i < MT53_MAX_PARTICIPANTS; i++)
    {
        if(shared->participants[i].mark == true && shared->participants[i].pid == pid)
        {
            participant = &shared->participants[i];
        }
    }

    if(participant != NULL)
    {
        fusion_call_destroy(&participant->call);
        participant->mark = false;
        participant->inputfilter = false;
        participant->pid = -1;
        shared->participant_number--;
    }
}

static bool
system_participant_dispatch_inputevent(MT53Shared *shared, DFBInputEvent *event)
{
    int i, mark = 0, retcall = 0;
    D_ASSERT((shared != NULL));
    D_ASSERT((event != NULL));

    if(dfb_mt53->input_filter != NULL)
    {
        mark |= (int) dfb_mt53->input_filter((const DFBInputEvent *)event);
    }

    if(shared->participant_number <= 1)
    {
        return ((bool) mark);
    }

    shared->input_event = *event;
    
    for(i = 0; i < MT53_MAX_PARTICIPANTS; i++)
    {
        if(shared->participants[i].mark == true  && shared->participants[i].inputfilter == true)
        {
            fusion_call_execute(&shared->participants[i].call, FCEF_NONE, 0, 0, &retcall);
            mark |= retcall;
            //D_INFO("return retcall = %d \n", retcall);
        }
    }

    //D_INFO("return mark = %d \n", mark);

    return ((bool) mark);
}
#endif

static void
system_get_info( CoreSystemInfo *info )
{
     info->type = CORE_ANY;
     info->caps = CSCAPS_ACCELERATION;

     snprintf( info->name, DFB_CORE_SYSTEM_INFO_NAME_LENGTH, "MediaTek 53xx" );
}

static DFBResult
system_initialize( CoreDFB *core, void **data )
{
     DFBResult                 ret = DFB_INIT;
     struct fb_var_screeninfo  var;
     FusionSHMPoolShared      *pool;
     CoreScreen               *screen;
     MT53Shared               *shared = NULL;
#ifdef CC_FBM_TWO_FBP_SHARED_WITH_DFB    
     char str[50];
     char size[50];
#endif
     (void)screen;


     DIRECT_INTERFACE_DBG_DELTA_START();

     D_ASSERT( dfb_mt53 == NULL );

     pool = dfb_core_shmpool( core );

     dfb_mt53 = (MT53 *)D_CALLOC( 1, sizeof(MT53) );
     if (!dfb_mt53)
          return D_OOM();

     dfb_mt53->fd = -1;

     shared = (MT53Shared*) SHCALLOC( pool, 1, sizeof(MT53Shared) );
     if (!shared) {
          ret = D_OOSHM();
          goto error;
     }

     shared->shmpool = pool;

     fusion_arena_add_shared_field( dfb_core_arena( core ), "mt53", shared );

     dfb_mt53->core   = core;
     dfb_mt53->shared = shared;
#ifdef CC_ANDROID_TWO_WORLDS
     dfb_mt53->fd = direct_try_open( "/dev/graphics/fb1", "/dev/graphics/fb/1", O_RDWR, true );
#else
     dfb_mt53->fd = direct_try_open( "/dev/fb0", "/dev/fb/0", O_RDWR, true );
#endif
     if (dfb_mt53->fd < 0)
          goto error;
     
          dfb_fb = dfb_mt53->fd;

     ret = DFB_INIT;

     /* Initialization of mt53fb */
     var.xres           = MT53_PRIMARY_DEFAULT_WIDTH;
     var.yres           = MT53_PRIMARY_DEFAULT_HEIGHT;
     var.xres_virtual   = MT53_PRIMARY_DEFAULT_WIDTH;
     var.yres_virtual   = MT53_PRIMARY_DEFAULT_HEIGHT * 4;
     var.xoffset        = 0;
     var.yoffset        = 0;
     var.bits_per_pixel = 32;
     var.vmode = CM_ARGB8888_DIRECT32;

     if (ioctl( dfb_mt53->fd, FBIO_WAITLOGO, &var ) < 0) {
          D_PERROR( "DirectFB/MT53: FBIO_WAITLOGO failed!\n" );
          goto error;
     }

     if (ioctl( dfb_mt53->fd, FBIO_INIT, &var ) < 0) {
          D_PERROR( "DirectFB/MT53: FBIO_INIT failed!\n" );
          goto error;
     }

     /* Map the framebuffer */
     system_fb_mmap();  
     
     dfb_surface_pool_initialize( core, &mt53SurfacePoolFuncs, &dfb_mt53->shared->pool );

     *data = dfb_mt53;
#ifdef CC_FBM_TWO_FBP_SHARED_WITH_DFB
     snprintf(str, 50, "%d",dfb_mt53->imagebuf2.u4VirtAddr);
     snprintf(size, 50, "%d",dfb_mt53->imagebuf2.u4Size);
     printf("======DFB 3DMM u4VirtAddr : 0x%x, and DFB 3DMM u4Size : 0x%x======\n", dfb_mt53->imagebuf2.u4VirtAddr,dfb_mt53->imagebuf2.u4Size);

     if (setenv("DFB_3DMM_VIRTUAL_SIZE", size, 1) == -1)
     {
         D_PERROR( "DirectFB/MT53: Set DFB_3DMM_VIRTUAL_SIZE env error!\n");
         putenv("DFB_3DMM_VIRTUAL_SIZE=0");
     }
     
     if (setenv("DFB_3DMM_VIRTUAL_ADDR", str, 1) == -1)
     {
         D_PERROR( "DirectFB/MT53: Set DFB_3DMM_VIRTUAL_ADDR env error!\n");
         putenv("DFB_3DMM_VIRTUAL_ADDR=0");
     }
#endif
#ifdef DFB_INPUT_FILER_EN

     system_participant_init(shared);
     dfb_mt53->input_filter = NULL;
#endif
     DIRECT_INTERFACE_DBG_DELTA_END(DDDT_SYS_INIT);
     return DFB_OK;


error:
     if (shared)
          SHFREE( pool, shared );

     if (dfb_mt53->mem)
          munmap( dfb_mt53->mem, dfb_mt53->fix.smem_len );

     if (dfb_mt53->fd >= 0)
          close( dfb_mt53->fd );

     D_FREE( dfb_mt53 );
     dfb_mt53 = NULL;

     return ret;
}

int system_get_fb(void)
{
    D_ASSERT( dfb_mt53 == NULL );
    
    return dfb_mt53->fd;
}

static DFBResult
system_join( CoreDFB *core, void **data )
{
     DFBResult   ret = DFB_INIT;
     struct fb_var_screeninfo  var;
     CoreScreen *screen;
     void       *shared;
     
     DIRECT_INTERFACE_DBG_DELTA_START();
     
     D_ASSERT( dfb_mt53 == NULL );
     
     dfb_mt53 = D_CALLOC( 1, sizeof(MT53) );
     if (!dfb_mt53)
          return D_OOM();

     if(fusion_arena_get_shared_field( dfb_core_arena( core ), "mt53", &shared )) {
         ret =  DFB_FUSION;
         goto error;
     }

     dfb_mt53->core   = core;
     dfb_mt53->shared = shared;

#ifdef CC_ANDROID_TWO_WORLDS
     dfb_mt53->fd = direct_try_open( "/dev/graphics/fb1", "/dev/graphics/fb/1", O_RDWR, true );
#else
     dfb_mt53->fd = direct_try_open( "/dev/fb0", "/dev/fb/0", O_RDWR, true );
#endif   
     if (dfb_mt53->fd < 0)
          goto error;
     
#ifdef CC_SUPPORT_DYNAMIC_ENABLE_DFB_INPUTEVENT
          dfb_fb = dfb_mt53->fd;
#endif

     if (ioctl( dfb_mt53->fd, FBIO_WAITLOGO, &var ) < 0) {
          D_PERROR( "DirectFB/MT53: FBIO_WAITLOGO failed!\n" );
          goto error;
     }

     /* Map the framebuffer */
     system_fb_mmap();

     dfb_surface_pool_join( core, dfb_mt53->shared->pool, &mt53SurfacePoolFuncs );

     (void)screen;

     *data = dfb_mt53;
#ifdef DFB_INPUT_FILER_EN
     system_participant_attend(shared);
     dfb_mt53->input_filter = NULL;
#endif
     DIRECT_INTERFACE_DBG_DELTA_END(DDDT_SYS_INIT);
     return DFB_OK;
error:
     if (dfb_mt53->mem)
          munmap( dfb_mt53->mem, dfb_mt53->fix.smem_len );

     if (dfb_mt53->fd >= 0)
          close( dfb_mt53->fd );

     D_FREE( dfb_mt53 );
     dfb_mt53 = NULL;

     return ret;
}

static DFBResult
system_shutdown( bool emergency )
{
     MT53Shared          *shared;
     FusionSHMPoolShared *pool;

     D_ASSERT( dfb_mt53 != NULL );

     shared = dfb_mt53->shared;
     D_ASSERT( shared != NULL );

     pool = shared->shmpool;
     D_ASSERT( pool != NULL );

     dfb_surface_pool_destroy( shared->pool );

     SHFREE( pool, shared );


     munmap( dfb_mt53->mem, dfb_mt53->fix.smem_len );

     close( dfb_mt53->fd );

     D_FREE( dfb_mt53 );
     dfb_mt53 = NULL;

     return DFB_OK;
}

static DFBResult
system_leave( bool emergency )
{
     D_ASSERT( dfb_mt53 != NULL );
#ifdef DFB_INPUT_FILER_EN
     system_participant_leave(dfb_mt53->shared);
#endif
     munmap( dfb_mt53->mem, dfb_mt53->fix.smem_len );

     close( dfb_mt53->fd );

     D_FREE( dfb_mt53 );
     dfb_mt53 = NULL;

     return DFB_OK;
}

static DFBResult
system_suspend()
{
     return DFB_OK;
}

static DFBResult
system_resume()
{
     return DFB_OK;
}

/******************************************************************************/

static volatile void *
system_map_mmio( unsigned int    offset,
                 int             length )
{
     return NULL;
}

static void
system_unmap_mmio( volatile void  *addr,
                   int             length )
{
}

int system_get_accelerator()
{
     return FB_ACCEL_MEDIATEK_53XX;
}

static VideoMode *
system_get_modes()
{
     return NULL;
}

static VideoMode *
system_get_current_mode()
{
     return NULL;
}

static DFBResult
system_thread_init()
{
     return DFB_OK;
}

static bool
system_input_filter( CoreInputDevice *device,
                     DFBInputEvent   *event )
{
#ifdef DFB_INPUT_FILER_EN

     return system_participant_dispatch_inputevent(dfb_mt53->shared, event);
#else
    return false;
#endif
}

unsigned long system_video_memory_physical( unsigned int offset )
{
     return dfb_mt53->fix.smem_start + offset;
}

void* system_video_memory_virtual( unsigned int offset )
{
     return dfb_mt53->mem + offset;
}

unsigned int system_videoram_length()
{
     return dfb_mt53->fix.smem_len;
}

unsigned long system_aux_memory_physical( unsigned int offset )
{
#ifdef CC_OSD_USE_FBM
     return dfb_mt53->imagebuf.u4PhyAddr;
#else
     return NULL;
#endif
}

void *system_aux_memory_virtual( unsigned int offset )
{
#ifdef CC_OSD_USE_FBM
     return (void*)dfb_mt53->imagebuf.u4VirtAddr;
#else
     return NULL;
#endif
}

unsigned int system_auxram_length()
{
#ifdef CC_OSD_USE_FBM
     return dfb_mt53->imagebuf.u4Size;
#else
     return 0;
#endif
}

void
system_get_busid( int *ret_bus, int *ret_dev, int *ret_func )
{
}

void
system_get_deviceid( unsigned int *ret_vendor_id,
                     unsigned int *ret_device_id )
{
}

int system_surface_data_size( void )
{
    return 0x0;
}

void system_surface_data_init( CoreSurface *surface, void *data )
{
    return;
}

void system_surface_data_destroy( CoreSurface *surface, void *data )
{
    return;
}
int system_mmu_pin_mem( DFB_IOMMU_PIN_RANGE_T *pt_page )
{
#ifdef GFX_IOMMU_IOVA_SUPPORT//need to be kept.
    unsigned int va = 0;
#endif
    DIRECT_INTERFACE_DBG_DELTA_START();
    
#ifdef GFX_IOMMU_IOVA_SUPPORT//need to be kept.
    pt_page->devIdx=0; //gfx
    pt_page->direction=DFB_MTIOMMU_DMA_BIDIRECTION;
    va=(pt_page->start&0xfff);
    direct_log_printf(NULL, "%s ", __FUNCTION__);
#endif

    if(ioctl( dfb_mt53->fd, FBIO_MMU_PINMEM, pt_page ) < 0)
    {
        direct_log_printf(NULL, "mmu_pin_mem Fail![0x%llx,0x%x]\n",pt_page->start,pt_page->size);
    }
#ifdef GFX_IOMMU_IOVA_SUPPORT//need to be kept.
    pt_page->iova|=va;
#endif

    DIRECT_INTERFACE_DBG_DELTA_END(DDDT_PIN_MEM);
        
    return 0x0;
}

#ifdef DFB_IOMMU_PRECHECK
unsigned int system_mmu_get_ttb(void)
{
    unsigned int TTB = 0;
    if(ioctl( dfb_mt53->fd, FBIO_MMU_GETPGD, &TTB ) < 0)
    {
        direct_log_printf(NULL, "system_mmu_get_ttb Fail!\n");
    }
    return TTB;
}

unsigned long long system_mmu_va_to_pa(unsigned int va)
{
    DFB_ADDR_PRECHECK_T rCheck;

    memset(&rCheck, 0x0, sizeof(rCheck));

    rCheck.u4_uaddr = va;

    if (ioctl(dfb_mt53->fd, FBIO_GET_PA_FROM_VA, &rCheck) < 0)
    {
        direct_log_printf(NULL, "%s Fail!\n", __func__);
    }

    return rCheck.u8_phy_addr;
}

unsigned long long system_mmu_iova_to_pa(unsigned int iova)
{
    DFB_ADDR_PRECHECK_T rCheck;

    memset(&rCheck, 0x0, sizeof(rCheck));

    rCheck.u4_uaddr = iova;

    if (ioctl(dfb_mt53->fd, FBIO_GET_PA_FROM_IOVA, &rCheck) < 0)
    {
        direct_log_printf(NULL, "%s Fail!\n", __func__);
    }

    return rCheck.u8_phy_addr;
}

#endif
int system_mmu_pin_iomem( DFB_IOMMU_PIN_RANGE_T *pt_page )
{
    DIRECT_INTERFACE_DBG_DELTA_START();
    if(ioctl( dfb_mt53->fd, FBIO_MMU_IOMAP_PINMEM, pt_page ) < 0)
    {
        direct_log_printf(NULL, "mmu_pin_iomem Fail![0x%llx,0x%x], pid=0x%x\n",pt_page->start,pt_page->size, getpid());
    }
    DIRECT_INTERFACE_DBG_DELTA_END(DDDT_PIN_MEM);
    return 0x0;
}

int system_mmu_unpin_mem( DFB_IOMMU_PIN_RANGE_T *pt_page )
{
    DIRECT_INTERFACE_DBG_DELTA_START();
#ifdef GFX_IOMMU_IOVA_SUPPORT//need to be kept.
    pt_page->devIdx=0; //gfx
#endif
    if(ioctl( dfb_mt53->fd, FBIO_MMU_UNPINMEM, pt_page ) < 0)
    {
        direct_log_printf(NULL, "mmu_unpin_mem Fail![0x%llx,0x%x]\n",pt_page->start,pt_page->size);
    }
    DIRECT_INTERFACE_DBG_DELTA_END(DDDT_UNPIN_MEM);
    return 0x0;
}

void system_get_fbm_buf(struct mt53fb_imagebuffer *pt_fbm)
{
    int i4_cnt =0x0;
    
    if(pt_fbm == NULL )
    {
         return ;
    }
    
    do
    {
        if( dfb_mt53 == NULL )
        {
             break;
        }
        if (ioctl( dfb_mt53->fd, FBIO_FBM_INFO, dfb_mt53->t_fbm ) < 0)
        {
            D_PERROR( "DirectFB/MT53: FBIO_VDP_GETBUFFER failed!\n" );
            break;
        }


        dfb_mt53->t_fbm[0].u4VirtAddr = (unsigned int)mmap(
                             NULL,
                             dfb_mt53->t_fbm[0].u4Size,
                             PROT_READ | PROT_WRITE,
                             MAP_SHARED,
                             dfb_mt53->fd,
                             dfb_mt53->t_fbm[0].u4PhyAddr
                             );
        if (dfb_mt53->t_fbm[0].u4VirtAddr == (unsigned int)MAP_FAILED)
        {
            D_PERROR( "DirectFB/MT53: Could not mmap the fbm total buffer!\n");
            break;
        }
        else
        {
            D_INFO( "DirectFB/MT53: FBM[vir=0x%x,phy=0x%x,size=0x%x]\n",
            dfb_mt53->t_fbm[0].u4VirtAddr,dfb_mt53->t_fbm[0].u4PhyAddr,dfb_mt53->t_fbm[0].u4Size);
        }
        pt_fbm->u4VirtAddr  = dfb_mt53->t_fbm[0].u4VirtAddr;
        pt_fbm->u4PhyAddr   = dfb_mt53->t_fbm[0].u4PhyAddr;
        pt_fbm->u4Size      = dfb_mt53->t_fbm[0].u4Size;

    }while(0);

    return ;
}



void* system_get_crsr_addr(void)
{
    if( dfb_mt53 == NULL )
    {
         return 0x0;
    }
    
    return (void*)dfb_mt53->t_crsr.u4VirtAddr;
}


unsigned int system_get_crsr_phy(void)
{
    if( dfb_mt53 == NULL )
    {
         return 0x0;
    }
    
    return dfb_mt53->t_crsr.u4PhyAddr;
}

unsigned int system_get_crsr_size(void)
{
    if( dfb_mt53 == NULL )
    {
         return 0x0;
    }
    
    return dfb_mt53->t_crsr.u4Size;
}

void dfb_dbg_delta_clear(void)
{
    unsigned int u4_idx =0x0;
    
    if( dfb_mt53 == NULL )
    {
         return;
    }
    
    for(u4_idx =0x0;u4_idx < DDDT_MAX;u4_idx++)
    {
        dfb_mt53->shared->a_dbg_delta[u4_idx].u8_cnt            = 0x0;
        dfb_mt53->shared->a_dbg_delta[u4_idx].u8_dfb_delta_time = 0x0;
    }
}

void dfb_dbg_delta_print(void)
{
    unsigned int u4_idx         = 0x0;
    long long    u8_val         = 0x0;
    long long    u8_drv_val     = 0x0;
    long long    u8_surf_val    = 0x0;
    long long    u8_card_val    = 0x0;
    
    if( dfb_mt53 == NULL )
    {
         return;
    }
    
    for(u4_idx =0;u4_idx < DDDT_EMMT_CMD;u4_idx++)
    {
        u8_val += dfb_mt53->shared->a_dbg_delta[u4_idx].u8_dfb_delta_time;
        
        if((u4_idx>=DDDT_SURFACE_FLIP)&&(u4_idx<=DDDT_SURFACE_DRAWMONOGLYPHS))
        {
            u8_surf_val += dfb_mt53->shared->a_dbg_delta[u4_idx].u8_dfb_delta_time;
        }

        if((u4_idx>=DDDT_CARD_FILLRECT)&&(u4_idx<=DDDT_CARD_TEXTURE_TRIANGLES))
        {
            u8_card_val += dfb_mt53->shared->a_dbg_delta[u4_idx].u8_dfb_delta_time;
        }
    }
    direct_log_printf(NULL,"%s[pid = %d] cpu[%lld ms] s[%lld ms] c[%lld ms]",__FUNCTION__,getpid(),u8_val/1000,u8_surf_val/1000,u8_card_val/1000);

    for(u4_idx = DDDT_EMMT_CMD;u4_idx < DDDT_MAX;u4_idx++)
    {
        u8_drv_val += dfb_mt53->shared->a_dbg_delta[u4_idx].u8_dfb_delta_time;
    }

    direct_log_printf(NULL,"hw[%lld ms] \n",u8_drv_val/1000);

    for(u4_idx = 0;u4_idx < DDDT_MAX;u4_idx++)
    {
        if(!(u4_idx%2))
        {
            direct_log_printf(NULL,"\n");
        }
        direct_log_printf(NULL,"delta[%4d][%4lld][%8lld ms] ",u4_idx,dfb_mt53->shared->a_dbg_delta[u4_idx].u8_cnt,dfb_mt53->shared->a_dbg_delta[u4_idx].u8_dfb_delta_time/1000);
    }

    direct_log_printf(NULL,"\n");
}


u32 dfb_interface_dbg_delta_enable(void)
{
    if( dfb_mt53 == NULL )
    {
         return 0x0;
    }

    return (dfb_mt53->shared->u4_dbg_lvl&MT53_DBG_DELTA_ENABLE);
}

void dfb_interface_dbg_set_delta_enable(unsigned int u4_enable)
{
    if( dfb_mt53 == NULL )
    {
         return;
    }

    if(u4_enable)
    {
        dfb_mt53->shared->u4_dbg_lvl |= (MT53_DBG_DELTA_ENABLE);
    }
    else
    {
        dfb_mt53->shared->u4_dbg_lvl &= (~MT53_DBG_DELTA_ENABLE);
    }

    return;
}

void dfb_interface_dbg_set_delta_data(unsigned int u4_idx,long long u8_val)
{
    if( dfb_mt53 == NULL )
    {
         return;
    }
    
    if(u4_idx >= MT53_MAX_DBG_DELTA)
    {
        return;
    }

    if(u8_val>1000000)
    {
        direct_log_printf(NULL,"set_delta_data fail[%d][%lld ms] \n",u4_idx,u8_val/1000);
        return;
    }
    
    dfb_mt53->shared->a_dbg_delta[u4_idx].u8_cnt++;
    dfb_mt53->shared->a_dbg_delta[u4_idx].u8_dfb_delta_time += u8_val;
}


void system_get_tmp_buf(struct mt53fb_imagebuffer *pt_fbm)
{
    if(pt_fbm == NULL )
    {
         return ;
    }
    
    do
    {
        if( dfb_mt53 == NULL )
        {
             break;
        }
        
        if (ioctl( dfb_mt53->fd, FBIO_GET_TMP_BUF, pt_fbm ) < 0) 
        {
            D_PERROR( "DirectFB/MT53: FBIO_VDP_GETBUFFER failed!\n" );
            break;
        }
    }while(0);

    return ;
}

void system_lock_tmp_buf(void)
{
    do
    {
        if( dfb_mt53 == NULL )
        {
             break;
        }
        
        if (ioctl( dfb_mt53->fd, FBIO_LOCK_TMP_BUF) < 0) 
        {
            D_PERROR( "DirectFB/MT53: system_lock_tmp_buf failed!\n" );
            break;
        }
    }while(0);

    return ;
}

void system_unlock_tmp_buf(void)
{
    do
    {
        if( dfb_mt53 == NULL )
        {
             break;
        }
        
        if (ioctl( dfb_mt53->fd, FBIO_UNLOCK_TMP_BUF) < 0) 
        {
            D_PERROR( "DirectFB/MT53: system_unlock_tmp_buf failed!\n" );
            break;
        }
    }while(0);

    return ;
}

void system_munmap_check(void)
{
    system_munmap_imagebuf_addr();
    system_munmap_imagebuf2_addr();
    system_munmap_vdpbuf_addr();
    
    #ifdef CC_B2R44K2K_SUPPORT
    system_munmap_b2r44K2Kbuf_addr();
    #endif
}
#ifdef DFB_INPUT_FILER_EN

void dfb_register_inputfilter(DFBInputFilter filter)
{
    int i, pid;
    MT53Shared *shared;

    if(dfb_mt53 != NULL)
    {
        dfb_mt53->input_filter = filter;
        if(dfb_core_is_master(dfb_mt53->core) == false)
        {
            pid = getpid();
            shared = dfb_mt53->shared;
            for(i = 0; i < MT53_MAX_PARTICIPANTS; i++)
            {
                if(shared->participants[i].mark == true && shared->participants[i].pid == pid)
                {
                    shared->participants[i].inputfilter = (bool) filter;
                }
            }
        }
    }
}
#endif
