/* 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.
 *
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 *
 * $Author: shuo.ding $
 * $Date: 2015/08/19 $
 * $RCSfile: osd_plane_if.c,v $
 * $Revision: #10 $
 *
 *---------------------------------------------------------------------------*/

/** @file osd_plane_if.c
 *  osd plane header, incluse osd plane setting
 */

//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------

#include "osd_hw.h"
#include "osd_drvif.h"
#include "osd_debug.h"
#include "drvcust_if.h"
#include "panel.h"
LINT_EXT_HEADER_BEGIN
#include "x_hal_5381.h"
LINT_EXT_HEADER_END
#include "x_timer.h"
#include "drv_tdtv_drvif.h"
#ifndef CC_MTK_LOADER
#include "gfx_if.h"
#endif
#ifdef CC_MTK_LOADER
#define CRIT_STATE_T    UINT32
#ifdef x_crit_start
#undef x_crit_start
#define x_crit_start()  (0)
#endif
#ifdef x_crit_end
#undef x_crit_end
#define x_crit_end(x)   UNUSED(x)
#endif
#endif /* CC_MTK_LOADER */

#ifndef CC_MTK_LOADER
#ifdef SYS_3D_SUPPORT
#include "imgrz_if.h"
#endif
#endif

#ifndef CC_MTK_LOADER
#ifdef CC_CONFIG_OSD_SBS
#include "imgrz_if.h"
#include "gfx_if.h"
#endif
#endif

#ifndef CC_MTK_LOADER
#ifdef CC_ANDROID_3D_UI_SUPPORT
#include "imgrz_if.h"
#include "gfx_if.h"
#endif
#endif
#include "ovl_drvif.h"

//-----------------------------------------------------------------------------
// Constant definitions
//-----------------------------------------------------------------------------
INT32 OSD_PLA_DoFlipTo(UINT32 u4Plane, UINT32 u4List);

// delay to avoid temporal status when switching display mode
#define MUTE_VSYNC 10

//define the DRAM access configuration for OSD plane 3
#define OSD3_ContReqLmt 3
#define OSD3_FifoSize 3
#define OSD3_VacTh 3
#define OSD3_PauseCnt 0xf
#define OSD3_ContReqLmt0 1
#define OSD3_BurstDis 0

#ifndef CC_MTK_LOADER
#ifdef SYS_3D_SUPPORT
#define UI_WIDTH    960
#define UI_HEIGHT    540
#define UI_BPP    4
#endif
#endif

BOOL bIsPanelLock = FALSE;

//-----------------------------------------------------------------------------
// Type definitions
//-----------------------------------------------------------------------------

typedef struct _OSD_PLANE_INFO_T
{
    UPTR u4FirstRegionAddr;
    UPTR u4RightRegionAddr;
    INT32 fgPlaneEnable;
    INT32 fgGlobeEnable;
    INT32 i4FlipedList;
    INT32 i4FirstRegionId;
    INT32 i4RightRegionId;
    UINT32 u4DecEn;
} OSD_PLANE_INFO_T;

typedef struct
{
    const UINT32 u4Plane;
    const UINT32 u4Scaler;
    UINT32 u4RgnList;
    UINT32 u4SCSrcWidth;
    UINT32 u4SCSrcHeight;
    UINT32 u4SCDstWidth;
    UINT32 u4SCDstHeight;
    BOOL fgEnable;
    BOOL fgAvailable;
    BOOL fgPlaCache;
    BOOL fgSCCache;
    BOOL fgEnCache;
}
OSD_PLA_CACHE_IFNO_T;

//-----------------------------------------------------------------------------
// Static variables
//-----------------------------------------------------------------------------

static OSD_PLANE_INFO_T _arOsdPlaneInfo[OSD_PLANE_MAX_NUM];
static UINT32 _u4MuteCounter = 0;
//static UINT8 _u1FadingCache[OSD_PLANE_MAX_NUM];
//static BOOL _fgInit = FALSE;

#if 0
//For 3D OSD
UINT8 _u13DMode = 0;
UINT8 _u1Previous3DMode = 0;
UINT32 _u4_3D_Plane;
UINT32 _u4_3D_Region;
UINT32 _au4_3D_L_Addr;
UINT32 _au4_3D_R_Addr;
//UINT32 _au4_3D_L_Addr[2];
//UINT32 _au4_3D_R_Addr[2];
#endif

#ifndef CC_MTK_LOADER
#ifdef SYS_3D_SUPPORT
static UINT32 _u43DPlane = 0;
static UINT32 _e3DMode = 0;
static UINT32 _u4Shift = 0;
static UINT32 _u4BmpWidth = 0;
static UINT32 _u4BmpHeight = 0;
static UINT32 _u4BmpPitch = 0;
static UPTR _u4DstAddr = 0;
static UINT32 _eColorMode = 0;
static UPTR _u4SrcAddr = 0;
static UPTR _u4TmpBuf = 0;
static UPTR _u4TmpBuf1 = 0;
#endif
#endif


#if defined(GAL_DDI_SUPPORT)
#ifndef CC_MTK_LOADER
extern UINT32 _u4Posd0Rgn0, _u4Posd0Rgn1;
extern UINT32 _u4Posd1Rgn0, _u4Posd1Rgn1;
#endif
#endif

#if defined(CC_MT5893) || defined(CC_MT5895)
//static INT32 arOsdPlaneRgnList[OSD_PLANE_MAX_NUM];
static INT32 arOsdPlaneInternalRgnList[OSD_PLANE_MAX_NUM][OSD_PLANE_RGN_MAX];
static INT32 arOsdPlaneInternalRgnState[OSD_PLANE_MAX_NUM];

void OSD_PLA_InitialInternalRgnList(void)
{
#ifndef CC_MTK_LOADER
    UINT32 i, j, u4RgnId, u4RgnList;
    for (i = 0; i < OSD_PLANE_MAX_NUM; i++)
    {
        for (j = 0; j < OSD_PLANE_RGN_MAX; j++)
        {
            IGNORE_RET(OSD_RGN_LIST_Create(&u4RgnList));
            IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
            IGNORE_RET(OSD_RGN_Insert(u4RgnId, u4RgnList));
            arOsdPlaneInternalRgnList[i][j] = u4RgnList;
        }
        arOsdPlaneInternalRgnState[i] = OSD_PLANE_RGN_STATE_FRONT;
    }
#else
#if defined(CC_MT5895)
    if ((IS_SUPPORT_VB1_GRAPH_MODE == 0) && PANEL_Is4K2K120())
    {
        UINT32 u4LogoPlane_loader = OSD_PLANE_1;
        UINT32 u4LogoPlane_upgrade = OSD_PLANE_2;
        UINT32 u4RgnId, u4RgnList;
        UINT32 i;
        for (i = 0; i < OSD_PLANE_RGN_MAX; i++)
        {
            IGNORE_RET(OSD_RGN_LIST_Create(&u4RgnList));
            IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
            IGNORE_RET(OSD_RGN_Insert(u4RgnId, u4RgnList));
            arOsdPlaneInternalRgnList[u4LogoPlane_loader][i] = u4RgnList;
        }
        arOsdPlaneInternalRgnState[u4LogoPlane_loader] = OSD_PLANE_RGN_STATE_FRONT;

        u4LogoPlane_loader = OSD_RT_PLANE_1;
        for (i = 0; i < OSD_PLANE_RGN_MAX; i++)
        {
            IGNORE_RET(OSD_RGN_LIST_Create(&u4RgnList));
            IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
            IGNORE_RET(OSD_RGN_Insert(u4RgnId, u4RgnList));
            arOsdPlaneInternalRgnList[u4LogoPlane_loader][i] = u4RgnList;
        }
        arOsdPlaneInternalRgnState[u4LogoPlane_loader] = OSD_PLANE_RGN_STATE_FRONT;

        for (i = 0; i < OSD_PLANE_RGN_MAX; i++)
        {
            IGNORE_RET(OSD_RGN_LIST_Create(&u4RgnList));
            IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
            IGNORE_RET(OSD_RGN_Insert(u4RgnId, u4RgnList));
            arOsdPlaneInternalRgnList[u4LogoPlane_upgrade][i] = u4RgnList;
        }
        arOsdPlaneInternalRgnState[u4LogoPlane_upgrade] = OSD_PLANE_RGN_STATE_FRONT;

        u4LogoPlane_upgrade = OSD_RT_PLANE_2;
        for (i = 0; i < OSD_PLANE_RGN_MAX; i++)
        {
            IGNORE_RET(OSD_RGN_LIST_Create(&u4RgnList));
            IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
            IGNORE_RET(OSD_RGN_Insert(u4RgnId, u4RgnList));
            arOsdPlaneInternalRgnList[u4LogoPlane_upgrade][i] = u4RgnList;
        }
        arOsdPlaneInternalRgnState[u4LogoPlane_upgrade] = OSD_PLANE_RGN_STATE_FRONT;

    }
    else
#endif
{
    UINT32 u4LogoPlane = OSD_PLANE_2;
    UINT32 u4RgnId, u4RgnList;
    UINT32 i;
    for (i = 0; i < OSD_PLANE_RGN_MAX; i++)
    {
        IGNORE_RET(OSD_RGN_LIST_Create(&u4RgnList));
        IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
        IGNORE_RET(OSD_RGN_Insert(u4RgnId, u4RgnList));
        arOsdPlaneInternalRgnList[u4LogoPlane][i] = u4RgnList;
    }
    arOsdPlaneInternalRgnState[u4LogoPlane] = OSD_PLANE_RGN_STATE_FRONT;

    u4LogoPlane = OSD_RT_PLANE_2;
    for (i = 0; i < OSD_PLANE_RGN_MAX; i++)
    {
        IGNORE_RET(OSD_RGN_LIST_Create(&u4RgnList));
        IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
        IGNORE_RET(OSD_RGN_Insert(u4RgnId, u4RgnList));
        arOsdPlaneInternalRgnList[u4LogoPlane][i] = u4RgnList;
    }
    arOsdPlaneInternalRgnState[u4LogoPlane] = OSD_PLANE_RGN_STATE_FRONT;
}
#endif
}

void OSD_PLA_SwitchInternalRgnId(UINT32 u4Plane)
{
    arOsdPlaneInternalRgnState[u4Plane] = !arOsdPlaneInternalRgnState[u4Plane];
}

UINT32 OSD_PLA_GetAvailableInternalRgnList(UINT32 u4Plane)
{
    UINT32 u4ListId = !arOsdPlaneInternalRgnState[u4Plane];
    return arOsdPlaneInternalRgnList[u4Plane][u4ListId];
}

UINT32 OSD_PLA_GetCurrentInternalRgnList(UINT32 u4Plane)
{
    UINT32 u4ListId = arOsdPlaneInternalRgnState[u4Plane];
    return arOsdPlaneInternalRgnList[u4Plane][u4ListId];
}
#endif

