#include "osd_debug.h"
#include "osd_exp.h"
#include "osd_hw.h"
#include "panel.h"
#include "drv_ttd.h"
#include "x_hal_reg.h"
#include "hw_vdoin.h"

EXTERN UINT8 fgIsSupportUHD(void);
/***************************************************************************************************************************
****************************************************************************************************************************
//The implementation for OSD callback
****************************************************************************************************************************
***************************************************************************************************************************/

typedef struct
{
    BOOL fgRegisted;
    OSD_EXP_CALLBACK_T fnCallback;
}
REGISTER_CALLBACK_T;

static REGISTER_CALLBACK_T _rRegisterCallback[] =
{
    {
        .fgRegisted = FALSE,
    },
    {
        .fgRegisted = FALSE,
    },
    {
        .fgRegisted = FALSE,
    }
};

static UINT32 _u4CallbackMaxNumber = sizeof(_rRegisterCallback) / sizeof(REGISTER_CALLBACK_T);
static INT32 _i4Identity = 0;

static REGISTER_CALLBACK_T *OSD_Internal_GetIdleRegisterCallback(VOID)
{
    INT32 i;

    for (i = 0; i < _u4CallbackMaxNumber; i++)
    {
        if (_rRegisterCallback[i].fgRegisted == FALSE)
        {
            return (&_rRegisterCallback[i]);
        }
    }

    return NULL;
}


static OSD_EXP_RET_T OSD_Internal_CheckCallbackRegistered(INT32 i4Identity)
{
    INT32 i;

    for (i = 0; i < _u4CallbackMaxNumber; i++)
    {
        if (_rRegisterCallback[i].fgRegisted == TRUE)
        {
            if (_rRegisterCallback[i].fnCallback.i4Identity == i4Identity)
            {
                return OSD_EXP_RET_CALLBACK_REGISTED;
            }
        }
    }

    return OSD_EXP_RET_OK;
}

OSD_EXP_RET_T OSD_EXP_GenCallback(INT32 *pi4Identity)
{
    INT32 i4Identity;

    if (pi4Identity == NULL)
    {
        return OSD_EXP_RET_INVALID_ARGV;
    }

    while (1)
    {
        i4Identity = _i4Identity++;

        if (OSD_Internal_CheckCallbackRegistered(i4Identity) == OSD_EXP_RET_OK)
        {
            break;
        }
    }

    *pi4Identity = i4Identity;
    return OSD_EXP_RET_OK;
}


OSD_EXP_RET_T OSD_EXP_RegisterCallback(OSD_EXP_CALLBACK_T *pfnCb)
{
    OSD_EXP_RET_T rRet;
    REGISTER_CALLBACK_T *prRegCb = NULL;

    if (pfnCb == NULL)
    {
        return OSD_EXP_RET_INVALID_ARGV;
    }

    rRet = OSD_Internal_CheckCallbackRegistered(pfnCb->i4Identity);

    if (rRet != OSD_EXP_RET_OK)
    {
        return rRet;
    }

    prRegCb = OSD_Internal_GetIdleRegisterCallback();

    if (prRegCb == NULL)
    {
        return OSD_EXP_RET_OUTOF_RESOURCE;
    }

    prRegCb->fgRegisted = TRUE;
    prRegCb->fnCallback = *pfnCb;
    return OSD_EXP_RET_OK;
}

OSD_EXP_RET_T OSD_EXP_RemoveCallback(INT32 i4Identity)
{
    INT32 i;

    for (i = 0; i < _u4CallbackMaxNumber; i++)
    {
        if (_rRegisterCallback[i].fgRegisted == TRUE)
        {
            if (_rRegisterCallback[i].fnCallback.i4Identity == i4Identity)
            {
                _rRegisterCallback[i].fgRegisted = FALSE;
                return OSD_EXP_RET_OK;
            }
        }
    }

    return OSD_EXP_RET_INVALID_ARGV;
}

OSD_EXP_RET_T OSD_EXP_HandleVSync(VOID)
{
    INT32 i;

    for (i = 0; i < _u4CallbackMaxNumber; i++)
    {
        if (_rRegisterCallback[i].fgRegisted == TRUE)
        {
            if (_rRegisterCallback[i].fnCallback.pfnVsyncIsr != NULL)
            {
                _rRegisterCallback[i].fnCallback.pfnVsyncIsr();
            }
        }
    }

    return OSD_EXP_RET_OK;
}

