/* 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/04 $
 * $RCSfile: pmx_hw.c,v $
 * $Revision: #4 $
 *
 *---------------------------------------------------------------------------*/

/** @file pmx_hw.c
 *  Brief of file pmx_hw.c.
 *  Details of file pmx_hw.c (optional).
 */


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

#include "pmx_hw.h"
#include "x_lint.h"
LINT_EXT_HEADER_BEGIN
#include "osd_drvif.h"
#include "pmx_drvif.h"
#include "x_hal_5381.h"
#include "drvcust_if.h"
//#include "vdp_drvif.h"
#include "drv_scaler.h"
#if defined(CC_MTK_LOADER)
#define DEFINE_IS_LOG(level, fmt...) Printf(fmt)
#else /* CC_MTK_LOADER  */
#define DEFINE_IS_LOG PMX_IsLog
#endif /* CC_MTK_LOADER */
#include "hw_ospe.h"
#ifdef CC_FOR_POC_DEMO
//#include "drv_mjc.h"
#endif
#include "x_debug.h"
LINT_EXT_HEADER_END


//-----------------------------------------------------------------------------
// Constant definitions
//-----------------------------------------------------------------------------


// hw id for plane
#define PMX_SRC_PIP 0
#define PMX_SRC_MAIN 1
#define PMX_SRC_OSD1 3
#define PMX_SRC_OSD3 2
#ifdef CC_MT5360
#ifdef CC_MT5360B
#define PMX_SRC_OSD2 3
#else
#define PMX_SRC_OSD2 2
#endif
#else
#define PMX_SRC_OSD2 3
#endif

//#define PMX_SIZE_OF_MIX_CTRL_FIELD 2
#define PMX_SIZE_OF_MIX_CTRL_FIELD 1

#define PMX_UPDATE_PLANE_ORDER 1
#define PMX_UPDATE_BG_COLOR 2

#define PMX_TOP_PLANE_INDEX 3

#if 0
#define PMX_UPDATE_DISPLAY_MODE 8
#endif

//-----------------------------------------------------------------------------
// Type definitions
//-----------------------------------------------------------------------------
/*
typedef struct _PMX_MIX_GRP_FIELD_T
{
    UINT8 fgTopMixBg   :   1;
    UINT8 fgDeOr       :   1;
    UINT8 fgMuteDe     :   1;
    UINT8 fgGrpSel     :   2;
    UINT8 fgBypass     :   1;
    UINT8              :   2;
LINT_SUPPRESS_NEXT_EXPRESSION(950)
} __attribute__ ((packed)) PMX_MIX_GRP_FIELD_T;
*/
// arGroup[0] is bottommost, arGroup[4] is topmost and must be OSD1
/*
typedef struct _PMX_MIX_CTRL_FIELD_T
{
    PMX_MIX_GRP_FIELD_T arGroup[5];

    UINT8 fgMainAlpha;
    UINT8 fgPipAlpha;
    UINT8 fgOutputDelay;
LINT_SUPPRESS_NEXT_EXPRESSION(950)
} __attribute__ ((packed)) PMX_MIX_CTRL_FIELD_T;
*/
typedef struct _PMX_MIX_CTRL_FIELD_T
{
    UINT32        MainTopEn          :   1;	//0: PIP top, 1: main top
    UINT32                      :   7;
UINT32        AlphaMixGrp1_0          :
    1;	//Group1 Top mixed with Bot, 0: bypass Bot, 1: mix output
    UINT32        AlphaMixGrp1_1          :   1;   //Group1 DE output, 0: Bot DE, 1: Top and Bot DE
    UINT32                  :   3;
    UINT32        AlphaMixGrp1_5          :   1;   //Group1 bypass mode
    UINT32                  :   2;
UINT32        AlphaMixGrp2_0          :
    1;	//Group2 Top mixed with Bot, 0: bypass Bot, 1: mix output
    UINT32        AlphaMixGrp2_1          :   1;   //Group2 DE output, 0: Bot DE, 1: Top and Bot DE
    UINT32                  :   3;
    UINT32        AlphaMixGrp2_5          :   1;   //Group2 bypass mode
    UINT32                  :   2;
    UINT32        RGBOP2Sel          :   1;
    UINT32                  :   7;
    LINT_SUPPRESS_NEXT_EXPRESSION(950)
} __attribute__((packed)) PMX_MIX_CTRL_FIELD_T;

