/* 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: jiewen.zhou $
 * $Date  $
 * $RCSfile: drv_pwm.c,v $
 * $Revision: #5 $
 *
 *---------------------------------------------------------------------------*/


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

#include "drv_pwm.h"
#include "x_hal_5381.h"
#include "x_pinmux.h"
#include "x_assert.h"
#include "nptv_debug.h"
#include "drvcust_if.h"
#include "drv_tdtv_drvif.h"
#include "hw_tcon.h"
#include "hw_mlvds.h"
#include "drv_display.h"
#include "sv_const.h"

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

//-----------------------------------------------------------------------------
/** Brief
 *  @param
 *  @return
 */
//-----------------------------------------------------------------------------
EXTERN UINT8 bSI_DISPLAY_DCLK_TYPE;
#ifdef SUPPORT_SCANPWM_HALF_MODE
UINT8 u1ScanPWMHalfModeEn;
#endif

extern BOOL fgIsVsyncIsrStart;

#define PWMSCAN_MAX_CH SrcPWM2  // Please input the scanPWM CH index, whose channel number is max in the current case.
typedef struct
{
	UINT8 u1Initialed;	
	UINT32 u4Start;        // permillage
	UINT32 u4High;         // permillage
	UINT32 u4Low;          // permillage
	UINT32 u4High_target;  // permillage
	UINT32 u4Low_target;   // permillage 
	UINT32 u4LineTotalPre;
	UINT8 u1CrossZone;	
}SCANPWM_INFO_T;

static SCANPWM_INFO_T PWMSCAN_SETDATA[PWMSCAN_MAX_CH+1];

#define SCANPWM_DEBUGLOG 0
UINT8 _bScanPWMDbgLogLev=3;

UINT8 fgApplyScanPWMSetData=0;
UINT8 u1ScanPwmCrossFlg=0;
UINT8 fgScanPWMSetpControl=0;
UINT16 u2ScanPWMSetp=2;

BOOL _fgScanPWMAuto;
UINT8 _u1ScanPWMTestChg;
UINT32 _u4ScanPWMTesFreq;
INT32 _i4ScanPWMTestStart;
UINT32 _u4ScanPWMTestHigh;
UINT32 _u4ScanPWMTestLow;
UINT32 _u4ScanPWMTestBottom;
UINT32 _u4ScanPWMTestTop;
UINT8 _u1ScanPWMTestSrc;

BOOL fgTX2CHMode(void)
{
	if (PANEL_Is4K2K60())
	{
	    return (TRUE);
	}
	else
	{
	    return (FALSE);
	}
}