OSD_PLA_CACHE_IFNO_T _arPlaneCacheInfo[] =
{
    {
        .u4Plane = OSD_PLANE_1,
        .u4Scaler = OSD_SCALER_1,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
    {
        .u4Plane = OSD_PLANE_2,
        .u4Scaler = OSD_SCALER_2,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
    {
        .u4Plane = OSD_PLANE_3,
        .u4Scaler = OSD_SCALER_3,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
    {
        .u4Plane = OSD_PLANE_4,
        .u4Scaler = OSD_SCALER_MAX_NUM,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
    {
        .u4Plane = OSD_PLANE_5,
        .u4Scaler = OSD_SCALER_MAX_NUM,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
#if defined(CC_MT5893) || defined(CC_MT5895)
    {
        .u4Plane = OSD_RT_PLANE_1,
        .u4Scaler = OSD_RT_SCALER_1,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
    {
        .u4Plane = OSD_RT_PLANE_2,
        .u4Scaler = OSD_RT_SCALER_2,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
    {
        .u4Plane = OSD_RT_PLANE_3,
        .u4Scaler = OSD_RT_SCALER_3,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
    {
        .u4Plane = OSD_RT_PLANE_5,
        .u4Scaler = OSD_SCALER_MAX_NUM,
        .fgAvailable = TRUE,
        .fgPlaCache = FALSE,
        .fgSCCache = FALSE
    },
#endif
};

VOID OSD_PLA_SetAvailable(UINT32 u4Plane, BOOL fgVailable)
{
    static UINT32 setUnAvailableTimes[OSD_PLANE_MAX_NUM] = {0};

    ASSERT((u4Plane < OSD_PLANE_MAX_NUM));

    if (fgVailable == FALSE)
    {
        setUnAvailableTimes[u4Plane]++;
        _arPlaneCacheInfo[u4Plane].fgAvailable = FALSE;
    }
    else
    {
        setUnAvailableTimes[u4Plane]--;
        if (setUnAvailableTimes[u4Plane] == 0)
        {
            _arPlaneCacheInfo[u4Plane].fgAvailable = TRUE;
        }
    }

    if (_arPlaneCacheInfo[u4Plane].fgAvailable == TRUE)
    {
        if (_arPlaneCacheInfo[u4Plane].fgPlaCache == TRUE)
        {
            OSD_PLA_DoFlipTo(u4Plane, _arPlaneCacheInfo[u4Plane].u4RgnList);
            _arPlaneCacheInfo[u4Plane].fgPlaCache = FALSE;
        }

        if (_arPlaneCacheInfo[u4Plane].fgSCCache == TRUE)
        {
            IGNORE_RET(OSD_SC_Scale(_arPlaneCacheInfo[u4Plane].u4Scaler, 1, _arPlaneCacheInfo[u4Plane].u4SCSrcWidth,
                         _arPlaneCacheInfo[u4Plane].u4SCSrcHeight, _arPlaneCacheInfo[u4Plane].u4SCDstWidth,
                         _arPlaneCacheInfo[u4Plane].u4SCDstHeight));
            _arPlaneCacheInfo[u4Plane].fgSCCache = FALSE;
        }

        if (_arPlaneCacheInfo[u4Plane].fgEnCache == TRUE)
        {
            OSD_PLA_Enable(u4Plane, _arPlaneCacheInfo[u4Plane].fgEnable);
            _arPlaneCacheInfo[u4Plane].fgEnCache = FALSE;
        }
    }

#if defined(CC_MT5893) || defined(CC_MT5895)
    if (_arPlaneCacheInfo[OSD_PLANE_1].fgAvailable && _arPlaneCacheInfo[OSD_PLANE_2].fgAvailable &&
            _arPlaneCacheInfo[OSD_PLANE_3].fgAvailable && _arPlaneCacheInfo[OSD_RT_PLANE_1].fgAvailable &&
            _arPlaneCacheInfo[OSD_RT_PLANE_2].fgAvailable && _arPlaneCacheInfo[OSD_RT_PLANE_3].fgAvailable)
#else
    if (_arPlaneCacheInfo[OSD_PLANE_1].fgAvailable && _arPlaneCacheInfo[OSD_PLANE_2].fgAvailable &&
            _arPlaneCacheInfo[OSD_PLANE_3].fgAvailable)
#endif
    {
        bIsPanelLock = FALSE;
    }
    else
    {
        bIsPanelLock = TRUE;
    }

    if (_arPlaneCacheInfo[u4Plane].fgAvailable == TRUE)
    {
        _OSD_UpdateReg();
    }
}

BOOL OSD_PLA_GetAllPanelAvailable(VOID)
{
    return bIsPanelLock;
}

BOOL OSD_PLA_GetAvailable(UINT32 u4Plane)
{
    ASSERT((u4Plane < OSD_PLANE_MAX_NUM));
    return _arPlaneCacheInfo[u4Plane].fgAvailable;
}


INT32 OSD_PLA_CacheRngList(UINT32 u4Plane, UINT32 u4RgnList)
{
    ASSERT((u4Plane < OSD_PLANE_MAX_NUM));

    if (_arPlaneCacheInfo[u4Plane].fgAvailable == FALSE)
    {
        _arPlaneCacheInfo[u4Plane].u4RgnList = u4RgnList;
        _arPlaneCacheInfo[u4Plane].fgPlaCache = TRUE;
        return 0;
    }

    return -1;
}

INT32 OSD_PLA_CacheScaler(UINT32 u4Scaler, UINT32 u4SrcWidth, UINT32 u4SrcHeight, UINT32 u4DstWidth,
                          UINT32 u4DstHeight)
{
    UINT32 u4Plane;

    if (u4Scaler == OSD_SCALER_1)
    {
        u4Plane = OSD_PLANE_1;
    }
    else if (u4Scaler == OSD_SCALER_2)
    {
        u4Plane = OSD_PLANE_2;
    }
    else if (u4Scaler == OSD_SCALER_3)
    {
        u4Plane = OSD_PLANE_3;
    }
#if defined(CC_MT5893) || defined(CC_MT5895)
    else if (u4Scaler > 2 && u4Scaler < 6)
    {
        u4Plane = u4Scaler + 2;
    }
#endif
    else
    {
        return -1;
    }

    if (_arPlaneCacheInfo[u4Plane].fgAvailable == FALSE)
    {
        _arPlaneCacheInfo[u4Plane].u4SCSrcWidth = u4SrcWidth;
        _arPlaneCacheInfo[u4Plane].u4SCSrcHeight = u4SrcHeight;
        _arPlaneCacheInfo[u4Plane].u4SCDstWidth = u4DstWidth;
        _arPlaneCacheInfo[u4Plane].u4SCDstHeight = u4DstHeight;
        _arPlaneCacheInfo[u4Plane].fgSCCache = TRUE;
        return 0;
    }

    return -1;
}

INT32 OSD_PLA_CacheEnable(UINT32 u4Plane, BOOL fgEnable)
{
    ASSERT((u4Plane < OSD_PLANE_MAX_NUM));

    if (_arPlaneCacheInfo[u4Plane].fgAvailable == FALSE)
    {
        _arPlaneCacheInfo[u4Plane].fgEnable = fgEnable;
        _arPlaneCacheInfo[u4Plane].fgEnCache = TRUE;
        return 0;
    }

    return -1;
}

BOOL OSD_PLA_GetEnableCacheState(UINT32 u4Plane)
{
    return _arPlaneCacheInfo[u4Plane].fgEnCache;
}

BOOL OSD_PLA_GetFlipCacheState(UINT32 u4Plane)
{
    return _arPlaneCacheInfo[u4Plane].fgPlaCache;
}

BOOL OSD_PLA_GetSCCacheState(UINT32 u4Plane)
{
    return _arPlaneCacheInfo[u4Plane].fgSCCache;
}

BOOL _OsdPlaReadyToDisplay(UINT32 u4Plane)
{
    return (_arOsdPlaneInfo[u4Plane].fgGlobeEnable
            && _arOsdPlaneInfo[u4Plane].u4FirstRegionAddr
            && _arOsdPlaneInfo[u4Plane].fgPlaneEnable);
}

//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
/** set osd plane fast mute
 *  @param  u4Plane plane id
 *  @param  u1Mute
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_SetFastMute(UINT32 u4Plane, UINT32 u4Mute)
{
    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32)OSD_RET_OK == _OSD_PLA_SetFastMute(u4Plane, u4Mute));
    VERIFY((INT32)OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4Plane));
    return (INT32)OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** get osd plane fast mute
 *  @param  u4Plane plane id
 *  @param  u1Mute
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_GetFastMute(UINT32 u4Plane, UINT32 *pu4Mute)
{
    UINT32 u4FastMute = 0x0;

    if (pu4Mute == NULL)
    {
        return -(INT32) OSD_RET_INV_ARG;
    }

    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_GetFastMute(u4Plane, &u4FastMute));
    *pu4Mute = (UINT8) u4FastMute;
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_SetGlobeEnable(UINT32 u4Plane, BOOL fgGlobeEnable)
{
    OSD_VERIFY_PLANE(u4Plane);
    _arOsdPlaneInfo[u4Plane].fgGlobeEnable = fgGlobeEnable;
    _OSD_PLA_UpdateHwReg(u4Plane);
    return (INT32) OSD_RET_OK;
}

VOID OSD_PLA_InitAll(VOID)
{
    UINT32 u4Plane;
    for (u4Plane = 0; u4Plane < OSD_PLANE_MAX_NUM; u4Plane++)
    {
        IGNORE_RET(OSD_PLA_Reset(u4Plane));
    }

#ifndef CC_MTK_LOADER
#if defined(ANDROID_TWO_WORLDS) || defined(ANDROID)
    OSD_PLA_SetPremulEn(OSD_PLANE_3, 1);
#endif
#endif

}

VOID OSD_PLA_SwResetAll(VOID)
{
    UINT32 u4Plane;
    for (u4Plane = 0; u4Plane < OSD_PLANE_MAX_NUM; u4Plane++)
    {
        IGNORE_RET(OSD_PLA_SwReset(u4Plane));
    }

#ifndef CC_MTK_LOADER
#if defined(ANDROID_TWO_WORLDS) || defined(ANDROID)
    OSD_PLA_SetPremulEn(OSD_PLANE_3, 1);
#endif
#endif
}

static void _OSD_PLA_ResetPlaneInfo(UINT32 u4Plane)
{
    LOG(0, "_OSD_PLA_ResetPlaneInfo:%d\n", u4Plane);
    //set i4FirstRegionId to -1 at initial state
    _arOsdPlaneInfo[u4Plane].i4FirstRegionId = -1;
    _arOsdPlaneInfo[u4Plane].i4FlipedList = -1;
    _arOsdPlaneInfo[u4Plane].fgGlobeEnable = TRUE;
}

INT32 OSD_PLA_Reset(UINT32 u4Plane)
{
    OSD_VERIFY_PLANE(u4Plane);
    // restore plane's hardware state
    IGNORE_RET(_OSD_PLA_ResetCacheRegs(u4Plane));
    IGNORE_RET(_OSD_PLA_SetHFilter(u4Plane, 1));
    IGNORE_RET(_OSD_PLA_SetBlending(u4Plane, 0xFF));
    IGNORE_RET(_OSD_PLA_SetHeaderAddr(u4Plane, 0));
    IGNORE_RET(_OSD_PLA_SetFading(u4Plane, 0xFF));
    IGNORE_RET(_OSD_PLA_SetEnHwRstDec(u4Plane, 1));
    IGNORE_RET(_OSD_PLA_SetFSMProtDis(u4Plane, 1));
    IGNORE_RET(_OSD_PLA_SetEnHdrIrq(u4Plane, 1));
    IGNORE_RET(_OSD_PLA_SetEnable(u4Plane, 0));
    // reset plane's software state
    x_memset((void *)&_arOsdPlaneInfo[u4Plane], 0, sizeof(OSD_PLANE_INFO_T));
    _OSD_PLA_ResetPlaneInfo(u4Plane);
    _OSD_PLA_UpdateHwReg(u4Plane);
    //_fgInit = TRUE;
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_SwReset(UINT32 u4Plane)
{
    UINT32 fgEnable = 0;
    OSD_VERIFY_PLANE(u4Plane);
    // restore plane's hardware state
    IGNORE_RET(_OSD_PLA_ResetCacheRegs(u4Plane));
    // reset plane's software state
    x_memset((void *)&_arOsdPlaneInfo[u4Plane], 0, sizeof(OSD_PLANE_INFO_T));
    _OSD_PLA_ResetPlaneInfo(u4Plane);
    _OSD_PLA_GetEnable(u4Plane, &fgEnable);
    _arOsdPlaneInfo[u4Plane].fgPlaneEnable = fgEnable;
    //_fgInit = TRUE;
    return (INT32) OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** enable/disable osd plane, it will also disable scaler when disable plane
 *  @param  u4Plane plane id
 *  @param  fgEnable enable=TRUE/disable=FALSE
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_Enable(UINT32 u4Plane, BOOL fgEnable)
{
    OSD_VERIFY_PLANE(u4Plane);

    CHECK_OSD_INIT();

    if ((OSD_Get_Dbg_Info(2) & 0x1) || (0 == OSD_PLA_CacheEnable(u4Plane, fgEnable)) || ((_arOsdPlaneInfo[u4Plane].fgPlaneEnable == fgEnable) && (u4Plane <= OSD_PLANE_5)))

    {
        return (INT32) OSD_RET_OK;
    }

    OSD_DUMP_LOG("plane:%d, enable:%d\n", u4Plane + 1, fgEnable);
    OSD_Dump_Stack();

    // temp change for M5
    #ifndef CC_MT5895
    if (_arOsdPlaneInfo[u4Plane].i4FirstRegionId == -1 ||
          _arOsdPlaneInfo[u4Plane].u4FirstRegionAddr == 0)
    {
        fgEnable = FALSE;
    }
    #endif

    IGNORE_RET(_OSD_PLA_SetEnable(u4Plane, fgEnable));
    _arOsdPlaneInfo[u4Plane].fgPlaneEnable = fgEnable;
    _OSD_PLA_UpdateHwReg(u4Plane);
#if defined(__KERNEL__) && !defined(CC_UBOOT)
    if (fgEnable == FALSE)
    {
        BOOL bAllDisabled = TRUE;
        UINT32 plane;
        for (plane = OSD_PLANE_1; plane <= OSD_PLANE_3; plane++)
        {
            if (_arOsdPlaneInfo[plane].fgPlaneEnable == TRUE)
            {
                bAllDisabled = FALSE;
                break;
            }
        }
        if (bAllDisabled == TRUE)
        {
            //if all OSD planes are disabled, there would be no vsync interrupt.
            //then need to switch vsync source to software sleep.
            OSD_EnableHwVsync(FALSE);
        }
    }
    else
    {
        OSD_EnableHwVsync(TRUE);
    }
#endif

    // we suppose no abnormal case when using MJC, so don't care about
    // _UpdatePlaneEnableState now.
#if defined(DRV_SUPPORT_EXTMJC) && !defined(CC_MTK_LOADER)

    if (IS_COMPANION_CHIP_ON() && _OsdPlaReadyToDisplay(u4Plane))
    {
        OSD_LOG_D("drv_extmjc_set_osd_enable, fgEnable=%d\n", fgEnable);
        drv_extmjc_set_osd_turn_on();
    }

#endif
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_Enables(UINT32 *pu4Planes, BOOL *pfEnables, UINT32 u4Num)
{
    UINT32 i;

    for (i = 0; i < u4Num; ++i)
    {
        UINT32 u4Plane = pu4Planes[i];
        BOOL fEnable = pfEnables[i];
        OSD_VERIFY_PLANE(u4Plane);
        IGNORE_RET(_OSD_PLA_SetEnable(u4Plane, fEnable));
        _arOsdPlaneInfo[u4Plane].fgPlaneEnable = fEnable;
        _OSD_PLA_UpdateHwReg(u4Plane);
    }

    return (INT32)OSD_RET_OK;
}
UINT32 OSD_PLA_GetRgnPlane(INT32 i4FirstRegion)
{
    UINT32 ui4_plane = 0x0;

    for (ui4_plane = 0x0; ui4_plane < OSD_PLANE_MAX_NUM; ui4_plane++)
    {
        if (_arOsdPlaneInfo[ui4_plane].i4FirstRegionId == i4FirstRegion)
        {
            break;
        }
    }

    return ui4_plane;
}

//-----------------------------------------------------------------------------
/** attach a specific list to osd plane
 *  @param  u4Plane plane id
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_DoFlipTo(UINT32 u4Plane, UINT32 u4List)
{
    INT32 i4FirstRegion;
    UPTR upFirstRegionAddr = 0;
    static BOOL OSD_OSD2PLS_ENABLE = FALSE;
    BOOL fgOSD2PrLshift_ENABLE = FALSE;
    UINT32 u4_dec   = 0x0;
#if defined(CC_MT5893) || defined(CC_MT5895)
    UINT32 u4SrcWidth, u4SrcHeight;
    UINT32 u4OvlDlModeEnable;
#endif
    OSD_VERIFY_PLANE(u4Plane);
    OSD_VERIFY_RGNLIST(u4List);
    VERIFY((INT32) OSD_RET_OK == OSD_RGN_LIST_GetHead(u4List, &i4FirstRegion));

    if (_arOsdPlaneInfo[u4Plane].i4FirstRegionId == i4FirstRegion)
    {
        return (INT32) OSD_RET_OK;
    }

    OSD_LockLogoDisplaying();
    OSD_LockFlipTo();

    if ((UINT32)i4FirstRegion >= (UINT32)OSD_MAX_NUM_RGN)
    {
        OSD_UnLockFlipTo();
        OSD_UnLockLogoDisplaying();
        return -(INT32)OSD_RET_INV_REGION;
    }

    _arOsdPlaneInfo[u4Plane].i4FirstRegionId = i4FirstRegion;
    VERIFY(OSD_RGN_Get(i4FirstRegion, OSD_RGN_DEC_EN, &u4_dec) == OSD_RET_OK);

#if defined(CC_MT5893) || defined(CC_MT5895)
    // fix mpu vio error when using palette mode with length=2: disable burst disp
    {
        UINT32 u4RgnColorMode;
        UINT32 u4RgnPltLength;
        OSD_RGN_Get(i4FirstRegion, OSD_RGN_COLORMODE, &u4RgnColorMode);
        OSD_RGN_Get(i4FirstRegion, OSD_RGN_PAL_LEN, &u4RgnPltLength);
        if (u4RgnColorMode == OSD_CM_RGB_CLUT8 && u4RgnPltLength == 2)
        {
            _OSD_PLA_SetBurstDis(u4Plane, 1);
        }
        else
        {
            _OSD_PLA_SetBurstDis(u4Plane, 0);
        }
    }

    if (u4Plane == OSD_PLANE_3 /*|| u4Plane == OSD_RT_PLANE_3*/)
    {
        _OSD_BASE_GetOvlShareOsdScaler(&u4OvlDlModeEnable);
        if (u4OvlDlModeEnable)
        {
            OSD_RGN_Set(i4FirstRegion, OSD_RGN_DEC_EN, 0);
            u4_dec = 0;
        }
    }

    if (u4_dec || ((u4Plane == OSD_PLANE_3) && u4OvlDlModeEnable))
    {
        OSD_PLA_SetBurst8Enable(u4Plane, FALSE);
        OSD_PLA_SetBurst8FifoEnable(u4Plane, FALSE);
        if (OSD_IsDualOstgDisplay())
        {
            OSD_PLA_SetBurst8Enable(OSD_GET_RIGHT_PLANE(u4Plane), FALSE);
            OSD_PLA_SetBurst8FifoEnable(OSD_GET_RIGHT_PLANE(u4Plane), FALSE);
        }
    }
    else
    {
        OSD_RGN_Get(i4FirstRegion, (INT32)OSD_RGN_BMP_W, &u4SrcWidth);
        OSD_RGN_Get(i4FirstRegion, (INT32)OSD_RGN_BMP_H, &u4SrcHeight);
        OSD_PLA_SetBurst8Enable(u4Plane, TRUE);
        OSD_PLA_SetBurst8FifoEnable(u4Plane, TRUE);
        if (OSD_IsDualOstgDisplay())
        {
            OSD_PLA_SetBurst8Enable(OSD_GET_RIGHT_PLANE(u4Plane), TRUE);
            OSD_PLA_SetBurst8FifoEnable(OSD_GET_RIGHT_PLANE(u4Plane), TRUE);
        }
    }
#endif

#ifdef CC_FLIP_MIRROR_SUPPORT
    if (!u4_dec)
    {
        OSD_RGN_Set(i4FirstRegion, (INT32)OSD_RGN_V_FLIP, OSD_GetCpblty(E_OSD_CPBLTY_FLIP, 0x0));
        OSD_RGN_Set(i4FirstRegion, (INT32)OSD_RGN_H_MIRROR, OSD_GetCpblty(E_OSD_CPBLTY_MIRROR, 0x0));
    }
#endif

    _arOsdPlaneInfo[u4Plane].u4DecEn = u4_dec;
#if defined(CC_MT5893) || defined(CC_MT5895)
    if (OSD_IsDualOstgDisplay() && u4Plane != OSD_PLANE_4 && !(OSD_Get_Dbg_Info(0x08) & 0x8))
    {
        OSD_PLA_DualOstgFlipTo(u4Plane, i4FirstRegion);
    }
    else
#endif
    {
        VERIFY((INT32) OSD_RET_OK == _OSD_RGN_GetAddress((UINT32) i4FirstRegion,
                                                         &upFirstRegionAddr));
        VERIFY((INT32) OSD_RET_OK == _OSD_PLA_SetHeaderAddr(u4Plane,
                                                            PHYSICAL(upFirstRegionAddr)));

        OSD_RGN_MirrorFlipUpdate(i4FirstRegion, TRUE, TRUE);
    }
    _arOsdPlaneInfo[u4Plane].u4FirstRegionAddr = upFirstRegionAddr;
    VERIFY((INT32)OSD_RET_OK == _OSD_PLA_SetClrHdrIrq(u4Plane, 0));
    _OSD_PLA_UpdateHwReg(u4Plane);
    _arOsdPlaneInfo[u4Plane].i4FlipedList = (INT32) u4List;
#ifndef CC_MTK_LOADER
    fgOSD2PrLshift_ENABLE = GFX_Get3DFlag();
#endif

    if (OSD_OSD2PLS_ENABLE != fgOSD2PrLshift_ENABLE)
    {
        _OSD_3D_SetOsd2LShiftEn((UINT32) fgOSD2PrLshift_ENABLE);
        OSD_OSD2PLS_ENABLE = fgOSD2PrLshift_ENABLE;
    }

    _OSD_3D_UpdateHwReg();

    if (_arPlaneCacheInfo[u4Plane].fgPlaCache == FALSE)
    {
        _OSD_UpdateReg();
    }

    OSD_UnLockFlipTo();
    OSD_UnLockLogoDisplaying();
#if defined(__KERNEL__) && !defined(CC_UBOOT) && !defined(CONFIG_TV_DRV_VFY)
#if !defined(ANDROID) && !defined(ANDROID_TWO_WORLDS)
    OSD_PLA_DumpTask((UINT32)i4FirstRegion);
#endif
#endif
        return (INT32) OSD_RET_OK;
    }

INT32 OSD_PLA_FlipTo(UINT32 u4Plane, UINT32 u4List)
{
    OSD_VERIFY_PLANE(u4Plane);
    OSD_VERIFY_RGNLIST(u4List);

    OSD_LOG_D("plane:%d, rgnList:%d\n", u4Plane + 1, u4List);
    OSD_Dump_Stack();

    if (0 == OSD_PLA_CacheRngList(u4Plane, u4List))
    {
        return (INT32) OSD_RET_OK;
    }

    OSD_PLA_DoFlipTo(u4Plane, u4List);

    return (INT32) OSD_RET_OK;
}


INT32 OSD_PLA_Get_En(UINT32 u4Plane)
{
    return _arOsdPlaneInfo[u4Plane].fgPlaneEnable;
}

UINT32 OSD_PLA_Get_Dec(UINT32 u4Plane)
{
    return _arOsdPlaneInfo[u4Plane].u4DecEn;
}

INT32 OSD_PLA_FlipToNone(UINT32 u4Plane)
{
    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_SetHeaderAddr(u4Plane, 0));
    _OSD_PLA_ResetPlaneInfo(u4Plane);
    _OSD_PLA_UpdateHwReg(u4Plane);
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_Reflip(UINT32 u4List)
{
    INT32 i4Index;
    UINT32 u4Value;

    for (i4Index = 0; i4Index < (INT32) OSD_PLANE_MAX_NUM; i4Index++)
    {
        if (u4List == (UINT32) _arOsdPlaneInfo[i4Index].i4FlipedList)
        {
            IGNORE_RET(_OSD_PLA_GetEnable((UINT32)i4Index, &u4Value));

            if (u4Value)
            {
                IGNORE_RET(OSD_PLA_FlipTo((UINT32)i4Index, u4List));
            }
        }
    }

    return (INT32) OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** get osd plane alpha level
 *  @param  u4Plane plane id
 *  @param  pu1BlendLevel aplha level pointer
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_GetBlendLevel(UINT32 u4Plane, UINT8 *pu1BlendLevel)
{
    UINT32 u4Blending;

    if (pu1BlendLevel == NULL)
    {
        return -(INT32) OSD_RET_INV_ARG;
    }

    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_GetBlending(u4Plane, &u4Blending));
    *pu1BlendLevel = (UINT8) u4Blending;
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_GetEnable(UINT32 u4Plane, BOOL *pfgEnable)
{
    UINT32 u4Enable;

    if (pfgEnable == NULL)
    {
        return -(INT32) OSD_RET_INV_ARG;
    }

    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_GetEnable(u4Plane, &u4Enable));
    *pfgEnable = (BOOL) u4Enable;
    return (INT32) OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** set osd plane alpha level
 *  @param  u4Plane plane id
 *  @param  u1BlendLevel aplha level(0~255)
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_SetBlendLevel(UINT32 u4Plane, UINT8 u1BlendLevel)
{
    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_SetBlending(u4Plane, u1BlendLevel));
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4Plane));
    return (INT32) OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** get osd plane fading value
 *  @param  u4Plane plane id
 *  @param  pu1Fading fading value pointer
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_GetFading(UINT32 u4Plane, UINT8 *pu1Fading)
{
    UINT32 u4Fading;

    if (pu1Fading == NULL)
    {
        return -(INT32) OSD_RET_INV_ARG;
    }

    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_GetFading(u4Plane, &u4Fading));
    *pu1Fading = (UINT8) u4Fading;
    return (INT32) OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** set osd plane fading value
 *  @param  u4Plane plane id
 *  @param  u1Fading fading value
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_SetFading(UINT32 u4Plane, UINT8 u1Fading)
{
    OSD_VERIFY_PLANE(u4Plane);

    if (_u4MuteCounter > 1)
    {
        //_u1FadingCache[u4Plane] = u1Fading;
    }
    else
    {
        VERIFY((INT32) OSD_RET_OK == _OSD_PLA_SetFading(u4Plane, u1Fading));
        VERIFY((INT32) OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4Plane));
    }

    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_SetHFilter(UINT32 u4Plane, BOOL fgEnable)
{
    OSD_VERIFY_PLANE(u4Plane);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_SetHFilter(u4Plane, fgEnable));
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4Plane));
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_SetFifo(UINT32 u4Plane, BOOL fgFastReq, UINT8 u1ExVacThr,
                      UINT8 u1VacThr, UINT8 u1FullThr)
{
    UNUSED(u4Plane);
    UNUSED(fgFastReq);
    UNUSED(u1ExVacThr);
    UNUSED(u1VacThr);
    UNUSED(u1FullThr);
    return (INT32) OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** disable loader logo
 *  @param  u4Plane osd plane
 *  @retval OSD_RET_OK success
 */
//-----------------------------------------------------------------------------

INT32 OSD_PLA_DisableLoaderLogo(UINT32 u4Plane)
{
    OSD_VERIFY_PLANE(u4Plane);

    if (OSD_PLA_Get_En(u4Plane)) //the plane is showing loader logo
    {

        OSD_PLA_Reset(u4Plane);
        OSD_BASE_SetOsdPosition(u4Plane, 0, 0);
    }

    return (INT32) OSD_RET_OK;
}

//-----------------------------------------------------------------------------
/** get the first region id of osd plane
 *  @param  u4Plane osd plane
 *  @retval region id, -1 is no region
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_GetFirstRegion(UINT32 u4Plane)
{
    OSD_VERIFY_PLANE(u4Plane);
    return _arOsdPlaneInfo[u4Plane].i4FirstRegionId;
}

//-----------------------------------------------------------------------------
/** get the first region id of osd plane
 *  @param  u4Plane osd plane
 *  @retval region id, -1 is no region
 */
//-----------------------------------------------------------------------------
INT32 OSD_PLA_GetFirstRegionList(UINT32 u4Plane)
{
    OSD_VERIFY_PLANE(u4Plane);
    return _arOsdPlaneInfo[u4Plane].i4FlipedList;
}

//-----------------------------------------------------------------------------
/** get the first region address of osd plane
 *  @param  u4Plane osd plane
 *  @retval region address, 0 is no region
 */
//-----------------------------------------------------------------------------
UPTR OSD_PLA_GetFirstRegionAddress(UINT32 u4Plane)
{
    if (u4Plane >= (UINT32) OSD_PLANE_MAX_NUM)
    {
        return 0;
    }

    return _arOsdPlaneInfo[u4Plane].u4FirstRegionAddr;
}

//-----------------------------------------------------------------------------
/** wait OSD work stable
 *  @param  u4Plane osd plane
 *  @retval don't care
 */
//-----------------------------------------------------------------------------
void OSD_PLA_WaitStable(UINT32 u4_plane)
{
#if defined(__KERNEL__) && !defined(CC_UBOOT)
    UPTR upBmpAddr = 0x0;
    UPTR upRealBmpAddr = 0x0;
    UINT32 u4_rgn;

    if (FALSE == OSD_PLA_GetAvailable(u4_plane))
    {
        return;
    }

    u4_rgn = OSD_PLA_GetFirstRegion(u4_plane);

    if (u4_rgn >= OSD_MAX_NUM_RGN)
    {
        return;
    }

#if defined(CC_MT5893) || defined(CC_MT5895)
    // how to check if data addr has valid for dual ostg display
    if (OSD_IsDualOstgDisplay())
    {
        return;
    }
#endif

    _OSD_PLA_Get_Hw_RealBmpAddr(u4_plane, &upRealBmpAddr);
    _OSD_RGN_GetDataAddr(u4_rgn, &upBmpAddr);

    // if OSD has not read the latest header, it would read at next vsync
    if (upRealBmpAddr != upBmpAddr)
    {
        OSD_WaitVsync();
    }
#endif
}

//Add for Set DRAM parameters
void OSD_PLA_SetContReqLmt(UINT32 u4Plane, UINT32 u4Value)
{
    IGNORE_RET(_OSD_PLA_SetContReqLmt(u4Plane, u4Value));
}
void OSD_PLA_SetFifoSize(UINT32 u4Plane, UINT32 u4Value)
{
    IGNORE_RET(_OSD_PLA_SetFifoSize(u4Plane, u4Value));
}
void OSD_PLA_SetVacTh(UINT32 u4Plane, UINT32 u4Value)
{
    IGNORE_RET(_OSD_PLA_SetVacTh(u4Plane, u4Value));
}
void OSD_PLA_SetPauseCnt(UINT32 u4Plane, UINT32 u4Value)
{
    IGNORE_RET(_OSD_PLA_SetPauseCnt(u4Plane, u4Value));
}
void OSD_PLA_SetContReqLmt0(UINT32 u4Plane, UINT32 u4Value)
{
    IGNORE_RET(_OSD_PLA_SetContReqLmt0(u4Plane, u4Value));
}

#if 0
//For 3D OSD
INT32 OSD_PLA_Set3DAddress(UINT32 u4Plane, UINT32 u4L_Address, UINT32 u4R_Address)
{
    if ((u4Plane != OSD_PLANE_2) && (u4Plane != OSD_PLANE_3))
    {
        return -(INT32)OSD_RET_INV_PLANE;
    }

    _u4_3D_Plane = u4Plane;
    _au4_3D_L_Addr = u4L_Address;
    _au4_3D_R_Addr = u4R_Address;
    //_au4_3D_L_Addr[u4Plane-1]=u4L_Address;
    //_au4_3D_R_Addr[u4Plane-1]=u4R_Address;
    _u4_3D_Region = _arOsdPlaneInfo[u4Plane].i4FirstRegionId;
    return (INT32)OSD_RET_OK;
}

INT32 OSD_Vsync_3DUpdateLR(UINT32 u4L_R)
{
    if (_u13DMode == 1) // 3D mode
    {
        if (u4L_R == 0) // L
            //OSD_RGN_Set(_u4_3D_Region,OSD_RGN_BMP_ADDR,_au4_3D_L_Addr[_u4_3D_Plane]);
        {
            OSD_RGN_Set(_u4_3D_Region, OSD_RGN_BMP_ADDR, _au4_3D_L_Addr);
        }
        else
            //OSD_RGN_Set(_u4_3D_Region,OSD_RGN_BMP_ADDR,_au4_3D_R_Addr[_u4_3D_Plane]);
        {
            OSD_RGN_Set(_u4_3D_Region, OSD_RGN_BMP_ADDR, _au4_3D_R_Addr);
        }
    }
    else
    {
        if (_u1Previous3DMode != _u13DMode)
            //OSD_RGN_Set(_u4_3D_Region,OSD_RGN_BMP_ADDR,_au4_3D_L_Addr[_u4_3D_Plane]);
        {
            OSD_RGN_Set(_u4_3D_Region, OSD_RGN_BMP_ADDR, _au4_3D_L_Addr);
        }
    }

    _u1Previous3DMode = _u13DMode;
    return (INT32)OSD_RET_OK;
}

INT32 OSD_Set3DMode(UINT8 u1Mode)
{
    _u13DMode = u1Mode;
    return (INT32)OSD_RET_OK;
}
#endif

INT32 OSD_PLA_Set3DMode(UINT32 u4Plane, UINT8 u1Mode)
{
    if ((u4Plane != OSD_PLANE_2) && (u4Plane != OSD_PLANE_3))
    {
        return -(INT32) OSD_RET_INV_PLANE;
    }

    _OSD_PLA_SetShutter(u4Plane, u1Mode);
    _OSD_3D_SetTgenLREn(u1Mode);
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4Plane));
    VERIFY((INT32) OSD_RET_OK == _OSD_3D_UpdateHwReg());
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_Set3DRegion(UINT32 u4Plane, UINT32 u4LeftRgn, UINT32 u4RightRgn)
{
    UPTR upLeftRgnAddr;
    UPTR upRightRgnAddr;

    if ((u4Plane != OSD_PLANE_2) && (u4Plane != OSD_PLANE_3))
    {
        return -(INT32) OSD_RET_INV_PLANE;
    }

    OSD_VERIFY_REGION(u4LeftRgn);
    _arOsdPlaneInfo[u4Plane].i4FirstRegionId = u4LeftRgn;
    _arOsdPlaneInfo[u4Plane].i4RightRegionId = u4RightRgn;
    VERIFY(
        (INT32) OSD_RET_OK == _OSD_RGN_GetAddress((UINT32) u4LeftRgn,
                                                  &upLeftRgnAddr));
    VERIFY(
        (INT32) OSD_RET_OK == _OSD_PLA_SetHeaderAddr(u4Plane,
                                                     PHYSICAL(upLeftRgnAddr)));
    VERIFY(
        (INT32) OSD_RET_OK == _OSD_RGN_GetAddress((UINT32) u4RightRgn,
                                                  &upRightRgnAddr));
    VERIFY(
        (INT32) OSD_RET_OK == _OSD_PLA_SetRightHeaderAddr(u4Plane,
                                                          PHYSICAL(upRightRgnAddr)));
    //OSD_LOG_D("u4u4RightRgnAddr = 0x%x\n",u4u4RightRgnAddr);
    _arOsdPlaneInfo[u4Plane].u4FirstRegionAddr = upLeftRgnAddr;
    _arOsdPlaneInfo[u4Plane].u4RightRegionAddr = upRightRgnAddr;
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4Plane));
#if defined(__KERNEL__) && !defined(CC_UBOOT)
    OSD_WaitVsync();
#endif

    return (INT32) OSD_RET_OK;
}
INT32 OSD_PLA_GetAllRegion(UINT32 u4Plane, UINT32 *u4Rgn1, UINT32 *u4Rgn2)
{
#if defined(GAL_DDI_SUPPORT)
#ifndef CC_MTK_LOADER
    OSD_VERIFY_PLANE(u4Plane);

    if (u4Plane == OSD_PLANE_2)
    {
        *u4Rgn1 = _u4Posd0Rgn0;
        *u4Rgn2 = _u4Posd0Rgn1;
    }
    else if (u4Plane == OSD_PLANE_3)
    {
        *u4Rgn1 = _u4Posd1Rgn0;
        *u4Rgn2 = _u4Posd1Rgn1;
    }

#endif
#endif
    return (INT32) OSD_RET_OK;
}

INT32 OSD_PLA_GetSrcContentRegion(UINT32 u4Plane, UINT32 *u4Rgn1,
                                  UINT32 *u4Rgn2)
{
#if 0
#ifndef CC_MTK_LOADER
    OSD_VERIFY_PLANE(u4Plane);
    *u4Rgn1 = (UINT32)fb1_rgn;
    *u4Rgn2 = (UINT32)fb1_rgn_2;
    return (INT32)OSD_RET_OK;
#else
    return (INT32)OSD_RET_OK;
#endif
#else
    return (INT32) OSD_RET_OK;
#endif
}

#ifdef CC_GPU_SUPPORT
extern UINT32 fb1_width, fb1_height;
extern UINT32 fb2_width, fb2_height;
#endif

INT32 OSD_PLA_GetSrcContentSize(UINT32 u4Plane, UINT32 *pu4Width,
                                UINT32 *pu4Height)
{
#ifdef CC_GPU_SUPPORT
#ifndef CC_MTK_LOADER
    OSD_VERIFY_PLANE(u4Plane);

    if (u4Plane == OSD_PLANE_3 /*2*/)
    {
        *pu4Width = (UINT32)fb1_width;
        *pu4Height = (UINT32)fb1_height;
    }
    else if (u4Plane == OSD_PLANE_2 /*1*/)
    {
        *pu4Width = (UINT32)fb2_width;
        *pu4Height = (UINT32)fb2_height;
    }
    else
    {
        return -(INT32)OSD_RET_INV_ARG;
    }

    return (INT32)OSD_RET_OK;
#else
    return (INT32)OSD_RET_OK;
#endif
#endif
    return (INT32) OSD_RET_OK;
}

#ifndef CC_MTK_LOADER
#ifdef SYS_3D_SUPPORT
INT32 OSD_PLA_Set3DFlip(UINT32 u4Plane, OSD_3D_MODE_T e3DMode, UINT32 u4Shift,
                        UINT32 u4BmpWidth, UINT32 u4BmpHeight, UINT32 u4BmpPitch,
                        UPTR u4BmpAddr, UINT32 eColorMode)
{
    RZ_OSD_SCL_PARAM_SET_T rSclParam;
    E_RZ_INOUT_TYPE_T eRzType;
    _u43DPlane = u4Plane;
    _e3DMode = e3DMode;
    _u4Shift = u4Shift;
    _u4BmpWidth = u4BmpWidth;
    _u4BmpHeight = u4BmpHeight;
    _u4BmpPitch = u4BmpPitch;
    _u4DstAddr = u4BmpAddr;
    _eColorMode = eColorMode;

    if (_u4TmpBuf1 == 0)
    {
        _u4TmpBuf1 =
            (UPTR)BSP_AllocAlignedDmaMemory((UI_WIDTH * UI_HEIGHT * UI_BPP), (OSD_DMA_ALIGN_SIZE + 1));
        OSD_LOG_D("TmpBuf1 = 0x%x\n", _u4TmpBuf1);
        _u4SrcAddr = _u4TmpBuf1;
    }

    GFX_Lock();
    GFX_SetSrc((UINT8 *)(UPTR)u4BmpAddr, eColorMode, u4BmpPitch);
    GFX_SetDst((UINT8 *)(UPTR)_u4TmpBuf1, eColorMode, u4BmpPitch);
    GFX_BitBlt(0, 0, 0, 0, u4BmpWidth, u4BmpHeight);
    GFX_Flush();
    GFX_Wait();
    GFX_Unlock();
    x_memset(&rSclParam, 0, sizeof(RZ_OSD_SCL_PARAM_SET_T));

    if (e3DMode == OSD_3D_SBSHALF)
    {
        rSclParam.u4TgW = u4BmpWidth >> 1;
        rSclParam.u4TgH = u4BmpHeight;
    }
    else if (e3DMode == OSD_3D_TPANDBT)
    {
        rSclParam.u4TgW = u4BmpWidth;
        rSclParam.u4TgH = u4BmpHeight >> 1;
    }

    rSclParam.u4SrcBufLen = u4BmpPitch;
    rSclParam.u4SrcW = u4BmpWidth;
    rSclParam.u4SrcH = u4BmpHeight;
    rSclParam.u4SrcBase = u4BmpAddr;
    rSclParam.u4IsSrcDirCM = 1;
    rSclParam.u4SrcCM = (eColorMode == OSD_CM_ARGB4444_DIRECT16) ?
                        (UINT32) E_RZ_OSD_DIR_CM_ARGB4444 : (UINT32) E_RZ_OSD_DIR_CM_AYCbCr8888;
    rSclParam.u4SrcHOffset = 0;
    rSclParam.u4SrcVOffset = 0;
    rSclParam.u4TgBase = u4BmpAddr;
    rSclParam.u4TgHOffset = 0;
    rSclParam.u4TgVOffset = 0;
    rSclParam.u4TgCM = rSclParam.u4SrcCM;
    rSclParam.u4TgBufLen = u4BmpPitch;
    rSclParam.u4Size = sizeof(RZ_OSD_SCL_PARAM_SET_T);
    eRzType = E_RZ_INOUT_TYPE_OSDMD;
    IMGRZ_Lock();
    IMGRZ_ReInit();
    IMGRZ_SetScaleOpt(eRzType);
    IMGRZ_Scale(&rSclParam);
    IMGRZ_Flush();
    IMGRZ_Wait();
    IMGRZ_Unlock();
    GFX_Lock();
    GFX_SetSrc((UINT8 *)u4BmpAddr, eColorMode, u4BmpPitch);
    GFX_SetDst((UINT8 *)u4BmpAddr, eColorMode, u4BmpPitch);
    GFX_SetColor(0x0);
    GFX_SetBltOpt((UINT32)D_GFXFLAG_NONE, 0x00000000, 0xffffffff);

    if (e3DMode == OSD_3D_SBSHALF)
    {
        GFX_Fill(rSclParam.u4TgW, 0, rSclParam.u4TgW, rSclParam.u4TgH);
        GFX_BitBlt((u4Shift >> 1), 0, rSclParam.u4TgW, 0, (rSclParam.u4TgW - (u4Shift >> 1)),
                   rSclParam.u4TgH);
    }
    else if (e3DMode == OSD_3D_TPANDBT)
    {
        GFX_Fill(0, rSclParam.u4TgH, rSclParam.u4TgW, rSclParam.u4TgH);
        GFX_BitBlt(u4Shift, 0, 0, rSclParam.u4TgH, (rSclParam.u4TgW - u4Shift), rSclParam.u4TgH);
    }

    GFX_Flush();
    GFX_Wait();
    GFX_Unlock();
    return (INT32)OSD_RET_OK;
}

INT32 OSD_PLA_Set3DBlit(UINT32 u4Plane, OSD_3D_MODE_T e3DMode, UINT32 u4Shift,
                        UINT32 u4BmpWidth, UINT32 u4BmpHeight, UINT32 u4BmpPitch,
                        UPTR u4DstAddr, UINT32 eColorMode, UPTR u4SrcAddr)
{
    RZ_OSD_SCL_PARAM_SET_T rSclParam;
    E_RZ_INOUT_TYPE_T eRzType;
    _u43DPlane = u4Plane;
    _e3DMode = e3DMode;
    _u4Shift = u4Shift;
    _u4BmpWidth = u4BmpWidth;
    _u4BmpHeight = u4BmpHeight;
    _u4BmpPitch = u4BmpPitch;
    _u4SrcAddr = u4SrcAddr;
    _u4DstAddr = u4DstAddr;
    _eColorMode = eColorMode;

    if (_u4TmpBuf == 0)
    {
        _u4TmpBuf =
            (UPTR)BSP_AllocAlignedDmaMemory((UI_WIDTH * UI_HEIGHT * UI_BPP), (OSD_DMA_ALIGN_SIZE + 1));
        OSD_LOG_D("TmpBuf = 0x%x\n", _u4TmpBuf);
    }

    x_memset(&rSclParam, 0, sizeof(RZ_OSD_SCL_PARAM_SET_T));

    if (e3DMode == OSD_3D_SBSHALF)
    {
        rSclParam.u4TgW = u4BmpWidth >> 1;
        rSclParam.u4TgH = u4BmpHeight;
    }
    else if (e3DMode == OSD_3D_TPANDBT)
    {
        rSclParam.u4TgW = u4BmpWidth;
        rSclParam.u4TgH = u4BmpHeight >> 1;
    }

    rSclParam.u4SrcBufLen = u4BmpPitch;
    rSclParam.u4SrcW = u4BmpWidth;
    rSclParam.u4SrcH = u4BmpHeight;
    rSclParam.u4SrcBase = u4SrcAddr;
    rSclParam.u4IsSrcDirCM = 1;
    rSclParam.u4SrcCM = (eColorMode == OSD_CM_ARGB4444_DIRECT16) ?
                        (UINT32) E_RZ_OSD_DIR_CM_ARGB4444 : (UINT32) E_RZ_OSD_DIR_CM_AYCbCr8888;
    rSclParam.u4SrcHOffset = 0;
    rSclParam.u4SrcVOffset = 0;
    rSclParam.u4TgBase = _u4TmpBuf;
    rSclParam.u4TgHOffset = 0;
    rSclParam.u4TgVOffset = 0;
    rSclParam.u4TgCM = rSclParam.u4SrcCM;
    rSclParam.u4TgBufLen = u4BmpPitch;
    rSclParam.u4Size = sizeof(RZ_OSD_SCL_PARAM_SET_T);
    eRzType = E_RZ_INOUT_TYPE_OSDMD;
    IMGRZ_Lock();
    IMGRZ_ReInit();
    IMGRZ_SetScaleOpt(eRzType);
    IMGRZ_Scale(&rSclParam);
    IMGRZ_Flush();
    IMGRZ_Wait();
    IMGRZ_Unlock();
    GFX_Lock();
    GFX_SetSrc((UINT8 *)(UPTR)_u4TmpBuf, eColorMode, u4BmpPitch);
    GFX_SetDst((UINT8 *)(UPTR)_u4TmpBuf, eColorMode, u4BmpPitch);
    GFX_SetColor(0x0);
    GFX_SetBltOpt((UINT32)D_GFXFLAG_NONE, 0x00000000, 0xffffffff);

    if (e3DMode == OSD_3D_SBSHALF)
    {
        GFX_Fill(rSclParam.u4TgW, 0, rSclParam.u4TgW, rSclParam.u4TgH);
        GFX_BitBlt((u4Shift >> 1), 0, rSclParam.u4TgW, 0, (rSclParam.u4TgW - (u4Shift >> 1)),
                   rSclParam.u4TgH);
    }
    else if (e3DMode == OSD_3D_TPANDBT)
    {
        GFX_Fill(0, rSclParam.u4TgH, rSclParam.u4TgW, rSclParam.u4TgH);
        GFX_BitBlt(u4Shift, 0, 0, rSclParam.u4TgH, (rSclParam.u4TgW - u4Shift), rSclParam.u4TgH);
    }

    GFX_SetSrc((UINT8 *)(UPTR)_u4TmpBuf, eColorMode, u4BmpPitch);
    GFX_SetDst((UINT8 *)(UPTR)u4DstAddr, eColorMode, u4BmpPitch);
    GFX_BitBlt(0, 0, 0, 0, u4BmpWidth, u4BmpHeight);
    GFX_Flush();
    GFX_Wait();
    GFX_Unlock();
    return (INT32)OSD_RET_OK;
}

INT32 OSD_PLA_Redraw3D(OSD_3D_MODE_T e3DMode)
{
    if ((_u4DstAddr != 0) && (e3DMode != _e3DMode))
    {
        if (e3DMode == OSD_3D_NONE)
        {
            GFX_Lock();
            GFX_SetSrc((UINT8 *)(UPTR)_u4SrcAddr, _eColorMode, _u4BmpPitch);
            GFX_SetDst((UINT8 *)(UPTR)_u4DstAddr, _eColorMode, _u4BmpPitch);
            GFX_BitBlt(0, 0, 0, 0, _u4BmpWidth, _u4BmpHeight);
            GFX_Flush();
            GFX_Wait();
            GFX_Unlock();
        }
        else
        {
            OSD_PLA_Set3DBlit(_u43DPlane, e3DMode, _u4Shift,
                              _u4BmpWidth, _u4BmpHeight, _u4BmpPitch,
                              _u4DstAddr, _eColorMode, _u4SrcAddr);
        }

        _e3DMode = e3DMode;
    }

    return (INT32)OSD_RET_OK;
}
#endif

#ifdef CC_CONFIG_OSD_SBS
INT32 OSD_PLA_Set3DDFB(UINT32 u4Plane, UINT32 e3DMode, UINT32 u4Shift,
                       UINT32 u4BmpWidth, UINT32 u4BmpHeight, UINT32 u4BmpPitch,
                       UPTR u4DstAddr, UINT32 eColorMode, UPTR u4SrcAddr)
{
    RZ_OSD_SCL_PARAM_SET_T rSclParam;
    E_RZ_INOUT_TYPE_T eRzType;
    x_memset(&rSclParam, 0, sizeof(RZ_OSD_SCL_PARAM_SET_T));

    if (e3DMode == 0)//OSD_3D_SBSHALF
    {
        rSclParam.u4TgW = u4BmpWidth >> 1;
        rSclParam.u4TgH = u4BmpHeight;
    }
    else if (e3DMode == 1) //OSD_3D_TPANDBT
    {
        rSclParam.u4TgW = u4BmpWidth;
        rSclParam.u4TgH = u4BmpHeight >> 1;
    }
    else
    {
        GFX_Lock();
        GFX_MMU_Set_Enable(0x0);
        GFX_SetSrc((UINT8 *)(UPTR)u4SrcAddr, eColorMode, u4BmpPitch);
        GFX_SetDst((UINT8 *)(UPTR)u4DstAddr, eColorMode, u4BmpPitch);
        GFX_BitBlt(0, 0, 0, 0, u4BmpWidth, u4BmpHeight);
        GFX_Flush();
        GFX_Wait();
        GFX_Unlock();
        return (INT32)OSD_RET_OK;
    }

    rSclParam.u4SrcBufLen = u4BmpPitch;
    rSclParam.u4SrcW = u4BmpWidth;
    rSclParam.u4SrcH = u4BmpHeight;
    rSclParam.u4SrcBase = u4SrcAddr;
    rSclParam.u4IsSrcDirCM = 1;
    rSclParam.u4SrcCM = (eColorMode == OSD_CM_ARGB4444_DIRECT16) ?
                        (UINT32) E_RZ_OSD_DIR_CM_ARGB4444 : (UINT32) E_RZ_OSD_DIR_CM_AYCbCr8888;
    rSclParam.u4SrcHOffset = 0;
    rSclParam.u4SrcVOffset = 0;
    rSclParam.u4TgBase = u4DstAddr;
    rSclParam.u4TgHOffset = 0;
    rSclParam.u4TgVOffset = 0;
    rSclParam.u4TgCM = rSclParam.u4SrcCM;
    rSclParam.u4TgBufLen = u4BmpPitch;
    rSclParam.u4Size = sizeof(RZ_OSD_SCL_PARAM_SET_T);
    eRzType = E_RZ_INOUT_TYPE_OSDMD;
    IMGRZ_Lock();
    IMGRZ_ReInit();
    IMGRZ_SetScaleOpt(eRzType);
    IMGRZ_Scale(&rSclParam);
    IMGRZ_Flush();
    IMGRZ_Wait();
    IMGRZ_Unlock();
    GFX_Lock();
    GFX_MMU_Set_Enable(0x0);
    GFX_SetSrc((UINT8 *)(UPTR)u4DstAddr, eColorMode, u4BmpPitch);
    GFX_SetDst((UINT8 *)(UPTR)u4DstAddr, eColorMode, u4BmpPitch);
    GFX_SetColor(0x0);
    GFX_SetBltOpt((UINT32)D_GFXFLAG_NONE, 0x00000000, 0xffffffff);

    if (e3DMode == 0)// OSD_3D_SBSHALF
    {
        GFX_Fill(rSclParam.u4TgW, 0, rSclParam.u4TgW, rSclParam.u4TgH);
        GFX_BitBlt((u4Shift >> 1), 0, rSclParam.u4TgW, 0, (rSclParam.u4TgW - (u4Shift >> 1)),
                   rSclParam.u4TgH);
    }
    else //OSD_3D_TPANDBT
    {
        GFX_Fill(0, rSclParam.u4TgH, rSclParam.u4TgW, rSclParam.u4TgH);
        GFX_BitBlt(u4Shift, 0, 0, rSclParam.u4TgH, (rSclParam.u4TgW - u4Shift), rSclParam.u4TgH);
    }

    GFX_SetSrc((UINT8 *)(UPTR)u4DstAddr, eColorMode, u4BmpPitch);
    GFX_SetDst((UINT8 *)(UPTR)u4DstAddr, eColorMode, u4BmpPitch);
    GFX_BitBlt(0, 0, 0, 0, u4BmpWidth, u4BmpHeight);
    GFX_Flush();
    GFX_Wait();
    GFX_Unlock();
    return (INT32)OSD_RET_OK;
}
#endif
#ifdef OSD_DSC_PDP

INT32 OSD_PLA_DsBlit(UPTR u4SrcAddr, UINT32 u4SrcX, UINT32 u4SrcY,
                     UINT32 u4SrcWidth, UINT32 u4SrcHeight, UINT32 u4SrcPitch,
                     UPTR u4DstAddr, UINT32 u4DstX, UINT32 u4DstY,
                     UINT32 u4DstWidth, UINT32 u4DstHeight, UINT32 u4DstpPitch, UINT32 eColorMode)
{
    RZ_OSD_SCL_PARAM_SET_T rSclParam;
    E_RZ_INOUT_TYPE_T eRzType;
    x_memset(&rSclParam, 0, sizeof(RZ_OSD_SCL_PARAM_SET_T));
    rSclParam.u4TgW = u4DstWidth;
    rSclParam.u4TgH = u4DstHeight;
    rSclParam.u4SrcBufLen = u4SrcPitch;
    rSclParam.u4SrcW = u4SrcWidth;
    rSclParam.u4SrcH = u4SrcHeight;
    rSclParam.u4SrcBase = u4SrcAddr;
    rSclParam.u4IsSrcDirCM = 1;
    rSclParam.u4SrcCM = (eColorMode == OSD_CM_ARGB4444_DIRECT16) ?
                        (UINT32) E_RZ_OSD_DIR_CM_ARGB4444 : (UINT32) E_RZ_OSD_DIR_CM_ARGB8888;
    rSclParam.u4SrcHOffset = u4SrcX;
    rSclParam.u4SrcVOffset = u4SrcY;
    rSclParam.u4TgBase = u4DstAddr;
    rSclParam.u4TgHOffset = u4DstX;
    rSclParam.u4TgVOffset = u4DstY;
    rSclParam.u4TgCM = rSclParam.u4SrcCM;
    rSclParam.u4TgBufLen = u4DstpPitch;
    eRzType = E_RZ_INOUT_TYPE_OSDMD;
    IMGRZ_Lock();
    IMGRZ_ReInit();
    IMGRZ_SetScaleOpt(eRzType);
    IMGRZ_Scale(&rSclParam);
    IMGRZ_Flush();
    IMGRZ_Wait();
    IMGRZ_Unlock();
    return (INT32)OSD_RET_OK;
}
#endif
#ifdef CC_ANDROID_3D_UI_SUPPORT
UINT32 u4UiMode = OSD_3D_NONE;
UINT32 u4Plane2RegionList = 0;
BOOL u4Plane2Enabel = 0;
BOOL fgUpdateAttr = 1;
UINT32 u4UiWidth = 1280, u4UiHeight = 720;
UINT32 u4OriSc2_Enable = 0;
UINT32 u4OriSc2SrcW = 0;
UINT32 u4OriSc2SrcH = 0;
UINT32 u4OriSc2DstW = 0;
UINT32 u4OriSc2DstH = 0;
UINT32 u4OriSc2Is16Bpp = 0;

UINT32 OSD_PLA_SetUIMode(UINT32 u4Mode, UINT32 u4WIdth, UINT32 u4Height)
{
    u4UiMode = u4Mode;
    fgUpdateAttr = 0;

    if ((u4WIdth != 0) && (u4Height != 0))
    {
        u4UiWidth = u4WIdth;
        u4UiHeight = u4Height;
    }

    OSD_PLA_FlipTo(OSD_PLANE_2, u4Plane2RegionList);
    OSD_PLA_Enable(OSD_PLANE_2, u4Plane2Enabel);
    OSD_SC_Scale(OSD_SCALER_2, TRUE, u4OriSc2SrcW, u4OriSc2SrcH, u4OriSc2DstW, u4OriSc2DstH);
    return (INT32)OSD_RET_OK;
}

INT32 OSD_PLA_Set3DSwitchRegion(UINT32 u4LeftRgn, UINT32 u4RightRgn)
{
    UPTR upLeftRgnAddr;
    UPTR upRightRgnAddr;
    UINT32 u4LeftPlane = OSD_PLANE_3, u4RightPlane = OSD_PLANE_2;
    OSD_VERIFY_REGION(u4LeftRgn);
    _arOsdPlaneInfo[u4LeftPlane].i4FirstRegionId = u4LeftRgn;
    _arOsdPlaneInfo[u4RightPlane].i4FirstRegionId = u4RightRgn;
    OSD_LOG_D(" region = %d, %d,\n", u4LeftRgn, u4RightRgn);
    VERIFY((INT32)OSD_RET_OK ==
           _OSD_RGN_GetAddress((UINT32)u4LeftRgn, &upLeftRgnAddr));
    VERIFY((INT32)OSD_RET_OK ==
           _OSD_PLA_SetHeaderAddr(u4LeftPlane, PHYSICAL(upLeftRgnAddr)));
    VERIFY((INT32)OSD_RET_OK ==
           _OSD_RGN_GetAddress((UINT32)u4RightRgn, &upRightRgnAddr));
    OSD_LOG_D(" 111 region  = %d, %d, 0x%p, 0x%p\n", u4LeftRgn, u4RightRgn, upLeftRgnAddr,
        upRightRgnAddr);
    x_memcpy((void *)upRightRgnAddr, (void *)upLeftRgnAddr, sizeof(OSD_RGN_UNION_T));
    VERIFY((INT32)OSD_RET_OK ==
           _OSD_PLA_SetHeaderAddr(u4RightPlane, PHYSICAL(upRightRgnAddr)));
    OSD_LOG_D(" region= %d, %d, 0x%p, u4u4RightRgnAddr = 0x%p\n", u4LeftRgn, u4RightRgn, upLeftRgnAddr,
        upRightRgnAddr);
    _arOsdPlaneInfo[u4LeftPlane].u4FirstRegionAddr = upLeftRgnAddr;
    _arOsdPlaneInfo[u4RightPlane].u4FirstRegionAddr = upRightRgnAddr;
    VERIFY((INT32)OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4LeftPlane));
    VERIFY((INT32)OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4RightPlane));
    return (INT32)OSD_RET_OK;
}

