//
// Copyright  2009 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:		stda_grp.c

Abstract:			Implementation of Graphic Layer
				This module implements Middle Level S/W of Video Mixer

Functions:


Notes:


--*/

#include <windows.h>
#include <bsp_cfg.h>    // for reference HCLK, ECLK
#include <register_map.h>
#include "tvout_global.h"
#include "stda_common.h"
#include "stda_context.h"
#include "stda_resource.h"
#include "stda_interrupt.h"
#include "stda_grp.h"


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

static BOOL STDA_Grp_init_param(VMIXER_LAYER vmLayer, PBYTE pBufIn);
static BOOL STDA_Grp_init_burst_size(PBYTE pBufIn);
static BOOL STDA_Grp_init_src_endian(PBYTE pBufIn);
static BOOL STDA_Grp_set_start(VMIXER_LAYER vmLayer);
static BOOL STDA_Grp_set_stop(VMIXER_LAYER vmLayer);
static BOOL STDA_Grp_set_priority(VMIXER_LAYER vmLayer, PBYTE pBufIn);
static BOOL STDA_Grp_set_base_address(VMIXER_LAYER vmLayer, PBYTE pBufIn);
static BOOL STDA_Grp_set_dest_position(VMIXER_LAYER vmLayer, PBYTE pBufIn);
static BOOL STDA_Grp_get_priority(VMIXER_LAYER vmLayer, PBYTE pBufOut);
static BOOL STDA_HDMI_wait_hpdGRP0_status_change(PBYTE pBufIn, PBYTE pBufOut);
static BOOL STDA_HDMI_wait_hpdGRP1_status_change(PBYTE pBufIn, PBYTE pBufOut);

/*============================================================================*/