BOOL fgTX4CHMode(void)
{
	if (PANEL_Is4K2K120()||PANEL_Is8K4K30())
	{
		return (TRUE);
	}
	else
	{
		return (FALSE);
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Brief
 * This driver control the PWM0, PWM1 & PWM2 output frequence and duty cycle
 *
 * duty cycle = bDutyON/(bDutyAll+1);
 * PWM freq.(in 5368/96...) = (BUS Clock) / ((PWMP+1)x(PWMRSN+1))
 *
 * @param bSrc      PWM source (SrcPWM0/1/2)
 * @param bTimeBase PWMP, PWM basic unit = (0~0xfffff) * BUS Clock
 * @param bDutyON   PWMH, ON duty width = (0~0xfff) * bTimeBase
 * @param bDutyAll  PWMRSN, Period width = (0~0xffe) * bTimeBase
 * @return void
 *
 * @example  vDrvSetPWM(SrcPWM0, 6, u4DutyON, 254);
 *           	 Duty Cycle = u4DutyON/(254+1)
 */

void vDrvSetPWM(UINT32 u4Src, UINT32 u4TimeBase, UINT32 u4DutyON,
                UINT32 u4DutyAll)
{
    UINT32 u4Reg = REG_RW_PWM1, u4Value;
    //_bPWMSrc = u4Src;

    if(u4DutyON > (u4DutyAll+1))
    {
    #ifndef CC_UBOOT
        LOG(0,"PWM Error: u4DutyON and u4DutyAll= [0x %x,0x %x], u4DutyON is too large\n", u4DutyON, u4DutyAll);
	#endif
	}
#if defined(CC_MT5399) || defined(CC_MT5890) || defined(CC_MT5891) ||defined(CC_MT5893)
    switch(u4Src)
    {
        case SrcPWM0:
            u4Reg = REG_RW_PWM0;
            if(DRVCUST_InitGet(ePWM0Port)==PAD_PWM0_PWM0)
            {
                UNUSED(BSP_PinSet(PIN_OPWM0, PINMUX_FUNCTION2));
            }
            break;
        case SrcPWM1:
            u4Reg = REG_RW_PWM1;
            if(DRVCUST_InitGet(ePWM1Port)==PAD_PWM1_PWM1)
            {
                UNUSED(BSP_PinSet(PIN_OPWM1, PINMUX_FUNCTION2)); //Tuner 30V Boost-up PWM in BGA
            }
            else if(DRVCUST_InitGet(ePWM1Port)==PAD_PWM1_GPIO48)
            {
                UNUSED(BSP_PinSet(PIN_GPIO48, PINMUX_FUNCTION1));
            }
            break;
        case SrcPWM2:
            u4Reg = REG_RW_PWM2;
            if(DRVCUST_InitGet(ePWM2Port)==PAD_PWM2_PWM2)
            {
                UNUSED(BSP_PinSet(PIN_OPWM2, PINMUX_FUNCTION2)); //LED_CTL in BGA
            }
            break;
        default:
            ASSERT(u4Src <= SrcPWM2);
    }
#endif

    // workaround for full duty drop issue
    if(u4DutyAll==0xff && u4DutyON==0xff)	//we used 0xff at normal
    {
        u4DutyAll = 0xfe;
    }

    if(u4DutyAll==0xfff && u4DutyON==0xfff)
    {
        u4DutyAll = 0xffe;
    }
	IO_WRITE32MSK(HPDS_BASE, u4Reg+4, 0, 0xC0000000);
    IO_WRITE32MSK(HPDS_BASE, u4Reg+4, u4TimeBase, 0xFFFFF);
    u4Value = (((UINT32)u4DutyAll << 20) |
               ((UINT32)(u4DutyON & 0xFFF) << 4) | 1);
    IO_WRITE32(HPDS_BASE, u4Reg, u4Value);
}

/**
 * Set PWM sync to LVDS output v-sync signal.
 *
 * @param u4Src      PWM source (SrcPWM0/1/2)
 * @param u4LockON   Lock PWM on LVDS v-sync or not.
 */

void vDrvSetLock(UINT32 u4Src, UINT32 u4LockON)
{
    switch(u4Src)
    {
        default:
        case SrcPWM0:
            IO_WRITE32MSK(
                HPDS_BASE,
                REG_RW_PWM0VSYNC,
                u4LockON? 0x80000000 : 0,
                0xC0000000);
            break;

        case SrcPWM1:
            IO_WRITE32MSK(
                HPDS_BASE,
                REG_RW_PWM1VSYNC,
                u4LockON? 0x80000000 : 0,
                0xC0000000);
            break;

        case SrcPWM2:
            IO_WRITE32MSK(
                HPDS_BASE,
                REG_RW_PWM2VSYNC,
                u4LockON? 0x80000000 : 0,
                0xC0000000);
            break;
    }
}

//-----------------------------------------------------------------------------
/** Brief
 * This driver initialize pwm
 */
void vDrvInitSCANPWM(UINT8 u1Src)
{
	UINT8 i;
	
    vDrvSetScanPWMOnOff(u1Src, SV_OFF);	
    vDrvSetScanPWMOutBL(u1Src, SV_OFF); // SV_OFF: PWM_SCAN, SV_ON: TCON_3DBL

    //vDrvSetScanPWMLatchMode(SCAN_PWM_LATCH_MODE_SETDATA_OFF,SCAN_PWM_LATCH_MODE_OFF,SCAN_PWM_ALIGN_MODE_VSYNC);  // Aligned Vsync
    vDrvSetScanPWMLatchMode(SCAN_PWM_LATCH_MODE_SETDATA,SCAN_PWM_LATCH_MODE_OFF,SCAN_PWM_ALIGN_MODE_VSYNC);  // Set data

#if defined(CC_S_PLATFORM)
	vDrvSetScanPWMStartHigh(u1Src,SV_OFF);
#else
	vDrvSetScanPWMStartHigh(u1Src,SV_ON);
#endif
	vDrvSetScanStartModeOnOff(u1Src,SV_OFF);

    vDrvSetScanBLOnOff(SV_OFF);
	if(DRVCUST_PanelGet(eFlagBacklightDimmingInvert))
	{
    	vDrvSetScanPWMPolarity(u1Src, 1); 
	}
    vDrvSetScanPWMStartPhase(u1Src,0);
/*#ifdef SUPPORT_SCANPWM_HALF_MODE
	vDrvSetScanHalfModeEnable(SV_ON)
	vDrvSetScanHalfModeStart(0);
#endif*/

	if(IS_IC_5861())  // need to review after ECO
	{
		
		vIO32WriteFldAlign(PWM_SCAN_32, 0xF0000, REG_PWM_SCAN7_LOW);
		vIO32WriteFldAlign(PWM_SCAN_39, 0xF0000, REG_PWM_SCAN8_LOW);

		vIO32WriteFldAlign(PWM_SCAN_2F, 0, REG_PWM_SCAN7_START_PHASE);
		vIO32WriteFldAlign(PWM_SCAN_36, 0, REG_PWM_SCAN8_START_PHASE);
		vIO32WriteFldAlign(PWM_SCAN_3D, 0x1FF, REG_PWM_SCAN7_START_HIGH);
		vIO32WriteFldAlign(PWM_SCAN_3D, 0x1F, REG_PWM_SCAN8_HIGH_ENABLE);
		vIO32WriteFldAlign(PWM_SCAN_3D, 0x1FF, REG_PWM_SCAN8_START_HIGH);
		vIO32WriteFldAlign(PWM_SCAN_3D, 0x1F, REG_PWM_SCAN7_HIGH_ENABLE);
		vIO32WriteFldAlign(PWM_SCAN_3D, 0x1FF, REG_PWM_SCAN7_START_HIGH);
	}

    for (i=0; i<=PWMSCAN_MAX_CH; i++)
    {
        PWMSCAN_SETDATA[i].u1Initialed =0;	
        PWMSCAN_SETDATA[i].u4LineTotalPre =0;
		PWMSCAN_SETDATA[i].u4High = 0;
		PWMSCAN_SETDATA[i].u4Low = 0;
		PWMSCAN_SETDATA[i].u4Start = 0;
		PWMSCAN_SETDATA[i].u4High_target = 0;
		PWMSCAN_SETDATA[i].u4Low_target = 0;
		PWMSCAN_SETDATA[i].u1CrossZone = 0;
    }	
    //vDrvSetScanPWM(u1Src,0,0,0);
}

void vDrvInitPWM(UINT8 u1Src)
{
	vIO32WriteFldAlign(CKGEN_REG_PWM_PERI_CKCFG, 0x1, FLD_PWM_PERI_SEL);
}
//-----------------------------------------------------------------------------
/** Brief
 * This driver calculates the pwm duty cycle period ratio
 * @return ratio
 */
UINT8 vDrvGetPWMDutyCycleRatio(void)
{
    UINT8 u1Ratio, u1FrameRate;
    u1FrameRate = (bSI_DISPLAY_DCLK_TYPE == SV_DCLK_50HZ) ? 50 : 60;
    u1Ratio = (vDrvGetLCDFreq() / u1FrameRate);
    return u1Ratio;
}

static void vDrvSaveScanPWMStruct(UINT8 u1Src, UINT32 u4Start, UINT32 u4High, UINT32 u4Low)
{
#if SCANPWM_DEBUGLOG
	LOG(_bScanPWMDbgLogLev, "[ScanPWM]PWMSCAN_SETDATA[%d], u4Start=%d, u4High=%d, u4Low=%d \n", u1Src,u4Start, u4High, u4Low);
#endif
	if (u1Src <= PWMSCAN_MAX_CH)
	{
		PWMSCAN_SETDATA[u1Src].u1Initialed = 1;
		PWMSCAN_SETDATA[u1Src].u4Start = u4Start;
		PWMSCAN_SETDATA[u1Src].u4High = u4High;
		PWMSCAN_SETDATA[u1Src].u4Low = u4Low;
	}
}

/** Brief
 * This driver control the scanning PWM1 & PWM2
 * duty cycle = u4DutyON/u4DutyAll;
 * @param u1Src  PWM source (ScanPWM1/2/3/4/5/6)
 * @param u4Start  start_period (%) ex: 0 --> 0%
 * @param u4High  high_period (%) ex: 40 --> 40%
 * @param u4Low  low_period (%) ex: 60 --> 60%
 * @u4Start + u4High + u4Low = 100%
 * @return void
 */
//#define D_DRV_SCAN_PWM_DUTY_MAX 1000
UINT16 _u4ScanPWMTestPer=D_DRV_SCAN_PWM_DUTY_MAX;
#if defined(CC_S_PLATFORM)
#define TRINITY_SCANPWM_FIRST_CH 3
#endif
void vDrvSetScanPWM(UINT8 u1Src, UINT32 u4Start, UINT32 u4High, UINT32 u4Low)
{
    UINT16 u2HTotal, u2VTotal;
    UINT32 u4Val;
    UINT16 u2Divider = 1;
	UINT8 u1TX_2CH = 0;
	
	if(fgTX2CHMode())
	{
		u1TX_2CH = 1;
	}
	else if (fgTX4CHMode())
	{
		u1TX_2CH = 2;
	}

#if defined(CC_S_PLATFORM)// && !defined(CC_MTK_LOADER)
    if (u1Src >= TRINITY_SCANPWM_FIRST_CH && u1Src - TRINITY_SCANPWM_FIRST_CH < sizeof(arScanPWMPulseNum)/sizeof(UINT16)) //boundary check
    {
        if (!arScanPWMPulseNum[u1Src-TRINITY_SCANPWM_FIRST_CH])
        {
            LOG(0,"<%s>ERROR!!!The pulse number cannot be ZERO, %d!!!\n", __FUNCTION__, u1Src);
            u2Divider = 1;
        }
        else if (arScanPWMPulseNum[u1Src-TRINITY_SCANPWM_FIRST_CH] <= 0xFFFF)
        {
            u2Divider = arScanPWMPulseNum[u1Src-TRINITY_SCANPWM_FIRST_CH];
        }
    }
#endif

	u4Val = u4Start + u4High + u4Low;
#ifdef SUPPORT_SCANPWM_HALF_MODE
	if (u1ScanPWMHalfModeEn == 1) 
	{
		if(u4Val > _u4ScanPWMTestPer*2)
		{
			return;
		}
	}
	else
#endif	
	{
		if (u4Val > _u4ScanPWMTestPer)
		{
			return;
		}
	}

	vDrvSaveScanPWMStruct(u1Src, u4Start, u4High, u4Low);

	vDrvSetScanPWMOnOff(u1Src,SV_ON);

#ifdef CC_S_PLATFORM	
	u2HTotal = (wDrvGetPnlHTotal() >> u1TX_2CH);
	u2VTotal = wDrvGetPnlVTotal();
#else
    u2HTotal = (wDrvGetPnlHTotal() >> u1TX_2CH);
    u2VTotal = wDrvGetPnlVTotal();
#endif
    u4Val = u2HTotal * u2VTotal / _u4ScanPWMTestPer;

#ifdef SUPPORT_SCANPWM_HALF_MODE
	if (u1ScanPWMHalfModeEn == 1) 
	{
		_u4ScanPWMTestPer = D_DRV_SCAN_PWM_DUTY_MAX*2;

	}
#endif
	
	LOG(3, "_|-|_ vDrvSetScanPWM [SRC:scanPWM%d,%d*%d,start:%d,high:%d,low:%d,_u4ScanPWMTestPer: %d]\n", u1Src, u2HTotal, u2VTotal, u4Start, u4High, u4Low,_u4ScanPWMTestPer);
#if defined(CC_S_PLATFORM)
	LOG(3, "[Trinity][ScanPWM]#%d PulseNum=%d\n", u1Src, u2Divider);
#endif
    switch(u1Src)
    {
        case SrcPWM1:
            //UNUSED(BSP_PinSet(PIN_OPWM1, PINMUX_FUNCTION3));
            if (u4High == _u4ScanPWMTestPer)
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN1_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_LOW);		 			 			 			             
            }			
            else if (u4High == 0)			
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN1_FIXED_LOW);					 			 			 			
            }
            else
            {
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_LOW);			             			
            }
            if (u4Start==0)
            {
				vDrvSetScan1Start(0x0);
            }
            else
            {
            	vDrvSetScan1Start(u4Start*u4Val/u2Divider);
            }
            vDrvSetScan1High(u4High*u4Val/u2Divider);
            vDrvSetScan1Low(u4Low*u4Val/u2Divider);
            break;

        case SrcPWM2:
        	//UNUSED(BSP_PinSet(PIN_OPWM2, PINMUX_FUNCTION3));
            if (u4High == _u4ScanPWMTestPer)
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN2_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_LOW);		 			 			 			             
            }			
            else if (u4High == 0)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN2_FIXED_LOW);					 			 			 			
			}			
			else			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_LOW);			             			
			}
			if (u4Start==0)
			{
				vDrvSetScan2Start(0x0);
			}
			else
			{
            	vDrvSetScan2Start(u4Start*u4Val/u2Divider);
            }
            vDrvSetScan2High(u4High*u4Val/u2Divider);
            vDrvSetScan2Low(u4Low*u4Val/u2Divider);
            break;

        case SrcPWM3:
            // JTMS PINMUX --> FUNCTION4
            if (u4High == _u4ScanPWMTestPer)
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN3_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_LOW);		 			 			 			             
            }			
            else if (u4High == 0)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN3_FIXED_LOW);					 			 			 			
			}			
			else			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_LOW);			             			
			}
			if (u4Start==0)
			{
				vDrvSetScan3Start(0x0);
			}
			else
			{
            	vDrvSetScan3Start(u4Start*u4Val/u2Divider);
            }
            vDrvSetScan3High(u4High*u4Val/u2Divider);
            vDrvSetScan3Low(u4Low*u4Val/u2Divider);
            break;

        case SrcPWM4:
            // JTDI PINMUX --> FUNCTION4
            if (u4High == _u4ScanPWMTestPer)
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN4_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_LOW);		 			 			 			             
            }			
            else if (u4High == 0)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN4_FIXED_LOW);					 			 			 			
			}			
			else			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_LOW);			             			
			}
			if (u4Start==0)
			{
				vDrvSetScan4Start(0x0);
			}
			else
			{
            	vDrvSetScan4Start(u4Start*u4Val/u2Divider);
            }
            vDrvSetScan4High(u4High*u4Val/u2Divider);
            vDrvSetScan4Low(u4Low*u4Val/u2Divider);
            break;

        case SrcPWM5:
            // JTRST PINMUX --> FUNCTION4
            if (u4High == _u4ScanPWMTestPer)
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN5_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_LOW);		 			 			 			             
            }			
            else if (u4High == 0)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN5_FIXED_LOW);					 			 			 			
			}			
			else			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_LOW);			             			
			}
			if (u4Start==0)
			{
				vDrvSetScan5Start(0x0);
			}
			else
			{
            	vDrvSetScan5Start(u4Start*u4Val/u2Divider);
            }
            vDrvSetScan5High(u4High*u4Val/u2Divider);
            vDrvSetScan5Low(u4Low*u4Val/u2Divider);
            break;

		case SrcPWM6:
			// OPWM0/1/2 PINMUX --> FUNCTION1
            if (u4High == _u4ScanPWMTestPer)
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN6_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_LOW);		 			 			 			             
            }			
            else if (u4High == 0)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN6_FIXED_LOW);					 			 			 			
			}			
			else			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_LOW);			             			
			}
			if (u4Start==0)
			{
				vDrvSetScan6Start(0x0);
			}
			else
			{
            	vDrvSetScan6Start(u4Start*u4Val/u2Divider);
            }
            vDrvSetScan6High(u4High*u4Val/u2Divider);
            vDrvSetScan6Low(u4Low*u4Val/u2Divider);
            break;
				
		case SrcPWM7:
			// TCON6 PINMUX --> FUNCTION3
			if (u4High == _u4ScanPWMTestPer) 		   
			{			 
				vIO32WriteFldAlign(PWM_SCAN_30, 1, REG_PWM_SCAN7_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_LOW);														 
			}			
			else if (u4High == 0)			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_30, 1, REG_PWM_SCAN7_FIXED_LOW);														
			}			
			else			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_LOW);									
			}
			if (u4Start==0)
			{
				vDrvSetScan7Start(0x0);
			}
			else
			{
				vDrvSetScan7Start(u4Start*u4Val/u2Divider);
			}
			vDrvSetScan7High(u4High*u4Val/u2Divider);
			vDrvSetScan7Low(u4Low*u4Val/u2Divider);
			break;
				
		case SrcPWM8:
			// TCON7 PINMUX --> FUNCTION3
			if (u4High == _u4ScanPWMTestPer) 		   
			{			 
				vIO32WriteFldAlign(PWM_SCAN_37, 1, REG_PWM_SCAN8_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_LOW);														 
			}			
			else if (u4High == 0)			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_37, 1, REG_PWM_SCAN8_FIXED_LOW);														
			}			
			else			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_LOW);									
			}
			if (u4Start==0)
			{
				vDrvSetScan8Start(0x0);
			}
			else
			{
				vDrvSetScan8Start(u4Start*u4Val/u2Divider);
			}
			vDrvSetScan8High(u4High*u4Val/u2Divider);
			vDrvSetScan8Low(u4Low*u4Val/u2Divider);
			break;
				
        default:
            ASSERT(u1Src <= SrcPWM8);
    }

