/* 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 <stdio.h>
#include <sys/mman.h>

#include <directfb.h>

#include <direct/debug.h>
#include <direct/messages.h>
#include <direct/system.h>

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

#include <mt53/mt53.h>

#include <gfx_if.h>

#include "mt53_2d.h"
#include "mt53_gfxdriver.h"

#include <core/graphics_driver.h>

DFB_GRAPHICS_DRIVER( mt53gfx )


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

static int
driver_probe( CoreGraphicsDevice *device )
{
     switch (dfb_gfxcard_get_accelerator( device )) {
          case FB_ACCEL_MEDIATEK_53XX:
               return 1;
     }

     return 0;
}

static void
driver_get_info( CoreGraphicsDevice *device,
                 GraphicsDriverInfo *info )
{
     /* fill driver info structure */
     snprintf( info->name,
               DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH,
               "MediaTek 53xx Driver" );

     snprintf( info->vendor,
               DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH,
               "Denis Oliver Kropp" );

     info->version.major = 0;
     info->version.minor = 3;

     info->driver_data_size = sizeof(MT53DriverData);
     info->device_data_size = sizeof(MT53DeviceData);
}

static DFBResult
driver_init_driver( CoreGraphicsDevice  *device,
                    GraphicsDeviceFuncs *funcs,
                    void                *driver_data,
                    void                *device_data,
                    CoreDFB             *core )
{
     MT53DriverData *mdrv = driver_data;
     MT53           *mt53 = dfb_system_data();
     int plane_order = 0;

     mdrv->fd = mt53->fd;

     mdrv->num_plane = 0;

     mdrv->shm_cmd_que = mmap( NULL, direct_pagesize(), PROT_READ | PROT_WRITE, MAP_SHARED,
                               mdrv->fd, direct_page_align( mt53->fix.smem_len ) );
     if (mdrv->shm_cmd_que == MAP_FAILED) {
          D_PERROR( "MediaTek/Driver: Mapping shared command queue control structure failed!\n" );
          return DFB_INIT;
     }

     D_INFO( "MediaTek/Driver: Mapped shared command queue control structure to %p\n", mdrv->shm_cmd_que );

     mdrv->cmd_que_buf = mmap( NULL, 256 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED,
                               mdrv->fd, direct_page_align( mt53->fix.smem_len ) + direct_pagesize() );
     if (mdrv->cmd_que_buf == MAP_FAILED) {
          D_PERROR( "MediaTek/Driver: Mapping DMA region failed!\n" );
          munmap( (void*) mdrv->shm_cmd_que, direct_pagesize() );
          return DFB_INIT;
     }

     D_INFO( "MediaTek/Driver: Mapped DMA region to %p\n", mdrv->cmd_que_buf );

     GFX_CmdQueInit( mdrv->shm_cmd_que, &mdrv->cmd_que_buf );

     /* initialize function pointers */
     funcs->EngineSync   = mt53EngineSync;
     funcs->EngineReset  = mt53EngineReset;
     funcs->EmitCommands = mt53EmitCommands;
     funcs->CheckState   = mt53CheckState;
     funcs->SetState     = mt53SetState;
     funcs->StopDrawing  = mt53EngineStopDrawing;

     funcs->FlushTextureCache = mt53FlushTextureCache;
     funcs->FlushReadCache = mt53FlushReadCache;


     /* Register primary screen functions */
     mdrv->screen = dfb_screens_register( device, driver_data, &mt53PrimaryScreenFuncs );

     /* Register primary layer functions */
     mdrv->layer1 = dfb_layers_register( mdrv->screen, driver_data, &mt53PrimaryLayerFuncs );
     mdrv->layer2 = dfb_layers_register( mdrv->screen, driver_data, &mt53PrimaryLayerFuncs );
     mdrv->layer3 = dfb_layers_register( mdrv->screen, driver_data, &mt53PrimaryLayerFuncs );
#ifdef CC_B2R44K2K_SUPPORT
     mdrv->layer_vdp = dfb_layers_register( mdrv->screen, driver_data, &mt53PrimaryLayerFuncs );
#else
     mdrv->layer_vdp = dfb_layers_register( mdrv->screen, driver_data, &mt53VdpLayerFuncs );
#endif     
     mdrv->cursor = dfb_layers_register( mdrv->screen, driver_data, &mt53PrimaryLayerFuncs );
	 mdrv->layer_vdp2 = dfb_layers_register( mdrv->screen, driver_data, &mt53VdpLayerFuncs );
#ifdef CC_B2R44K2K_SUPPORT
	 mdrv->m_ContainerLayer = dfb_layers_register( mdrv->screen, driver_data, &mt53PrimaryLayerFuncs );
#endif	 

     return DFB_OK;
}

static DFBResult
driver_init_device( CoreGraphicsDevice *device,
                    GraphicsDeviceInfo *device_info,
                    void               *driver_data,
                    void               *device_data )
{
     /* fill device info */
     snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "MediaTek" );
     snprintf( device_info->name,   DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH,   "53xx" );

     /* device limitations */
     device_info->limits.surface_byteoffset_alignment = 4096;
     device_info->limits.surface_bytepitch_alignment  = 64;

     device_info->caps.flags    = 0;
     device_info->caps.accel    = MT53_SUPPORTED_DRAWINGFUNCTIONS |
                                  MT53_SUPPORTED_BLITTINGFUNCTIONS;
     device_info->caps.drawing  = MT53_SUPPORTED_DRAWINGFLAGS;
     device_info->caps.blitting = MT53_SUPPORTED_BLITTINGFLAGS;

     return DFB_OK;
}

static void
driver_close_device( CoreGraphicsDevice *device,
                     void               *driver_data,
                     void               *device_data )
{
}

static void
driver_close_driver( CoreGraphicsDevice *device,
                     void               *driver_data )
{
    MT53DriverData *mdrv = driver_data;

    munmap( (void*) mdrv->cmd_que_buf, 256 * 1024 );
    munmap( (void*) mdrv->shm_cmd_que, direct_pagesize() );
}