BOOL
STDA_Grp_API_Proc
(DWORD hOpenContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	VMIXER_LAYER vmLayer;

	RETAILMSG(TV_PLAY,(_T("[GRP] ++STDA_Grp_API_Proc(0x%x)\n\r"),dwCode));

	if(!(pPMCtxt->bTvOutputParam))
	{
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : must not initialize GRPx before initializing TVoutIF parameters\n\r")));
		return FALSE;
	}

	switch(dwCode)
	{
		case STDA_GRP0_INIT_PROCESSING_PARAM:
		case STDA_GRP0_START:
		case STDA_GRP0_STOP:
		case STDA_GRP0_SET_PRIORITY:
		case STDA_GRP0_SET_BASE_ADDRESS:
		case STDA_GRP0_SET_DEST_POSITION:
		case STDA_GRP0_GET_PRIORITY:
			if(!STDA_resource_compare_GRP0(hOpenContext))
			{
				return FALSE;
			}
			vmLayer = VM_GPR0_LAYER;
			break;
		case STDA_GRP1_INIT_PROCESSING_PARAM:
		case STDA_GRP1_START:
		case STDA_GRP1_STOP:
		case STDA_GRP1_SET_PRIORITY:
		case STDA_GRP1_SET_BASE_ADDRESS:
		case STDA_GRP1_SET_DEST_POSITION:
		case STDA_GRP1_GET_PRIORITY:
			if(!STDA_resource_compare_GRP1(hOpenContext))
			{
				return FALSE;
			}
			vmLayer = VM_GPR1_LAYER;
			break;
		case STDA_HDMI_WAIT_HPD_STATUS_CHANGE:
			if(STDA_resource_compare_GRP0(hOpenContext))
			{
				vmLayer = VM_GPR0_LAYER;
			}
			else if(STDA_resource_compare_GRP1(hOpenContext))
			{
				vmLayer = VM_GPR1_LAYER;
			}
			else
			{
				return FALSE;
			}
				break;
		default:
			DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : invalid dwCode parameter(%d)\n\r"),dwCode));
			return FALSE;
			break;
	}

	switch(dwCode)
	{
		case STDA_GRP0_START:
			if(!(pPMCtxt->bGRPMode[0]))
			{
				DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : Graphic Layer 0 is not initialized with basic default value\n\r")));
				return FALSE;
			}
			break;
		case STDA_GRP0_INIT_PROCESSING_PARAM:
			if(pPMCtxt->bGRPLayerEnable[0])
			{
				DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : Graphic Layer 0 is already running status\n\r")));
				return FALSE;
			}
			break;
		case STDA_GRP1_START:
			if(!(pPMCtxt->bGRPMode[1]))
			{
				DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : Graphic Layer 1 is not initialized with basic default value\n\r")));
				return FALSE;
			}
			break;
		case STDA_GRP1_INIT_PROCESSING_PARAM:
			if(pPMCtxt->bGRPLayerEnable[1])
			{
				DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : Graphic Layer 1 is already running status\n\r")));
				return FALSE;
			}
			break;
		case STDA_GRP0_STOP:
		case STDA_GRP0_SET_PRIORITY:
		case STDA_GRP0_SET_BASE_ADDRESS:
		case STDA_GRP0_SET_DEST_POSITION:
			if(!(pPMCtxt->bGRPLayerEnable[0]))
			{
				DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Video_Layer_API_Proc() : Graphic Layer 0 is not running\n\r")));
				return FALSE;
			}
			break;
		case STDA_GRP1_STOP:
		case STDA_GRP1_SET_PRIORITY:
		case STDA_GRP1_SET_BASE_ADDRESS:
		case STDA_GRP1_SET_DEST_POSITION:
			if(!(pPMCtxt->bGRPLayerEnable[1]))
			{
				DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Video_Layer_API_Proc() : Graphic Layer 1 is not running\n\r")));
				return FALSE;
			}
			break;
		case STDA_HDMI_WAIT_HPD_STATUS_CHANGE:
		case STDA_GRP0_GET_PRIORITY:
		case STDA_GRP1_GET_PRIORITY:
			break;
		default:
			DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : invalid dwCode parameter(%d)\n\r"),dwCode));
			return FALSE;
			break;
	}

	switch(dwCode)
	{
		case STDA_GRP0_INIT_PROCESSING_PARAM:
		case STDA_GRP1_INIT_PROCESSING_PARAM:
			return STDA_Grp_init_param(vmLayer, pBufIn);
			break;
		case STDA_GRP0_START:
		case STDA_GRP1_START:
			return STDA_Grp_start(vmLayer);
			break;
		case STDA_GRP0_STOP:
		case STDA_GRP1_STOP:
			return STDA_Grp_stop(vmLayer);
			break;
		case STDA_GRP0_SET_PRIORITY:
		case STDA_GRP1_SET_PRIORITY:
			return STDA_Grp_set_priority(vmLayer, pBufIn);
			break;
		case STDA_GRP0_SET_BASE_ADDRESS:
		case STDA_GRP1_SET_BASE_ADDRESS:
			return STDA_Grp_set_base_address(vmLayer, pBufIn);
			break;
		case STDA_GRP0_SET_DEST_POSITION:
		case STDA_GRP1_SET_DEST_POSITION:
			return STDA_Grp_set_dest_position(vmLayer, pBufIn);
			break;
		case STDA_GRP0_GET_PRIORITY:
		case STDA_GRP1_GET_PRIORITY:
			return STDA_Grp_get_priority(vmLayer, pBufOut);
			break;
		case STDA_HDMI_WAIT_HPD_STATUS_CHANGE:
			switch(vmLayer)
			{
				case VM_GPR0_LAYER:
					return STDA_HDMI_wait_hpdGRP0_status_change(pBufIn, pBufOut);
					break;
				case VM_GPR1_LAYER:
					return STDA_HDMI_wait_hpdGRP1_status_change(pBufIn, pBufOut);
					break;
				default:
					DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
					return FALSE;
			}
			break;
	default:
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_API_Proc() : invalid dwCode parameter(%d)\n\r"),dwCode));
		return FALSE;
		break;
	}

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_API_Proc(0x%08x)\n\r"),dwCode));

	return TRUE;
}

static BOOL
STDA_Grp_init_param
(VMIXER_LAYER vmLayer,
PBYTE pBufIn)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	STDA_ARG_GRP_BASIC_PARAM *pGrp = (STDA_ARG_GRP_BASIC_PARAM*)pBufIn;

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_init_param()\n\r")));

	switch(vmLayer)
	{
		case VM_GPR0_LAYER:
			memcpy((void *)&(pPMCtxt->tGrpParam[0]), (const void *)pGrp,
			sizeof(STDA_ARG_GRP_BASIC_PARAM));
			pPMCtxt->bGRPMode[0] = TRUE;
			break;
		case VM_GPR1_LAYER:
			memcpy((void *)&(pPMCtxt->tGrpParam[1]), (const void *)pGrp,
			sizeof(STDA_ARG_GRP_BASIC_PARAM));
			pPMCtxt->bGRPMode[1] = TRUE;
			break;
		default:
			DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_init_param() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
			return FALSE;
			break;
	}

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_init_param()\n\r")));

	return TRUE;
}

static BOOL
STDA_Grp_init_burst_size
(PBYTE pBufIn)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_init_burst_size()\n\r")));

	pPMCtxt->grpBurst = (VMIXER_BURST_MODE)*pBufIn;

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_init_burst_size()\n\r")));

	return TRUE;
}

static BOOL
STDA_Grp_init_src_endian
(PBYTE pBufIn)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_init_src_endian()\n\r")));

	pPMCtxt->grpEndian = (TVOUT_ENDIAN_FORMAT_TYPE)*pBufIn;

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_init_src_endian()\n\r")));

	return TRUE;
}