typedef union _PMX_MIX_CTRL_UNION_T
{
    UINT32 u4Reg[PMX_SIZE_OF_MIX_CTRL_FIELD];
    PMX_MIX_CTRL_FIELD_T rField;
} PMX_MIX_CTRL_UNION_T;


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

static UINT32 _u4UpdateEvent = 0;
static UINT32 _u4BgColor = 0;
static PMX_MIX_CTRL_UNION_T _rPmxMixCtrlReg;
//static UINT8 _au1PreAllHideState[PMX_PLANE_NUMBER];

static void _PMX_Set_ALPHA_MIX_VIDEO(const UINT32 *pu4Alpha);

#if 0
static UINT32 _u4UpdateDisplayModeState = 0;
static BOOL _fgDisplayModeEnable = FALSE;
#endif

//-----------------------------------------------------------------------------
// Imported functions
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Macro definitions
//-----------------------------------------------------------------------------

#define PLANE_TO_SRC(PLANE, SRC) \
    do \
    { \
        switch (PLANE) \
        { \
        case PMX_MAIN: SRC = PMX_SRC_MAIN; break; \
        case PMX_PIP : SRC = PMX_SRC_PIP; break; \
        case PMX_OSD1: SRC = PMX_SRC_OSD1; break; \
        case PMX_OSD2: SRC = PMX_SRC_OSD2; break; \
        case PMX_OSD3: SRC = PMX_SRC_OSD3; break; \
        default: SRC = PMX_MAX_INPORT_NS; break; \
        } \
    } \
    while (0)

// 3 depends on hardware bit allocation
#define ORDER_TO_GRP_IDX(PLANE_ORDER) \
    (((INT32)(PLANE_ORDER) > (INT32)PMX_TOP_PLANE_INDEX) ? \
    0 : ((INT32)PMX_TOP_PLANE_INDEX - (INT32)(PLANE_ORDER)))


//-----------------------------------------------------------------------------
// Static functions
//-----------------------------------------------------------------------------


UINT32 _PmxRgb2Ybr(UINT32 u4RGB)
{
#ifdef DRV_SUPPORT_EXTMJC
    INT32 s4Y, s4Cb, s4Cr;
    INT32 s4R, s4G, s4B;
    s4R = (u4RGB >> 16) & 0xff;
    s4G = (u4RGB >> 8) & 0xff;
    s4B = u4RGB & 0xff;
    s4Y = (((s4R * 76) + (s4G * 149) + (s4B * 29)) / 255);
    s4Cb = (((128 * 255) + (s4B * 130)) - ((s4R * 43) + (s4G * 86))) / 255;
    s4Cr = (((128 * 255) + (s4R * 130)) - ((s4G * 109) + (s4B * 21))) / 255;

    if (s4Y > 255)
    {
        s4Y = 255;
    }

    if (s4Cb > 255)
    {
        s4Cb = 255;
    }

    if (s4Cr > 255)
    {
        s4Cr = 255;
    }

    if (s4Y < 0)
    {
        s4Y = 0;
    }

    if (s4Cb < 0)
    {
        s4Cb = 0;
    }

    if (s4Cr < 0)
    {
        s4Cr = 0;
    }

    //Printf("\nMute Value:%x",((UINT32)(s4Cb << 16) |(UINT32) (s4Y << 8) |(UINT32) (s4Cr)));
    return ((UINT32)(s4Cb << 16) | (UINT32)(s4Y << 8) | (UINT32)(s4Cr));
#else
    UINT32 u4Y, u4Cb, u4Cr;
    UINT32 u4R, u4G, u4B;
    u4R = (u4RGB >> 16) & 0xff;
    u4G = (u4RGB >> 8) & 0xff;
    u4B = u4RGB & 0xff;
    u4Y = ((((u4R * 76) + (u4G * 149) + (u4B * 29)) / 255)) & 0xFF;
    u4Cb = ((((128 * 255) + (u4B * 130)) - ((u4R * 43) + (u4G * 86))) / 255) & 0xFF;
    u4Cr = ((((128 * 255) + (u4R * 130)) - ((u4G * 109) + (u4B * 21))) / 255) & 0xFF;
    return ((u4Cb << 16) | (u4Y << 8) | (u4Cr));
#endif
}