INT32 OSD_PLA_Set3DSwitchRgnAddr(UINT32 u4LeftRgn, UINT32 u4RightRgn, UPTR upLeftAddr,
                                 UPTR upRightAddr)
{
    // UINT32 u4u4LeftRgnAddr;
    // UINT32 u4u4RightRgnAddr;
    //OSD_LockFlipTo();
    //GFX_FlushInvalidateDCacheMultipleLine();
    _OSD_RGN_SetDataAddr(u4LeftRgn, upLeftAddr);
    _OSD_RGN_SetDataAddr(u4RightRgn, upRightAddr);
    //OSD_UnLockFlipTo();
    return (INT32)OSD_RET_OK;
}
#endif

#endif

UINT32 OSD_PLA_GetHStart(UINT32 u4Plane)
{
    UINT32 u4Start = OSD_INVALID_VALUE_U32;

    switch (u4Plane)
    {
        case OSD_PLANE_1:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_1:
#endif
            _OSD_BASE_GetOsd1HStart(&u4Start);
            break;

        case OSD_PLANE_2:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_2:
#endif
            _OSD_BASE_GetOsd2HStart(&u4Start);
            break;

        case OSD_PLANE_3:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_3:
#endif
            _OSD_BASE_GetOsd3HStart(&u4Start);
            break;

        case OSD_PLANE_5:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_5:
#endif
            _OSD_BASE_GetCsrHStart(&u4Start);
            break;

        default:
            break;
    }

    return u4Start;
}

