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


/**
 * @file HDMI customization file:
 *
 * @author josh.pan@mediatek.com
 */
#include "x_gpio.h"
#include "x_printf.h"

#include "hw_vdoin.h"
#include "hw_pdwnc.h"
#include "drv_mhl.h"
#include "drv_hdmi2.h"
#include "drv_hdmi2_if.h"
#include "drv_hdmi2com.h"
#include "drv_video.h"
#include "drv_adcset.h"
#include "cec_if.h"
#include "sv_const.h"
#include "source_table.h"
#ifdef CC_HDMI_EARC_SUPPORT
#include "hdmi_earc_if.h"
#endif
#include "pe_if.h"
#include "drv_earc.h"

#define HDMI_GPIO_HPD0 (250)
#define HDMI_GPIO_HPD1 (255)
#define HDMI_GPIO_HPD2 (239)
#define HDMI_GPIO_HPD3 (243)

#define HDMI_GPIO_PWR0 (249)
#define HDMI_GPIO_PWR1 (252)
#define HDMI_GPIO_PWR2 (240)
#define HDMI_GPIO_PWR3 (251)

/* FY20 new spec : add for HDMI input detect when device is turn off  */
#define HDMI_GPIO_IN_DET0          (ADIN(3))
#define HDMI_GPIO_IN_DET1          (ADIN(4))
#define HDMI_GPIO_IN_DET2          (ADIN(5))
#define HDMI_GPIO_IN_DET3          (ADIN(6))

extern E_HDMI_SWITCH_NUM eActiveHdmiPort[2];

static UINT8 _u1HdmiPort5vStatus[HDMI_SWITCH_MAX];
//====================//
void vHDMIHPDHigh(E_HDMI_SWITCH_NUM eSwitch)
{
    printf("[HDMI]HPD P[%d] set High\n",eSwitch);
    vHDMI2SetHpdPulse(eSwitch, 1);
#ifdef CC_HDMI_EARC_SUPPORT
    //if(eSwitch == GeteARCPortInfo())
    {
        vHDMIEARCSetHPD(eSwitch, 1);
    }
#endif
    switch(eSwitch)
    {
#ifdef HDMI_GPIO_HPD0
        case HDMI_SWITCH_1:
            if(!fgMHL3GetMhlCableStatus())
            {
                GPIO_SetOut(HDMI_GPIO_HPD0, 0);
            }
            break;
#endif
#ifdef HDMI_GPIO_HPD1
        case HDMI_SWITCH_2:
            GPIO_SetOut(HDMI_GPIO_HPD1, 0);
            break;
#endif
#ifdef HDMI_GPIO_HPD2
        case HDMI_SWITCH_3:
            GPIO_SetOut(HDMI_GPIO_HPD2, 0);
            break;
#endif
#ifdef HDMI_GPIO_HPD3
        case HDMI_SWITCH_4:
           GPIO_SetOut(HDMI_GPIO_HPD3, 0);
            break;
#endif
        default: /* disable all */
            break;
    }
}

//====================//
void vHDMIHPDLow(E_HDMI_SWITCH_NUM eSwitch)
{
    printf("[HDMI]HPD P[%d] set Low\n",eSwitch);
    vHDMI2SetHpdPulse(eSwitch, 0);
#ifdef CC_HDMI_EARC_SUPPORT
    //if(eSwitch == GeteARCPortInfo())
    {
        vHDMIEARCSetHPD(eSwitch, 0);
    }
#endif
    switch(eSwitch)
    {
#ifdef HDMI_GPIO_HPD0
        case HDMI_SWITCH_1:
            if(!fgMHL3GetMhlCableStatus())
            {
                GPIO_SetOut(HDMI_GPIO_HPD0, 1);
            }
            break;
#endif
#ifdef HDMI_GPIO_HPD1
        case HDMI_SWITCH_2:
            GPIO_SetOut(HDMI_GPIO_HPD1, 1);
            break;
#endif
#ifdef HDMI_GPIO_HPD2
        case HDMI_SWITCH_3:
            GPIO_SetOut(HDMI_GPIO_HPD2, 1);
            break;
#endif
#ifdef HDMI_GPIO_HPD3
        case HDMI_SWITCH_4:
            GPIO_SetOut(HDMI_GPIO_HPD3, 1);
            break;
#endif
        default: /* disable all */
            break;
    }
}

