//
// Copyright  2009 Samsung Electronics Co; Ltd. All Rights Reserved.
//
//
//
//
// Copyright (c) Samsung Electronics. Co. LTD.  All rights reserved.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:    tvout_power.c

Abstract:       Implementation of tvout power Library
                This module implements Low Level HW control

Functions:


Notes:


--*/

#include <windows.h>
#include <bsp_cfg.h>    // for reference HCLK, ECLK
#include <register_map.h>
#include "tvout_global.h"
#include <pmplatform.h>
#include "tvout_message.h"
#include "tvout_power.h"
#include "tvout_power_internal.h"

#ifdef SUPPORT_APM_TVD

// 1. Message Queue Declaration

HANDLE PWC_msgQ = NULL;
MSG_DEV_STATE   txmqParam;    // MSG_DEV_STATE is defined in bsp_args.h
MSGQUEUEOPTIONS msgOptions;

#endif


/*============================================================================*/
// Pre-defined functions
/*============================================================================*/


void Tvout_power_print()
{

	DBGMSG(TV_INFO,(_T("[TVPWR_PRT]  g_pPmuMisc->IP_CON_REG.DAC_CONTROL = [0x%08x]\n\r"),
				g_pPmuMisc->IP_CON_REG.DAC_CONTROL));
	DBGMSG(TV_INFO,(_T("[TVPWR_PRT]  g_pPmuPm->PWR_CONF.NORMAL_CFG = [0x%08x]\n\r"),
				g_pPmuPm->PWR_CONF.NORMAL_CFG));
	DBGMSG(TV_INFO,(_T("[TVPWR_PRT]  g_pPmuPm->STATUS_REG.BLK_PWR_STAT = [0x%08x]\n\r"),
				g_pPmuPm->STATUS_REG.BLK_PWR_STAT));

	DBGMSG(TV_INFO,(_T("[TVPWR_PRT]  g_pPmuMisc->IP_CON_REG.HDMI_CONTROL = [0x%08x]\n\r"),
				g_pPmuMisc->IP_CON_REG.HDMI_CONTROL));

	return;
}


// initialization
//  - iniization functions are only called under stopping tvout power
TVOUT_POWER_ERROR 
Tvout_power_initialize_register_address
(void *pPmuPmCon, void *pPmuMiscCon)
{
	DBGMSG(TV_FUNC,(_T("[TVPWR]++Tvout_power_initialize_register_address(0x%08x, 0x%08x)\n\r"), pPmuPmCon, pPmuMiscCon));

	if (pPmuPmCon == NULL)
	{
		DBGMSG(TV_USR1,(_T("[TVPWR:ERR] Tvout_power_initialize_register_address() : NULL pointer parameter\n\r")));
		return TVOUT_POWER_ERROR_INVALID_PARAM;
	}
	else if (pPmuMiscCon == NULL)
	{
		DBGMSG(TV_USR1,(_T("[TVPWR:ERR] Tvout_power_initialize_register_address() : NULL pointer parameter\n\r")));
		return TVOUT_POWER_ERROR_INVALID_PARAM;
	}
	else
	{
		g_pPmuPm = (PPMU_PM_REG)pPmuPmCon;
		g_pPmuMisc= (PPMU_MISC_REG)pPmuMiscCon;

#ifdef USE_POWERCON_FUNCTION
		g_hPowerCon = CreateFile( L"PWC0:", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);

		if (g_hPowerCon == INVALID_HANDLE_VALUE)
		{
			DBGMSG(TV_USR1,(_T("[DISPDRV:ERR] AllocResource() : TVD0 Open Device Failed\n\r")));
			return FALSE;
		}
#endif
	}

	DBGMSG(TV_FUNC,(_T("[TVPWR]--Tvout_power_initialize_register_address()\n\r")));
	return TVOUT_POWER_ERROR_NO_ERROR;


}

void
TVout_power_initialize_dac_onoff
(BOOL bOn)
{
	DBGMSG(TV_FUNC,(_T("[TVPWR]++TVout_power_initialize_dac_onff(%d)\n\r"), bOn));

	g_bDacPwrOn = bOn;

	DBGMSG(TV_FUNC,(_T("[TVPWR]--TVout_power_initialize_dac_onff(0x%08x)\n\r"), g_bDacPwrOn));
}


// set
//  - set functions are only called under running tvout power
void
TVout_power_set_dac_onoff
(BOOL bOn)
{
	DBGMSG(TV_FUNC,(_T("[TVPWR]++TVout_power_initialize_dac_onff(%d)\n\r"), bOn));

	if(bOn)
	{
		g_pPmuMisc->IP_CON_REG.DAC_CONTROL |=  ((BW_ENABLE_DAC)<<(BP_ENABLE_DAC));
	}
	else
	{
		g_pPmuMisc->IP_CON_REG.DAC_CONTROL &= ~((BW_ENABLE_DAC)<<(BP_ENABLE_DAC));
	}

	DBGMSG(TV_FUNC,(_T("[TVPWR]--TVout_power_initialize_dac_onff(0x%08x)\n\r"), g_pPmuPm->PWR_CONF.NORMAL_CFG));
}