#ifdef SUPPORT_SCANPWM_HALF_MODE
	if (u1ScanPWMHalfModeEn == 1) 
	{
		_u4ScanPWMTestPer = D_DRV_SCAN_PWM_DUTY_MAX;

	}
#endif

}

void vDrvSetScanPWMStartPhase(UINT32 u4Src, UINT32 u4Start_Phase)
{
    UINT16 u2HTotal, u2VTotal;
    UINT32 u4Val;
	UINT16 u2Divider = 1;
	UINT8 u1TX_2CH = 0;

	if(fgTX2CHMode())
	{
		u1TX_2CH = 1;
	}
	else if (fgTX4CHMode())
	{
		u1TX_2CH = 2;
	}

#if defined(CC_S_PLATFORM) && !defined(CC_MTK_LOADER)
    if (u4Src >= TRINITY_SCANPWM_FIRST_CH && u4Src - TRINITY_SCANPWM_FIRST_CH < sizeof(arScanPWMPulseNum)/sizeof(UINT16)) //boundary check
    {
        if (!arScanPWMPulseNum[u4Src-TRINITY_SCANPWM_FIRST_CH])
        {
            LOG(0,"<%s>ERROR!!!The pulse number cannot be ZERO, %d!!!\n", __FUNCTION__, u4Src);
            u2Divider = 1;
        }
        else if (arScanPWMPulseNum[u4Src-TRINITY_SCANPWM_FIRST_CH] <= 0xFFFF)
        {
            u2Divider = arScanPWMPulseNum[u4Src-TRINITY_SCANPWM_FIRST_CH];
        }
    }
#endif

#ifdef CC_S_PLATFORM	
	u2HTotal = (wDrvGetPnlHTotal() >> u1TX_2CH);
	u2VTotal = wDrvGetPnlVTotal();
#else
	u2HTotal = (wDrvGetPnlHTotal() >> u1TX_2CH);
    u2VTotal = wDrvGetPnlVTotal();
#endif

	u4Val = u2HTotal * u2VTotal / 1000;

	LOG(3, "_|-|_ vDrvSetScanPWMStartPhase [SRC:scanPWM%d,%d*%d,phase:%d]\n", u4Src, u2HTotal, u2VTotal, u4Start_Phase);
#if defined(CC_S_PLATFORM)
	LOG(3, "[Trinity][ScanPWM]#%d PulseNum=%d\n", u4Src, u2Divider);
#endif

    switch(u4Src)
    {
        case SrcPWM1:
			vDrvSetScan1Phase(u4Val*u4Start_Phase/u2Divider);
			break;

		case SrcPWM2:
			vDrvSetScan2Phase(u4Val*u4Start_Phase/u2Divider);
			break;

		case SrcPWM3:
			vDrvSetScan3Phase(u4Val*u4Start_Phase/u2Divider);
			break;

		case SrcPWM4:
			vDrvSetScan4Phase(u4Val*u4Start_Phase/u2Divider);
			break;

		case SrcPWM5:
			vDrvSetScan5Phase(u4Val*u4Start_Phase/u2Divider);
			break;

		case SrcPWM6:
			vDrvSetScan6Phase(u4Val*u4Start_Phase/u2Divider);
			break;
			
		case SrcPWM7:
			vDrvSetScan7Phase(u4Val*u4Start_Phase/u2Divider);
			break;
				
		case SrcPWM8:
			vDrvSetScan8Phase(u4Val*u4Start_Phase/u2Divider);
			break;				

		default:
            ASSERT(u4Src <= SrcPWM8);
    }
}

/** Brief
 * This driver control the scanning backlight enable
 * @param u1OnOff
 * @return void
 */
void vDrvSetScanBLOnOff(UINT8 u1OnOff)
{
    vIO32WriteFldAlign(PWM_HS_01, u1OnOff, TCON_BL_EN);
}

#ifdef SUPPORT_SCANPWM_HALF_MODE

/** Brief
 * This driver control the scanning 0.5 mode enable
 * @param u1OnOff
 * @return void
 */
void vDrvSetScanHalfModeEnable(UINT8 u1OnOff)
{
    vIO32WriteFldAlign(PWM_SCAN_01, u1OnOff, RG_VSYNC_F_PWM_SEL);
}

/** Brief
 * This driver get the scanning 0.5 mode enable
 * @param void
 * @return enable or not
 */

UINT8 vDrvGetScanHalfModeEnable(void)
{
    return (UINT8)IO32ReadFldAlign(PWM_SCAN_01, RG_VSYNC_F_PWM_SEL);
}

/** Brief
 * This driver control the scanning 0.5 mode start pluse of LLRR,if not LLRR,the function can not work
 * @param u1Start 0: first L/R (edge)/1: Secone L/R(mid)
 * @return void
 */
void vDrvSetScanHalfModeStart(UINT8 u1Start)
{
    vIO32WriteFldAlign(PWM_SCAN_01, u1Start, RG_VSYNC_F_DISP_SEL);
}

#endif

/** Brief
 * This driver control the scanning backlight polarify
 * @param bSrc  PWM source (ScanPWM1/2)
 * @param u1blPol  0: Normal/1: Reverse
 * @return void
 */
void vDrvSetScanPWMPolarity(UINT32 u4Src, UINT8 u1blPol)
{
    switch(u4Src)
    {
        case SrcPWM1:
            vIO32WriteFldAlign(PWM_SCAN_06, u1blPol, REG_PWM_SCAN1_POL);
            break;

        case SrcPWM2:
            vIO32WriteFldAlign(PWM_SCAN_06, u1blPol, REG_PWM_SCAN2_POL);
            break;

        case SrcPWM3:
            vIO32WriteFldAlign(PWM_SCAN_10, u1blPol, REG_PWM_SCAN3_POL);
            break;

        case SrcPWM4:
            vIO32WriteFldAlign(PWM_SCAN_10, u1blPol, REG_PWM_SCAN4_POL);
            break;

        case SrcPWM5:
            vIO32WriteFldAlign(PWM_SCAN_11, u1blPol, REG_PWM_SCAN5_POL);
            break;

		case SrcPWM6:
			vIO32WriteFldAlign(PWM_SCAN_11, u1blPol, REG_PWM_SCAN6_POL);
            break;
			
		case SrcPWM7:
			vIO32WriteFldAlign(PWM_SCAN_30, u1blPol, REG_PWM_SCAN7_POL);
			break;
				
		case SrcPWM8:
			vIO32WriteFldAlign(PWM_SCAN_37, u1blPol, REG_PWM_SCAN8_POL);
			break;	

        default:
            ASSERT(u4Src <= SrcPWM8);
    }
}

/** Brief
 * This driver control the scanning PWM enable
 * @param u1OnOff
 * @return void
 */
