/* 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: dtvbm11 $
 * $Date: 2015/11/10 $
 * $RCSfile: drv_resume.c,v $
 * $Revision: #1 $
 *
 *---------------------------------------------------------------------------*/

/** @file drv_resume.c
 *  This file implements for full driver resume.
 */
#include <linux/kernel.h> 
#include <linux/module.h>
#include <linux/opm_device.h>
#include "x_bim.h"
#include "x_assert.h"
#include "eeprom_if.h"

#include "ostg_if.h"
#include "nptv_if.h"
#include "drv_vdoclk.h"
#include "drv_display.h"
#include "drv_video.h"
#include "osd_drvif.h"

#include "drv_video.h"
#include "drv_display.h"
#include "hw_vdoin.h"
#include "gfx_if.h"



#if defined(CC_FAST_INIT)
extern void PDWNC_Reboot(void);
static int opmcls_reboot;
void opmcls_shutdown(struct opm_device *devptr)
{
	DTVCFG_T rDtvCfg;

	printk("opmcls_shutdown:opmcls_reboot 0x%x\n", opmcls_reboot);
	// if(opmcls_reboot) // force reboot when necessary
	{
		if (EEPDTV_GetCfg(&rDtvCfg))
		{
			printk("[opmcls_shutdown]Get configuration fail...\n");
			ASSERT(0);
			return ;
		}
		rDtvCfg.u1Flags3 |= ((UINT8)DTVCFG_FLAG3_FAST_BOOT);  
		rDtvCfg.u1Flags3 &= ~((UINT8)DTVCFG_FLAG3_NORMAL_BOOT_WITH_SUSPEND);               
		rDtvCfg.u1Flags3 &= ~((UINT8)DTVCFG_FLAG3_NORMAL_BOOT_WITHOUT_SUSPEND);
		if (EEPDTV_SetCfg(&rDtvCfg))
		{
			printk("[opmcls_shutdown]Set boot mode fail...\n");
			ASSERT(0);
			return;
		}
		// PDWNC_Reboot();
	}
	/* never retrun to here */
}

static struct opm_driver opmcls_driver_reboot = {
	.shutdown	= opmcls_shutdown,
	.driver		= {
		.name	= "opm_sysclass"
	},
};

static int __devinit _mt53xx_drvset_probe(struct platform_device *pdev)
{
	printk("_mt53xx_drvset_probe\n");
	return 0;
}

static int __devexit _mt53xx_drvset_remove(struct platform_device *pdev)
{
	printk("_mt53xx_drvset_remove\n");
	return 0;	
}

//BSP
extern void BspMainTask(void);

// RM SWI
extern void rm_swi_resume(void);

//SIF
extern void SIF_pm_suspend(void);
extern void SIF_pm_resume(void);

// GPIO
extern void GPIO_pm_suspend(void);
extern void GPIO_pm_resume(void);

// Tuner
extern void TUNER_pm_suspend(void);
extern void TUNER_pm_resume(void);

// Audio
extern void AUD_pm_suspend(void);
extern void AUD_pm_resume(void);

//OSD
void OSD_pm_suspend(void);
void OSD_pm_resume(void);
//PMX
void PMX_pm_suspend(void);
void PMX_pm_resume(void);
//DMX
extern void DMX_pm_resume(void);

//VDEC
void VDEC_pm_suspend(void);
void VDEC_pm_resume(void);
//B2R
void VDP_pm_suspend(void);
void VDP_pm_resume(void);
// PE
void PE_pm_resume(void);
void PE_pm_resume(void) {} // add for mt5396.compile.fail
//TVD
extern void TVD_pm_suspend(void);
extern void TVD_pm_resume(void);
extern void VBI_pm_suspend(void);
extern void VBI_pm_resume(void);
extern void TVE_pm_suspend(void);
extern void TVE_pm_resume(void);
//CEC
void CEC_pm_suspend(void);
void CEC_pm_resume(void);
//MID
void MID_pm_suspend(void);
void MID_pm_resume(void);
void MID_pm_suspend(void) {} // add for mt5396.compile.fail
void MID_pm_resume(void) {} // add for mt5396.compile.fail
// vdoin
void vDrvVideoHwInit_pm_resume(void);