void
Tvout_power_set_hdmi_div(unsigned int uiDiv)
{
	DBGMSG(TV_FUNC,(_T("[TVCLK]++Tvout_clk_set_hdmi_div(0x%x)\n\r"),uiDiv));

	g_pPmuMisc->IP_CON_REG.HDMI_CONTROL &= ~(0x3ff<<16);
	g_pPmuMisc->IP_CON_REG.HDMI_CONTROL |= (uiDiv<<16);

	DBGMSG(TV_FUNC,(_T("[TVCLK]--Tvout_clk_set_hdmi_div(0x%x)\n\r"),g_pPmuMisc->IP_CON_REG.HDMI_CONTROL));    
}

void
Tvout_power_set_hdmi_en
(BOOL bEn)
{
	DBGMSG(TV_FUNC,(_T("[TVCLK]++Tvout_clk_set_hdmi_en(%d)\n\r"),bEn));

	if(bEn)
	{
		g_pPmuMisc->IP_CON_REG.HDMI_CONTROL |= (HDMI_CON_SET_EN);
	}
	else
	{
		g_pPmuMisc->IP_CON_REG.HDMI_CONTROL &= ~(HDMI_CON_SET_EN);
	}

	DBGMSG(TV_FUNC,(_T("[TVCLK]--Tvout_clk_set_hdmi_en(0x%x)\n\r"),g_pPmuMisc->IP_CON_REG.HDMI_CONTROL));    
}


// etc
//  -
BOOL
Tvout_power_get_power_status
(void)
{
	DBGMSG(TV_FUNC,(_T("[TVPWR]++Tvout_power_get_power_status()\n\r")));

	DBGMSG(TV_FUNC,(_T("[TVPWR]--Tvout_power_get_power_status(0x%08x)\n\r"), g_pPmuPm->STATUS_REG.BLK_PWR_STAT));

	return((g_pPmuPm->STATUS_REG.BLK_PWR_STAT)&(BW_TV_PWR_STAT<<BP_TV_PWR_STAT))? TRUE:FALSE;
}

BOOL
Tvout_power_get_dac_power_status
(void)
{
	DBGMSG(TV_FUNC,(_T("[TVPWR]++Tvout_power_get_dac_power_status()\n\r")));

	DBGMSG(TV_FUNC,(_T("[TVPWR]--Tvout_power_get_dac_power_status(0x%08x)\n\r"), g_pPmuPm->PWR_CONF.NORMAL_CFG));

	return ((g_pPmuMisc->IP_CON_REG.DAC_CONTROL)&((BW_ENABLE_DAC)<<(BP_ENABLE_DAC)))? TRUE:FALSE;
}


// start
//  - start functions are only called under stopping tvout power
void
TVout_power_on
(void)
{
#ifdef USE_POWERCON_FUNCTION
	DWORD dwIPIndex = PWR_IP_TVENC, dwBytes;
#endif
	DBGMSG(TV_FUNC,(_T("[TVPWR]++TVout_power_on()\n\r")));

#ifdef USE_POWERCON_FUNCTION
	if ( !DeviceIoControl(g_hPowerCon, IOCTL_PWRCON_SET_POWER_ON, &dwIPIndex, sizeof(DWORD), NULL, 0, &dwBytes, NULL) )
	{
		DBGMSG(TV_USR1,(_T("[TVPWR:ERR] ++%s: IOCTL_PWRCON_SET_POWER_ON Failed\r\n"),_T(__FUNCTION__)));
	}
#else

	g_pPmuPm->PWR_CONF.NORMAL_CFG |= ((BW_TV_POWER_GATE)<<(BP_TV_POWER_GATE));

	//TVout_power_set_dac_onoff(g_bDacPwrOn);
	while(!((BW_TV_PWR_STAT<<BP_TV_PWR_STAT)&g_pPmuPm->STATUS_REG.BLK_PWR_STAT))
	{
		Sleep(1);
	}

#endif

	DBGMSG(TV_FUNC,(_T("[TVPWR]--TVout_power_on(0x%08x,0x%08x)\n\r"), g_pPmuPm->PWR_CONF.NORMAL_CFG, g_pPmuPm->STATUS_REG.BLK_PWR_STAT));


}