OSD_EXP_RET_T OSD_EXP_UpdateVsyncTime(UINT64 *pu8VsyncTime)
{
    INT32 i;

    for (i = 0; i < _u4CallbackMaxNumber; i++)
    {
        if (_rRegisterCallback[i].fgRegisted == TRUE)
        {
            if (_rRegisterCallback[i].fnCallback.pfnUpdateVsyncTime != NULL)
            {
                _rRegisterCallback[i].fnCallback.pfnUpdateVsyncTime(pu8VsyncTime);
            }
        }
    }

    return OSD_EXP_RET_OK;
}

OSD_EXP_RET_T OSD_EXP_HandleResumeSuspend(BOOL fgSuspend)
{
    INT32 i;

    for (i = 0; i < _u4CallbackMaxNumber; i++)
    {
        if (_rRegisterCallback[i].fgRegisted == TRUE)
        {
            if (_rRegisterCallback[i].fnCallback.pfnResumeSuspend != NULL)
            {
                _rRegisterCallback[i].fnCallback.pfnResumeSuspend(fgSuspend);
            }
        }
    }

    return OSD_EXP_RET_OK;
}

OSD_EXP_RET_T OSD_EXP_HandleTimingChanged(VOID)
{
    INT32 i;

    for (i = 0; i < _u4CallbackMaxNumber; i++)
    {
        if (_rRegisterCallback[i].fgRegisted == TRUE)
        {
            if (_rRegisterCallback[i].fnCallback.pfnTimingChanged != NULL)
            {
                _rRegisterCallback[i].fnCallback.pfnTimingChanged();
            }
        }
    }

    return OSD_EXP_RET_OK;
}

/***************************************************************************************************************************
****************************************************************************************************************************
//The implementation for OSD PQ path and Gfx path
****************************************************************************************************************************
***************************************************************************************************************************/
typedef struct
{
    UINT32 u4MixOsdPreMJCSel: 1;
    UINT32 u4BotMaskSel : 1;

    UINT32 u4Mix11TopMixBg : 1;
    UINT32 u4Mix11MaskOrEn : 1;
    UINT32 u4Mix11Bypass : 1;

    UINT32 u4Mix12TopMixBg : 1;
    UINT32 u4Mix12MaskOrEn : 1;
    UINT32 u4Mix12Bypass : 1;

    UINT32 u4Mix2TopMixBg : 1;
    UINT32 u4Mix2MaskOrEn : 1;
    UINT32 u4Mix2Bypass : 1;

    UINT32 u4Mix3TopMixBg : 1;
    UINT32 u4Mix3MaskOrEn : 1;
    UINT32 u4Mix3Bypass : 1;

    UINT32 u4RegMix3SignEn : 1;
    UINT32 u4RegMix2SignEn : 1;
    UINT32 u4RegMix1SignEn : 1;

    UINT32 u4RegMixSignAutoOff : 1;
    UINT32 : 2;
    UINT32 u4RegMix3BotAlpha : 8;
#if defined(CC_MT5893) || defined(CC_MT5895)
    UINT32 u4MixOutClipEn : 1;
    UINT32 : 3;
#else
    UINT32 : 4;
#endif
}
OSD_MIX_0_FIELD_T;

typedef struct
{
    UINT32 u4RegMix11SelBotAlpha : 1;
    UINT32 u4RegMix12SelBotAlpha : 1;
    UINT32 u4RegMix2SelBotAlpha : 1;
    UINT32 u4RegMix3SelBotAlpha : 1;
    UINT32 : 4;
    UINT32 u4RegMix11BotAlpha : 8;
    UINT32 u4RegMix12BotAlpha : 8;
    UINT32 u4RegMix2BotAlpha : 8;
}
OSD_MIX_1_FILED_T;

typedef union
{
    UINT32 u4Value;
    OSD_MIX_0_FIELD_T rFiled;
} OSD_MIX_0_T;

typedef union
{
    UINT32 u4Value;
    OSD_MIX_1_FILED_T rFiled;
} OSD_MIX_1_T;

#if defined(CC_MT5893) || defined(CC_MT5895)