void vDrvSetScanPWMOnOff(UINT32 u4Src, UINT8 u1OnOff)
{
	switch(u4Src)    
	{        
		case SrcPWM1:            
			vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN1_EN);            
			break;        
		case SrcPWM2:            
			vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN2_EN);            
			break;        
		case SrcPWM3:            
			vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN3_EN);           
			break;        
		case SrcPWM4:            
			vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN4_EN);            
			break;        
		case SrcPWM5:            
			vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN5_EN);            
			break;		
		case SrcPWM6:			
			vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN6_EN);            
			break;
		case SrcPWM7:			
			vIO32WriteFldAlign(PWM_SCAN_2F, u1OnOff, REG_PWM_SCAN7_EN);            
			break;
		case SrcPWM8:			
			vIO32WriteFldAlign(PWM_SCAN_36, u1OnOff, REG_PWM_SCAN8_EN);            
			break;			
		default:		    
			ASSERT(u4Src <= SrcPWM8);    
	}
}

/** Brief
 * This driver control the scanning PWM high frame mode enable
 * @param u1OnOff
 * @return void
 */
void vDrvSetScanPWMHFOnOff(UINT32 u4Src, UINT8 u1OnOff)
{
	switch(u4Src)    
	{        
		case SrcPWM1:            
			vIO32WriteFldAlign(PWM_SCAN_00, u1OnOff, REG_PWM_SCAN1_HIGH_FRAME_MODE);            
			break;        
		case SrcPWM2:            
			vIO32WriteFldAlign(PWM_SCAN_03, u1OnOff, REG_PWM_SCAN2_HIGH_FRAME_MODE);            
			break;        
		case SrcPWM3:            
			vIO32WriteFldAlign(PWM_SCAN_07, u1OnOff, REG_PWM_SCAN3_HIGH_FRAME_MODE);           
			break;        
		case SrcPWM4:            
			vIO32WriteFldAlign(PWM_SCAN_0A, u1OnOff, REG_PWM_SCAN4_HIGH_FRAME_MODE);            
			break;        
		case SrcPWM5:            
			vIO32WriteFldAlign(PWM_SCAN_0D, u1OnOff, REG_PWM_SCAN5_HIGH_FRAME_MODE);            
			break;		
		case SrcPWM6:			
			vIO32WriteFldAlign(PWM_SCAN_23, u1OnOff, REG_PWM_SCAN6_HIGH_FRAME_MODE);            
			break;
		case SrcPWM7:			
			vIO32WriteFldAlign(PWM_SCAN_30, u1OnOff, REG_PWM_SCAN7_HIGH_FRAME_MODE);            
			break;
		case SrcPWM8:			
			vIO32WriteFldAlign(PWM_SCAN_37, u1OnOff, REG_PWM_SCAN8_HIGH_FRAME_MODE);            
			break;	
		default:		    
			ASSERT(u4Src <= SrcPWM8);    
	}
}

/** Brief
 * This driver control the scanning PWM high frame mode select
 * @param u1Mode 1:One Frame ON/One Frame OFF 2:One Frame OFF/One Frame ON
 * @return void
 */
void vDrvSetScanPWMHFMode(UINT32 u4Src, UINT8 u1Mode)
{
	switch(u4Src)    
	{        
		case SrcPWM1:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_00, 0x0A, REG_PWM_SCAN1_HIGH_FRAME_MODE);
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_00, 0x14, REG_PWM_SCAN1_HIGH_FRAME_MODE);
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_00, 0x1F, REG_PWM_SCAN1_HIGH_FRAME_MODE);
			}
			break;        
		case SrcPWM2:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_03, 0x0A, REG_PWM_SCAN2_HIGH_FRAME_MODE);
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_03, 0x14, REG_PWM_SCAN2_HIGH_FRAME_MODE);
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_03, 0x1F, REG_PWM_SCAN2_HIGH_FRAME_MODE);
			}
			break;        
		case SrcPWM3:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_07, 0x0A, REG_PWM_SCAN3_HIGH_FRAME_MODE);
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_07, 0x14, REG_PWM_SCAN3_HIGH_FRAME_MODE);
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_07, 0x1F, REG_PWM_SCAN3_HIGH_FRAME_MODE);
			}
			break;        
		case SrcPWM4:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_0A, 0x0A, REG_PWM_SCAN4_HIGH_FRAME_MODE);
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_0A, 0x14, REG_PWM_SCAN4_HIGH_FRAME_MODE);
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_0A, 0x14, REG_PWM_SCAN4_HIGH_FRAME_MODE);
			}
			break;        
		case SrcPWM5:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_0D, 0x0A, REG_PWM_SCAN5_HIGH_FRAME_MODE);
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_0D, 0x14, REG_PWM_SCAN5_HIGH_FRAME_MODE);
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_0D, 0x1F, REG_PWM_SCAN5_HIGH_FRAME_MODE);
			}
			break;		
		case SrcPWM6:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_23, 0x0A, REG_PWM_SCAN6_HIGH_FRAME_MODE); 
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_23, 0x14, REG_PWM_SCAN6_HIGH_FRAME_MODE); 
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_23, 0x1F, REG_PWM_SCAN6_HIGH_FRAME_MODE);
			}
			break;
		case SrcPWM7:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_30, 0x0A, REG_PWM_SCAN7_HIGH_FRAME_MODE); 
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_30, 0x14, REG_PWM_SCAN7_HIGH_FRAME_MODE); 
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_30, 0x1F, REG_PWM_SCAN7_HIGH_FRAME_MODE);
			}
			break;
		case SrcPWM8:
			if(u1Mode == 1)
			{
				vIO32WriteFldAlign(PWM_SCAN_37, 0x0A, REG_PWM_SCAN8_HIGH_FRAME_MODE); 
			}
			else if(u1Mode == 2)
			{
				vIO32WriteFldAlign(PWM_SCAN_37, 0x14, REG_PWM_SCAN8_HIGH_FRAME_MODE); 
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_37, 0x1F, REG_PWM_SCAN8_HIGH_FRAME_MODE);
			}
			break;	
		default:		    
			ASSERT(u4Src <= SrcPWM8);    
	}
}

BOOL fgIsScanPWMSetDataLatch(void)
{
	if ((IO32ReadFldAlign(PWM_HS_01,REG_PWM_SCAN_SET_DATA_EN)==1)
	   &&(IO32ReadFldAlign(PWM_HS_01,REG_PWM_SCAN_SET_DATA_EN2)==1))
	{
		return (TRUE);
	}
	return (FALSE);
}

/** Brief
 * This driver control the scanning PWM latch mode
 * @param u1Mode
 * @param 0: Latch until set_data assert
 * @param 1: Update at once
 * @return void
 */
void vDrvSetScanPWMLatchMode(UINT8 u1SetDataMode,UINT8 u1Mode, UINT8 u1AlignMode)
{
    vIO32WriteFldAlign(PWM_HS_01, u1SetDataMode, REG_PWM_SCAN_SET_DATA_EN);
    vIO32WriteFldAlign(PWM_HS_01, u1SetDataMode, REG_PWM_SCAN_SET_DATA_EN2);
    vIO32WriteFldAlign(PWM_HS_01, u1Mode, REG_PWM_SCAN_LATCH_OFF);
    vIO32WriteFldAlign(PWM_HS_01, u1Mode, REG_PWM_SCAN_LATCH_OFF2);
	vIO32WriteFldAlign(PWM_HS_01, u1AlignMode, REG_PWM_SCAN_LATCH_SEL);
}

void vDrvScanPWMDataFire(void)
{
	vIO32WriteFldAlign(PWM_HS_01, 1, REG_PWM_SCAN_LATCH_OFF);
    vIO32WriteFldAlign(PWM_HS_01, 0, REG_PWM_SCAN_LATCH_OFF);
    
    vIO32WriteFldAlign(PWM_HS_01, 1, REG_PWM_SCAN_LATCH_OFF2);
    vIO32WriteFldAlign(PWM_HS_01, 0, REG_PWM_SCAN_LATCH_OFF2);
}

/** Brief
 * This driver control the output mux for scanning pwm
 * @param bSrc  PWM source (ScanPWM1/2)
 * @param u1OutBL
 * @param 0: output SCAN_PWM
 * @param 1: output TCON_3dbl_out which is from Panel_intf
 * @return void
 */
void vDrvSetScanPWMOutBL(UINT32 u4Src, UINT8 u1OutBL)
{
    switch(u4Src)
    {
        case SrcPWM1:
            vIO32WriteFldAlign(PWM_SCAN_06, u1OutBL, REG_TCON_3DBL_OUT_EN1);
            break;

        case SrcPWM2:
            vIO32WriteFldAlign(PWM_SCAN_06, u1OutBL, REG_TCON_3DBL_OUT_EN2);
            break;

        case SrcPWM3:
            vIO32WriteFldAlign(PWM_SCAN_10, u1OutBL, REG_TCON_3DBL_OUT_EN3);
            break;

        case SrcPWM4:
            vIO32WriteFldAlign(PWM_SCAN_10, u1OutBL, REG_TCON_3DBL_OUT_EN4);
            break;

        case SrcPWM5:
            vIO32WriteFldAlign(PWM_SCAN_11, u1OutBL, REG_TCON_3DBL_OUT_EN5);
            break;

		case SrcPWM6:
            vIO32WriteFldAlign(PWM_SCAN_11, u1OutBL, REG_TCON_3DBL_OUT_EN6);
            break;
			
		case SrcPWM7:
			vIO32WriteFldAlign(PWM_SCAN_2F, u1OutBL, REG_TCON_3DBL_OUT_EN7);
			break;
			
		case SrcPWM8:
			vIO32WriteFldAlign(PWM_SCAN_36, u1OutBL, REG_TCON_3DBL_OUT_EN8);
			break;

        default:
            ASSERT(u4Src <= SrcPWM8);
    }

}