//#define CC_TOI_DRIVER_V_REINIT // call nptv init functions directly
//#define CC_TOI_DRIVER_V_BASIC // enter susupend immediately after insmod dtv_driver_adpt.ko
//#define CC_TOI_DRIVER_V_ALLDRV_FOR_MT5366 // all driver suspend/resume functions for MT5366
#define CC_TOI_DRIVER_V_ALLDRV_FOR_MT5396 // all driver suspend/resume functions for MT5366

#if defined(CC_TOI_DRIVER_V_REINIT)
static void _mt53xx_modules_pm_suspend(void)
{
    OSD_pm_suspend();
    PMX_pm_suspend();
    BIM_DisableIrq(VECTOR_VDOIN);
    GFX_Lock();
    msleep(2000); //make sure mloop stop, sometimes mloop wait for SIF
}
#elif defined(CC_TOI_DRIVER_V_BASIC)
static void _mt53xx_modules_pm_suspend(void)
{
    OSD_pm_suspend();
    PMX_pm_suspend();
    GFX_Lock();
    msleep(2000); //make sure mloop stop, sometimes mloop wait for SIF
}
#elif defined(CC_TOI_DRIVER_V_ALLDRV_FOR_MT5396)
static void MM_pm_suspend(void)
{
    VDEC_pm_suspend();
    VDP_pm_suspend();
}

static void _mt53xx_modules_pm_suspend(void)
{
    CEC_pm_suspend();
    OSD_pm_suspend();
    PMX_pm_suspend();
    TVD_pm_suspend();
    VBI_pm_suspend();
    TVE_pm_suspend();
    MM_pm_suspend();

    TUNER_pm_suspend();
    AUD_pm_suspend();
    GFX_Lock();
    msleep(2000); //make sure mloop stop, sometimes mloop wait for SIF
}
#elif defined(CC_TOI_DRIVER_V_ALLDRV_FOR_MT5366)
static void MM_pm_suspend(void)
{
    VDEC_pm_suspend();
    VDP_pm_suspend();
}

static void _mt53xx_modules_pm_suspend(void)
{
    MID_pm_suspend();
    CEC_pm_suspend();
    OSD_pm_suspend();
    PMX_pm_suspend();
    TVD_pm_suspend();
    VBI_pm_suspend();
    TVE_pm_suspend();
    MM_pm_suspend();
    GPIO_pm_suspend();
    PDWNC_pm_suspend();    

    TUNER_pm_suspend();
    AUD_pm_suspend();
    GFX_Lock();
    msleep(2000); //make sure mloop stop, sometimes mloop wait for SIF
}
#else
#error "Please define CC_TOI_DRIVER_Vx"
#endif

static int _mt53xx_drvset_suspend(struct platform_device *pdev, pm_message_t state)
{
    printk("_mt53xx_drvset_suspend\n");
    opmcls_reboot=1;

    _mt53xx_modules_pm_suspend();

    return 0;
}

#define DRV_PARALLEL_INIT
#define DRV_TUNER_PARALLEL_INIT

#if defined(DRV_PARALLEL_INIT)
static void _ParallelInitThread2(void *pvArgs)
{
    //SelectPanel(14);
    LoadPanelIndex();
    vApiPanelPowerSequence(TRUE);
}
#endif

#if defined(DRV_TUNER_PARALLEL_INIT)
static void _ParallelInitTunerThread(void *pvArgs)
{
    TUNER_pm_resume();
}
#endif

static void MM_pm_resume(void)
{
    VDEC_pm_resume();
    VDP_pm_resume();
}