#ifndef OSD_MIX_R_OFFSET
#if defined(CC_MT5893)
#define OSD_MIX_R_OFFSET                      (0xF000)
#elif defined(CC_MT5895)
#define OSD_MIX_R_OFFSET                      (0x14000)
#endif
#endif

#if defined(CC_MT5893)
#define OSD_R_MIX_0_REG (POST_PROC_BASE + OSD_MIX_R_OFFSET + 0x984)
#define OSD_R_MIX_1_REG (POST_PROC_BASE + OSD_MIX_R_OFFSET + 0x988)
#define GFX_R_MIX_0_REG (POST_PROC_BASE + OSD_MIX_R_OFFSET + 0xA48)
#define GFX_R_MIX_1_REG (POST_PROC_BASE + OSD_MIX_R_OFFSET + 0xA4C)
#else
#define OSD_R_MIX_0_REG (IO_POSTPROC_BASE + OSD_MIX_R_OFFSET + 0x984)
#define OSD_R_MIX_1_REG (IO_POSTPROC_BASE + OSD_MIX_R_OFFSET + 0x988)
#define GFX_R_MIX_0_REG (IO_POSTPROC_BASE + OSD_MIX_R_OFFSET + 0xA48)
#define GFX_R_MIX_1_REG (IO_POSTPROC_BASE + OSD_MIX_R_OFFSET + 0xA4C)
#endif
#define OSD_R_MIX_0_READ32()            IO_READ32(OSD_R_MIX_0_REG,(0))
#define OSD_R_MIX_1_READ32()            IO_READ32(OSD_R_MIX_1_REG,(0))
#define GFX_R_MIX_0_READ32()            IO_READ32(GFX_R_MIX_0_REG,(0))
#define GFX_R_MIX_1_READ32()            IO_READ32(GFX_R_MIX_1_REG,(0))
#define OSD_R_MIX_0_WRITE32(value)      IO_WRITE32(OSD_R_MIX_0_REG,(0),(value))
#define OSD_R_MIX_1_WRITE32(value)      IO_WRITE32(OSD_R_MIX_1_REG,(0),(value))
#define GFX_R_MIX_0_WRITE32(value)      IO_WRITE32(GFX_R_MIX_0_REG,(0),(value))
#define GFX_R_MIX_1_WRITE32(value)      IO_WRITE32(GFX_R_MIX_1_REG,(0),(value))
#endif

#if defined(CC_MT5893)
#define OSD_MIX_0_REG (POST_PROC_BASE + 0x984)
#define OSD_MIX_1_REG (POST_PROC_BASE + 0x988)
#define GFX_MIX_0_REG (POST_PROC_BASE + 0xA48)
#define GFX_MIX_1_REG (POST_PROC_BASE + 0xA4C)
#else
#define OSD_MIX_0_REG (IO_POSTPROC_BASE + 0x984)
#define OSD_MIX_1_REG (IO_POSTPROC_BASE + 0x988)
#define GFX_MIX_0_REG (IO_POSTPROC_BASE + 0xA48)
#define GFX_MIX_1_REG (IO_POSTPROC_BASE + 0xA4C)
#endif
#define UHD_MIX_0_REG (IO_VIRT + 0x9984)
#define UHD_MIX_1_REG (IO_VIRT + 0x9988)
#define OSD_MIX_0_READ32()            IO_READ32(OSD_MIX_0_REG,(0))
#define OSD_MIX_1_READ32()            IO_READ32(OSD_MIX_1_REG,(0))
#define GFX_MIX_0_READ32()            IO_READ32(GFX_MIX_0_REG,(0))
#define GFX_MIX_1_READ32()            IO_READ32(GFX_MIX_1_REG,(0))
#define UHD_MIX_0_READ32()            IO_READ32(UHD_MIX_0_REG,(0))
#define UHD_MIX_1_READ32()            IO_READ32(UHD_MIX_1_REG,(0))
#define OSD_MIX_0_WRITE32(value)      IO_WRITE32(OSD_MIX_0_REG,(0),(value))
#define OSD_MIX_1_WRITE32(value)      IO_WRITE32(OSD_MIX_1_REG,(0),(value))
#define GFX_MIX_0_WRITE32(value)      IO_WRITE32(GFX_MIX_0_REG,(0),(value))
#define GFX_MIX_1_WRITE32(value)      IO_WRITE32(GFX_MIX_1_REG,(0),(value))
#define UHD_MIX_0_WRITE32(value)      IO_WRITE32(UHD_MIX_0_REG,(0),(value))
#define UHD_MIX_1_WRITE32(value)      IO_WRITE32(UHD_MIX_1_REG,(0),(value))