UINT32 OSD_PLA_GetVStart(UINT32 u4Plane)
{
    UINT32 u4Start = OSD_INVALID_VALUE_U32;

    switch (u4Plane)
    {
        case OSD_PLANE_1:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_1:
#endif
            _OSD_BASE_GetOsd1VStart(&u4Start);
            break;

        case OSD_PLANE_2:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_2:
#endif
            _OSD_BASE_GetOsd2VStart(&u4Start);
            break;

        case OSD_PLANE_3:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_3:
#endif
            _OSD_BASE_GetOsd3VStart(&u4Start);
            break;

        case OSD_PLANE_5:
#if defined(CC_MT5893) || defined(CC_MT5895)
        case OSD_RT_PLANE_5:
#endif
            _OSD_BASE_GetCsrVStart(&u4Start);
            break;

        default:
            break;
    }

    return u4Start;
}

INT32 OSD_PLA_SetPremulEn(UINT32 u4Plane, UINT32 u4Value)
{
    UINT32 u4OSD1Order = 0;
    UINT32 u4OSD2Order = 0;
    UINT32 u4OSD3Order = 0;
    UINT32 u4OrderPlane = 0;
    _OSD_BASE_GetOSD1Switch(&u4OSD1Order);
    _OSD_BASE_GetOSD2Switch(&u4OSD2Order);
    _OSD_BASE_GetOSD3Switch(&u4OSD3Order);

    if (u4Plane + 1 == u4OSD1Order)
    {
        u4OrderPlane = OSD_PLANE_1;
    }
    else if (u4Plane + 1 == u4OSD2Order)
    {
        u4OrderPlane = OSD_PLANE_2;
    }
    else if (u4Plane + 1 == u4OSD3Order)
    {
        u4OrderPlane = OSD_PLANE_3;
    }
    else
    {
        return -(INT32)OSD_RET_INV_ARG;
    }

    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_SetPremulEn(u4OrderPlane, u4Value));
    VERIFY((INT32) OSD_RET_OK == _OSD_PLA_UpdateHwReg(u4OrderPlane));
    return OSD_RET_OK;
}