//====================//
UINT8 bHDMIPort5VStatus(E_HDMI_SWITCH_NUM ePort)
{
    UINT32 input = 0;

    if (u1HDMI2IsHpdPulse(ePort) == 1)
    {
        // hpd pulse period
        return (input);
    }

    switch(ePort)
    {
#ifdef HDMI_GPIO_PWR0
        case HDMI_SWITCH_1:
            if(fgMHL3GetMhlCableStatus())
            {
                input = 1;
            }
            else
            {
                input = GPIO_GetIn(HDMI_GPIO_PWR0);
            }
            break;
#endif
#ifdef HDMI_GPIO_PWR1
        case HDMI_SWITCH_2:
            input = GPIO_GetIn(HDMI_GPIO_PWR1);
            break;
#endif
#ifdef HDMI_GPIO_PWR2
        case HDMI_SWITCH_3:
            input = GPIO_GetIn(HDMI_GPIO_PWR2);
            break;
#endif
#ifdef HDMI_GPIO_PWR3
        case HDMI_SWITCH_4:
            input = GPIO_GetIn(HDMI_GPIO_PWR3);
            break;
#endif
        default:
            break;
    }

    return input;
}

//====================//
void vHDMISwitchInit(void)
{
}

//====================//
void vHDMISetSwitch(E_HDMI_SWITCH_NUM eSwitch,UINT8 u1Type)
{
    E_HDMI_SWITCH_NUM eHdmiRx;
    UINT8 u1PwOnInit = 0;

    // port mapping here
    eHdmiRx = eHDMIGetPhysicalPortId(eSwitch);

    if (eActiveHdmiPort[u1Type] == HDMI_SWITCH_INIT)
    {
        u1PwOnInit = 1;
    }

    if ((eHDMICurrSwitch != eHdmiRx) || (eActiveHdmiPort[u1Type] != eHdmiRx))
    {
        eHDMICurrSwitch = eHdmiRx;
        eActiveHdmiPort[u1Type] = eHdmiRx;

        DRVCUST_SendEvent(E_CUST_SOURCE_CHANGE, 0);

        vHDMI2PortSel(eActiveHdmiPort[u1Type],u1Type);
        vHDMI2PllSel(eActiveHdmiPort[u1Type],u1Type);

        if(u1IsHDMI2Stable(eHdmiRx) && !(fgHDMI21GetFRLMode(eHdmiRx)))
        {
            vHDMI2SetStateMachine(eHdmiRx,HDMI_WAIT_STABLE_STATE);
        }

        if(u1IsHDMI2Stable(eHdmiRx) == TRUE)
            vHDMI2ComDolbyEdrEn(1);
    }
}

void vHDMISetARCSwitch(UINT8 u1Port)
{
    return;
}

UINT8 u1HDMIGetPhysicalPortConnected(E_HDMI_SWITCH_NUM ePort)
{
    E_HDMI_SWITCH_NUM eHdmiVirtualPort = eHDMIGetVirtualPortId(ePort);

    return _u1HdmiPort5vStatus[eHdmiVirtualPort];
}

void vHDMIMonitorConnectedDevices(void)
{
    E_HDMI_SWITCH_NUM eHDMISwitch = HDMI_SWITCH_1;

    for(eHDMISwitch = HDMI_SWITCH_1; eHDMISwitch <= HDMI_SWITCH_4; eHDMISwitch++)
    {
        _u1HdmiPort5vStatus[eHDMISwitch] = bHDMIPort5VStatus(eHDMISwitch);
        #ifdef CECNFY5VSTATUS
        _Cec_Notify5VStatus((UINT8)eHDMISwitch,_u1HdmiPort5vStatus[eHDMISwitch]);
        #endif
    }
}