static void _PmxWriteHwRegister(void)
{
#if defined(CC_MT5368)||defined(CC_MT5396)||defined(CC_MT5389)
    vRegWriteFldAlign(OSTG_01, _rPmxMixCtrlReg.rField.MainTopEn, REG_MAIN_TOP_EN);
#else
    IO_WRITE32MSK(POST_PROC_BASE, REG_OS_ALPHA_MIX1, _rPmxMixCtrlReg.u4Reg[0], 0xFFFFFF);
#endif
}

#ifdef CC_SUPPORT_STR
static UINT32 pmx_pm_save_os_mix;
void PMX_pm_suspend(void)
{
#if defined(CC_MT5368)||defined(CC_MT5396)
    pmx_pm_save_os_mix = RegReadFldAlign(OSTG_01, REG_MAIN_TOP_EN);
#else
    pmx_pm_save_os_mix = IO_READ32(POST_PROC_BASE, REG_OS_ALPHA_MIX1);
#endif
}
void PMX_pm_resume(void)
{
#if defined(CC_MT5368)||defined(CC_MT5396)
    vRegWriteFldAlign(OSTG_01, pmx_pm_save_os_mix, REG_MAIN_TOP_EN);
#else
    IO_WRITE32(POST_PROC_BASE, REG_OS_ALPHA_MIX1, pmx_pm_save_os_mix);
#endif
    PMX_Set_ALPHA_MIX_GRP1_0(SV_TRUE);
    //instead call _PmxWriteHwRegister() api
    // prevent  _PMX_Init not called, just use HW default value
}
#endif
//-----------------------------------------------------------------------------
// Inter-file functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_Init(void)
{
    // reset alpha mix control
    _rPmxMixCtrlReg.u4Reg[0] = 0;
    // _rPmxMixCtrlReg.u4Reg[1] = 0;
#if 0
    _rPmxMixCtrlReg.rField.arGroup[0].fgGrpSel = PMX_SRC_PIP;
    _rPmxMixCtrlReg.rField.arGroup[0].fgTopMixBg = 1;
    _rPmxMixCtrlReg.rField.arGroup[1].fgGrpSel = PMX_SRC_MAIN;
    _rPmxMixCtrlReg.rField.arGroup[1].fgTopMixBg = 1;
#ifdef CC_MT5360
    _rPmxMixCtrlReg.rField.arGroup[2].fgGrpSel = PMX_SRC_OSD2;
    _rPmxMixCtrlReg.rField.arGroup[2].fgTopMixBg = 1;
    _rPmxMixCtrlReg.rField.arGroup[3].fgGrpSel = PMX_SRC_OSD1;
    _rPmxMixCtrlReg.rField.arGroup[3].fgTopMixBg = 1;
#else
    _rPmxMixCtrlReg.rField.arGroup[2].fgGrpSel = PMX_SRC_OSD3;
    _rPmxMixCtrlReg.rField.arGroup[2].fgTopMixBg = 1;
    _rPmxMixCtrlReg.rField.arGroup[3].fgGrpSel = PMX_SRC_OSD2;
    _rPmxMixCtrlReg.rField.arGroup[3].fgTopMixBg = 1;
#endif
    // don't care field
    //_rPmxMixCtrlReg.rField.arGroup[4].fgGrpSel = PMX_SRC_OSD2;
    //_rPmxMixCtrlReg.rField.arGroup[4].fgTopMixBg = 1;
    _rPmxMixCtrlReg.rField.fgMainAlpha = 0xff;
    _rPmxMixCtrlReg.rField.fgPipAlpha = 0xff;
#endif
    _rPmxMixCtrlReg.rField.MainTopEn = 0;
    _rPmxMixCtrlReg.rField.AlphaMixGrp1_0 = 1;
    _rPmxMixCtrlReg.rField.AlphaMixGrp1_1 = 0;
    _rPmxMixCtrlReg.rField.AlphaMixGrp1_5 = 0;
    _rPmxMixCtrlReg.rField.AlphaMixGrp2_0 = 1;
    _rPmxMixCtrlReg.rField.AlphaMixGrp2_1 = 0;
    _rPmxMixCtrlReg.rField.AlphaMixGrp2_5 = 0;
    _PmxWriteHwRegister();
#if !defined(CC_MTK_LOADER)

    if (!DRVCUST_GetDrvInit())
#endif /* CC_MTK_LOADER */
    {
    }
}