INT32 OSD_PLA_GetPremulEn(UINT32 u4Plane, UINT32 *pu4Value)
{
    UINT32 u4Enable;
    UINT32 u4OSD1Order = 0;
    UINT32 u4OSD2Order = 0;
    UINT32 u4OSD3Order = 0;
    OSD_VERIFY_PLANE(u4Plane);
    _OSD_BASE_GetOSD1Switch(&u4OSD1Order);
    _OSD_BASE_GetOSD2Switch(&u4OSD2Order);
    _OSD_BASE_GetOSD3Switch(&u4OSD3Order);

    if (u4Plane + 1 == u4OSD1Order)
    {
        VERIFY((INT32)OSD_RET_OK == _OSD_PLA_GetPremulEn(OSD_PLANE_1, &u4Enable));
    }
    else if (u4Plane + 1 == u4OSD2Order)
    {
        VERIFY((INT32)OSD_RET_OK == _OSD_PLA_GetPremulEn(OSD_PLANE_2, &u4Enable));
    }
    else if (u4Plane + 1 == u4OSD3Order)
    {
        VERIFY((INT32)OSD_RET_OK == _OSD_PLA_GetPremulEn(OSD_PLANE_3, &u4Enable));
    }
    else
    {
        return -(INT32)OSD_RET_INV_ARG;
    }

    *pu4Value = u4Enable;
    return (INT32)OSD_RET_OK;
}

void OSD_PLA_Chg_Clock_Action(UINT32 u4_enable)
{
    UINT32 u4Plane;

    for (u4Plane = 0; u4Plane < OSD_PLANE_MAX_NUM; ++u4Plane)
    {
        if (_arOsdPlaneInfo[u4Plane].fgPlaneEnable)
        {
            _OSD_PLA_SetEnable(u4Plane, u4_enable);
            _OSD_PLA_UpdateHwReg(u4Plane);
        }
    }
}

UINT32 OSD_PLA_GetScaler(UINT32 u4Plane)
{
    UINT32 u4Scaler = OSD_SCALER_MAX_NUM;

    if (u4Plane == (UINT32)OSD_PLANE_2)
    {
        u4Scaler = (UINT32)OSD_SCALER_2;
    }
    else if (u4Plane == (UINT32)OSD_PLANE_3)
    {
        u4Scaler = (UINT32)OSD_SCALER_3;
    }
    else if (u4Plane == (UINT32)OSD_PLANE_1)
    {
        u4Scaler = (UINT32)OSD_SCALER_1;
    }
#if defined(CC_MT5893) || defined(CC_MT5895)
    else if (u4Plane > OSD_PLANE_5 && u4Plane < OSD_PLANE_MAX_NUM)
    {
        u4Scaler = u4Plane - 2;
    }
#endif

    return u4Scaler;
}

INT32 OSD_PLA_LineScalerShow(UINT32 u4Plane, UPTR u4BufferAddr, UINT32 u4SrcWidth,
                             UINT32 u4SrcHeight, UINT32 u4SrcPitch, UINT32 u4DstX, UINT32 u4DstY,
                             UINT32 u4DstWidth, UINT32 u4DstHeight, UINT32 u4ColorMode)
{
    static UINT32 u4RegionList = 0xFFFFFFFF;
    UINT32 u4FirstRegion = 0;

    if (u4RegionList == 0xFFFFFFFF)
    {
        IGNORE_RET(OSD_RGN_LIST_Create(&u4RegionList));
    }

    OSD_VERIFY_RGNLIST(u4RegionList);

    OSD_LOG_D("RegionList = %d\n", u4RegionList);
    OSD_RGN_LIST_LineScaler(u4RegionList, u4SrcWidth, u4SrcHeight, (void *)u4BufferAddr,
                            u4ColorMode, u4SrcPitch, u4DstX, u4DstY, u4DstWidth, u4DstHeight);
    OSD_PLA_FlipTo(u4Plane, u4RegionList);
    u4FirstRegion = OSD_PLA_GetFirstRegion(u4Plane);
    OSD_RGN_Set(u4FirstRegion, OSD_RGN_DISP_H, u4DstHeight / 2);
    OSD_SC_Scale(OSD_PLA_GetScaler(u4Plane), FALSE, OSD_BASE_GetDisplayWidth(),
                 OSD_BASE_GetDisplayHeight(),
                 OSD_BASE_GetDisplayWidth(), OSD_BASE_GetDisplayHeight());
    OSD_PLA_Enable(u4Plane, TRUE);
    return (INT32)OSD_RET_OK;
}
INT32 OSD_PLA_Get_Hw_RealBmpAddr(UINT32 u4Plane, UPTR *pupValue)
{
    return _OSD_PLA_Get_Hw_RealBmpAddr(u4Plane, pupValue);
}

void OSD_PLA_SetMatrixEnable(BOOL fgEnable)
{
    CHECK_OSD_INIT();

    OSD_LOG_D("OSD_PLA_SetMatrixEnable set all planes matrix %d\n", fgEnable);
    _OSD_PLA_SetMatixEnable(OSD_PLANE_1, fgEnable);
    _OSD_PLA_SetMatixEnable(OSD_PLANE_2, fgEnable);
    _OSD_PLA_SetMatixEnable(OSD_PLANE_3, fgEnable);
    _OSD_PLA_UpdateHwReg(OSD_PLANE_1);
    _OSD_PLA_UpdateHwReg(OSD_PLANE_2);
    _OSD_PLA_UpdateHwReg(OSD_PLANE_3);
#if defined(CC_MT5893) || defined(CC_MT5895)
    _OSD_PLA_SetMatixEnable(OSD_RT_PLANE_1, fgEnable);
    _OSD_PLA_SetMatixEnable(OSD_RT_PLANE_2, fgEnable);
    _OSD_PLA_SetMatixEnable(OSD_RT_PLANE_3, fgEnable);
    _OSD_PLA_UpdateHwReg(OSD_RT_PLANE_1);
    _OSD_PLA_UpdateHwReg(OSD_RT_PLANE_2);
    _OSD_PLA_UpdateHwReg(OSD_RT_PLANE_3);
#endif
    OSD_UpdateReg();
}
/*
    Input: pwMatrix
    Desc: input an array with size12
    array[0-8] is for gain value: bit12 is sign, bit0-8 is value
    array[9-11] is for offset: bit0-9 is value
*/
void OSD_PLA_SetMatrixAndOffset(const UINT16 *pwMatrix)
{
    UINT32 value;
    OSD_LOG_D("OSD_PLA_SetMatrixAndOffset set all planes matrix\n");

    CHECK_OSD_INIT();

    value = (UINT32)((pwMatrix[0] << 16) | pwMatrix[1]);
    IO_WRITE32(OSD_BASE_REG, 0x160, value);
    IO_WRITE32(OSD_BASE_REG, 0x260, value);
    IO_WRITE32(OSD_BASE_REG, 0x360, value);
#if defined(CC_MT5893) || defined(CC_MT5895)
    IO_WRITE32(OSD_RT_BASE_REG, 0x160, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x260, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x360, value);
#endif

    value = (UINT32)((pwMatrix[2] << 16) | pwMatrix[9]);
    IO_WRITE32(OSD_BASE_REG, 0x164, value);
    IO_WRITE32(OSD_BASE_REG, 0x264, value);
    IO_WRITE32(OSD_BASE_REG, 0x364, value);
#if defined(CC_MT5893) || defined(CC_MT5895)
    IO_WRITE32(OSD_RT_BASE_REG, 0x164, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x264, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x364, value);
#endif

    value = (UINT32)((pwMatrix[3] << 16) | pwMatrix[4]);
    IO_WRITE32(OSD_BASE_REG, 0x168, value);
    IO_WRITE32(OSD_BASE_REG, 0x268, value);
    IO_WRITE32(OSD_BASE_REG, 0x368, value);
#if defined(CC_MT5893) || defined(CC_MT5895)
    IO_WRITE32(OSD_RT_BASE_REG, 0x168, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x268, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x368, value);
#endif

    value = (UINT32)((pwMatrix[5] << 16) | pwMatrix[10]);
    IO_WRITE32(OSD_BASE_REG, 0x16c, value);
    IO_WRITE32(OSD_BASE_REG, 0x26c, value);
    IO_WRITE32(OSD_BASE_REG, 0x36c, value);
#if defined(CC_MT5893) || defined(CC_MT5895)
    IO_WRITE32(OSD_RT_BASE_REG, 0x16c, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x26c, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x36c, value);
#endif

    value = (UINT32)((pwMatrix[6] << 16) | pwMatrix[7]);
    IO_WRITE32(OSD_BASE_REG, 0x170, value);
    IO_WRITE32(OSD_BASE_REG, 0x270, value);
    IO_WRITE32(OSD_BASE_REG, 0x370, value);
#if defined(CC_MT5893) || defined(CC_MT5895)
    IO_WRITE32(OSD_RT_BASE_REG, 0x170, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x270, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x370, value);
#endif

    value = (UINT32)((pwMatrix[8] << 16) | pwMatrix[11]);
    IO_WRITE32(OSD_BASE_REG, 0x174, value);
    IO_WRITE32(OSD_BASE_REG, 0x274, value);
    IO_WRITE32(OSD_BASE_REG, 0x374, value);
#if defined(CC_MT5893) || defined(CC_MT5895)
    IO_WRITE32(OSD_RT_BASE_REG, 0x174, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x274, value);
    IO_WRITE32(OSD_RT_BASE_REG, 0x374, value);
#endif

    OSD_UpdateReg();
}

void OSD_PLA_SetUltraEn(UINT32 u4Plane, UINT32 u4Enable)
{
    UINT32 u4PlaBaseReg;
    u4PlaBaseReg = OSD_PLA_GetBaseAddr(u4Plane);

    if (u4Enable)
    {
        IO_WRITE32MSK(u4PlaBaseReg, 0x94, 1 << 7, 1 << 7);
        IO_WRITE32MSK(u4PlaBaseReg, 0x94, 1 << 24, 1 << 24);
    }
    else
    {
        IO_WRITE32MSK(u4PlaBaseReg, 0x94, 0, 1 << 7);
        IO_WRITE32MSK(u4PlaBaseReg, 0x94, 0, 1 << 24);
    }

    OSD_UpdateReg();
}

void OSD_PLA_SetUltraThdValue(UINT32 u4Plane, UINT8 u1ThdLow, UINT8 u1ThdHigh)
{
    UINT32 u4PlaBaseReg;
    u4PlaBaseReg = OSD_PLA_GetBaseAddr(u4Plane);

    IO_WRITE32MSK(u4PlaBaseReg, 0x94, u1ThdLow << 8, 0xFF << 8);
    IO_WRITE32MSK(u4PlaBaseReg, 0x94, u1ThdHigh << 16, 0xFF << 16);

    OSD_UpdateReg();
}

void OSD_PLA_SetPreUltraThdValue(UINT32 u4Plane, UINT8 u1ThdValue)
{
    UINT32 u4PlaBaseReg;
    u4PlaBaseReg = OSD_PLA_GetBaseAddr(u4Plane);

    IO_WRITE32MSK(u4PlaBaseReg, 0x98, u1ThdValue << 16, 0xFF << 16);

    OSD_UpdateReg();
}