void vDrvSetScanStartModeOnOff(UINT32 u4Src, UINT8 u1OnOff)
{
     switch(u4Src)
    {
        case SrcPWM1:
            vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN1_START_MODE);
            break;

        case SrcPWM2:
            vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN2_START_MODE);
            break;

        case SrcPWM3:
            vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN3_START_MODE);
            break;

        case SrcPWM4:
            vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN4_START_MODE);
            break;

        case SrcPWM5:
            vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN5_START_MODE);
            break;

		case SrcPWM6:
			vIO32WriteFldAlign(PWM_SCAN_12, u1OnOff, REG_PWM_SCAN6_START_MODE);
            break;
			
		case SrcPWM7:
			vIO32WriteFldAlign(PWM_SCAN_2F, u1OnOff, REG_PWM_SCAN7_START_MODE);
			break;
			
		case SrcPWM8:
			vIO32WriteFldAlign(PWM_SCAN_36, u1OnOff, REG_PWM_SCAN8_START_MODE);
			break;

		default:
            ASSERT(u4Src <= SrcPWM8);
    }

	vDrvScanPWMDataFire();
}

/** Brief
 * This driver control the scanning backlight polarify
 * @param u1blPol  0: Normal/1: Reverse
 * @return void
 */
void vDrvSetScanBLPolarity(UINT8 u1blPol)
{
    vIO32WriteFldAlign(PWM_HS_01, u1blPol, TCON_BL_IN_POL);
}

/** Brief
 * This driver control the scanning backlight latch mode
 * @param 0: Latch BL into a whole frame
 * @param 1: Direct use BL info to mask PWM
 * @return void
 */
void vDrvSetScanBLLatchMode(UINT8 u1Mode)
{
    vIO32WriteFldAlign(PWM_SCAN_06, u1Mode, REG_PWM_SCAN_BL_DIS_LATCH);
}

/** Brief
 * This driver control the scanning PWM start with high or low
 * @param 0: scan PWM channel
 * @param 1: On/Off. On:start with high. Off:start with low
 * @return void
 */
void vDrvSetScanPWMStartHigh(UINT32 u4Src, UINT8 u1OnOff)
{
	UINT32 u4Val=0;

	if (u1OnOff)  // start with high
	{
		u4Val = 0;
	}
	else
	{
		u4Val = 0x1FF;
	}

    switch(u4Src)
    {
        case SrcPWM1:
            vIO32WriteFldAlign(PWM_SCAN_06, u4Val, REG_PWM_SCAN1_START_HIGH);
            break;

        case SrcPWM2:
            vIO32WriteFldAlign(PWM_SCAN_06, u4Val, REG_PWM_SCAN2_START_HIGH);
            break;

        case SrcPWM3:
            vIO32WriteFldAlign(PWM_SCAN_10, u4Val, REG_PWM_SCAN3_START_HIGH);
            break;

        case SrcPWM4:
            vIO32WriteFldAlign(PWM_SCAN_10, u4Val, REG_PWM_SCAN4_START_HIGH);
            break;

        case SrcPWM5:
            vIO32WriteFldAlign(PWM_SCAN_11, u4Val, REG_PWM_SCAN5_START_HIGH);
            break;

		case SrcPWM6:
			vIO32WriteFldAlign(PWM_SCAN_11, u4Val, REG_PWM_SCAN6_START_HIGH);
            break;
			
		case SrcPWM7:
			vIO32WriteFldAlign(PWM_SCAN_3D, u4Val, REG_PWM_SCAN7_START_HIGH);
			break;
			
		case SrcPWM8:
			vIO32WriteFldAlign(PWM_SCAN_3D, u4Val, REG_PWM_SCAN8_START_HIGH);
			break;

		default:
            ASSERT(u4Src <= SrcPWM8);
    }

	vDrvScanPWMDataFire();
}

void vDrvSetScanFixHighLow(UINT8 channel, UINT8 mode)
{
	switch(channel)
    {
        case SrcPWM1:
			if (mode==1)            
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN1_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_LOW);		 			 			 			             
            }			
            else if (mode==2)			
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN1_FIXED_LOW);					 			 			 			
            }
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN1_FIXED_LOW);
			}
			break;
		case SrcPWM2:
			if (mode==1)            
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN2_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_LOW);		 			 			 			             
            }			
            else if (mode==2)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_06, 1, REG_PWM_SCAN2_FIXED_LOW);					 			 			 			
			}	
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_06, 0, REG_PWM_SCAN2_FIXED_LOW);
			}
			break;
		case SrcPWM3:
			if (mode==1)            
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN3_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_LOW);		 			 			 			             
            }			
            else if (mode==2)		
            {			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN3_FIXED_LOW);					 			 			 			
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN3_FIXED_LOW);
			}
			break;
		case SrcPWM4:
			if (mode==1)            
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN4_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_LOW);		 			 			 			             
            }			
            else if (mode==2)		
            {			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 1, REG_PWM_SCAN4_FIXED_LOW);					 			 			 			
			}	
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_10, 0, REG_PWM_SCAN4_FIXED_LOW);
			}
			break;
		case SrcPWM5:
			if (mode==1)            
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN5_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_LOW);		 			 			 			             
            }			
            else if (mode==2)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN5_FIXED_LOW);					 			 			 			
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN5_FIXED_LOW);
			}
			break;
		case SrcPWM6:
			if (mode==1)            
            {			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN6_FIXED_HIGH);			 
	            vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_LOW);		 			 			 			             
            }			
            else if (mode==2)			
            {			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 1, REG_PWM_SCAN6_FIXED_LOW);					 			 			 			
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_11, 0, REG_PWM_SCAN6_FIXED_LOW);
			}
			break;
		case SrcPWM7:
			if (mode==1)			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_30, 1, REG_PWM_SCAN7_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_LOW);														 
			}			
			else if (mode==2)			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_30, 1, REG_PWM_SCAN7_FIXED_LOW);														
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_30, 0, REG_PWM_SCAN7_FIXED_LOW);
			}
			break;
		case SrcPWM8:
			if (mode==1)			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_37, 1, REG_PWM_SCAN8_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_LOW);														 
			}			
			else if (mode==2)			
			{			 
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_37, 1, REG_PWM_SCAN8_FIXED_LOW);														
			}
			else
			{
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_HIGH);			 
				vIO32WriteFldAlign(PWM_SCAN_37, 0, REG_PWM_SCAN8_FIXED_LOW);
			}
			break;

		default:
            ASSERT(channel <= SrcPWM8);
	}
}

UINT8 u1DrvGetScanFixHighLow(UINT8 channel)
{
	UINT8 mode;
	mode = 0;
	
	switch(channel)
    {
        case SrcPWM1:
			if (IO32ReadFldAlign(PWM_SCAN_06,REG_PWM_SCAN1_FIXED_HIGH))            
            {	
            	mode = 1;		 			 			 			             
            }			
            else if (IO32ReadFldAlign(PWM_SCAN_06,REG_PWM_SCAN1_FIXED_LOW))			
            {			 
	            mode = 2;					 			 			 			
            }
			else
			{
            	mode = 0;
			}
			break;
		case SrcPWM2:
			if (IO32ReadFldAlign(PWM_SCAN_06,REG_PWM_SCAN2_FIXED_HIGH))            
            {	
            	mode = 1;		 			 			 			             
            }			
            else if (IO32ReadFldAlign(PWM_SCAN_06,REG_PWM_SCAN2_FIXED_LOW))			
            {			 
	            mode = 2;					 			 			 			
            }
			else
			{
            	mode = 0;
			}
			break;
		case SrcPWM3:
			if (IO32ReadFldAlign(PWM_SCAN_10,REG_PWM_SCAN3_FIXED_HIGH))            
            {	
            	mode = 1;		 			 			 			             
            }			
            else if (IO32ReadFldAlign(PWM_SCAN_10,REG_PWM_SCAN3_FIXED_LOW))			
            {			 
	            mode = 2;					 			 			 			
            }
			else
			{
            	mode = 0;
			}
			break;
		case SrcPWM4:
			if (IO32ReadFldAlign(PWM_SCAN_10,REG_PWM_SCAN4_FIXED_HIGH))            
            {	
            	mode = 1;		 			 			 			             
            }			
            else if (IO32ReadFldAlign(PWM_SCAN_10,REG_PWM_SCAN4_FIXED_LOW))			
            {			 
	            mode = 2;					 			 			 			
            }
			else
			{
            	mode = 0;
			}
			break;
		case SrcPWM5:
			if (IO32ReadFldAlign(PWM_SCAN_11,REG_PWM_SCAN5_FIXED_HIGH))            
            {	
            	mode = 1;		 			 			 			             
            }			
            else if (IO32ReadFldAlign(PWM_SCAN_11,REG_PWM_SCAN5_FIXED_LOW))			
            {			 
	            mode = 2;					 			 			 			
            }
			else
			{
            	mode = 0;
			}
			break;
		case SrcPWM6:
			if (IO32ReadFldAlign(PWM_SCAN_11,REG_PWM_SCAN6_FIXED_HIGH))            
            {	
            	mode = 1;		 			 			 			             
            }			
            else if (IO32ReadFldAlign(PWM_SCAN_11,REG_PWM_SCAN6_FIXED_LOW))			
            {			 
	            mode = 2;					 			 			 			
            }
			else
			{
            	mode = 0;
			}
			break;
		case SrcPWM7:
			if (IO32ReadFldAlign(PWM_SCAN_30,REG_PWM_SCAN7_FIXED_HIGH)) 		   
			{	
				mode = 1;														 
			}			
			else if (IO32ReadFldAlign(PWM_SCAN_30,REG_PWM_SCAN7_FIXED_LOW)) 		
			{			 
				mode = 2;														
			}
			else
			{
				mode = 0;
			}
			break;
		case SrcPWM8:
			if (IO32ReadFldAlign(PWM_SCAN_37,REG_PWM_SCAN8_FIXED_HIGH)) 		   
			{	
				mode = 1;														 
			}			
			else if (IO32ReadFldAlign(PWM_SCAN_37,REG_PWM_SCAN8_FIXED_LOW)) 		
			{			 
				mode = 2;														
			}
			else
			{
				mode = 0;
			}
			break;

		default:
            ASSERT(channel <= SrcPWM8);
	}
	return (mode);
}