//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_SetPlaneOrder(UCHAR ucPlaneId, UCHAR ucPlaneOrder)
{
    UNUSED(ucPlaneId);
    UNUSED(ucPlaneOrder);
#if 0
    UINT32 u4Src = 0;
    UINT32 u4GroupIdx = ORDER_TO_GRP_IDX(ucPlaneOrder);
    PLANE_TO_SRC(ucPlaneId, u4Src);

    if (ucPlaneOrder < PMX_PLANE_NUMBER)
    {
        _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgGrpSel
            = u4Src;
        _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass = FALSE;
        _au1PreAllHideState[u4GroupIdx] = _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass;
    }

    _PmxWriteHwRegister();
#endif
}


//-----------------------------------------------------------------------------
/** Brief
 *  @param pu4PlaneOrder: contains component ID
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_SetPlaneOrderArray(const UINT32 *pu4PlaneOrder)
{
    UINT8 i;

    //set order of main, pip
    _rPmxMixCtrlReg.rField.MainTopEn = 1;

    for (i = 0; i < PMX_PLANE_NUMBER; i++)
    {
        if (pu4PlaneOrder[i] == PMX_PIP)
        {
            for (i += 1; i < PMX_PLANE_NUMBER; i++)  // keep searching to find out if PIP is on top of main
            {
                if (pu4PlaneOrder[i] == PMX_MAIN)
                {
                    _rPmxMixCtrlReg.rField.MainTopEn = 0;
                    break;
                }
            }

            //_rPmxMixCtrlReg.rField.MainTopEn=0;
            break;
        }
    }

    _PmxWriteHwRegister();
    //remove the part of changing OSD plane order which should only be initialized once in loader and framebuffer. 
}


//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_SetAlpha(UCHAR ucPlaneId, UCHAR ucValue)
{
#if 0

    if (ucPlaneId == PMX_MAIN)   // main
    {
        _rPmxMixCtrlReg.rField.fgMainAlpha = ucValue;
    }
    else if (ucPlaneId == PMX_PIP)   // pip
    {
        _rPmxMixCtrlReg.rField.fgPipAlpha = ucValue;
    }
    else
    {
        return;
    }

    _PmxWriteHwRegister();
#endif
}

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_Set_ALPHA_MIX_GRP1_0(BOOL fgEnable)
{
#if defined(CC_MT5368) ||defined(CC_MT5396)||defined(CC_MT5389)||defined(CC_MT5398)||defined(CC_MT5880)||defined(CC_MT5881)||defined(CC_MT5399) || defined(CC_MT5890) || defined(CC_MT5882) || defined(CC_MT5883) || defined(CC_MT5891)

    if (fgEnable)
    {
        vRegWriteFldAlign(OSD_MIX_0, 1, ALPHA_MIX_GRP1_0);
    }
    else
    {
        vRegWriteFldAlign(OSD_MIX_0, 0, ALPHA_MIX_GRP1_0);
    }

#endif
    return ;
}

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_Set_ALPHA_MIX_GRP12_0(BOOL fgEnable)
{
#if defined(CC_MT5368) ||defined(CC_MT5396)||defined(CC_MT5389)||defined(CC_MT5398)||defined(CC_MT5880)||defined(CC_MT5881)||defined(CC_MT5399)|| defined(CC_MT5890) || defined(CC_MT5882) || defined(CC_MT5883) || defined(CC_MT5891)

    if (fgEnable)
    {
        vRegWriteFldAlign(OSD_MIX_0, 1, ALPHA_MIX_GRP12_0);
    }
    else
    {
        vRegWriteFldAlign(OSD_MIX_0, 0, ALPHA_MIX_GRP12_0);
    }

#endif
    return ;
}


//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
static void _PMX_Set_ALPHA_MIX_VIDEO(const UINT32 *pu4Alpha)
{
    vRegWriteFldAlign(OSD_MIX_1, (UCHAR)pu4Alpha[OSD_MIX_AL_11], REG_MIX11_BOT_ALPHA);
#if defined(CC_MT5396)
    vRegWriteFldAlign(OSD_MIX_1, (UCHAR)pu4Alpha[OSD_MIX_AL_12], REG_MIX12_BOT_ALPHA);
#endif
    vRegWriteFldAlign(OSD_MIX_1, (UCHAR)pu4Alpha[OSD_MIX_AL_2], REG_MIX2_BOT_ALPHA);
    return;
}

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_Set_ALPHA_MIX_VIDEO_BOT(const UINT32 *pu4Alpha)
{
    vRegWriteFldAlign(OSD_MIX_1, 0, REG_MIX11_SEL_BOT_ALPHA);
#if defined(CC_MT5396)
    vRegWriteFldAlign(OSD_MIX_1, 0, REG_MIX12_SEL_BOT_ALPHA);
#endif
    vRegWriteFldAlign(OSD_MIX_1, 0, REG_MIX2_SEL_BOT_ALPHA);
    _PMX_Set_ALPHA_MIX_VIDEO(pu4Alpha);
    return ;
}

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_Set_ALPHA_MIX_VIDEO_1_OSD_BELOW(const UINT32 *pu4Alpha)
{
    _PMX_Set_ALPHA_MIX_VIDEO(pu4Alpha);
    vRegWriteFldAlign(OSD_MIX_1, 1, REG_MIX11_SEL_BOT_ALPHA);
#if defined(CC_MT5396)
    vRegWriteFldAlign(OSD_MIX_1, 0, REG_MIX12_SEL_BOT_ALPHA);
#endif
    vRegWriteFldAlign(OSD_MIX_1, 0, REG_MIX2_SEL_BOT_ALPHA);
    return ;
}

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_Set_ALPHA_MIX_VIDEO_2_OSD_BELOW(const UINT32 *pu4Alpha)
{
    _PMX_Set_ALPHA_MIX_VIDEO(pu4Alpha);
    vRegWriteFldAlign(OSD_MIX_1, 1, REG_MIX11_SEL_BOT_ALPHA);
#if defined(CC_MT5396)
    vRegWriteFldAlign(OSD_MIX_1, 1, REG_MIX12_SEL_BOT_ALPHA);
#endif
    vRegWriteFldAlign(OSD_MIX_1, 0, REG_MIX2_SEL_BOT_ALPHA);
    return ;
}

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_Set_ALPHA_MIX_VIDEO_TOP(const UINT32 *pu4Alpha)
{
    _PMX_Set_ALPHA_MIX_VIDEO(pu4Alpha);
    vRegWriteFldAlign(OSD_MIX_1, 1, REG_MIX11_SEL_BOT_ALPHA);
#if defined(CC_MT5396)
    vRegWriteFldAlign(OSD_MIX_1, 1, REG_MIX12_SEL_BOT_ALPHA);
#endif
    vRegWriteFldAlign(OSD_MIX_1, 1, REG_MIX2_SEL_BOT_ALPHA);
    return ;
}


//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
#ifdef CC_MAPLE_CUST_DRV
#ifndef CC_MTK_LOADER
BOOL IsPQICExists(void);
#endif
#endif

void _PMX_SetBgColor(UINT32 u4Value, BOOL fgYuvMode, BOOL fgInVsync)
{
#ifdef CC_MAPLE_CUST_DRV
#ifndef CC_MTK_LOADER
    if (((fgYuvMode)|| IS_DISP_4K2K_FORMAT_YUV444)&&(!IsPQICExists()))
#else
    if(fgYuvMode)
#endif
#else
    if (fgYuvMode)
#endif
    {
        _u4BgColor = _PmxRgb2Ybr(u4Value);
    }
    else
    {
        UINT32 r, g, b;
        r = (u4Value & 0xff0000) >> 16;
        g = (u4Value & 0xff00) >> 8;
        b = (u4Value & 0xff);
        _u4BgColor = ((b << 16) | (g << 8) | r);
    }

#if !defined(CC_MTK_LOADER)

    if (fgInVsync)
    {
        _u4UpdateEvent |= PMX_UPDATE_BG_COLOR;
    }
    else
#endif
    {
#if defined(CC_MT5368)||defined(CC_MT5396)||defined(CC_MT5398)||defined(CC_MT5880)||defined(CC_MT5881)||defined(CC_MT5399)||defined(CC_MT5890) || defined(CC_MT5882) || defined(CC_MT5883) || defined(CC_MT5891) || defined(CC_MT5893) || defined(CC_MT5895)
#ifdef CC_SUPPORT_UHD
        vRegWriteFldAlign(MUTE_00_PQPATH, _u4BgColor, BGR_BACKGROUND);
        vRegWriteFldAlign(MUTE_04_PQPATH, _u4BgColor, BGR_BACKGROUND_MJC);
#else
        vOSTG_IO32WriteFldAlign(MUTE_00, _u4BgColor, BGR_BACKGROUND);
        vOSTG_IO32WriteFldAlign(MUTE_04, _u4BgColor, BGR_BACKGROUND_MJC);
#endif
#else
        IO_WRITE32MSK(POST_PROC_BASE, REG_OS_BGCOLOR, _u4BgColor, REG_OS_BGCOLOR_MSK);
#endif
    }
}

#ifdef CC_FOR_POC_DEMO
//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
void _PMX_SetBlkColor(UINT32 u4BlkColor)
{
    // Mute color is changed to 12 bits, convert 8-bit into 12 bits as "00xxxxxxxx00"
    UINT16 u2R, u2G, u2B;
    u2R = ((u4BlkColor >> 16) & 0xFF) << 2;
    u2G = ((u4BlkColor >> 8) & 0xFF) << 2;
    u2B = ((u4BlkColor & 0xFF)) << 2;
    vIO32WriteFldAlign(MUTE_02, u2R, R_MUTE_MAIN);
    vIO32WriteFldAlign(MUTE_01, u2G, G_MUTE_MAIN);
    vIO32WriteFldAlign(MUTE_01, u2B, B_MUTE_MAIN);
#if defined(CC_MT5399) || defined(CC_MT5890) || defined(CC_MT5891)
    vIO32WriteFldAlign(MUTE_06, u2R, R_MUTE_MAIN_MJC);
    vIO32WriteFldAlign(MUTE_05, u2G, G_MUTE_MAIN_MJC);
    vIO32WriteFldAlign(MUTE_05, u2B, B_MUTE_MAIN_MJC);
#endif
#if SUPPORT_POP
    vIO32WriteFldAlign(MUTE_03, u2R, R_MUTE_PIP);
    vIO32WriteFldAlign(MUTE_03, u2G, G_MUTE_PIP);
    vIO32WriteFldAlign(MUTE_02, u2B, B_MUTE_PIP);
#endif
#if defined(CC_MT5399) || defined(CC_MT5890) || defined(CC_MT5891)
#ifndef CC_MT5893
    vDrvMJCSetMuteColor((UINT8)((u4BlkColor >> 16) & 0xFF),
                          (UINT8)((u4BlkColor >> 8) & 0xFF), (UINT8)((u4BlkColor & 0xFF)));
#endif             
    vIO32WriteFldAlign(MUTE_06, u2R , R_MUTE_MAIN_MJC);
    vIO32WriteFldAlign(MUTE_05, u2R , G_MUTE_MAIN_MJC);
    vIO32WriteFldAlign(MUTE_05, u2R , B_MUTE_MAIN_MJC);
#endif
}
#endif

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

void PMX_OnOutputVSync(void)
{
    static UINT32 i4VsyncDelay = PMX_UPDATE_DELAY;

    if (_u4UpdateEvent & PMX_UPDATE_PLANE_ORDER)
    {
        if (i4VsyncDelay == 0)
        {
            _PmxWriteHwRegister();
            _u4UpdateEvent &= ~PMX_UPDATE_PLANE_ORDER;
            i4VsyncDelay = PMX_UPDATE_DELAY;
        }
    }

    if (_u4UpdateEvent & PMX_UPDATE_BG_COLOR)
    {
#if defined(CC_MT5368)||defined(CC_MT5396)||defined(CC_MT5398)||defined(CC_MT5880)||defined(CC_MT5881)||defined(CC_MT5399)||defined(CC_MT5890) || defined(CC_MT5882) || defined(CC_MT5883) || defined(CC_MT5891) || defined(CC_MT5893) || defined(CC_MT5895)
#ifdef CC_SUPPORT_UHD
        vRegWriteFldAlign(MUTE_00_PQPATH, _u4BgColor, BGR_BACKGROUND);
        vRegWriteFldAlign(MUTE_04_PQPATH, _u4BgColor, BGR_BACKGROUND_MJC);
#else
        vOSTG_IO32WriteFldAlign(MUTE_00, _u4BgColor, BGR_BACKGROUND);
        vOSTG_IO32WriteFldAlign(MUTE_04, _u4BgColor, BGR_BACKGROUND_MJC);
#endif
#else
        IO_WRITE32MSK(POST_PROC_BASE, REG_OS_BGCOLOR, _u4BgColor, REG_OS_BGCOLOR_MSK);
#endif
        _u4UpdateEvent &= ~PMX_UPDATE_BG_COLOR;
    }
}

void PMX_ShowPattern(BOOL fgEnable)
{
    if (fgEnable)
    {
        IO_WRITE32MSK(POST_PROC_BASE, REG_OS_PATTERN, REG_OS_PATTERN_MSK, REG_OS_PATTERN_MSK);
    }
    else
    {
        IO_WRITE32MSK(POST_PROC_BASE, REG_OS_PATTERN, 0, REG_OS_PATTERN_MSK);
    }
}

void PMX_SetFastBlank(BOOL fgEnable)
{
    if (fgEnable)
    {
        IO_WRITE32MSK(POST_PROC_BASE, REG_OS_PATTERN, REG_OS_FASTBLANK_MSK, REG_OS_FASTBLANK_MSK);
    }
    else
    {
        IO_WRITE32MSK(POST_PROC_BASE, REG_OS_PATTERN, 0, REG_OS_FASTBLANK_MSK);
    }
}

void PMX_SetPlaneHide(UCHAR ucPlaneId, BOOL fgHide)
{
#if 0
    UINT32 u4Src;
    UINT32 u4GroupIdx;
    PLANE_TO_SRC(ucPlaneId, u4Src);

    if (u4Src < PMX_PLANE_NUMBER)
    {
        for (u4GroupIdx = 0; u4GroupIdx < PMX_PLANE_NUMBER; u4GroupIdx++)
        {
            if (_rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgGrpSel == u4Src)
            {
                if (fgHide)
                {
                    _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass = TRUE;
                }
                else
                {
                    _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass = FALSE;
                }

                _PmxWriteHwRegister();
                break;
            }
        }
    }

#endif
}

void PMX_GetPlaneHide(UCHAR ucPlaneId, BOOL *pHide)
{
#if 0
    UINT32 u4Src;
    UINT32 u4GroupIdx;
    PLANE_TO_SRC(ucPlaneId, u4Src);

    if (u4Src < PMX_PLANE_NUMBER)
    {
        for (u4GroupIdx = 0; u4GroupIdx < PMX_PLANE_NUMBER; u4GroupIdx++)
        {
            if (_rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgGrpSel == u4Src)
            {
                *pHide = _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass;
                break;
            }
        }
    }

#endif
}

void PMX_SetAllPlaneHide(BOOL fgHide)
{
#if 0
    UINT32 u4GroupIdx;

    if (fgHide)  //Hide all planes
    {
        for (u4GroupIdx = 0; u4GroupIdx < PMX_PLANE_NUMBER; u4GroupIdx++)
        {
            _au1PreAllHideState[u4GroupIdx] = _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass;
            _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass = TRUE;
        }

        _PmxWriteHwRegister();
    }
    else //Unhide all planes that were originally unhidden
    {
        for (u4GroupIdx = 0; u4GroupIdx < PMX_PLANE_NUMBER; u4GroupIdx++)
        {
            _rPmxMixCtrlReg.rField.arGroup[u4GroupIdx].fgBypass = _au1PreAllHideState[u4GroupIdx];
        }

        _PmxWriteHwRegister();
    }

#endif
}