#if defined(CC_TOI_DRIVER_V_REINIT)
extern BOOL fgYJInit;
BOOL fgYJInit; // add for mt5396.compile.fail
extern BOOL _fgPanelOn;
BOOL _fgPanelOn; // add for mt5396.compile.fail
extern UINT8 bSI_DISPLAY_DCLK_TYPE;
static void _mt53xx_modules_pm_resume(void)
{
    #if defined(DRV_PARALLEL_INIT)
    HANDLE_T hThread2;
    #endif

    rm_swi_resume(); // no need for tux-on-ice, need for software suspend ?
    //BspMainTask();
    //FBM no need
    //DMX,AUD,MPV
    SIF_pm_resume();
    BIM_EnableIrq(VECTOR_SERIAL);
    //Panel
    fgYJInit=FALSE;
    bSI_DISPLAY_DCLK_TYPE = SV_DCLK_UNKNOW;

    vDrvVideoSwInit();

    vApiHwInit();
    DRVCUST_HwInit();

    vApiVideoInit();
    DRVCUST_VideoInit();
    BIM_EnableIrq(VECTOR_VDOIN);
    BIM_EnableIrq(VECTOR_POST_PROC);

    // turn off panel
    // vApiPanelPowerSequence(FALSE);    
    _fgPanelOn = FALSE;
    // SelectPanel(12);
    vDrvOutputStageInit();
    vDrvVOFreqSet(PANEL_GetPixelClk60Hz());
    vDrvSetLCDTiming();
    OSTG_OnOutputVSync();
    OSD_UpdateTiming();
    #if defined(DRV_PARALLEL_INIT)
    x_thread_create(&hThread2, "DrvPanelPowerOnParallelInit",
	    2048,
	    100,
	    _ParallelInitThread2, 0, NULL);
    #else
    vApiPanelPowerSequence(TRUE);
    #endif

    PMX_pm_resume();
    OSD_pm_resume();

    GFX_HwReset();
    //GFX_CmdQueInit();
    GFX_CmdQueSetup();
    GFX_CmdQueReset();
    BIM_EnableIrq(VECTOR_GFX);
    GFX_Unlock();
}
#elif defined(CC_TOI_DRIVER_V_BASIC)
static void _mt53xx_modules_pm_resume(void)
{
    rm_swi_resume(); // no need for tux-on-ice, need for software suspend ?

    SIF_pm_resume();
    BIM_EnableIrq(VECTOR_SERIAL);

    PMX_pm_resume();
    OSD_pm_resume();

    GFX_HwReset();
    //GFX_CmdQueInit();
    GFX_CmdQueSetup();
    GFX_CmdQueReset();
    BIM_EnableIrq(VECTOR_GFX);
    GFX_Unlock();
}
#elif defined(CC_TOI_DRIVER_V_ALLDRV_FOR_MT5396)
static void _mt53xx_modules_pm_resume(void)
{
    #if defined(DRV_PARALLEL_INIT)
    HANDLE_T hThread2;
    #endif
    #if defined(DRV_TUNER_PARALLEL_INIT)
    HANDLE_T TunerThread;
    #endif

    rm_swi_resume(); // no need for tux-on-ice, need for software suspend ?

    SIF_pm_resume();
    BIM_EnableIrq(VECTOR_SERIAL);

    #if defined(DRV_TUNER_PARALLEL_INIT)
    x_thread_create(&TunerThread, "DrvTunerParallelInit",
	    2048,
	    100,
	    _ParallelInitTunerThread, 0, NULL);
    #else
    TUNER_pm_resume();
    #endif

    DMX_pm_resume();

    vApiHwInit();
    DRVCUST_HwInit();
    vApiVideoInit();
    DRVCUST_VideoInit();
    vDrvCvbsVfePD();
    vDrvAllHDADCPow(SV_FALSE);

    ostg_set_fgPanelOn(FALSE);
    vDrvDisplayInit_pm_resume();

    TVD_pm_resume();
    VBI_pm_resume();
    TVE_pm_resume();

    CEC_pm_resume();
    vHDMI_pm_resume();

    PMX_pm_resume();
    OSD_pm_resume();

    MM_pm_resume();

    AUD_pm_resume();

    #if defined(DRV_PARALLEL_INIT)
    x_thread_create(&hThread2, "DrvPanelPowerOnParallelInit",
	    2048,
	    100,
	    _ParallelInitThread2, 0, NULL);
    #else
    vApiPanelPowerSequence(TRUE);
    #endif

    GFX_HwReset();
    //GFX_CmdQueInit();
    GFX_CmdQueSetup();
    GFX_CmdQueReset();
    BIM_EnableIrq(VECTOR_GFX);
    GFX_Unlock();
}
#elif defined(CC_TOI_DRIVER_V_ALLDRV_FOR_MT5366)
extern void _mt5365_u0_direct_write_byte(unsigned int byte);
void _mt5365_u0_direct_write_byte(unsigned int byte) {} // add for mt5396.compile.fail
#define FASTBOOT_LOGB(c) \
    do {\
	_mt5365_u0_direct_write_byte(c);\
	_mt5365_u0_direct_write_byte(0xA);\
	_mt5365_u0_direct_write_byte(0xD);\
    } while (0)