BOOL
STDA_Grp_start
(VMIXER_LAYER vmLayer)
{
	STDAContext *pCtxt = STDA_get_context();
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	VMIXER_ERROR error;

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_start()\n\r")));


	if(vmLayer != VM_GPR0_LAYER && vmLayer != VM_GPR1_LAYER)
	{
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_start() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
		return FALSE;
	}

	if(pPMCtxt->powerState == D0)
	{
		if(!(pCtxt->bGRPEnable[0] || pCtxt->bGRPEnable[1]))
		{
			error = VMixer_initialize_status_reg(pPMCtxt->grpBurst,
			pPMCtxt->grpEndian);
			if(error != VMIXER_NO_ERROR)
			{
				return FALSE;
			}
		}

		error = VMixer_initialize_layer(vmLayer,
								TRUE,
								pPMCtxt->tGrpParam[vmLayer].bWinBlending,
								pPMCtxt->tGrpParam[vmLayer].uiAlpha,
								pPMCtxt->tGrpParam[vmLayer].uiPriority,
								pPMCtxt->tGrpParam[vmLayer].color,
								pPMCtxt->tGrpParam[vmLayer].bBlankChange,
								pPMCtxt->tGrpParam[vmLayer].bPixelBlending,
								pPMCtxt->tGrpParam[vmLayer].bPreMul,
								pPMCtxt->tGrpParam[vmLayer].uiBlankColor,
								pPMCtxt->tGrpParam[vmLayer].uiBaseAddress,
								pPMCtxt->tGrpParam[vmLayer].uiSpan,
								pPMCtxt->tGrpParam[vmLayer].uiWidth,
								pPMCtxt->tGrpParam[vmLayer].uiHeight,
								pPMCtxt->tGrpParam[vmLayer].uiSrcOffsetX,
								pPMCtxt->tGrpParam[vmLayer].uiSrcOffsetY,
								pPMCtxt->tGrpParam[vmLayer].uiDestOffsetX,
								pPMCtxt->tGrpParam[vmLayer].uiDestOffsetY,
								pPMCtxt->tGrpParam[vmLayer].uiScaleEnH,
								pPMCtxt->tGrpParam[vmLayer].uiScaleEnV);

		if(error != VMIXER_NO_ERROR)
		{
			return FALSE;
		}

		VMixer_start();

		pCtxt->bGRPEnable[vmLayer] = TRUE;
	}

	pPMCtxt->bGRPLayerEnable[vmLayer] = TRUE;

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_start()\n\r")));

	return TRUE;
}

BOOL
STDA_Grp_stop
(VMIXER_LAYER vmLayer)
{
	STDAContext *pCtxt = STDA_get_context();
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	VMIXER_ERROR error;

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_stop()\n\r")));

	if(vmLayer != VM_GPR0_LAYER && vmLayer != VM_GPR1_LAYER)
	{
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_stop() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
		return FALSE;
	}

	if(pPMCtxt->powerState == D0)
	{
		error = VMixer_set_layer_show(vmLayer, FALSE);
		if(error != VMIXER_NO_ERROR)
		{
			return FALSE;
		}

		error = VMixer_set_layer_priority(vmLayer, 0);
		if(error != VMIXER_NO_ERROR)
		{
			return FALSE;
		}

		VMixer_start();
	}

	pCtxt->bGRPEnable[vmLayer] = FALSE;
	pPMCtxt->bGRPLayerEnable[vmLayer] = FALSE;

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_stop()\n\r")));

	return TRUE;
}

static BOOL
STDA_Grp_set_priority
(VMIXER_LAYER vmLayer,
PBYTE pBufIn)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	VMIXER_ERROR error;

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_set_priority()\n\r")));

	if(vmLayer != VM_GPR0_LAYER && vmLayer != VM_GPR1_LAYER)
	{
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_set_priority() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
		return FALSE;
	}

	if(pPMCtxt->powerState == D0)
	{
		error = VMixer_set_layer_priority(vmLayer, (unsigned int)(*pBufIn));
		if(error != VMIXER_NO_ERROR)
		{
			return FALSE;
		}
	}

	pPMCtxt->tGrpParam[vmLayer].uiPriority = (unsigned int)(*pBufIn);

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_set_priority()\n\r")));

	return TRUE;
}