static void vDrvUpdataPWMCrossZoneStatus(void)
{
	UINT8 i;
	UINT8 src1=1; 
	UINT8 src2=2;

	for (i=SrcPWM1; i<=PWMSCAN_MAX_CH; i++)
	{
		if (PWMSCAN_SETDATA[i].u1Initialed)
		{
			if (src1==1)
			{
				src1 = i;
			}
			else if (src2==2)
			{
				src2 = i;
			}
		}
	}

	if (((PWMSCAN_SETDATA[src1].u1CrossZone == 2)&&(PWMSCAN_SETDATA[src1].u1Initialed == 1))
		||((PWMSCAN_SETDATA[src2].u1CrossZone == 2)&&(PWMSCAN_SETDATA[src2].u1Initialed == 1)))
	{
		u1ScanPwmCrossFlg = 2;
	}	
	else if (((PWMSCAN_SETDATA[src1].u1CrossZone == 1)&&(PWMSCAN_SETDATA[src1].u1Initialed == 1))
		||((PWMSCAN_SETDATA[src2].u1CrossZone ==1)&&(PWMSCAN_SETDATA[src2].u1Initialed ==1)))
	{
		u1ScanPwmCrossFlg = 1;
	}	
	else
	{
		u1ScanPwmCrossFlg = 0;
	}
}

static void vDrvUpdatePWMCrossZoneStatus2(void)
{
	UINT8 i;
	UINT8 src1=1; 
	UINT8 src2=2;

	for (i=SrcPWM1; i<=PWMSCAN_MAX_CH; i++)
	{
		if (PWMSCAN_SETDATA[i].u1Initialed)
		{
			if (src1==1)
			{
				src1 = i;
			}
			else if (src2==2)
			{
				src2 = i;
			}
		}
	}

	if (((PWMSCAN_SETDATA[src1].u1CrossZone == 0)&&(PWMSCAN_SETDATA[src1].u1Initialed == 1))
		||((PWMSCAN_SETDATA[src2].u1CrossZone == 0)&&(PWMSCAN_SETDATA[src2].u1Initialed == 1)))
	{
		u1ScanPwmCrossFlg = 0;
	}	
	else
	{
		u1ScanPwmCrossFlg = 2;
	}
}

UINT32 u4DrvGetScanPWMStructData_Start(UINT8 u1Src)
{
	UINT32 u4Start;
	if (u1Src <= PWMSCAN_MAX_CH)
	{
		u4Start = PWMSCAN_SETDATA[u1Src].u4Start;
		return (u4Start);
	}
	else
	{
		return 0;
	}
}

UINT32 u4DrvGetScanPWMStructData_High(UINT8 u1Src)
{
	UINT32 u4High;
	if (u1Src <= PWMSCAN_MAX_CH)
	{
		u4High = PWMSCAN_SETDATA[u1Src].u4High;
		return (u4High);
	}
	else
	{
		return 0;
	}
}

UINT32 u4DrvGetScanPWMStructData_Low(UINT8 u1Src)
{
	UINT32 u4Low;
	if (u1Src <= PWMSCAN_MAX_CH)
	{
		u4Low = PWMSCAN_SETDATA[u1Src].u4Low;
		return (u4Low);
	}
	else
	{
		return 0;
	}
}

void vDrvSetScanPWMStructData(UINT8 u1Src, UINT32 u4Start, UINT32 u4High, UINT32 u4Low)
{
	if (u1Src <= PWMSCAN_MAX_CH)
	{
		PWMSCAN_SETDATA[u1Src].u4High = u4High;
		PWMSCAN_SETDATA[u1Src].u4Low = u4Low;
		PWMSCAN_SETDATA[u1Src].u4Start= u4Start;			
		LOG(0,"[PWMSCAN_SETDATA]Start=%d, High=%d, Low=%d\n", u4Start, u4High, u4Low);
	}
}

#ifndef CC_MTK_LOADER
static void vDrvSetScanPWMStruct_target(UINT8 u1Src, UINT32 u4High, UINT32 u4Low)
{
	if (u1Src <= PWMSCAN_MAX_CH)
	{
		 PWMSCAN_SETDATA[u1Src].u4High_target = u4High;
		 PWMSCAN_SETDATA[u1Src].u4Low_target = u4Low;	  
	}
}
#endif

UINT8 u1DrvGetScanPWMStruct_Ready(void)
{
	UINT8 u1Ch = 0, u1Ready = 0;;

	for (u1Ch = SrcPWM1; u1Ch <= PWMSCAN_MAX_CH; u1Ch++)
	{
	  if((PWMSCAN_SETDATA[u1Ch].u4High_target == PWMSCAN_SETDATA[u1Ch].u4High)
	  	&& (PWMSCAN_SETDATA[u1Ch].u4Low_target == PWMSCAN_SETDATA[u1Ch].u4Low))
	  {
	   u1Ready |= 1;
	  }
	}
	#if SCANPWM_DEBUGLOG
	LOG(_bScanPWMDbgLogLev+3, "[ScanPWM]u1Ready = %d\n", u1Ready);
	if(!u1Ready)
	{
	 vDrvSetScanPWMSW_SETDATA_Status();	
	}
	#endif
	return(u1Ready);
}

void vDrvSetScanPWMStepControlEn(UINT8 fgEnable)
{
	fgScanPWMSetpControl = fgEnable;
}

void vDrvSetScanPWMStepControl(UINT8 fgEnable, UINT16 u2Step)
{
	vDrvSetScanPWMStepControlEn(fgEnable);
	u2ScanPWMSetp = u2Step;
}

void vDrvSetScanPWMStepTarget(UINT32 u4High, UINT32 u4Low)
{
	UINT8 i;

	for (i=SrcPWM1; i<=PWMSCAN_MAX_CH; i++)
	{
		if (PWMSCAN_SETDATA[i].u1Initialed)
		{
			PWMSCAN_SETDATA[i].u4High_target= u4High;
			PWMSCAN_SETDATA[i].u4Low_target = u4Low;
		}
	}
	fgApplyScanPWMSetData = 1;
}

void vDrvGetScanPWMStepControlStatus(void)
{
	LOG(0,"fgScanPWMSetpControl=%d\n", fgScanPWMSetpControl);
	LOG(0,"u2ScanPWMSetp=%d\n", u2ScanPWMSetp);	
}

UINT16 u2PWMCrossZoneup = 81; // 36 (sync widthe + VBp) + 45

void vDrvSetCrozzUpLimit(UINT16 u2Value)
{
	UINT16 u2Range;
	if (_u4ScanPWMTestPer==255)
		u2Range = 2;
	else  // _u4ScanPWMTestPer=1000 or 1024
		u2Range = 10;

	if (u2Value >= u2Range)
		u2PWMCrossZoneup = u2Value-u2Range;
	else
		u2PWMCrossZoneup = 81;
}

UINT16 u2DrvGetCrozzUpLimit(void)
{
	return u2PWMCrossZoneup;
}