static UINT32 u4MixRegBakUp[10] = {0};

VOID OSD_EXP_BakUpMIX(VOID)
{
	u4MixRegBakUp[0] = OSD_MIX_0_READ32();
	u4MixRegBakUp[1] = OSD_MIX_1_READ32();
	u4MixRegBakUp[2] = GFX_MIX_0_READ32();
	u4MixRegBakUp[3] = GFX_MIX_1_READ32();
	u4MixRegBakUp[4] = UHD_MIX_0_READ32();
	u4MixRegBakUp[5] = UHD_MIX_1_READ32();
#if defined(CC_MT5893) || defined(CC_MT5895)
    u4MixRegBakUp[6] = OSD_R_MIX_0_READ32();
    u4MixRegBakUp[7] = OSD_R_MIX_1_READ32();
    u4MixRegBakUp[8] = GFX_R_MIX_0_READ32();
    u4MixRegBakUp[9] = GFX_R_MIX_1_READ32();
#endif
}

VOID OSD_EXP_ReSumeMix(VOID)
{
	OSD_MIX_0_WRITE32(u4MixRegBakUp[0]);
	OSD_MIX_1_WRITE32(u4MixRegBakUp[1]);
	GFX_MIX_0_WRITE32(u4MixRegBakUp[2]);
	GFX_MIX_1_WRITE32(u4MixRegBakUp[3]);
	UHD_MIX_0_WRITE32(u4MixRegBakUp[4]);
	UHD_MIX_1_WRITE32(u4MixRegBakUp[5]);
#if defined(CC_MT5893) || defined(CC_MT5895)
    OSD_R_MIX_0_WRITE32(u4MixRegBakUp[6]);
    OSD_R_MIX_1_WRITE32(u4MixRegBakUp[7]);
    GFX_R_MIX_0_WRITE32(u4MixRegBakUp[8]);
    GFX_R_MIX_1_WRITE32(u4MixRegBakUp[9]);
#endif
}


BOOL OSD_EXP_GetOSDMixPreMJCEn(VOID)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = OSD_MIX_0_READ32();
    return (BOOL)rMix0.rFiled.u4MixOsdPreMJCSel;
}

VOID OSD_EXP_SetOSDMixPreMJCEn(BOOL u4Enable)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = OSD_MIX_0_READ32();
    rMix0.rFiled.u4MixOsdPreMJCSel = u4Enable;
    OSD_MIX_0_WRITE32(rMix0.u4Value);

    OSD_BASE_SetPoclk(u4Enable);
    OSD_Base_SetHStart();
}

VOID OSD_EXP_BypPQPath(VOID)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = OSD_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 1;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 1;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 1;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 1;
    rMix0.rFiled.u4Mix3TopMixBg = 1;

    OSD_MIX_0_WRITE32(rMix0.u4Value);

#if defined(CC_MT5893) || defined(CC_MT5895)
    rMix0.u4Value = OSD_R_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 1;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 1;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 1;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 1;
    rMix0.rFiled.u4Mix3TopMixBg = 1;

    OSD_R_MIX_0_WRITE32(rMix0.u4Value);
#endif
}

VOID OSD_EXP_EnablePQPath(VOID)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = OSD_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 0;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 0;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 0;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 0;
    rMix0.rFiled.u4Mix3TopMixBg = 1;

    OSD_MIX_0_WRITE32(rMix0.u4Value);

#if defined(CC_MT5893) || defined(CC_MT5895)
    rMix0.u4Value = OSD_R_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 0;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 0;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 0;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 0;
    rMix0.rFiled.u4Mix3TopMixBg = 1;

    OSD_R_MIX_0_WRITE32(rMix0.u4Value);
#endif
}

VOID OSD_EXP_BypGFXPath(VOID)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = GFX_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 1;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 1;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 1;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 1;
    rMix0.rFiled.u4Mix3TopMixBg = 1;
    GFX_MIX_0_WRITE32(rMix0.u4Value);