static void _mt53xx_modules_pm_resume(void)
{
    #if defined(DRV_PARALLEL_INIT)
    HANDLE_T hThread2;
    #endif
    #if defined(DRV_TUNER_PARALLEL_INIT)
    HANDLE_T TunerThread;
    #endif

    rm_swi_resume(); // no need for tux-on-ice, need for software suspend ?
    SIF_pm_resume();
    BIM_EnableIrq(VECTOR_SERIAL);
    GPIO_pm_resume();

    #if defined(DRV_TUNER_PARALLEL_INIT)
    x_thread_create(&TunerThread, "DrvTunerParallelInit",
	    2048,
	    100,
	    _ParallelInitTunerThread, 0, NULL);
    #else
    TUNER_pm_resume();
    #endif

    IRRX_pm_resume();
    BIM_EnableIrq(VECTOR_PDWNC);
    CEC_pm_resume();
    DMX_pm_resume();

    ostg_set_fgPanelOn(FALSE);
    vDrvDisplayInit_pm_resume();

    vDrvVideoHwInit_pm_resume();
    TVD_pm_resume();
    VBI_pm_resume();
    TVE_pm_resume();
    BIM_EnableIrq(VECTOR_VDOIN);
    BIM_EnableIrq(VECTOR_POST_PROC);
    // vApiHwInit();

    vHDMI_pm_resume();

    PMX_pm_resume();
    OSD_pm_resume();
    //DI_pm_resume();
    PE_pm_resume();
    BIM_EnableIrq(VECTOR_PSCAN);

    MM_pm_resume();

    AUD_pm_resume();

    #if defined(DRV_PARALLEL_INIT)
    x_thread_create(&hThread2, "DrvPanelPowerOnParallelInit",
	    2048,
	    100,
	    _ParallelInitThread2, 0, NULL);
    #else
    vApiPanelPowerSequence(TRUE);
    #endif

    GFX_HwReset();
    //GFX_CmdQueInit();
    GFX_CmdQueSetup();
    GFX_CmdQueReset();
    BIM_EnableIrq(VECTOR_GFX);
    GFX_Unlock();
    MID_pm_resume();

    BIM_EnableIrq(VECTOR_MISC);
}
#else
#error "Please define CC_TOI_DRIVER_Vx"
#endif

static int _mt53xx_drvset_resume(struct platform_device *pdev)
{
    opmcls_reboot=0;
    printk("_mt53xx_drvset_resume\n");

    _mt53xx_modules_pm_resume();
    return 0;
}


#include <linux/err.h>

static struct opm_device *device;

static struct opm_driver _mt53xx_drvset_driver = {
	.probe		= _mt53xx_drvset_probe,
	.remove		= _mt53xx_drvset_remove,
	.suspend        = _mt53xx_drvset_suspend,
	.resume         = _mt53xx_drvset_resume,
	.driver		= {
		.name	= "mt53xx_drvset",
		.owner	= THIS_MODULE,
	},
};
static struct opm_device *device;

int  mt53xx_drvset_init(void)
{
	int err;

	if ((err = opm_driver_register(&_mt53xx_drvset_driver)) < 0)
		return err;
	if ((err = opm_driver_register(&opmcls_driver_reboot)) < 0)
		return err;
	device = opm_device_register_simple("mt53xx_drvset",0,ORDER_IGNORE);
	if (IS_ERR(device))
		return -ENODEV;						 
	return 0;
}

#endif