static void vDrvSetScanPWMStruct(UINT8 u1Src, UINT32 u4Start, UINT32 u4High, UINT32 u4Low)
{
   UINT8 u1DoubleFrame=0;
   UINT32 u4LineTotalCur = 0,u4LineTotalCur2 = 0;
   UINT16 u2CrossLine = 0, u2CrossLine_top = 0;      

   #if SCANPWM_DEBUGLOG
   LOG(_bScanPWMDbgLogLev, "[ScanPWM]u1Src=%d, u4Start=%d, u4High=%d, u4Low=%d \n",u1Src,u4Start, u4High, u4Low);
   #endif
   if (u1Src <= PWMSCAN_MAX_CH)
   {
   		if (PWMSCAN_SETDATA[u1Src].u1Initialed != 1)
   		{
			PWMSCAN_SETDATA[u1Src].u4High_target= u4High;
			PWMSCAN_SETDATA[u1Src].u4Low_target = u4Low;	 
   		}
   		PWMSCAN_SETDATA[u1Src].u1Initialed = 1;
   		PWMSCAN_SETDATA[u1Src].u4Start = u4Start;
   		PWMSCAN_SETDATA[u1Src].u4High = u4High;
   		PWMSCAN_SETDATA[u1Src].u4Low = u4Low;    
   
   		if (((u4High+u4Low)<510) || ((u4High+u4Low)<137))
   		{
     		u1DoubleFrame =1;
   		}  

   		if(u1DoubleFrame)
  		{
     		u4LineTotalCur = (u4Start + u4High + u4Low + u4High);
			u4LineTotalCur2 = u4LineTotalCur;
			if(u4LineTotalCur>_u4ScanPWMTestPer)
			{
				#if SCANPWM_DEBUGLOG
				LOG(_bScanPWMDbgLogLev+3, "[ScanPWM]DoubleFrame #1\n");
				#endif
				u4LineTotalCur = (u4LineTotalCur - _u4ScanPWMTestPer);
			}
			else
			{
				#if SCANPWM_DEBUGLOG
				LOG(_bScanPWMDbgLogLev+3, "[ScanPWM]DoubleFrame #2\n");
				#endif
				u4LineTotalCur = (u4Start + u4High);
			}
   		}
   		else
   		{
     		u4LineTotalCur = (u4Start + u4High);
			u4LineTotalCur2 = u4LineTotalCur;
			if(u4LineTotalCur>_u4ScanPWMTestPer)
			{
				#if SCANPWM_DEBUGLOG
				LOG(_bScanPWMDbgLogLev+3, "[ScanPWM]SingleFrame #0\n");
				#endif
				u4LineTotalCur = (u4LineTotalCur - _u4ScanPWMTestPer);
			}			
   		}   
		#if SCANPWM_DEBUGLOG
   		LOG(_bScanPWMDbgLogLev, "[ScanPWM]u4LineTotalCur=%d\n",u4LineTotalCur);
   		#endif
		u2CrossLine = wDrvGetOutputVTotal()-wDrvGetOutputVActive()-wDrvGetVsyncFp(); // [Apply point1 position] VDE Rising
		#if SCANPWM_DEBUGLOG
   		LOG(_bScanPWMDbgLogLev, "[ScanPWM]u2CrossLine=%d(line)\n",u2CrossLine);
   		#endif
		u2CrossLine = u2CrossLine * _u4ScanPWMTestPer / wDrvGetOutputVTotal();
		#if SCANPWM_DEBUGLOG
   		LOG(_bScanPWMDbgLogLev, "[ScanPWM]u2CrossLine=%d(%)\n",u2CrossLine);
   		#endif
		if (_u4ScanPWMTestPer==255)
			u2CrossLine_top = u2CrossLine + 12;
		else  // _u4ScanPWMTestPer=1000 or 1024
			u2CrossLine_top = u2CrossLine + 45;
		#if SCANPWM_DEBUGLOG
   		LOG(_bScanPWMDbgLogLev, "[ScanPWM]u2CrossLine_top=%d(%)\n",u2CrossLine_top);
   		#endif
		vDrvSetCrozzUpLimit(u2CrossLine_top);

		if(fgScanPWMSetpControl)
		{
		// Use apply point 2 instead of apply point 1 to avoid VDE rising set  next step transient
		// if((u4LineTotalCur >= 0) && (u4LineTotalCur <= u2CrossLine_top))  // pointless comparison of unsigned integer with zero
		if((u4LineTotalCur >= 0) && (u4LineTotalCur <= u2CrossLine_top))
		{

 			PWMSCAN_SETDATA[u1Src].u1CrossZone = 1;  // OR 2
			#if SCANPWM_DEBUGLOG
	   		LOG(_bScanPWMDbgLogLev, "[ScanPWM][Step_ctrl]VDE_R_ZONE->VDE_F\n");
	   		#endif
		}
		else
   		{
     		PWMSCAN_SETDATA[u1Src].u1CrossZone = 0;
			#if SCANPWM_DEBUGLOG
	   		LOG(_bScanPWMDbgLogLev, "[ScanPWM][Step_ctrl]VDE_F_ZONE->TCON_ISR\n");
	   		#endif
   		}   

   		PWMSCAN_SETDATA[u1Src].u4LineTotalPre = u4LineTotalCur2;
   		vDrvUpdataPWMCrossZoneStatus();
		}
		else
		{
			  if(u4LineTotalCur >= u2CrossLine_top)
			  {
			 	PWMSCAN_SETDATA[u1Src].u1CrossZone = 0;
				#if SCANPWM_DEBUGLOG
		   		LOG(_bScanPWMDbgLogLev, "[ScanPWM][Step_ctrl]VDE_F_ZONE->TCON_ISR\n");
		   		#endif
			  }
			  else
			  {
			  	PWMSCAN_SETDATA[u1Src].u1CrossZone = 2;
				#if SCANPWM_DEBUGLOG
		   		LOG(_bScanPWMDbgLogLev, "[ScanPWM][Step_ctrl]OutVsyncISR setdata\n");
		   		#endif
			  }
			  
	     PWMSCAN_SETDATA[u1Src].u4LineTotalPre = u4LineTotalCur;		
		 vDrvUpdatePWMCrossZoneStatus2(); 
		}
   }
}

void vDrvSetScanPWMSW_StepControl(void)
{
	UINT32 u4HighChg=0, u4LowChg=0;

	UINT8 u1Ch = 0;

	for (u1Ch = SrcPWM1; u1Ch <= PWMSCAN_MAX_CH; u1Ch++)
	{
		if((PWMSCAN_SETDATA[u1Ch].u4High_target != PWMSCAN_SETDATA[u1Ch].u4High)
		|| (PWMSCAN_SETDATA[u1Ch].u4Low_target != PWMSCAN_SETDATA[u1Ch].u4Low))	
		{
			#if SCANPWM_DEBUGLOG
			LOG(_bScanPWMDbgLogLev+3, "[ScanPWM]High_step=%d, Low_step=%d \n",PWMSCAN_SETDATA[u1Ch].u4High,PWMSCAN_SETDATA[u1Ch].u4Low);
			#endif
			
			if (PWMSCAN_SETDATA[u1Ch].u4High_target >= PWMSCAN_SETDATA[u1Ch].u4High)
			{
				u4HighChg = PWMSCAN_SETDATA[u1Ch].u4High + u2ScanPWMSetp;
				if (u4HighChg > PWMSCAN_SETDATA[u1Ch].u4High_target)
				{
				 u4HighChg = PWMSCAN_SETDATA[u1Ch].u4High_target;	
				} 
			}
			else
			{
				u4HighChg = PWMSCAN_SETDATA[u1Ch].u4High - u2ScanPWMSetp;				
				if (u4HighChg < PWMSCAN_SETDATA[u1Ch].u4High_target)
				{
				 u4HighChg = PWMSCAN_SETDATA[u1Ch].u4High_target;	
				} 				
			}
		
			if (PWMSCAN_SETDATA[u1Ch].u4Low_target >= PWMSCAN_SETDATA[u1Ch].u4Low)
			{
				u4LowChg = PWMSCAN_SETDATA[u1Ch].u4Low + u2ScanPWMSetp;
				if (u4LowChg > PWMSCAN_SETDATA[u1Ch].u4Low_target)
				{
				 u4LowChg = PWMSCAN_SETDATA[u1Ch].u4Low_target;	
				} 				
			}
			else
			{
				u4LowChg = PWMSCAN_SETDATA[u1Ch].u4Low - u2ScanPWMSetp; 			
				if (u4LowChg < PWMSCAN_SETDATA[u1Ch].u4Low_target)
				{
				 u4LowChg = PWMSCAN_SETDATA[u1Ch].u4Low_target;	
				} 								
			}
			#if SCANPWM_DEBUGLOG
			LOG(_bScanPWMDbgLogLev+3, "[ScanPWM]u4HighChg=%d, u4LowChg=%d \n",u4HighChg,u4LowChg);
			#endif
			
			vDrvSetScanPWMStruct(u1Ch,PWMSCAN_SETDATA[u1Ch].u4Start,u4HighChg,u4LowChg);			
		}
	}
}


void vDrvSetScanPWMSW(UINT8 u1Src, UINT32 u4Start, UINT32 u4High, UINT32 u4Low)
{
#ifndef CC_MTK_LOADER 
    // CRIT_STATE_T csState;
    // csState = x_crit_start();
#endif     

#ifndef CC_MTK_LOADER
	{
	    vDrvSetScanPWMStruct_target(u1Src,u4High,u4Low);
		
		if (!fgScanPWMSetpControl)
		{
 		 vDrvSetScanPWMStruct(u1Src,u4Start,u4High,u4Low);
		}
		
         fgApplyScanPWMSetData = 1;        
		
        vDrvSetScanPWMLatchMode(SCAN_PWM_LATCH_MODE_SETDATA,SCAN_PWM_LATCH_MODE_OFF,SCAN_PWM_ALIGN_MODE_VSYNC);  // Set data
	}	
#else   
    {
    	vDrvSetScanPWM(u1Src, u4Start, u4High, u4Low);
		vDrvSetScanPWMStruct(u1Src,u4Start,u4High,u4Low);
        vDrvSetScanPWMLatchMode(SCAN_PWM_LATCH_MODE_SETDATA_OFF,SCAN_PWM_LATCH_MODE_OFF,SCAN_PWM_ALIGN_MODE_ONCE);  // Aligned at once
        vDrvScanPWMDataFire();
    }
#endif



#ifndef CC_MTK_LOADER    
    // x_crit_end(csState);
#endif    

}

void vDrvSetScanPWMSW_SETDATA(void)
{
	UINT8 i;
	
	for (i=SrcPWM1; i<=PWMSCAN_MAX_CH; i++)
	{
		if (PWMSCAN_SETDATA[i].u1Initialed)
		{
			vDrvSetScanPWM(i, PWMSCAN_SETDATA[i].u4Start, PWMSCAN_SETDATA[i].u4High, PWMSCAN_SETDATA[i].u4Low );
		#if SCANPWM_DEBUGLOG
			LOG(_bScanPWMDbgLogLev, "[ScanPWM]vDrvSetScanPWMSW_SETDATA: src=%d S=%d H=%d L=%d\n", i, PWMSCAN_SETDATA[i].u4Start, PWMSCAN_SETDATA[i].u4High, PWMSCAN_SETDATA[i].u4Low);
		#endif
		}
	}
}