// stop
//  - stop functions are only called under running tvout power
void
TVout_power_off
(void)
{

	int n_cnt=0;

#ifdef USE_POWERCON_FUNCTION
	DWORD dwIPIndex = PWR_IP_TVENC, dwBytes;
#endif


	DBGMSG(TV_FUNC,(_T("[TVPWR]++TVout_power_off()\n\r")));


#ifdef USE_POWERCON_FUNCTION
	if ( !DeviceIoControl(g_hPowerCon, IOCTL_PWRCON_SET_POWER_OFF, &dwIPIndex, sizeof(DWORD), NULL, 0, &dwBytes, NULL) )
	{
		DBGMSG(TV_USR1,(_T("[TVPWR:ERR] ++%s: IOCTL_PWRCON_SET_POWER_OFF Failed\r\n"),_T(__FUNCTION__)));
	}
#else

	g_pPmuPm->PWR_CONF.NORMAL_CFG &= ~(BW_TV_POWER_GATE<<(BP_TV_POWER_GATE));

	//TVout_power_set_dac_onoff(g_bDacPwrOn);

	n_cnt = 0;
	while(((BW_TV_PWR_STAT<<BP_TV_PWR_STAT)&g_pPmuPm->STATUS_REG.BLK_PWR_STAT))
	{
		Sleep(1);
		DBGMSG(TV_DBG,(_T("[TVPWR:DBG] %s: Wait for T-Block Power Off \r\n"),_T(__FUNCTION__)));
		if(n_cnt++ > 1000)	
		{
			DBGMSG(TV_USR1,(_T("[TVPWR:ERR] %s: Fail to off the T-Block Power\r\n"),_T(__FUNCTION__)));
			break;		
	}

#endif

	DBGMSG(TV_FUNC,(_T("[TVPWR]--TVout_power_off(0x%08x,0x%08x)\n\r"), g_pPmuPm->PWR_CONF.NORMAL_CFG, g_pPmuPm->STATUS_REG.BLK_PWR_STAT));

}

#ifdef BSP_USEDVFS
BOOL
TVout_dvfs_set_level_fix()
{
	DWORD dwBytes;
	PROFILE_LIST Profile = HIGH_NORM_PERF;

	if(!DeviceIoControl(g_hPowerCon, IOCTL_DVFS_SET_PROFILE, &Profile, sizeof(DWORD),NULL,0,&dwBytes,NULL))
	{
		DBGMSG(TV_USR1,(_T("[TVPWR:ERR] ++%s: IOCTL_DVFS_SET_PROFILE Failed\r\n"),_T(__FUNCTION__)));
		return FALSE;
	}
	
	return TRUE;
}

BOOL
TVout_dvfs_clear_level_fix()
{
	DWORD dwBytes;
	PROFILE_LIST Profile = HIGH_NORM_PERF;

	if(!DeviceIoControl(g_hPowerCon, IOCTL_DVFS_CLEAR_PROFILE, &Profile, sizeof(DWORD),NULL,0,&dwBytes,NULL))
	{
		DBGMSG(TV_USR1,(_T("[TVPWR:ERR] ++%s: IOCTL_DVFS_CLEAR_PROFILE Failed\r\n"),_T(__FUNCTION__)));
		return FALSE;
	}
	
	
	return TRUE;
	
}
#endif // BSP_USEDVFS


#ifdef SUPPORT_APM_TVD


void TVout_power_set_APM(CEDEVICE_POWER_STATE APM_POWER_STATUS)
{
	// 3. Message Queue notify when the device power state is changed
	//    Before sending Msg to power control, you should confirm the power state from the MS Power manager
	//      To confirm the power state you should call the DevicePowerNotify(), 
	//                      and receive the confirm message "IOCTL_POWER_SET" from MS Power manager

	txmqParam.bLPModeSupport = FALSE;
	txmqParam.dwDeviceID = IRQ_MIXER;  // ex) IRQ_EINT31
	txmqParam.dwMsg = DTOP_POWER_SET;    // This message type is also defined in bsp_args.h
	txmqParam.dwLParam = APM_POWER_STATUS;
	txmqParam.dwRParam = 0;

        DBGMSG(TV_FUNC,(_T("[TVPWR]++TVout_power_set_APM()\n\r")));

	if(!WriteMsgQueue(PWC_msgQ, &txmqParam, sizeof(MSG_DEV_STATE), INFINITE, 0))
	{
		RETAILMSG(1,(TEXT(" [TVOUT]WriteMsgQueue Error(0x%x)\r\n"),GetLastError()));
	}

        DBGMSG(TV_FUNC,(_T("[TVPWR]--TVout_power_set_APM()\n\r")));

	return;
	
}

void TVout_power_init_APM()
{

        DBGMSG(TV_FUNC,(_T("[TVPWR]++TVout_power_init_APM()\n\r")));

	// 2. Message Queue initialization for Device Power State transition
	memset((void *)&msgOptions, 0x0, sizeof(msgOptions));
	msgOptions.dwSize = sizeof(MSGQUEUEOPTIONS);
	msgOptions.dwFlags = 0;
	msgOptions.dwMaxMessages = 1024;        // Max number of MSG queue entries
	msgOptions.cbMaxMessage = sizeof(MSG_DEV_STATE);
	msgOptions.bReadAccess = FALSE;     // Write Only

	PWC_msgQ = CreateMsgQueue(OEMPM_MSGQ_NAME, &msgOptions);
	
        DBGMSG(TV_FUNC,(_T("[TVPWR]--TVout_power_init_APM()\n\r")));


	return;
}

void TVout_power_deinit_APM()
{
	CloseMsgQueue(PWC_msgQ);
}

#endif