#if defined(CC_MT5893) || defined(CC_MT5895)
    rMix0.u4Value = GFX_R_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 1;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 1;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 1;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 1;
    rMix0.rFiled.u4Mix3TopMixBg = 1;
    GFX_R_MIX_0_WRITE32(rMix0.u4Value);
#endif
}

VOID OSD_EXP_EnableGFXPath(VOID)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = GFX_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 0;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 0;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 0;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 0;
    rMix0.rFiled.u4Mix3TopMixBg = 1;
#if defined(CC_MT5893) || defined(CC_MT5895)
    rMix0.rFiled.u4MixOutClipEn = 1;
#endif
    GFX_MIX_0_WRITE32(rMix0.u4Value);

#if defined(CC_MT5893) || defined(CC_MT5895)
    rMix0.u4Value = GFX_R_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 0;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 0;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 0;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 0;
    rMix0.rFiled.u4Mix3TopMixBg = 1;
    rMix0.rFiled.u4MixOutClipEn = 1;
    GFX_R_MIX_0_WRITE32(rMix0.u4Value);
#endif
}


VOID OSD_EXP_UHD_EnableGFXPathOnly(VOID)
{
    OSD_MIX_0_T rMix0;
    OSD_LOG_D("Call OSD_EXP_UHD_EnableGFXPathOnly enter 0xF0009984[0x%08x]\n",
           UHD_MIX_0_READ32());

    if (OSD_EXP_IS_GFX() == FALSE)
    {
        OSD_LOG_E("%s fail, Timing is not from GFX TG \n", __FUNCTION__);
        return;
    }

    OSD_EXP_EnableGFXPath();
    rMix0.u4Value = UHD_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 1;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 0;
    rMix0.rFiled.u4Mix12TopMixBg = 0;
    rMix0.rFiled.u4Mix2Bypass = 0;
    rMix0.rFiled.u4Mix2TopMixBg = 0;
    rMix0.rFiled.u4Mix3Bypass = 0;
    rMix0.rFiled.u4Mix3TopMixBg = 0;
    UHD_MIX_0_WRITE32(rMix0.u4Value);
    OSD_LOG_D("Call OSD_EXP_UHD_EnableGFXPathOnly leave 0xF0009984[0x%08x]\n",
           UHD_MIX_0_READ32());
}

VOID OSD_EXP_UHD_EnableMergePathOnly(VOID)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = UHD_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 0;
    rMix0.rFiled.u4Mix11TopMixBg = 0;
    rMix0.rFiled.u4Mix12Bypass = 1;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 1;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 1;
    rMix0.rFiled.u4Mix3TopMixBg = 1;
    UHD_MIX_0_WRITE32(rMix0.u4Value);
}

VOID OSD_EXP_BypUHDPath(VOID)
{
    OSD_MIX_0_T rMix0;
    rMix0.u4Value = UHD_MIX_0_READ32();
    rMix0.rFiled.u4Mix11Bypass = 1;
    rMix0.rFiled.u4Mix11TopMixBg = 1;
    rMix0.rFiled.u4Mix12Bypass = 1;
    rMix0.rFiled.u4Mix12TopMixBg = 1;
    rMix0.rFiled.u4Mix2Bypass = 1;
    rMix0.rFiled.u4Mix2TopMixBg = 1;
    rMix0.rFiled.u4Mix3Bypass = 1;
    rMix0.rFiled.u4Mix3TopMixBg = 1;
    UHD_MIX_0_WRITE32(rMix0.u4Value);
}

VOID OSD_EXP_InitOsdPath(VOID)
{
#ifdef CC_SUPPORT_UHD

    if (IS_SUPPORT_UHD_OSD_SEPARATE && OSD_EXP_IS_GFX())
    {
        OSD_EXP_BypPQPath();
        OSD_EXP_EnableGFXPath();
        OSD_EXP_BypUHDPath();
    }
    else if (fgIsSupportUHD() && OSD_EXP_IS_GFX())
    {
        OSD_EXP_BypPQPath();
        OSD_EXP_UHD_EnableGFXPathOnly();
    }
    else if (OSD_EXP_IS_GFX())
    {
        OSD_EXP_BypPQPath();
        OSD_EXP_EnableGFXPath();
        OSD_EXP_BypUHDPath();
    }
    else
    {
        OSD_EXP_EnablePQPath();
        OSD_EXP_BypGFXPath();
        OSD_EXP_BypUHDPath();
    }

#else

#if  defined(CC_S_PLATFORM) && (defined(CC_PHX_CUST) || defined(CC_HK_CUST) || defined(CC_WK_CUST) || defined(CC_CP_CUST))
    if (IS_SUPPORT_VB1_GRAPH_MODE)
#else
    if (OSD_EXP_IS_GFX())
#endif
    {
        OSD_EXP_BypPQPath();
        OSD_EXP_EnableGFXPath();
    }
    else
    {
        OSD_EXP_EnablePQPath();
        OSD_EXP_BypGFXPath();
    }

#endif

    OSD_EXP_BypassApply();
}