void vDrvSetScanPWMSW_SETDATA_Status(void)
{
	UINT8 u1Ch = 0;

	for (u1Ch = SrcPWM1; u1Ch <= PWMSCAN_MAX_CH; u1Ch++)
	{
	 LOG(0,"[SCAN_PWM_%d] u1Initialed=%d, u4Start=%d, u4High=%d,  u4Low=%d , u4High_target=%d,  u4Low_target=%d\n",u1Ch,PWMSCAN_SETDATA[u1Ch].u1Initialed, PWMSCAN_SETDATA[u1Ch].u4Start, PWMSCAN_SETDATA[u1Ch].u4High, PWMSCAN_SETDATA[u1Ch].u4Low, PWMSCAN_SETDATA[u1Ch].u4High_target, PWMSCAN_SETDATA[u1Ch].u4Low_target);	
	 LOG(0,"[SCAN_PWM_%d] u4LineTotalPre=%d, u1CrossZone=%d\n",u1Ch,PWMSCAN_SETDATA[u1Ch].u4LineTotalPre, PWMSCAN_SETDATA[u1Ch].u1CrossZone);		 
	}
	LOG(0,"[ScanPWM]u2PWMCrossZoneup = %d \n",u2DrvGetCrozzUpLimit());
}

void vDrvSetISOnOff(UINT8 u1Src, UINT8 u1OnOff)
{
    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
        case MINILVDS_IS_VSYNC:
            vIO32WriteFldAlign(VINTF_P20, u1OnOff, VINTF_INV_SYNC_START);
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }
}

void vDrvScanPWMAutoTest(void)
{
	UINT32 u4Devider=1;
	static UINT32 u4High1 ;
	u4Devider = _u4ScanPWMTesFreq;

	if (_fgScanPWMAuto==TRUE)
	{
		if (_u1ScanPWMTestChg==1)
		{
			if (_u4ScanPWMTestHigh>_u4ScanPWMTestBottom)
			{
				u4High1 = _u4ScanPWMTestHigh/u4Devider;
				_u4ScanPWMTestLow = (1000 - (_u4ScanPWMTestHigh))/u4Devider;
				LOG(6, "#1 u4Devider=%d, u4High1=%d, Low=%d\n", u4Devider,u4High1,_u4ScanPWMTestLow);
				vDrvSetScanPWMSW(_u1ScanPWMTestSrc,_i4ScanPWMTestStart,u4High1,_u4ScanPWMTestLow);
				_u4ScanPWMTestHigh--;
			}
			if (_u4ScanPWMTestHigh == _u4ScanPWMTestBottom)
			{
				_u4ScanPWMTestHigh = _u4ScanPWMTestTop;
				vDrvSetScanPWMStructData(_u1ScanPWMTestSrc,_i4ScanPWMTestStart,_u4ScanPWMTestHigh/u4Devider,((1000 - (_u4ScanPWMTestHigh))/u4Devider));
			}
		}
		else if (!_u1ScanPWMTestChg)
		{
			if (_u4ScanPWMTestHigh<_u4ScanPWMTestTop)
			{
				u4High1 = _u4ScanPWMTestHigh/u4Devider;
				_u4ScanPWMTestLow = (1000 - (_u4ScanPWMTestHigh))/u4Devider;
				LOG(6, "#0 u4Devider=%d, u4High1=%d, Low=%d\n", u4Devider,u4High1,_u4ScanPWMTestLow);
				vDrvSetScanPWMSW(_u1ScanPWMTestSrc,_i4ScanPWMTestStart,u4High1,_u4ScanPWMTestLow);
				_u4ScanPWMTestHigh++;
			}
			if (_u4ScanPWMTestHigh == _u4ScanPWMTestTop)
			{
				_u4ScanPWMTestHigh = _u4ScanPWMTestBottom;
				vDrvSetScanPWMStructData(_u1ScanPWMTestSrc,_i4ScanPWMTestStart,_u4ScanPWMTestHigh/u4Devider,((1000 - (_u4ScanPWMTestHigh))/u4Devider));
			}
		}
	}
}

void vDrvSetISMaskNum(UINT8 u1Src, UINT8 u1MaskNum)
{
    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
            vIO32WriteFldAlign(VINTF_P21, u1MaskNum, VINTF_IS_MASK_LEN_H);
            break;

        case MINILVDS_IS_VSYNC:
            vIO32WriteFldAlign(VINTF_P23, u1MaskNum, VINTF_IS_MASK_LEN_V);
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }
}

void vDrvSetISInputInverse(UINT8 u1Src, UINT8 u1Enable)
{
    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
            vIO32WriteFldAlign(VINTF_P20, u1Enable, VINTF_IS_POL_H);
            break;

        case MINILVDS_IS_VSYNC:
            vIO32WriteFldAlign(VINTF_P22, u1Enable, VINTF_IS_POL_V);
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }
}

void vDrvSetISDelayOnOff(UINT8 u1Src, UINT8 u1OnOff)
{
    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
        case MINILVDS_IS_VSYNC:
            vIO32WriteFldAlign(VINTF_P20, u1OnOff, VINTF_IS_FORCE_DELAY);
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }
}

void vDrvSetISDelayNum(UINT8 u1Src, UINT16 u2DelayNum)
{
    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
            vIO32WriteFldAlign(VINTF_P20, u2DelayNum, VINTF_IS_DELAY_H);
            break;

        case MINILVDS_IS_VSYNC:
            vIO32WriteFldAlign(VINTF_P22, u2DelayNum, VINTF_IS_DELAY_V);
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }
}

void vDrvSetISHoldOnOff(UINT8 u1Src, UINT8 u1OnOff)
{
    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
            vIO32WriteFldAlign(VINTF_P20, u1OnOff, VINTF_IS_HOLD_EN_H);
            break;

        case MINILVDS_IS_VSYNC:
            vIO32WriteFldAlign(VINTF_P22, u1OnOff, VINTF_IS_HOLD_EN_V);
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }
}

void vDrvSetISRelation(UINT8 u1Src, UINT8 u1SyncCnt, UINT8 u1ISSyncCnt)
{
    UINT32 u4Total =0, u4ISTotal=0;
    UINT8 u1Scatter =0;

    if(u1SyncCnt >= 15) u1SyncCnt = 15;

    if(u1ISSyncCnt >= 15) u1ISSyncCnt = 15;

    if(u1SyncCnt == 0) u1SyncCnt = 1;

    if(u1ISSyncCnt == 0) u1ISSyncCnt = 1;

    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
            u4Total = wDrvGetOutputHTotal();
            break;

        case MINILVDS_IS_VSYNC:
            u4Total = wDrvGetOutputVTotal();
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }

    u4ISTotal = (u4Total * u1SyncCnt) / u1ISSyncCnt;
    u1Scatter =(UINT8) ((u4Total * u1SyncCnt) % u1ISSyncCnt);

    switch(u1Src)
    {
        case MINILVDS_IS_HSYNC:
            vIO32WriteFldAlign(VINTF_P20, u1ISSyncCnt, VINTF_IS_DIV_H);
            vIO32WriteFldAlign(VINTF_P20, u1SyncCnt, VINTF_IS_MUL_H);
            vIO32WriteFldAlign(VINTF_P20, u1Scatter, VINTF_SYNC_TOTAL_PLUS_1_H);
            vIO32WriteFldAlign(VINTF_P21, u4ISTotal, VINTF_IS_PWM_SYNC_TOTAL_H);
            break;

        case MINILVDS_IS_VSYNC:
            vIO32WriteFldAlign(VINTF_P22, u1ISSyncCnt, VINTF_IS_DIV_V);
            vIO32WriteFldAlign(VINTF_P22, u1SyncCnt, VINTF_IS_MUL_V);
            vIO32WriteFldAlign(VINTF_P23, u1Scatter, VINTF_IS_LEN_PLUS_1_V);
            vIO32WriteFldAlign(VINTF_P23, u4ISTotal, VINTF_IS_PWM_SYNC_TOTAL_V);
            break;

        default:
            ASSERT(u1Src <= MINILVDS_IS_VSYNC);
    }
}

#ifdef CC_SUPPORT_STR
//-----------------------------------------------------------------------------
/** PWM_pm_str_suspend
 */
//-----------------------------------------------------------------------------
static  UINT32 PWM[6];
void PWM_pm_str_suspend(void)
{
    UINT32 u4Reg;
	// power off
	CKGEN_WRITE32(0x1CC, CKGEN_READ32(0x1CC) & ~(1U << 10));

    u4Reg = REG_RW_PWM0;
    PWM[0] = IO_READ32(HPDS_BASE, u4Reg);
    PWM[1] = IO_READ32(HPDS_BASE, u4Reg + 4);
    u4Reg = REG_RW_PWM1;
    PWM[2] = IO_READ32(HPDS_BASE, u4Reg);
    PWM[3] = IO_READ32(HPDS_BASE, u4Reg + 4);
    u4Reg = REG_RW_PWM2;
    PWM[4] = IO_READ32(HPDS_BASE, u4Reg);
    PWM[5] = IO_READ32(HPDS_BASE, u4Reg + 4);
   
}


//-----------------------------------------------------------------------------
/** PWM_pm_str_resume
 */
//-----------------------------------------------------------------------------
void PWM_pm_str_resume(void)
{
    UINT32 u4Reg;
	CKGEN_WRITE32(0x1CC, CKGEN_READ32(0x1CC) | (1U << 10));

    u4Reg = REG_RW_PWM0;
    IO_WRITE32(HPDS_BASE, u4Reg, PWM[0]);
    IO_WRITE32(HPDS_BASE, u4Reg + 4, PWM[1]);
    u4Reg = REG_RW_PWM1;
    IO_WRITE32(HPDS_BASE, u4Reg, PWM[2]);
    IO_WRITE32(HPDS_BASE, u4Reg + 4, PWM[3]);
    u4Reg = REG_RW_PWM2;
    IO_WRITE32(HPDS_BASE, u4Reg, PWM[4]);
    IO_WRITE32(HPDS_BASE, u4Reg + 4, PWM[5]);

}
#endif // CC_SUPPORT_STR