static BOOL
STDA_Grp_set_base_address
(VMIXER_LAYER vmLayer,
PBYTE pBufIn)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	VMIXER_ERROR error;

	STDA_ARG_GRP_IMG_ADDRESS *pAddress = (STDA_ARG_GRP_IMG_ADDRESS*)pBufIn;

	RETAILMSG(TV_PLAY,(_T("[GRP] ++STDA_Grp_set_base_address()\n\r")));

	if(vmLayer != VM_GPR0_LAYER && vmLayer != VM_GPR1_LAYER)
	{
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_set_base_address() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
		return FALSE;
	}

	if(pPMCtxt->powerState == D0)
	{
		error = VMixer_set_grp_base_address(vmLayer, pAddress->uiRGBAddress);
		if(error != VMIXER_NO_ERROR)
		{
			return FALSE;
		}
	}

	pPMCtxt->tGrpParam[vmLayer].uiBaseAddress = (unsigned int)(*pBufIn);

	RETAILMSG(TV_PLAY,(_T("[GRP] --STDA_Grp_set_base_address()\n\r")));

	return TRUE;
}

static BOOL
STDA_Grp_set_dest_position
(VMIXER_LAYER vmLayer,
PBYTE pBufIn)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	VMIXER_ERROR error;
	STDA_ARG_IMG_OFFSET *pOffset = (STDA_ARG_IMG_OFFSET*)pBufIn;

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_set_dest_position()\n\r")));

	if(vmLayer != VM_GPR0_LAYER && vmLayer != VM_GPR1_LAYER)
	{
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_set_dest_position() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
		return FALSE;
	}

	if(pPMCtxt->powerState == D0)
	{
		error = VMixer_set_grp_layer_position(vmLayer,
		pOffset->uiOffsetX,
		pOffset->uiOffsetY);
		if(error != VMIXER_NO_ERROR)
		{
			return FALSE;
		}
	}

	pPMCtxt->tGrpParam[vmLayer].uiDestOffsetX = pOffset->uiOffsetX;
	pPMCtxt->tGrpParam[vmLayer].uiDestOffsetY = pOffset->uiOffsetY;

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_set_dest_position()\n\r")));

	return TRUE;
}

static BOOL
STDA_Grp_get_priority
(VMIXER_LAYER vmLayer,
PBYTE pBufOut)
{
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	unsigned int *pOut = (unsigned int*)pBufOut;

	DBGMSG(TV_FUNC,(_T("[GRP] ++STDA_Grp_get_priority()\n\r")));

	if(vmLayer != VM_GPR0_LAYER && vmLayer != VM_GPR1_LAYER)
	{
		DBGMSG(TV_USR1,(_T("[GRP:ERR] STDA_Grp_get_priority() : invalid vmLayer parameter(%d)\n\r"),vmLayer));
		return FALSE;
	}

	*pOut = pPMCtxt->tGrpParam[vmLayer].uiPriority;

	DBGMSG(TV_FUNC,(_T("[GRP] --STDA_Grp_get_priority()\n\r")));

	return TRUE;
}

static BOOL
STDA_HDMI_wait_hpdGRP0_status_change
(PBYTE pBufIn,
PBYTE pBufOut)
{
	PDWORD pOut = (PDWORD)pBufOut;
	PDWORD pdwWaitTime = (PDWORD)pBufIn;

	DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP0_status_change(%d)\n\r"),*pdwWaitTime));

	if(!pBufOut)
	{
		DBGMSG(TV_USR1,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP0_status_change() pBufOut is NULL\n\r")));
		return FALSE;
	}

	*pOut = STDA_interrupt_wait_hpdGRP0_cmd_done(*pdwWaitTime);

	if(*pOut == WAIT_TIMEOUT)
	{
		DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP0_status_change() TIMEOUT~\n\r")));
	}
	else if(*pOut == WAIT_FAILED)
	{
		DBGMSG(TV_USR1,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP0_status_change() WAIT_FAILED\n\r")));
	}

	DBGMSG(TV_USR4,(_T("[TVOUT] --STDA_HDMI_wait_hpdGRP0_status_change() change hpd status\n\r")));

	return TRUE;
}

static BOOL
STDA_HDMI_wait_hpdGRP1_status_change
(PBYTE pBufIn,
PBYTE pBufOut)
{
	PDWORD pOut = (PDWORD)pBufOut;
	PDWORD pdwWaitTime = (PDWORD)pBufIn;

	DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP1_status_change(%d)\n\r"),*pdwWaitTime));

	if(!pBufOut)
	{
		DBGMSG(TV_USR1,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP1_status_change() pBufOut is NULL\n\r")));
		return FALSE;
	}

	*pOut = STDA_interrupt_wait_hpdGRP1_cmd_done(*pdwWaitTime);

	if(*pOut == WAIT_TIMEOUT)
	{
		DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP1_status_change() TIMEOUT~\n\r")));
	}
	else if(*pOut == WAIT_FAILED)
	{
		DBGMSG(TV_USR1,(_T("[TVOUT] ++STDA_HDMI_wait_hpdGRP1_status_change() WAIT_FAILED\n\r")));
	}

	DBGMSG(TV_USR4,(_T("[TVOUT] --STDA_HDMI_wait_hpdGRP1_status_change() change hpd status\n\r")));

	return TRUE;
}