#if defined(CC_MT5895)
#define OSD_TIMGEN_SRC_REG     (IO_VIRT_SRE + 0x43350)
#define OSD_TIMGEN_SRC_BIT     14
#define OSD_TIMGEN_SRC_MARKS   0x3
#else
#define OSD_TIMGEN_SRC_REG     (IO_VIRT + 0x25350)
#if defined(CC_MT5882) || defined(MT5863)
#define OSD_TIMGEN_SRC_BIT     11
#define OSD_TIMGEN_SRC_MARKS   0x1
#else
#define OSD_TIMGEN_SRC_BIT     13
#define OSD_TIMGEN_SRC_MARKS   0x3
#endif
#endif

static INT32 OSD_EXP_TimGenVal(VOID)
{
    UINT32 u4Value = IO_READ32(OSD_TIMGEN_SRC_REG, 0);
    u4Value = (u4Value >> OSD_TIMGEN_SRC_BIT);
    return (u4Value & OSD_TIMGEN_SRC_MARKS);
}
BOOL OSD_EXP_IS_GFX_4K2K(VOID)
{
    if (OSD_EXP_TimGenVal() == 0x2 && OSD_BASE_GetDisplayWidth() == 3840 &&
            OSD_BASE_GetDisplayHeight() == 2160)
    {
        return TRUE;
    }

    return FALSE;
}
BOOL OSD_EXP_IS_GFX_FHD(VOID)
{
    if (OSD_EXP_TimGenVal() == 0x2 && OSD_BASE_GetDisplayWidth() == 1920 &&
            OSD_BASE_GetDisplayHeight() == 1080)
    {
        return TRUE;
    }

    return FALSE;
}
BOOL OSD_EXP_IS_GFX(VOID)
{
    if (OSD_EXP_TimGenVal() == 0x2)
    {
        return TRUE;
    }

    return FALSE;
}
static BOOL _fgVerticalSharpnessBypass = FALSE;

BOOL OSD_EXP_IS_vertical_sharpness_bypass(VOID)
{
    return _fgVerticalSharpnessBypass;
}

VOID OSD_EXP_set_vertical_sharpness_bypass(BOOL fgBypass)
{
    _fgVerticalSharpnessBypass = fgBypass;
}

#ifdef CC_MT5891
#define OSD_BYPASS_TTD_SRC_REG     (IO_VIRT + 0x5DC18)
#define OSD_BYPASS_TTD_SRC_BIT    1
#define OSD_BYPASS_TTD_SRC_MARKS   0x1
#else
#define OSD_BYPASS_TTD_SRC_REG     (IO_VIRT + 0x36C18)
#define OSD_BYPASS_TTD_SRC_BIT     1
#define OSD_BYPASS_TTD_SRC_MARKS   0x1
#endif
static INT32 OSD_EXP_BYPASSTTDVal(VOID)
{
    UINT32 u4Value = IO_READ32(OSD_BYPASS_TTD_SRC_REG, 0);
    u4Value = (u4Value >> OSD_BYPASS_TTD_SRC_BIT);
    return (u4Value & OSD_BYPASS_TTD_SRC_MARKS);
}

BOOL OSD_EXP_IS_BYPASSTTD(VOID)
{
    if (OSD_EXP_BYPASSTTDVal() == 0x1)
    {
        return TRUE;
    }

    return FALSE;
}

#ifdef CC_MT5891
#define OSD_TTD_POSITION_SRC_REG     (IO_VIRT + 0x27800)
#define OSD_TTD_POSITION_SRC_BIT    30
#define OSD_TTD_POSITION_SRC_MARKS   0x1