UINT32 OSD_PLA_GetBaseAddr(UINT32 u4Plane)
{
    switch(u4Plane)
    {
    case OSD_PLANE_1:
        return OSD_PLA1_REG;
    case OSD_PLANE_2:
        return OSD_PLA2_REG;
    case OSD_PLANE_3:
        return OSD_PLA3_REG;
    case OSD_PLANE_4:
        return OSD_PLA4_REG;
    case OSD_PLANE_5:
        return OSD_PLA5_REG;
#if defined(CC_MT5893) || defined(CC_MT5895)
    case OSD_RT_PLANE_1:
        return OSD_RT_PLA1_REG;
    case OSD_RT_PLANE_2:
        return OSD_RT_PLA2_REG;
    case OSD_RT_PLANE_3:
        return OSD_RT_PLA3_REG;
    case OSD_RT_PLANE_5:
        return OSD_RT_PLA5_REG;
#endif
    default:
        OSD_LOG_E("[invalid plane id:%d]\n", u4Plane);
        return OSD_PLA1_REG;
    }
}

#if defined(CC_MT5893) || defined(CC_MT5895)
UINT32 OSD_PLA_GetBaseReg(UINT32 u4Plane)
{
    switch(u4Plane)
    {
    case OSD_PLANE_1:
    case OSD_PLANE_2:
    case OSD_PLANE_3:
        return OSD_PLA1_REG + u4Plane * 0x100;
    case OSD_PLANE_4:
        return OSD_PLA4_REG;
    case OSD_PLANE_5:
        return OSD_PLA5_REG;
    case OSD_RT_PLANE_1:
    case OSD_RT_PLANE_2:
    case OSD_RT_PLANE_3:
        return OSD_RT_PLA1_REG + (u4Plane - OSD_RT_PLANE_1) * 0x100;
    case OSD_RT_PLANE_5:
        return OSD_RT_PLA5_REG;
    default:
        return 0;
    }
}
/*
    Note:
    default: burst8 enable & fifo disable
    ovl2osd direct-link mode: burst8 disable & fifo disable
    4k src: burst8 enable & fifo enable
    dec mode: burst8 disable & fifo disable
*/
INT32 OSD_PLA_SetBurst8Enable(UINT32 u4Plane, BOOL enable)
{
    UINT32 u4BaseReg;
    OSD_VERIFY_PLANE(u4Plane);

    u4BaseReg = OSD_PLA_GetBaseReg(u4Plane);
    if (enable)
    {
        IO_WRITE32MSK(u4BaseReg, 0x98, 1<<12, 1<<12);
    }
    else
    {
        IO_WRITE32MSK(u4BaseReg, 0x98, 0, 1<<12);
    }

    return (INT32)OSD_RET_OK;
}

INT32 OSD_PLA_SetBurst8FifoEnable(UINT32 u4Plane, BOOL enable)
{
    UINT32 u4BaseReg;
    OSD_VERIFY_PLANE(u4Plane);

    u4BaseReg = OSD_PLA_GetBaseReg(u4Plane);
    if (enable)
    {
        IO_WRITE32MSK(u4BaseReg, 0x98, 1<<13, 1<<13);
    }
    else
    {
        IO_WRITE32MSK(u4BaseReg, 0x98, 0, 1<<13);
    }

    return (INT32)OSD_RET_OK;
}

#endif

#if defined(__KERNEL__) && !defined(CC_UBOOT) && !defined(CONFIG_TV_DRV_VFY)
#include <linux/file_ops.h>
#include <asm/io.h>
#include <linux/timer.h>
#include <linux/version.h>
#include <linux/mm.h>

#if defined(CC_MT5886) || defined(CC_MT5863)
#include <linux/sched.h>
#include <linux/highmem.h>
#include <linux/slab.h>
extern struct task_struct *bind_tsk;
static unsigned char *cache = NULL;

static UINT32 FileWriteFromPage(struct file *file, struct page *page, UINT32 size, UINT32 m_offset, UINT64 *f_offset)
{
    UINT32 w_size = 0;
    void *kernel_addr;

    //cannot do block operations in atomic, so memcpy the page to cache
    //if use API page_address, some pages would return null.
    kernel_addr = kmap_atomic(page);
    memcpy(cache, kernel_addr, PAGE_SIZE);
    kunmap_atomic(kernel_addr);
    put_page(page);
    w_size = FILE_Write(file, (unsigned char *)((unsigned long)cache + m_offset), size, f_offset);
    return w_size;
}