static INT32 OSD_EXP_TTDPOSVal(VOID)
{
    UINT32 u4Value = IO_READ32(OSD_TTD_POSITION_SRC_REG, 0);
    u4Value = (u4Value >> OSD_TTD_POSITION_SRC_BIT);
    return (u4Value & OSD_TTD_POSITION_SRC_MARKS);
}

BOOL OSD_EXP_IS_TTDPosBeforeSRS(VOID)
{
    if (OSD_EXP_TTDPOSVal() == 0x1)
    {
        return TRUE;
    }

    return FALSE;
}

#endif

#if defined(CC_MT5893) || defined(CC_MT5895)
//ostg1:0x27A30[0x27A50] ostg2:0x36A30[0x37A50]
void OSD_EXP_SetIndexEnable(UINT32 enable)
{
    IO_WRITE32MSK(OSD_MIXER_OSTG1, 0, enable << 8, OSD_MIXER_INDEX_ENABLE_MASK);
    IO_WRITE32MSK(OSD_MIXER_OSTG2, 0, enable << 8, OSD_MIXER_INDEX_ENABLE_MASK);
    IO_WRITE32MSK(GFX_MIXER_OSTG1, 0, enable << 8, OSD_MIXER_INDEX_ENABLE_MASK);
    IO_WRITE32MSK(GFX_MIXER_OSTG2, 0, enable << 8, OSD_MIXER_INDEX_ENABLE_MASK);
}

void OSD_EXP_SetIndexThd(UINT8 thdValue)
{
    IO_WRITE32MSK(OSD_MIXER_OSTG1, 0, thdValue, OSD_MIXER_INDEX_THD_MASK);
    IO_WRITE32MSK(OSD_MIXER_OSTG2, 0, thdValue, OSD_MIXER_INDEX_THD_MASK);
    IO_WRITE32MSK(GFX_MIXER_OSTG1, 0, thdValue, OSD_MIXER_INDEX_THD_MASK);
    IO_WRITE32MSK(GFX_MIXER_OSTG2, 0, thdValue, OSD_MIXER_INDEX_THD_MASK);
}

BOOL OSD_EXP_GetIndexEnable(void)
{
    return IO_READ32MSK_BOOL(OSD_MIXER_OSTG1, 0, OSD_MIXER_INDEX_ENABLE_MASK);
}

UINT32 OSD_EXP_GetIndexThd(void)
{
    return IO_READ32MSK(OSD_MIXER_OSTG1, 0, OSD_MIXER_INDEX_THD_MASK);
}

// default get the overall counter[include left & right]
UINT32 OSD_EXP_GetIndexCounter(void)
{
    return (IO_READ32MSK(OSD_MIXER_OSTG1, 0, OSD_MIXER_INDEX_COUNTER_MASK) >> 9) +
           (IO_READ32MSK(OSD_MIXER_OSTG2, 0, OSD_MIXER_INDEX_COUNTER_MASK) >> 9);
}

#endif

static UINT32 u4BypassOsdIndex = 0;

void OSD_EXP_BypassEnable(UINT32 u4Plane, UINT32 u4BypEnable)
{
    switch(u4Plane)
    {
    case OSD_PLANE_1:
    case OSD_PLANE_2:
    case OSD_PLANE_3:
    case OSD_PLANE_5:
#if defined(CC_MT5893) || defined(CC_MT5895)
    case OSD_RT_PLANE_1:
    case OSD_RT_PLANE_2:
    case OSD_RT_PLANE_3:
    case OSD_RT_PLANE_5:
#endif
        if (u4BypEnable) u4BypassOsdIndex |= (1 << u4Plane);
        else u4BypassOsdIndex &= (~(1 << u4Plane));
        break;
    default:
        OSD_LOG_E("invalid plane id:%d\n", u4Plane);
    }

    OSD_LOG_D("bypass index:%d\n", u4BypassOsdIndex);

    OSD_EXP_BypassApply();
}

void OSD_EXP_BypassApply(void)
{
    // mixer bypass index is based on osd plane sw zorder
    // mixer3->cursor plane
    // mixer2->top plane
    // mixer12->middle plane
    // mixer1->bottom plane
    UINT32 u4TopPlane, u4MiddlePlane, u4BottomPlane;
    UINT32 u4MixerReg;
    OSD_MIX_0_T u4MixerValue;
    u4TopPlane = ((OSD_READ32(0x08) >> 26) & 0x3);
    u4BottomPlane = ((OSD_READ32(0x08) >> 28) & 0x3);
    u4MiddlePlane = ((OSD_READ32(0x08) >> 30) & 0x3);

    u4TopPlane = (u4TopPlane == 0) ? OSD_PLANE_MAX_NUM : (u4TopPlane - 1);
    u4MiddlePlane = (u4MiddlePlane == 0) ? OSD_PLANE_MAX_NUM : (u4MiddlePlane - 1);
    u4BottomPlane = (u4BottomPlane == 0) ? OSD_PLANE_MAX_NUM : (u4BottomPlane - 1);

    if (OSD_EXP_IS_GFX())
    {
        u4MixerReg = GFX_MIX_0_REG;
    }
    else
    {
        u4MixerReg = OSD_MIX_0_REG;
    }

    u4MixerValue.u4Value = IO_READ32(u4MixerReg, 0x00);

    if (u4BypassOsdIndex & OSD_PLANE_5)
    {
        u4MixerValue.rFiled.u4Mix3Bypass = 1;
    }
    else
    {
        u4MixerValue.rFiled.u4Mix3Bypass = 0;
    }

    if (u4TopPlane != OSD_PLANE_MAX_NUM)
    {
        if (u4BypassOsdIndex & ( 1 << u4TopPlane))
        {
            u4MixerValue.rFiled.u4Mix2Bypass = 1;
        }
        else
        {
            u4MixerValue.rFiled.u4Mix2Bypass = 0;
        }
    }

    if (u4MiddlePlane != OSD_PLANE_MAX_NUM)
    {
        if (u4BypassOsdIndex & ( 1 << u4MiddlePlane))
        {
            u4MixerValue.rFiled.u4Mix12Bypass = 1;
        }
        else
        {
            u4MixerValue.rFiled.u4Mix12Bypass = 0;
        }
    }

    if (u4BottomPlane != OSD_PLANE_MAX_NUM)
    {
        if (u4BypassOsdIndex & ( 1 << u4BottomPlane))
        {
            u4MixerValue.rFiled.u4Mix11Bypass = 1;
        }
        else
        {
            u4MixerValue.rFiled.u4Mix11Bypass = 0;
        }
    }

    IO_WRITE32(u4MixerReg, 0, u4MixerValue.u4Value);

#if defined(CC_MT5893) || defined(CC_MT5895)
    // if modify left osd plane, then first auto sync to right;
    // if only modify right, then just apply the right
    if (OSD_EXP_IS_GFX())
    {
        u4MixerReg = GFX_R_MIX_0_REG;
    }
    else
    {
        u4MixerReg = OSD_R_MIX_0_REG;
    }

    IO_WRITE32(u4MixerReg, 0, u4MixerValue.u4Value);

    if (u4BypassOsdIndex & OSD_RT_PLANE_5)
    {
        u4MixerValue.rFiled.u4Mix3Bypass = 1;
    }
    else
    {
        u4MixerValue.rFiled.u4Mix3Bypass = 0;
    }

    if (u4TopPlane != OSD_PLANE_MAX_NUM)
    {
        if (u4BypassOsdIndex & ( 1 << (u4TopPlane + OSD_RT_PLANE_1)))
        {
            u4MixerValue.rFiled.u4Mix2Bypass = 1;
        }
        else
        {
            u4MixerValue.rFiled.u4Mix2Bypass = 0;
        }
    }

    if (u4MiddlePlane != OSD_PLANE_MAX_NUM)
    {
        if (u4BypassOsdIndex & ( 1 << (u4MiddlePlane + OSD_RT_PLANE_1)))
        {
            u4MixerValue.rFiled.u4Mix12Bypass = 1;
        }
        else
        {
            u4MixerValue.rFiled.u4Mix12Bypass = 0;
        }
    }

    if (u4BottomPlane != OSD_PLANE_MAX_NUM)
    {
        if (u4BypassOsdIndex & ( 1 << (u4BottomPlane + OSD_RT_PLANE_1)))
        {
            u4MixerValue.rFiled.u4Mix11Bypass = 1;
        }
        else
        {
            u4MixerValue.rFiled.u4Mix11Bypass = 0;
        }
    }

    IO_WRITE32(u4MixerReg, 0, u4MixerValue.u4Value);
#endif
}