static UINT32 FileReadToPage(struct file *file, struct page *page, UINT32 size, UINT32 m_offset, UINT64 *f_offset)
{
    UINT32 r_size = 0;
    void *kernel_addr;

    //cannot do block operations in atomic, so memcpy the page to cache
    //if use API page_address, some pages would return null.
    r_size = FILE_Read(file, cache, size, f_offset);
    kernel_addr = kmap_atomic(page);
    memcpy((void *)((unsigned long)kernel_addr + m_offset), cache, size);
    kunmap_atomic(kernel_addr);
    put_page(page);
    return r_size;
}
#endif
INT32 OSD_PLA_DumpBitmap(UINT32 plane, const CHAR *filePath)
{
    UINT32 region;
    struct file *file;
    UPTR bmdata = 0;
    UINT32 size = 0;
    UINT64 offset = 0;
#if defined(CC_MT5886) || defined(CC_MT5863)
    BOOL fgMMUEnable = FALSE;
#endif

    region = OSD_PLA_GetFirstRegion(plane);
    file = FILE_Open(filePath, O_WRONLY|O_CREAT, 0644);

    if (!file)
    {
        OSD_LOG_E("open %s failed\n", filePath);
        return -(INT32)OSD_RET_INV_ARG;
    }
#if defined(CC_MT5886) || defined(CC_MT5863)
    OSD_MMU_GetEnable(plane, &fgMMUEnable);
    if (fgMMUEnable)
    {
        UINT32 pitch = 0, height = 0, pg_offset = 0;
        INT32 w_size = 0, left_size = 0;
        int nr_pages, i;
        unsigned long first,last;
        struct page **pages;

        OSD_RGN_GetAddress(region, OSD_RGN_BMP_ADDR, &bmdata);
        OSD_RGN_Get(region, OSD_RGN_BMP_PITCH, &pitch);
        OSD_RGN_Get(region, OSD_RGN_BMP_H, &height);
        left_size = size = pitch * height;
        pg_offset = (bmdata &~ PAGE_MASK);
        first = (bmdata & PAGE_MASK) >> PAGE_SHIFT;
        last  = ((bmdata + size) & PAGE_MASK) >> PAGE_SHIFT;
        if(0x0 == ((bmdata + size) % 0x1000))
        {
            nr_pages = last - first;
        }
        else
        {
            nr_pages = last-first + 1;
        }

        if((pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL)) == NULL)
        {
            return -ENOMEM;
        }
        if((cache = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
        {
            kfree(pages);
            return -ENOMEM;
        }
        down_read(&bind_tsk->mm->mmap_sem);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
        /* rw==READ means read from drive, write into memory area */
        get_user_pages(
                bind_tsk,
                bind_tsk->mm,
                bmdata,
                nr_pages,
                0, /* don't write */
                0, /* don't force */
                pages,
                NULL);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
        get_user_pages_remote(
                bind_tsk,
                bind_tsk->mm,
                bmdata,
                nr_pages,
                0, /* don't write, don't force */
                pages,
                NULL,
                NULL);
#else
        get_user_pages_remote(
                bind_tsk,
                bind_tsk->mm,
                bmdata,
                nr_pages,
                0, /* don't write, don't force */
                pages,
                NULL);
#endif
        up_read(&bind_tsk->mm->mmap_sem);
        //OSD request for 16 bytes align, so the first and the last page may be not full page.
        w_size = FileWriteFromPage(file, pages[0], PAGE_SIZE - pg_offset, pg_offset, &offset);
        left_size -= w_size;
        for (i = 1; i < nr_pages - 1; i++)
        {
            w_size = FileWriteFromPage(file, pages[i], PAGE_SIZE, 0, &offset);
            bmdata += w_size;
            left_size -= w_size;
        }
        if (left_size > 0)
        {
            w_size = FileWriteFromPage(file, pages[nr_pages - 1], left_size, 0, &offset);
        }
        kfree(pages);
        kfree(cache);
    }
    else
#endif
    {
        OSD_RGN_GetVirtBmpAddr(region, &bmdata, &size);
        if (!bmdata)
        {
            OSD_LOG_E("can't get virtual bitmap address of plane %d\n", plane + 1);
            return -(INT32)OSD_RET_INV_ARG;
        }
        size = FILE_Write(file, (unsigned char *)bmdata, size, &offset);
    }
    OSD_LOG_D("written size:%ld\n", size);
#if defined(CC_MT5886) || defined(CC_MT5863)
    if (!fgMMUEnable)
    {
        iounmap((void *)bmdata);
    }
#else
    iounmap((void *)bmdata);
#endif
    FILE_Close(file);

    return OSD_RET_OK;
}

INT32 OSD_PLA_DumpInBitmap(UINT32 plane, const CHAR *filePath)
{
    UINT32 region;
    struct file *file;
    UPTR bmdata = 0;
    UINT32 size = 0;
    UINT64 offset = 0;
#if defined(CC_MT5886) || defined(CC_MT5863)
    BOOL fgMMUEnable = FALSE;
#endif

    region = OSD_PLA_GetFirstRegion(plane);
    file = FILE_Open(filePath, O_RDONLY, 0);

    if (!file)
    {
        OSD_LOG_E("open %s failed\n", filePath);
        return -(INT32)OSD_RET_INV_ARG;
    }
#if defined(CC_MT5886) || defined(CC_MT5863)
    OSD_MMU_GetEnable(plane, &fgMMUEnable);
    if (fgMMUEnable)
    {
        UINT32 pitch = 0, height = 0, pg_offset = 0;
        INT32 r_size = 0, left_size = 0;
        int nr_pages, i;
        unsigned long first,last;
        struct page **pages;

        OSD_RGN_GetAddress(region, OSD_RGN_BMP_ADDR, &bmdata);
        OSD_RGN_Get(region, OSD_RGN_BMP_PITCH, &pitch);
        OSD_RGN_Get(region, OSD_RGN_BMP_H, &height);
        left_size = size = pitch * height;
        pg_offset = (bmdata &~ PAGE_MASK);
        first = (bmdata & PAGE_MASK) >> PAGE_SHIFT;
        last  = ((bmdata + size) & PAGE_MASK) >> PAGE_SHIFT;
        if(0x0 == ((bmdata + size) % 0x1000))
        {
            nr_pages = last - first;
        }
        else
        {
            nr_pages = last-first + 1;
        }

        if((pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL)) == NULL)
        {
            return -ENOMEM;
        }
        if((cache = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
        {
            kfree(pages);
            return -ENOMEM;
        }
        down_read(&bind_tsk->mm->mmap_sem);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
        /* rw==READ means read from drive, write into memory area */
        get_user_pages(
                bind_tsk,
                bind_tsk->mm,
                bmdata,
                nr_pages,
                1, /* to write */
                0, /* don't force */
                pages,
                NULL);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
        get_user_pages_remote(
                bind_tsk,
                bind_tsk->mm,
                bmdata,
                nr_pages,
                FOLL_WRITE, /* don't write, don't force */
                pages,
                NULL,
                NULL);
#else
        get_user_pages_remote(
                bind_tsk,
                bind_tsk->mm,
                bmdata,
                nr_pages,
                FOLL_WRITE, /* to write, don't force */
                pages,
                NULL);
#endif
        up_read(&bind_tsk->mm->mmap_sem);
        //OSD request for 16 bytes align, so the first and the last page may be not full page.
        r_size = FileReadToPage(file, pages[0], PAGE_SIZE - pg_offset, pg_offset, &offset);
        left_size -= r_size;
        for (i = 1; i < nr_pages - 1; i++)
        {
            r_size = FileReadToPage(file, pages[i], PAGE_SIZE, 0, &offset);
            bmdata += r_size;
            left_size -= r_size;
        }
        if (left_size > 0)
        {
            r_size = FileReadToPage(file, pages[nr_pages - 1], left_size, 0, &offset);
        }
        kfree(pages);
        kfree(cache);
    }
    else
#endif
    {
        OSD_RGN_GetVirtBmpAddr(region, &bmdata, &size);
        if (!bmdata)
        {
            OSD_LOG_E("can't get virtual bitmap address of plane %d\n", plane + 1);
            return -(INT32)OSD_RET_INV_ARG;
        }
        size = FILE_Read(file, (unsigned char *)bmdata, size, &offset);
    }
    HalFlushInvalidateDCache();
    OSD_LOG_D("read size:%u\n", size);
    FILE_Close(file);
#if defined(CC_MT5886) || defined(CC_MT5863)
    if (!fgMMUEnable)
    {
        iounmap((void *)bmdata);
    }
#else
    iounmap((void *)bmdata);
#endif

    return OSD_RET_OK;
}

static UINT32 dumpPlane = OSD_PLANE_MAX_NUM;
static UINT32 dumpAmount = 0;
static UINT32 dumpCount = 0;
static CHAR dumpPathPrefix[100] = {0};
static CHAR dumpPath[100] = {0};
static struct timer_list dumpTimer;

static void _DumpTaskCheckNeedEnd(BOOL prevResult)
{
    if (prevResult != OSD_RET_OK)
    {
        dumpPlane = OSD_PLANE_MAX_NUM;
        OSD_LOG_E("dump fail\n");
    }
    else
    {
        dumpCount++;
        if (dumpAmount != 0 && dumpCount >= dumpAmount)
        {
            dumpPlane = OSD_PLANE_MAX_NUM;
            OSD_LOG_I("dump finish\n");
        }
    }
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
static void _DumpPeriodEndCallback(unsigned long data)
#else
static void _DumpPeriodEndCallback(struct timer_list *data)
#endif
{
    UNUSED(data);
    if (dumpPlane != OSD_PLANE_MAX_NUM)
    {
        dumpPlane = OSD_PLANE_MAX_NUM;
        OSD_LOG_I("dump finish\n");
    }
}

static BOOL _DumpCurrentFrame(UINT32 u4Plane)
{
    snprintf(dumpPath, sizeof(dumpPath), "%s_%d.raw", dumpPathPrefix, dumpCount);
    OSD_LOG_I("dumping to %s\n", dumpPath);
    return OSD_PLA_DumpBitmap(u4Plane, dumpPath);
}

void OSD_PLA_DumpTask(UINT32 u4Region)
{
    if ((dumpPlane != OSD_PLANE_MAX_NUM) && (OSD_RGN_TO_PLANE(u4Region) == dumpPlane))
    {
        _DumpTaskCheckNeedEnd(_DumpCurrentFrame(dumpPlane));
    }
}

INT32 OSD_PLA_DumpTaskStart(UINT32 u4Plane, const CHAR *sDir, UINT32 u4Amount, UINT32 u4Period)
{
    if (dumpPlane != OSD_PLANE_MAX_NUM)
    {
        OSD_LOG_E("dump rawdata task is being processed\n");
        return -(INT32)OSD_RET_INV_ARG;
    }
    else if (sDir == NULL)
    {
        OSD_LOG_E("directory is NULL\n");
        return -(INT32)OSD_RET_INV_ARG;
    }
    else if (!OSD_PLA_Get_En(u4Plane) || OSD_PLA_Get_Dec(u4Plane))
    {
        OSD_LOG_E("OSD%d dump not available\n", u4Plane + 1);
        return -(INT32)OSD_RET_INV_ARG;
    }
    else
    {
        UINT32 region, bmpPitch, bmpHeight, bmpColorMode;
        UINT32 a, yr, ug, vb;

        dumpCount = 0;
        region = OSD_PLA_GetFirstRegion(u4Plane);
        OSD_RGN_Get(region, OSD_RGN_BMP_PITCH, &bmpPitch);
        OSD_RGN_Get(region, OSD_RGN_BMP_H, &bmpHeight);
        OSD_RGN_Get(region, OSD_RGN_COLORMODE, &bmpColorMode);
        OSD_RGN_Get(region, OSD_RGN_ALPHA_SEL, &a);
        OSD_RGN_Get(region, OSD_RGN_YR_SEL, &yr);
        OSD_RGN_Get(region, OSD_RGN_UG_SEL, &ug);
        OSD_RGN_Get(region, OSD_RGN_VB_SEL, &vb);
        if (sDir[strlen(sDir) - 1] == '/')
            snprintf(dumpPathPrefix, sizeof(dumpPathPrefix), "%sOSD%d_%d_%d%d%d%d_%d_%d",
                    sDir, u4Plane + 1, bmpColorMode, a, yr, ug, vb, bmpPitch, bmpHeight);
        else
            snprintf(dumpPathPrefix, sizeof(dumpPathPrefix), "%s/OSD%d_%d_%d%d%d%d_%d_%d",
                    sDir, u4Plane + 1, bmpColorMode, a, yr, ug, vb, bmpPitch, bmpHeight);
        if (u4Amount == 0 && u4Period == 0)
        {
            _DumpCurrentFrame(u4Plane);
        }
        else
        {
            dumpPlane = u4Plane;
            dumpAmount = u4Amount;
            if (u4Period > 0)
            {
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
                setup_timer(&dumpTimer, _DumpPeriodEndCallback, 0);
#else
                timer_setup(&dumpTimer, _DumpPeriodEndCallback, 0);
#endif
                mod_timer(&dumpTimer, jiffies + msecs_to_jiffies(u4Period));
            }
        }
        return OSD_RET_OK;
    }
}

#endif

#if defined(CC_MT5893) || defined(CC_MT5895)
#define CHECK_POSITIVE(x)   ((x) > 0)
#define GET_POSITIVE(x)     ((x) >= 0 ? (x) : 0)
#define CHECK_ADDR_ALIGN(addr)    ((addr + 0xF) & (~0xF))
#define MAX_SCALER_WIDTH    (7680)
#define MAX_SCLAER_HEIGHT   (4320)
#define MAX_SRC_WIDTH       (32)
typedef struct
{
    UPTR   upDataAddr;
    UINT32 u4RgnSrcW;
    UINT32 u4RgnSrcH;
    UINT32 u4RgnPitch;
    UINT32 u4RgnOutW;
    UINT32 u4RgnOutH;
    UINT32 u4RgnOutX;
    UINT32 u4RgnOutY;
    UINT32 u4ScalerSrcW;
    UINT32 u4ScalerSrcH;
    UINT32 u4ScalerDstW;
    UINT32 u4ScalerDstH;
} _OSD_MODULE_CONFIG_T;

typedef enum
{
    OSD_CURSOR_DISP_L,   // only Left side
    OSD_CURSOR_DISP_R,   // only right side
    OSD_CURSOR_DISP_M    // both left and right
} _OSD_MODULE_POS_STATUS;

static UINT32 widthToPitch(UINT32 u4Width, UINT32 u4ColorMode, UINT32* u4Pitch)
{
    UINT32 u4FitWidth, u4TempValue;
    switch(u4ColorMode)
    {
    case OSD_CM_YCBCR_CLUT2:
    case OSD_CM_RGB_CLUT2:
        u4TempValue = u4Width >> 2;
        *u4Pitch = CHECK_ADDR_ALIGN(u4TempValue);
        u4FitWidth = (*u4Pitch) << 2;
        break;
    case OSD_CM_YCBCR_CLUT4:
    case OSD_CM_RGB_CLUT4:
        u4TempValue = u4Width >> 1;
        *u4Pitch = CHECK_ADDR_ALIGN(u4TempValue);
        u4FitWidth = (*u4Pitch) << 1;
        break;
    case OSD_CM_YCBCR_CLUT8:
    case OSD_CM_RGB_CLUT8:
        u4TempValue = u4Width;
        *u4Pitch = CHECK_ADDR_ALIGN(u4TempValue);
        u4FitWidth = (*u4Pitch);
        break;
    case OSD_CM_AYCBCR8888_DIRECT32:
    case OSD_CM_ARGB8888_DIRECT32:
        u4TempValue = u4Width << 2;
        *u4Pitch = CHECK_ADDR_ALIGN(u4TempValue);
        u4FitWidth = (*u4Pitch) >> 2;
        break;
    case OSD_CM_ALPHA_BIT:
        u4TempValue = u4Width >> 3;
        *u4Pitch = CHECK_ADDR_ALIGN(u4TempValue);
        u4FitWidth = (*u4Pitch) << 3;
        break;
    case OSD_CM_ARGB4444_DIRECT16:
    default:
        u4TempValue = u4Width << 1;
        *u4Pitch = CHECK_ADDR_ALIGN(u4TempValue);
        u4FitWidth = (*u4Pitch) >> 1;
        break;
    }

    return u4FitWidth;
}
#if 0
static UINT32 pitchToWidth(UINT32 u4Pitch, UINT32 u4ColorMode)
{
    ASSERT((u4Pitch & 0xF) == 0x00);

    switch(u4ColorMode)
    {
    case OSD_CM_YCBCR_CLUT2:
    case OSD_CM_RGB_CLUT2:
        return (u4Pitch << 2);
        break;
    case OSD_CM_YCBCR_CLUT4:
    case OSD_CM_RGB_CLUT4:
        return (u4Pitch << 1);
        break;
    case OSD_CM_YCBCR_CLUT8:
    case OSD_CM_RGB_CLUT8:
        return u4Pitch;
        break;
    case OSD_CM_AYCBCR8888_DIRECT32:
    case OSD_CM_ARGB8888_DIRECT32:
        return (u4Pitch >> 2);
        break;
    case OSD_CM_ALPHA_BIT:
        return (u4Pitch << 3);
        break;
    default:
        return (u4Pitch >> 1);
        break;
    }
}
#endif

static VOID OSD_PLA_GetRgnInfo(INT32 region, OSD_RGN_INFO_T* RgnInfo)
{
    // this not right, disp_w not save, need to calculate via step size (internal scaler)
    OSD_RGN_Get(region,  OSD_RGN_BMP_ADDR, (UINT32*)&RgnInfo->pu4Bmp_addr);
    OSD_RGN_Get(region,     OSD_RGN_BMP_W, &RgnInfo->u4Src_w);
    OSD_RGN_Get(region,     OSD_RGN_BMP_H, &RgnInfo->u4Src_h);
    OSD_RGN_Get(region,     OSD_RGN_OUT_X, &RgnInfo->u4Dst_x);
    OSD_RGN_Get(region,     OSD_RGN_OUT_Y, &RgnInfo->u4Dst_y);
    OSD_RGN_Get(region,     OSD_RGN_OUT_W, &RgnInfo->u4Dst_w);
    OSD_RGN_Get(region,     OSD_RGN_OUT_H, &RgnInfo->u4Dst_h);
    OSD_RGN_Get(region,    OSD_RGN_DISP_W, &RgnInfo->u4Disp_w);
    OSD_RGN_Get(region,    OSD_RGN_DISP_H, &RgnInfo->u4Disp_h);
    OSD_RGN_Get(region,    OSD_RGN_CLIP_H, &RgnInfo->u4Clip_h);
    OSD_RGN_Get(region,    OSD_RGN_CLIP_V, &RgnInfo->u4Clip_v);
    OSD_RGN_Get(region,  OSD_RGN_H_MIRROR, &RgnInfo->u4Hmirror);
    OSD_RGN_Get(region,    OSD_RGN_V_FLIP, &RgnInfo->u4Vflip);
    OSD_RGN_Get(region, OSD_RGN_BMP_PITCH, &RgnInfo->u4Pitch);
    OSD_RGN_Get(region, OSD_RGN_COLORMODE, &RgnInfo->u4ColorMode);
}

static INT32 OSD_PLA_DualOstgForCursor(UINT32 u4Plane, INT32 region, OSD_RGN_INFO_T RgnInfo)
{
    UINT32 u4MidLen, u4RightClip;
    INT32 leftRgn, rightRgn;
    UINT32 u4PanelWidth, u4PanelHeight;
    _OSD_MODULE_POS_STATUS CursorPos;

    leftRgn  = OSD_PLA_GetAvailableInternalRgnList(OSD_PLANE_5);
    rightRgn = OSD_PLA_GetAvailableInternalRgnList(OSD_RT_PLANE_5);

    u4PanelWidth = PANEL_GetPanelWidth();
    u4PanelHeight = PANEL_GetPanelHeight();

    u4RightClip = 0;
    u4MidLen = u4PanelWidth / 2;

    // default copy region config
    IGNORE_RET(_OSD_RGN_Copy(leftRgn, region));
    IGNORE_RET(_OSD_RGN_Copy(rightRgn, region));

    if ( (RgnInfo.u4Dst_x + RgnInfo.u4Dst_w) < u4MidLen )
    {
        OSD_LOG_D("Cursor case 1 Left only\n");
        CursorPos = OSD_CURSOR_DISP_L;
        _OSD_RGN_SetInputWidth(rightRgn, 0);
    }

    if ( RgnInfo.u4Dst_x > u4MidLen )
    {
        OSD_LOG_D("Cursor case 2 Right only\n");
        CursorPos = OSD_CURSOR_DISP_R;
        _OSD_RGN_SetInputWidth(leftRgn, 0);
        _OSD_RGN_SetOutputPosX(rightRgn, RgnInfo.u4Dst_x - u4MidLen);
    }

    if ( (RgnInfo.u4Dst_x < u4MidLen) && (RgnInfo.u4Dst_x + RgnInfo.u4Dst_w) > u4MidLen )
    {
        UINT32 u4Width_L, u4Width_R;
        UINT32 u4AddrOffset;
        OSD_LOG_D("Cursor case 3 Middle pos\n");
        u4Width_L = u4MidLen - RgnInfo.u4Dst_x;
        u4Width_R = RgnInfo.u4Dst_w - u4Width_L;

        _OSD_RGN_SetInputWidth(leftRgn, u4Width_L);
        _OSD_RGN_SetOutputWidth(leftRgn, u4Width_L);
        _OSD_RGN_SetInputWidth(rightRgn, u4Width_R);
        _OSD_RGN_SetOutputWidth(rightRgn, u4Width_R);

        IGNORE_RET(widthToPitch(RgnInfo.u4Src_w, RgnInfo.u4ColorMode, &u4AddrOffset));
        _OSD_RGN_SetDataAddr(rightRgn, RgnInfo.pu4Bmp_addr + u4AddrOffset);
        _OSD_RGN_SetOutputPosX(rightRgn, 0);
        CursorPos = OSD_CURSOR_DISP_M;
    }

    _OSD_RGN_SetHClip(leftRgn, 0);
    _OSD_RGN_SetVClip(leftRgn, 0);
    _OSD_RGN_SetHClip(rightRgn, 0);
    _OSD_RGN_SetVClip(rightRgn, 0);

    _OSD_RGN_GetAddress(leftRgn, &RgnInfo.pu4Hdr_addr);
    _OSD_PLA_SetHeaderAddr(OSD_PLANE_5, PHYSICAL(RgnInfo.pu4Hdr_addr));
    _OSD_RGN_GetAddress(rightRgn, &RgnInfo.pu4Hdr_addr);
    _OSD_PLA_SetHeaderAddr(OSD_RT_PLANE_5, PHYSICAL(RgnInfo.pu4Hdr_addr));

    if (OSD_Get_Dbg_Info(9) & BIT2)
    {
        OSD_RGN_Dump(region);
        OSD_RGN_Dump(leftRgn);
        OSD_RGN_Dump(rightRgn);
    }

    _OSD_PLA_UpdateHwReg(OSD_PLANE_5);

    OSD_PLA_SwitchInternalRgnId(OSD_PLANE_5);
    OSD_PLA_SwitchInternalRgnId(OSD_RT_PLANE_5);

    return (INT32) OSD_RET_OK;
}


static INT32 g_osd_crop_offset = 32;
static BOOL g_osd_crop_enable = TRUE;
BOOL OSD_PLA_GetCropEnable(VOID)
{
    return g_osd_crop_enable;
}

VOID OSD_PLA_SetCropEnable(BOOL fgEnable)
{
    g_osd_crop_enable = fgEnable;
}

INT32 OSD_PLA_DualOstgFlipTo(UINT32 u4Plane, INT32 region)
{
    UINT32 u4Scaler;
    OSD_RGN_INFO_T RgnInfo;

    UINT32 u4ScalerEnable, u4Is16Bpp;
    UINT32 u4ScalerSrcW, u4ScalerSrcH, u4ScalerDstW, u4ScalerDstH;

    UINT32 u4PlanePosX, u4PlanePosY;
    UINT32 u4PanelWidth, u4PanelHeight;

    UINT32 u4ValidPosX, u4ValidPosY, u4ValidWidth, u4ValidHeight;
    UINT32 u4TempValue;

    INT32 leftRgn, rightRgn;

    _OSD_MODULE_CONFIG_T leftConfig, rightConfig;

    OSD_VERIFY_PLANE(u4Plane);
    OSD_VERIFY_REGION(region);
    OSD_PLA_GetRgnInfo(region, &RgnInfo);

    if (u4Plane == OSD_PLANE_5)
    {
        OSD_PLA_DualOstgForCursor(u4Plane, region, RgnInfo);
        return (INT32) OSD_RET_OK;
    }

    u4Scaler = OSD_PLANE_TO_SCALER(u4Plane);
    leftRgn = OSD_PLA_GetAvailableInternalRgnList(u4Plane);
    rightRgn = OSD_PLA_GetAvailableInternalRgnList(u4Plane + 5);

    x_memset((void*)&leftConfig, 0, sizeof(_OSD_MODULE_CONFIG_T));
    x_memset((void*)&rightConfig, 0, sizeof(_OSD_MODULE_CONFIG_T));

    OSD_SC_GetScalerInfo(u4Scaler, &u4ScalerEnable, &u4ScalerSrcW, &u4ScalerSrcH, &u4ScalerDstW, &u4ScalerDstH, &u4Is16Bpp);

    // for 4k120/8k30 panel, if use gfx path, osd cannot support dual ostg mode;
    u4PanelWidth  = PANEL_GetPanelWidth();
    u4PanelHeight = PANEL_GetPanelHeight();

    OSD_LOG_D("plane:%d, sclaer:%d, src:%d,%d, dst:%d,%d, panelSize:%d,%d\n",
               u4Plane, u4Scaler, u4ScalerSrcW, u4ScalerSrcH, u4ScalerDstW, u4ScalerDstH,
               u4PanelWidth, u4PanelHeight);

    // preprocessing: check params valid
    if (u4ScalerEnable == 0)
    {
        u4ScalerSrcW = u4ScalerDstW = u4PanelWidth;
        u4ScalerSrcH = u4ScalerDstH = u4PanelHeight;
    }

    if (u4ScalerSrcW == 0 || u4ScalerDstW == 0 || RgnInfo.u4Dst_w == 0 || RgnInfo.u4Disp_w == 0)
    {
        leftConfig.u4RgnSrcW = 0;
        rightConfig.u4RgnSrcW = 0;
        u4ScalerSrcW = u4ScalerDstW = u4PanelWidth;
        u4ScalerSrcH = u4ScalerDstH = u4PanelHeight;
        u4ValidHeight = 0;
        goto APPLY_CONFIG;
    }

    // default copy region config
    IGNORE_RET(_OSD_RGN_Copy(leftRgn, region));
    IGNORE_RET(_OSD_RGN_Copy(rightRgn, region));

    OSD_LOG_D("region:%d, leftRgn:%d, rightRgn:%d\n", region, leftRgn, rightRgn);

    if (OSD_Get_Dbg_Info(9) & BIT0)
    {
        OSD_RGN_Dump(region);
        OSD_RGN_Dump(leftRgn);
        OSD_RGN_Dump(rightRgn);
    }

    // 0.get initial addr & clip value[make sure start addr is 16byte align]
    RgnInfo.u4Clip_h = widthToPitch(RgnInfo.u4Clip_h, RgnInfo.u4ColorMode, &u4TempValue);
    RgnInfo.pu4Bmp_addr += u4TempValue + RgnInfo.u4Clip_v * RgnInfo.u4Pitch;
    OSD_LOG_D("initial data addr:0x%x\n", (UINT32)RgnInfo.pu4Bmp_addr);

    // 1.caculate valid area of source region
    // 1.1.check out position & scaler dst if beyond panel size
    OSD_BASE_GetOsdPosition(u4Plane, &u4PlanePosX, &u4PlanePosY);
    u4ValidPosX = u4PlanePosX + RgnInfo.u4Dst_x * u4ScalerDstW / u4ScalerSrcW;
    u4ValidPosY = u4PlanePosY + RgnInfo.u4Dst_y * u4ScalerDstW / u4ScalerSrcW;
    u4ValidWidth = GET_POSITIVE(RgnInfo.u4Src_w - RgnInfo.u4Clip_h);
    u4ValidHeight = GET_POSITIVE(RgnInfo.u4Src_h - RgnInfo.u4Clip_v);
    OSD_LOG_D("plane pos:%d, %d, validPos:%d,%d, validSize:%d,%d\n", u4PlanePosX, u4PlanePosY,
        u4ValidPosX, u4ValidPosY, u4ValidWidth, u4ValidHeight);

    // 2.get left region width based on internal/external scaler
    if (u4ValidPosX < u4PanelWidth /2)
    {
        OSD_LOG_D("u4ValidPosX < u4PanelWidth /2\n");
        //2.1.get valid disp width of source region
        u4TempValue = MIN(MIN(u4ValidWidth, RgnInfo.u4Dst_w), RgnInfo.u4Disp_w);
        OSD_LOG_D("tempValue:%d\n", u4TempValue);
        //2.2.check if need right config
        if (u4TempValue * u4ScalerDstW / u4ScalerSrcW > (u4PanelWidth / 2 - u4ValidPosX))
        {
            OSD_LOG_D("case1\n");
            //2.3.get valid left disp width of srouce region
             u4TempValue = (u4PanelWidth /2 - u4ValidPosX) * u4ScalerSrcW / u4ScalerDstW;
            OSD_LOG_D("tempValue:%d\n", u4TempValue);
            //2.3.1.handle internal scaler
            leftConfig.u4RgnSrcW = u4TempValue * u4ValidWidth / RgnInfo.u4Disp_w;
            //2.3.2.make sure left width pitch is 16byte align
            leftConfig.u4RgnSrcW = widthToPitch(leftConfig.u4RgnSrcW, RgnInfo.u4ColorMode, &u4TempValue);
            leftConfig.u4RgnOutW = leftConfig.u4RgnSrcW;
            leftConfig.u4RgnOutX = RgnInfo.u4Dst_x;
            //2.3.3.get right config based on left
            rightConfig.u4RgnSrcW = u4ValidWidth - leftConfig.u4RgnSrcW;
            rightConfig.u4RgnOutW = RgnInfo.u4Dst_w - leftConfig.u4RgnOutW;
            rightConfig.u4RgnOutX = 0;

            if (g_osd_crop_enable)
            {
                leftConfig.u4RgnSrcW  += g_osd_crop_offset;
                leftConfig.u4RgnOutW  += g_osd_crop_offset;
                rightConfig.u4RgnSrcW += g_osd_crop_offset;
                rightConfig.u4RgnOutW += g_osd_crop_offset;
            }

            //2.4.get scaler config
            //[NOTE]just keep old src sclaer config or recaulate based on seperate width
            //because it seems this will affect the center border effects
            leftConfig.u4ScalerSrcW = u4ScalerSrcW * leftConfig.u4RgnSrcW / u4ValidWidth;
            leftConfig.u4ScalerDstW = u4ScalerDstW * leftConfig.u4RgnSrcW / u4ValidWidth;
            rightConfig.u4ScalerSrcW = u4ScalerSrcW * rightConfig.u4RgnSrcW / u4ValidWidth;
            rightConfig.u4ScalerDstW = u4ScalerDstW * rightConfig.u4RgnSrcW / u4ValidWidth;

            OSD_LOG_V("tempValue:%d leftConfig.u4RgnSrcW: %d leftConfig.u4RgnOutW: %d leftConfig.u4RgnOutX: %d RgnInfo.u4Disp_w: %d rightConfig.u4RgnSrcW: %d rightConfig.u4RgnOutW: %d leftConfig.u4ScalerSrcW: %d leftConfig.u4ScalerDstW: %d rightConfig.u4ScalerSrcW: %d rightConfig.u4ScalerDstW: %d \n",
                       u4TempValue,
                       leftConfig.u4RgnSrcW,leftConfig.u4RgnOutW,
                       leftConfig.u4RgnOutX,RgnInfo.u4Disp_w,
                       rightConfig.u4RgnSrcW,rightConfig.u4RgnOutW,
                       leftConfig.u4ScalerSrcW,leftConfig.u4ScalerDstW,
                       rightConfig.u4ScalerSrcW,rightConfig.u4ScalerDstW);
        }
        else if (RgnInfo.u4Src_w == 64 && RgnInfo.u4Src_h == 32)
        {
            OSD_LOG_D("case transparent \n");
             //2.3.get valid left disp width of srouce region
            u4TempValue = (u4PanelWidth /2 - u4ValidPosX) * u4ScalerSrcW / u4ScalerDstW;
            OSD_LOG_D("tempValue:%d\n", u4TempValue);
            //2.3.1.handle internal scaler
            leftConfig.u4RgnSrcW = u4TempValue * u4ValidWidth / RgnInfo.u4Disp_w;
            //2.3.2.make sure left width pitch is 16byte align
            leftConfig.u4RgnSrcW = widthToPitch(leftConfig.u4RgnSrcW, RgnInfo.u4ColorMode, &u4TempValue);
            leftConfig.u4RgnOutW = leftConfig.u4RgnSrcW;
            leftConfig.u4RgnOutX = RgnInfo.u4Dst_x;
            //2.3.3.get right config based on left
            rightConfig.u4RgnSrcW = u4ValidWidth - leftConfig.u4RgnSrcW;
            rightConfig.u4RgnOutW = RgnInfo.u4Dst_w - leftConfig.u4RgnOutW;
            rightConfig.u4RgnOutX = 0;
            //2.4.get scaler config
            //[NOTE]just keep old src sclaer config or recaulate based on seperate width
            //because it seems this will affect the center border effects
            leftConfig.u4ScalerSrcW = u4ScalerSrcW * leftConfig.u4RgnSrcW / u4ValidWidth;
            leftConfig.u4ScalerDstW = u4ScalerDstW * leftConfig.u4RgnSrcW / u4ValidWidth;
            rightConfig.u4ScalerSrcW = u4ScalerSrcW * rightConfig.u4RgnSrcW / u4ValidWidth;
            rightConfig.u4ScalerDstW = u4ScalerDstW * rightConfig.u4RgnSrcW / u4ValidWidth;

            OSD_LOG_V("tempValue:%d leftConfig.u4RgnSrcW: %d leftConfig.u4RgnOutW: %d leftConfig.u4RgnOutX: %d RgnInfo.u4Disp_w: %d rightConfig.u4RgnSrcW: %d rightConfig.u4RgnOutW: %d leftConfig.u4ScalerSrcW: %d leftConfig.u4ScalerDstW: %d rightConfig.u4ScalerSrcW: %d rightConfig.u4ScalerDstW: %d \n",
                       u4TempValue,
                       leftConfig.u4RgnSrcW,leftConfig.u4RgnOutW,
                       leftConfig.u4RgnOutX,RgnInfo.u4Disp_w,
                       rightConfig.u4RgnSrcW,rightConfig.u4RgnOutW,
                       leftConfig.u4ScalerSrcW,leftConfig.u4ScalerDstW,
                       rightConfig.u4ScalerSrcW,rightConfig.u4ScalerDstW);

        }
        else
        {
            OSD_LOG_D("case 2\n");
            //2.3.right is invalid
            rightConfig.u4RgnSrcW = 0;

            //2.4.set the left region config to source
            leftConfig.u4RgnSrcW = u4ValidWidth;
            leftConfig.u4RgnOutW = RgnInfo.u4Dst_w;
            leftConfig.u4RgnOutX = RgnInfo.u4Dst_x;
            leftConfig.u4ScalerSrcW = u4ScalerSrcW;
            leftConfig.u4ScalerDstW = u4ScalerDstW;
        }
    }
    else
    {
        OSD_LOG_D("case 3\n");
        //2.1.left is invalid
        leftConfig.u4RgnSrcW = 0;

        //2.2.set the right region config to source
        rightConfig.u4RgnSrcW = u4ValidWidth;
        rightConfig.u4RgnOutW = RgnInfo.u4Dst_w;
        rightConfig.u4RgnOutX = (u4PlanePosX > u4PanelWidth / 2) ? RgnInfo.u4Dst_x :
                                 RgnInfo.u4Dst_x - (u4PanelWidth / 2 - u4PlanePosX) * u4ScalerSrcW / u4ScalerDstW; // u4ValidPosX - u4PanelWidth / 2;
        rightConfig.u4ScalerSrcW = u4ScalerSrcW;
        rightConfig.u4ScalerDstW = u4ScalerDstW;
    }

    // 3.get left/right data addr based on enable hmirror or not
    if (RgnInfo.u4Hmirror)
    {
        IGNORE_RET(widthToPitch(u4ValidWidth - leftConfig.u4RgnSrcW, RgnInfo.u4ColorMode, &u4TempValue));
        leftConfig.upDataAddr = RgnInfo.pu4Bmp_addr + u4TempValue;
        IGNORE_RET(widthToPitch(leftConfig.u4RgnSrcW, RgnInfo.u4ColorMode, &u4TempValue));
        rightConfig.upDataAddr = leftConfig.upDataAddr - u4TempValue;
    }
    else
    {
        // 3.1.get left width addr offset
        IGNORE_RET(widthToPitch(leftConfig.u4RgnSrcW, RgnInfo.u4ColorMode, &u4TempValue));
        leftConfig.upDataAddr = RgnInfo.pu4Bmp_addr;
        rightConfig.upDataAddr = RgnInfo.pu4Bmp_addr + u4TempValue;

        if (g_osd_crop_enable)
        {
            widthToPitch(g_osd_crop_offset * 2, RgnInfo.u4ColorMode, &u4TempValue);
            rightConfig.upDataAddr -= u4TempValue;
        }
    }

APPLY_CONFIG:
    // 4.get vertical config
    leftConfig.u4RgnSrcH = u4ValidHeight;
    leftConfig.u4RgnOutH = RgnInfo.u4Dst_h;
    leftConfig.u4ScalerSrcH = u4ScalerSrcH;
    leftConfig.u4ScalerDstH = u4ScalerDstH;
    rightConfig.u4RgnSrcH = u4ValidHeight;
    rightConfig.u4RgnOutH = RgnInfo.u4Dst_h;
    rightConfig.u4ScalerSrcH = u4ScalerSrcH;
    rightConfig.u4ScalerDstH = u4ScalerDstH;

    // 5.apply config
    _OSD_RGN_SetInputWidth(leftRgn, leftConfig.u4RgnSrcW);
    _OSD_RGN_SetInputHeight(leftRgn, leftConfig.u4RgnSrcH);
    _OSD_RGN_SetOutputWidth(leftRgn, leftConfig.u4RgnOutW);
    _OSD_RGN_SetOutputHeight(leftRgn, leftConfig.u4RgnOutH);
    _OSD_RGN_SetOutputPosX(leftRgn, leftConfig.u4RgnOutX);
    _OSD_RGN_SetDataAddr(leftRgn, leftConfig.upDataAddr);
    _OSD_RGN_SetHClip(leftRgn, 0);
    _OSD_RGN_SetVClip(leftRgn, 0);

    _OSD_RGN_SetInputWidth(rightRgn, rightConfig.u4RgnSrcW);
    _OSD_RGN_SetInputHeight(rightRgn, rightConfig.u4RgnSrcH);
    _OSD_RGN_SetOutputWidth(rightRgn, rightConfig.u4RgnOutW);
    _OSD_RGN_SetOutputHeight(rightRgn, rightConfig.u4RgnOutH);
    _OSD_RGN_SetOutputPosX(rightRgn, rightConfig.u4RgnOutX);
    _OSD_RGN_SetDataAddr(rightRgn, rightConfig.upDataAddr);
    _OSD_RGN_SetHClip(rightRgn, 0);
    _OSD_RGN_SetVClip(rightRgn, 0);

#ifndef CC_MTK_LOADER
    if (u4Plane == OSD_PLANE_3)
    {
        UINT32 fgOVLMode;
        _OSD_BASE_GetOvlShareOsdScaler(&fgOVLMode);
        if (1 == fgOVLMode) //OVL 0:DC mode 1:DL mode
        {
            OSD_LOG_D("Half pitch is needed in OVL directlink mode\n");
            u4TempValue = 0;
            if (g_osd_crop_enable)
            {
                IGNORE_RET(widthToPitch(g_osd_crop_offset, RgnInfo.u4ColorMode, &u4TempValue));
            }

            OSD_RGN_Set(rightRgn, OSD_RGN_BMP_PITCH, RgnInfo.u4Pitch / 2 + u4TempValue);
            OSD_RGN_Set(leftRgn , OSD_RGN_BMP_PITCH, RgnInfo.u4Pitch / 2 + u4TempValue);
        }
    }
#endif

#ifdef CC_MTK_LOADER
    // Fix CC_UPGRADING_DYNAMIC_LOGO_SUPPORT feature in 4k120 model incorrect display issue
    static INT32 u4LogoInternalSecondRgn[OSD_PLANE_RGN_STATE_MAX][OSD_PLANE_RGN_MAX] = {0};
    static BOOL fgLogoInternalRgnState = FALSE;
    static BOOL fgLogoRgnInit = FALSE;
    UINT32 NextRgnEn;
    UINT32 i4RgnNext;

    if (!fgLogoRgnInit)
    {
        UINT32 i, j, u4RgnId, u4RgnList;
        for (i = 0; i < OSD_PLANE_RGN_STATE_MAX; i++)
        {
            for (j = 0; j < OSD_PLANE_RGN_MAX; j++)
            {
                IGNORE_RET(OSD_RGN_Create(&u4RgnId, 1920, 1080, (void *)DRAM_START, 14, 7680, 0, 0, 1920, 1080));
                u4LogoInternalSecondRgn[i][j] = u4RgnId;
                OSD_LOG_D("Init second rgn[%d][%d] = %d\n", i, j, u4RgnId);
            }
            fgLogoInternalRgnState = (BOOL)OSD_PLANE_RGN_STATE_FRONT;
        }
        fgLogoRgnInit = TRUE;
    }

    _OSD_RGN_GetNextEnable(region, &NextRgnEn);
    OSD_LOG_D("NextRgnEn = %d \n", NextRgnEn);
    OSD_RGN_Get((UINT32) region, (INT32) OSD_RGN_NEXT, &i4RgnNext);

    if (NextRgnEn == TRUE)
    {
        INT32 Rgn_L, Rgn_R;
        UINT32 u4MidLen;
        UPTR pu4SecondHdrAddr;
        OSD_RGN_INFO_T SecondRgnInfo;

        OSD_RGN_Get((UINT32) region, (INT32) OSD_RGN_NEXT, &i4RgnNext);

        OSD_PLA_GetRgnInfo(i4RgnNext, &SecondRgnInfo);

        Rgn_L = u4LogoInternalSecondRgn[!fgLogoInternalRgnState][OSD_PLANE_RGN_LEFT];
        Rgn_R = u4LogoInternalSecondRgn[!fgLogoInternalRgnState][OSD_PLANE_RGN_RIGHT];
        OSD_LOG_D("i4RgnNext = %d, Rgn_L = %d, Rgn_R = %d \n", i4RgnNext, Rgn_L, Rgn_R);
        IGNORE_RET(_OSD_RGN_Copy(Rgn_L, i4RgnNext));
        IGNORE_RET(_OSD_RGN_Copy(Rgn_R, i4RgnNext));

        u4MidLen = 1920 / 2; // logo canvas size is 1920 x 1080

        if ( (SecondRgnInfo.u4Dst_x < u4MidLen) && (SecondRgnInfo.u4Dst_x + SecondRgnInfo.u4Dst_w) > u4MidLen )
        {
            UINT32 u4Width_L, u4Width_R, u4FitWidth_L;
            UINT32 u4AddrOffset;
            u4Width_L = u4MidLen - SecondRgnInfo.u4Dst_x;
            u4Width_R = SecondRgnInfo.u4Dst_w - u4Width_L;

            OSD_LOG_D("Second region set!\n");

            u4FitWidth_L  = widthToPitch(u4Width_L, SecondRgnInfo.u4ColorMode, &u4AddrOffset);

            if (u4FitWidth_L != u4Width_L)
            {
                INT32 Offset = 0;
                OSD_LOG_D("Right region not align!\n");

                if (u4FitWidth_L > u4Width_L)
                {
                    Offset = u4FitWidth_L - u4Width_L;
                    u4Width_R += Offset;
                    IGNORE_RET(widthToPitch(u4Width_L - Offset, SecondRgnInfo.u4ColorMode, &u4AddrOffset));
                    _OSD_RGN_SetHClip(Rgn_R, Offset);
                }
            }

            _OSD_RGN_SetInputWidth(Rgn_L, u4Width_L);
            _OSD_RGN_SetOutputWidth(Rgn_L, u4Width_L);
            _OSD_RGN_SetInputWidth(Rgn_R, u4Width_R - 4); //Avoid LOGO BMP garbage
            _OSD_RGN_SetOutputWidth(Rgn_R, u4Width_R);

            _OSD_RGN_SetDataAddr(Rgn_R, SecondRgnInfo.pu4Bmp_addr + u4AddrOffset);
            _OSD_RGN_SetOutputPosX(Rgn_R, 0);

            _OSD_RGN_GetAddress(Rgn_L, &pu4SecondHdrAddr);
            _OSD_RGN_SetNextEnable(leftRgn, TRUE);
            _OSD_RGN_SetNextRegion(leftRgn, PHYSICAL(pu4SecondHdrAddr));
            _OSD_RGN_GetAddress(Rgn_R, &pu4SecondHdrAddr);
            _OSD_RGN_SetNextEnable(rightRgn, TRUE);
            _OSD_RGN_SetNextRegion(rightRgn, PHYSICAL(pu4SecondHdrAddr));

            OSD_LOG_D("u4Width_L = %d , u4Width_R = %d , Addr-offset = %d\n", u4Width_L, u4Width_R, u4AddrOffset);
        }

        fgLogoInternalRgnState = !fgLogoInternalRgnState;
    }
#endif

    // 5.1.for now, not consider clip_h because wait_stable would check if the data_addr
    // same with set_addr to decide if need to wait another vsync
    {
        // to be done
    }

    OSD_SC_DoScale(u4Scaler, u4ScalerEnable, leftConfig.u4ScalerSrcW, leftConfig.u4ScalerSrcH,
                   leftConfig.u4ScalerDstW, leftConfig.u4ScalerDstH);
    OSD_SC_DoScale(u4Scaler + 3, u4ScalerEnable, rightConfig.u4ScalerSrcW, rightConfig.u4ScalerSrcH,
                   rightConfig.u4ScalerDstW, rightConfig.u4ScalerDstH);

    // 6.valid plane setting
    _OSD_RGN_GetAddress(leftRgn, &RgnInfo.pu4Hdr_addr);
    _OSD_PLA_SetHeaderAddr(u4Plane, PHYSICAL(RgnInfo.pu4Hdr_addr));
    _OSD_RGN_GetAddress(rightRgn, &RgnInfo.pu4Hdr_addr);
    _OSD_PLA_SetHeaderAddr(u4Plane + 5, PHYSICAL(RgnInfo.pu4Hdr_addr));

    _OSD_PLA_UpdateHwReg(u4Plane);

    if (OSD_Get_Dbg_Info(9) & BIT1)
    {
        OSD_RGN_Dump(region);
        OSD_RGN_Dump(leftRgn);
        OSD_RGN_Dump(rightRgn);
    }

    OSD_PLA_SwitchInternalRgnId(u4Plane);
    OSD_PLA_SwitchInternalRgnId(u4Plane + 5);

    return (INT32) OSD_RET_OK;
}

#endif
