//------------------------------------------------------------------------------
//
//  Copyright (C) 2004-2007, Freescale Semiconductor, Inc. All Rights Reserved.
//  THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
//  AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//------------------------------------------------------------------------------
//
//  File:  sdc.c
//
//  Init IPU for SDC operations
//
//------------------------------------------------------------------------------

#pragma warning(push)
#pragma warning(disable: 4115 4201 4204 4214)
#include <windows.h>
#include <Winbase.h>
#include <ceddk.h>
#pragma warning(pop)

#include "bsp.h"
#include "ipu.h"
#include "sdc.h"

//------------------------------------------------------------------------------
// External Functions
extern void BSPDisplayIOMUXEnable(IPU_DRIVE_TYPE);
extern void BSPDisplayIOMUXDisable(IPU_DRIVE_TYPE);


//------------------------------------------------------------------------------
// External Variables


//------------------------------------------------------------------------------
// Defines
#define SDC_DMA_CHANNEL             IPU_DMA_CHA_DMASDC_0_LSH    //  background
#define VF_DMA_CHANNEL              IPU_DMA_CHA_DMASDC_1_LSH    //  foreground
#define GRAPHICS_DMA_CHANNEL        IPU_DMA_CHA_DMASDC_1_LSH    //  foreground

#define FLOW_ARM                    0
#define FLOW_ROT_VF                 1
#define FLOW_ROT_PP                 2
#define FLOW_VF                     3
#define FLOW_PP                     4
#define FLOW_SNOOP                  5
#define FLOW_AUTO_REF               6
#define FLOW_AUTO_REF_SNOOP         7

#define SDC_ERROR                   DEBUGZONE(0)
#define DELAYTIMEOUT                20000

#define TVOUT_FS453                 1


//------------------------------------------------------------------------------
// Types


//------------------------------------------------------------------------------
// Global Variables
PCSP_IPU_REGS g_pIPU;
static HANDLE g_hIPUBase = NULL;
UINT32 g_IPUClk;

//TODO: replace this with registry driven values
// note that the "numPanelTypes" related enum kind of duplicates
// the enum in ddipu related to numPanels.  This array
// really should be numPanels, but since we need to move to
// the registry anyways, we'll keep this for now.
PANEL_INFO g_PanelArray[numPanelTypes] =
{
    // User mode stub
    {
        "User Panel 0",        	      // Name
        IPU_PANEL_USER0, 	         // type
        IPU_PIX_FMT_RGB565,          // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        240,                         // width
        320,                         // height
        60,                          // frequency
        1,                           // Vertical Sync width
        8,                           // Vertical Start Width
        80,                          // Vertical End Width
        1,                           // Horizontal Sync Width
        3,                           // Horizontal Start Width
        10,                          // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {       // Display Interface signal polarities
            FALSE,                       // Data mask enable
            TRUE,                        // Clock Idle enable
            FALSE,                       // Clock Select Enable
            FALSE,                       // Vertical Sync Polarity
            FALSE,                       // Output enable polarity(straight polarity for sharp signals)
            TRUE,                        // Data Pol   Inverse polarity.
            TRUE,                        // Clock Pol  Inverse polarity.
            TRUE,                        // HSync Pol
        }
    },

    // 5.7" Sharp
    {
        "Sharp 5.7in. QVGA Panel",          // Name
        IPU_PANEL_SHARP_57QVGA,         // type
        IPU_PIX_FMT_RGB666,           // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        320,                          // width
        240,                          // height
        60,                          // frequency
        2,                            // Vertical Sync width
        5,                         // Vertical Start Width
        20,                         // Vertical End Width
        20,                         // Horizontal Sync Width
        40,                         // Horizontal Start Width
        10,                         // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {      //Display Interface signal polarities
            FALSE,                        // Data mask enable
            FALSE,                        // Clock Idle enable
            FALSE,                        // Clock Select Enable
            FALSE,                        // Vertical Sync Polarity - active high
            TRUE,                         // Output enable polarity (straight polarity for VGA signals)
            FALSE,                        // Data Pol   FOR SURE FALSE HERE
            FALSE,                        // Clock Pol  Straight polarity.
            TRUE,                        // HSync Pol - active high
        }
    },

	// 12" or SVGA Panel definitions
    {
        "Sharp 12.1in SVGA Panel",              // Name
        IPU_PANEL_SHARP_121SVGA,            // type
        IPU_PIX_FMT_RGB666,           // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        800,                          // width
        600,                          // height
        60,                          // frequency
        4,                            // Vertical Sync width
        23,                         // Vertical Start Width
        100,                         // Vertical End Width
        5,                         // Horizontal Sync Width
        88,                         // Horizontal Start Width
        120,                         // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {      //Display Interface signal polarities
            FALSE,                        // Data mask enable
            FALSE,                        // Clock Idle enable
            FALSE,                        // Clock Select Enable
            FALSE,                        // Vertical Sync Polarity - active low
            TRUE,                         // Output enable polarity - straight
            FALSE,                        // Data Pol   FOR SURE FALSE HERE
            FALSE,                         // Clock Pol
            FALSE,                        // HSync Pol - active low
        }
    },

    //3.6" Sharp Panel definitions
    {
        "Sharp 3.6 QVGA Panel",              // Name
        IPU_PANEL_SHARP_36QVGA,            // type
        IPU_PIX_FMT_RGB666,           // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        320,                          // width
        240,                          // height
        60,                          // frequency
        2,                            // Vertical Sync width
        3,                         // Vertical Start Width
        3,                         // Vertical End Width
        20,                         // Horizontal Sync Width
        20,                         // Horizontal Start Width
        20,                         // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {      //Display Interface signal polarities
            FALSE,                        // Data mask enable
            FALSE,                        // Clock Idle enable
            FALSE,                        // Clock Select Enable
            TRUE,                        // Vertical Sync Polarity - active high
            TRUE,                         // Output enable polarity (straight polarity for VGA signals)
            FALSE,                        // Data Pol   FOR SURE FALSE HERE
            FALSE,                        // Clock Pol  Straight polarity.
            TRUE,                        // HSync Pol - active high
        }
    },

    // User mode stub
    {
        "Reserved Panel",          // Name
        IPU_PANEL_RSVD,         // type
        IPU_PIX_FMT_RGB565,          // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        240,                         // width
        320,                         // height
        60,                          // frequency
        1,                           // Vertical Sync width
        8,                           // Vertical Start Width
        80,                          // Vertical End Width
        1,                           // Horizontal Sync Width
        3,                           // Horizontal Start Width
        10,                          // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {       // Display Interface signal polarities
            FALSE,                       // Data mask enable
            TRUE,                        // Clock Idle enable
            FALSE,                       // Clock Select Enable
            FALSE,                       // Vertical Sync Polarity
            FALSE,                       // Output enable polarity(straight polarity for sharp signals)
            TRUE,                        // Data Pol   Inverse polarity.
            TRUE,                        // Clock Pol  Inverse polarity.
            TRUE,                        // HSync Pol
        }
    },

	// 6.4" Sharp VGA Panel definitions
    {
        "Sharp 6.4 VGA Panel",              // Name
        IPU_PANEL_SHARP_64VGA,            // type
        IPU_PIX_FMT_RGB666,           // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        640,                          // width
        480,                          // height
        60,                          // frequency
        2,                            // Vertical Sync width
        32,                         // Vertical Start Width
        10,                         // Vertical End Width
        49,                         // Horizontal Sync Width
        137,                         // Horizontal Start Width
        25,                         // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {      //Display Interface signal polarities
            FALSE,                        // Data mask enable
            FALSE,                        // Clock Idle enable
            FALSE,                        // Clock Select Enable
            FALSE,                        // Vertical Sync Polarity - active low*
            TRUE,                         // Output enable polarity - straight
            FALSE,                        // Data Pol   FOR SURE FALSE HERE
            FALSE,                         // Clock Pol*
            FALSE,                        // HSync Pol - active low*
        }
    },

    // 3.5" Sharp Panel LQ035Q7DB02
    {
        "Sharp 3.5 QVGA Panel",          // Name
        IPU_PANEL_SHARP_35HRQVGA,         // type
        IPU_PIX_FMT_RGB565,          // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        240,                         // width
        320,                         // height
        60,                          // frequency
        1,                           // Vertical Sync width
        8,                           // Vertical Start Width
        80,                          // Vertical End Width
        1,                           // Horizontal Sync Width
        3,                           // Horizontal Start Width
        10,                          // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {       // Display Interface signal polarities
            FALSE,                       // Data mask enable
            TRUE,                        // Clock Idle enable
            FALSE,                       // Clock Select Enable
            FALSE,                       // Vertical Sync Polarity
            FALSE,                       // Output enable polarity(straight polarity for sharp signals)
            FALSE,                        // Data Pol   Inverse polarity.
            TRUE,                        // Clock Pol  Inverse polarity.
            TRUE,                        // HSync Pol (FALSE = active low)
        }
    },

	// 10.4" Sharp VGA Panel definitions
    {
        "Sharp 10.4in VGA Panel",              // Name
        IPU_PANEL_SHARP_104VGA,            // type
        IPU_PIX_FMT_RGB666,           // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        640,                          // width
        480,                          // height
        60,                          // frequency
        2,                            // Vertical Sync width
        32,                         // Vertical Start Width
        10,                         // Vertical End Width
        49,                         // Horizontal Sync Width
        137,                         // Horizontal Start Width
        25,                         // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {      //Display Interface signal polarities
            FALSE,                        // Data mask enable
            FALSE,                        // Clock Idle enable
            FALSE,                        // Clock Select Enable
            FALSE,                        // Vertical Sync Polarity - active low*
            TRUE,                         // Output enable polarity - straight
            FALSE,                        // Data Pol   FOR SURE FALSE HERE
            FALSE,                         // Clock Pol*
            FALSE,                        // HSync Pol - active low*
        }
    },

	// 3.5" Sharp QVGA TFT ASIC Panel definitions
    {
        "Sharp 3.5 QVGA Panel w/ASIC",              // Name
        IPU_PANEL_SHARP_35QVGA,            // type
        IPU_PIX_FMT_RGB666,           // Pixel Format
        DISPLAY_MODE_DEVICE,         // Mode ID
        240,                          // width
        320,                          // height
        60,                          // frequency
        3,                            // Vertical Sync width
        5,                         // Vertical Start Width
        20,                         // Vertical End Width
        14,                         // Horizontal Sync Width
        59,                         // Horizontal Start Width
        3,                         // Horizontal End Width
        ADC_SETTING_FOR_SDC_PANEL,
        {      //Display Interface signal polarities
            FALSE,                        // Data mask enable
            FALSE,                        // Clock Idle enable
            FALSE,                        // Clock Select Enable
            TRUE,                        // Vertical Sync Polarity - active high
            TRUE,                         // Output enable polarity (straight polarity for VGA signals)
            FALSE,                        // Data Pol   FOR SURE FALSE HERE
            FALSE,                        // Clock Pol  Straight polarity.
            TRUE,                        // HSync Pol - active high
        }
    },

    // New Panel definitions go here
    // Put other Panel info here in future expasion
};

//------------------------------------------------------------------------------
// Local Variables
static HANDLE ipu_mutex;
static BOOL   need_map = TRUE;
static HANDLE g_hSDCBGIntrEvent = NULL;
static HANDLE g_hSDCFGIntrEvent = NULL;
static HANDLE g_hSDCIntrThread = NULL;
static const UINT32 m_RefreshRate = 60;
static UINT8 g_iSDCFGNextBuffer = 0;
static PANEL_INFO *g_pCurrentPanel;
static UINT32 g_SDCFGBuf_Saved = 0;
static int g_iXValMax = 0;
static int g_iCurrentFGXP = 0;


//------------------------------------------------------------------------------
// Local Functions
static void _init_dma(int width, int height, int bpp, int stride, BOOL vFlip, const UINT channel, IPU_PANEL_TYPE type);
static void SetSrcBuffer(int channel, PHYSICAL_ADDRESS *pAddr, DISP_BUF_TYPE bufNum);

//------------------------------------------------------------------------------
//
// Function: InitializeSDC
//
// This function initializes SDC related bits in IPU common registers, the
// IPU SDC registers and IDMAC registers for SDC operation.
//
// Parameters:
//      width
//          [in] width of the display
//      height
//          [in] height of the display
//      bpp
//          [in] bits per pixel of the display
//
// Returns:
//      TRUE if successful.
//------------------------------------------------------------------------------
UINT32 InitializeSDC(PANEL_INFO *currentPanel, int bpp, int width, int height, ULONG m_SkipLCDCInit)
{
    UINT32 ret = FALSE, temp = 0, m_PixelClock = 0, m_PixelDivider;
    PHYSICAL_ADDRESS phyAddr;
    SDC_IPU_DI_SIGNAL_CFG m_SignalPol; // variable to contain Polling information
    HANDLE hBKEvent;
    
    if (need_map == TRUE)
    {
        phyAddr.QuadPart = CSP_BASE_REG_PA_IPU;

        // Map peripheral physical address to virtual address
        g_pIPU = (PCSP_IPU_REGS)MmMapIoSpace(phyAddr, sizeof(CSP_IPU_REGS), FALSE);

        // Check if virtual mapping failed
        if (g_pIPU == NULL)
        {
            DEBUGMSG(SDC_ERROR,
                     (TEXT("%s(): MmMapIoSpace failed!\r\n"), __WFUNCTION__));
            return ret;
        }
        
        // Turn on clock for IPU
        DDKClockSetGatingMode(DDK_CLOCK_GATE_INDEX_IPU, DDK_CLOCK_GATE_MODE_ENABLED_ALL);

        need_map = FALSE;
    }

        // Create event for IPU interrupt for SDC BG EOF
        g_hSDCBGIntrEvent = CreateEvent(NULL, FALSE, FALSE, IPU_SDC_BG_INTR_EVENT);
        if (g_hSDCBGIntrEvent == NULL)
        {
            DEBUGMSG(SDC_ERROR,
                (TEXT("%s: CreateEvent for IPU Interrupt failed\r\n"), __WFUNCTION__));
            return ret;
        }

        // Create event for IPU interrupt for SDC FG EOF
        g_hSDCFGIntrEvent = CreateEvent(NULL, FALSE, FALSE, IPU_SDC_FG_INTR_EVENT);
        if (g_hSDCFGIntrEvent == NULL)
        {
            DEBUGMSG(SDC_ERROR,
                (TEXT("%s: CreateEvent for IPU Interrupt failed\r\n"), __WFUNCTION__));
            return ret;
        }

        // One-time creation of g_hIPUBase handle
        if (g_hIPUBase == NULL)
        {
            // open handle to the IPU_BASE driver in order to enable IC module
            g_hIPUBase = CreateFile(TEXT("IPU1:"),        // "special" file name
                GENERIC_READ|GENERIC_WRITE,                 // desired access
                FILE_SHARE_READ|FILE_SHARE_WRITE,        // sharing mode
                NULL,                                                           // security attributes (=NULL)
                OPEN_EXISTING,                                          // creation disposition
                FILE_FLAG_RANDOM_ACCESS,                      // flags and attributes
                NULL);                                                         // template file (ignored)
            if (g_hIPUBase == INVALID_HANDLE_VALUE)
            {
                DEBUGMSG(SDC_ERROR,
                    (TEXT("%s: Opening IPU_BASE handle failed!\r\n"), __WFUNCTION__));
                return ret;
            }
        }

    //----- General configuration

    // Set little endian
    INSREG32BF(&g_pIPU->IPU_CONF,
                IPU_IPU_CONF_PXL_ENDIAN, IPU_LITTLE_ENDIAN);

   if (!m_SkipLCDCInit)
   {
      m_SignalPol = currentPanel -> SDC_SIG_POL;
    //----- Display interface configuration
    switch(currentPanel -> TYPE)
    {
        case IPU_PANEL_SHARP_35HRQVGA:
            //... SDC_COM_CONF
            OUTREG32( &g_pIPU->SDC_COM_CONF,
               //.. SDC mode
                CSP_BITFVAL(IPU_SDC_COM_CONF_SDC_MODE, IPU_SDC_MODE_TFT_COLOR)|
               //.. sharp pannel enable
                CSP_BITFVAL(IPU_SDC_COM_CONF_SHARP, 0x1)|
               //.. dual mode enable
                CSP_BITFVAL(IPU_SDC_COM_CONF_DUAL_MODE, 0));


            //... SDC_SHARP_CONF_1
            OUTREG32( &g_pIPU->SDC_SHARP_CONF_1,
                //..cls rise delay
                CSP_BITFVAL( IPU_SDC_SHARP_CONF_1_CLS_RISE_DELAY, 0x2)|
                //..ps fall delay
                CSP_BITFVAL( IPU_SDC_SHARP_CONF_1_PS_FALL_DELAY, 0x1)|
                //..rev toggle delay
                CSP_BITFVAL( IPU_SDC_SHARP_CONF_1_REV_TOGGLE_DELAY, 0xfd));

            //... SDC_SHARP_CONF_2
            OUTREG32(&g_pIPU->SDC_SHARP_CONF_2,
                //..cls fall delay
                CSP_BITFVAL( IPU_SDC_SHARP_CONF_2_CLS_FALL_DELAY, 0xf4)|
                //..ps rise delay
                CSP_BITFVAL( IPU_SDC_SHARP_CONF_2_PS_RISE_DELAY, 0xf5));

            break;

         // TFT Drivers
         case IPU_PANEL_SHARP_121SVGA:
         case IPU_PANEL_SHARP_104VGA:
         case IPU_PANEL_SHARP_64VGA:
         case IPU_PANEL_SHARP_36QVGA:
         case IPU_PANEL_SHARP_35QVGA:
         case IPU_PANEL_SHARP_57QVGA:
            OUTREG32( &g_pIPU->SDC_COM_CONF,
            //.. SDC mode
            CSP_BITFVAL(IPU_SDC_COM_CONF_SDC_MODE, IPU_SDC_MODE_TFT_COLOR));

            break;
        
        default:
            DEBUGMSG(SDC_ERROR,
              (TEXT("Error configuring IPU SDC. Panel Type is not supported.\r\n Exiting Initialization\r\n")));
            return FALSE;
    }

    switch (currentPanel -> TYPE)
    {
			//LCD panels
			case IPU_PANEL_SHARP_121SVGA:
			case IPU_PANEL_SHARP_104VGA:
			case IPU_PANEL_SHARP_64VGA:
			case IPU_PANEL_SHARP_35HRQVGA:
			case IPU_PANEL_SHARP_36QVGA:
			case IPU_PANEL_SHARP_35QVGA:
			case IPU_PANEL_SHARP_57QVGA:

            //... SDC_HOR_CONF
            OUTREG32( &g_pIPU->SDC_HOR_CONF,
                      //.. display width for tearing and Vsync calculation
                      CSP_BITFVAL(IPU_SDC_HOR_CONF_SCREEN_WIDTH, (UINT32) (currentPanel -> WIDTH + currentPanel -> HSTARTWIDTH + currentPanel -> HENDWIDTH - 1) ) |
                      //.. horizontal synchronization pulse
                      CSP_BITFVAL(IPU_SDC_HOR_CONF_H_SYNC_WIDTH, currentPanel -> HSYNCWIDTH - 1));
            //... SDC_VER_CONF
            OUTREG32( &g_pIPU->SDC_VER_CONF,
                      //..line/pixel resolution
                      CSP_BITFVAL(IPU_SDC_VER_CONF_V_SYNC_WIDTH_L, 0x1)|
                      //..display height for tearing and Vsync calculation
                      CSP_BITFVAL(IPU_SDC_VER_CONF_SCREEN_HEIGHT, (UINT32) (currentPanel -> HEIGHT + currentPanel -> VSTARTWIDTH + currentPanel -> VENDWIDTH - 1) ) |
                      //..vsync size
                      CSP_BITFVAL(IPU_SDC_VER_CONF_V_SYNC_WIDTH, currentPanel -> VSYNCWIDTH - 1));
            break;
    }

    temp = INREG32(&g_pIPU->DI_DISP_IF_CONF) & 0x78FFFFFF;
    //... DI_DISP_IF_CONF
    OUTREG32(&g_pIPU->DI_DISP_IF_CONF,
              //..data mask
              CSP_BITFVAL( IPU_DI_DISP_IF_CONF_DISP3_DATAMASK, m_SignalPol.DATAMASK_EN )|
              // select interface display clock
              CSP_BITFVAL( IPU_DI_DISP_IF_CONF_DISP3_CLK_SEL, m_SignalPol.CLKSEL_EN)|
              // display clock idle enable
              CSP_BITFVAL( IPU_DI_DISP_IF_CONF_DISP3_CLK_IDLE, m_SignalPol.CLKIDLE_EN) |
              // Old value
              temp);

    temp = INREG32(&g_pIPU->DI_DISP_SIG_POL) & 0xE0FFFFFF;
    //... DI_DISP_SIG_POL
    OUTREG32(&g_pIPU->DI_DISP_SIG_POL,
              //..1: inverse data polarity
              CSP_BITFVAL( IPU_DI_DISP_SIG_POL_D3_DATA_POL, m_SignalPol.DATA_POL)|
              //..display interface clock polarity
              CSP_BITFVAL( IPU_DI_DISP_SIG_POL_D3_CLK_POL, m_SignalPol.CLK_POL)|
              //..1: active high horizontal signal polarity
              CSP_BITFVAL( IPU_DI_DISP_SIG_POL_D3_HSYNC_POL, m_SignalPol.HSYNC_POL)|
              //..1: active high vertical signal polarity
              CSP_BITFVAL( IPU_DI_DISP_SIG_POL_D3_VSYNC_POL, m_SignalPol.VSYNC_POL)|
              // output enable polarity
              CSP_BITFVAL( IPU_DI_DISP_SIG_POL_D3_DRDY_SHARP_POL, m_SignalPol.ENABLE_POL) |
              // old value
              temp);

    // DI_CLK = HSP_CLK * HSP_CLOCK_PER
    //        ==> HSP_CLOCK_PER = 1
    // these are 7 bit fields iiiffff
    // where i = integer part and f = fractional part of the value
    OUTREG32(&g_pIPU->DI_HSP_CLK_PER,
              CSP_BITFVAL( IPU_DI_HSP_CLK_PER_HSP_CLK_PERIOD_1, 1 << 4) |
              CSP_BITFVAL( IPU_DI_HSP_CLK_PER_HSP_CLK_PERIOD_2, 1 << 4));

    // DI_DISP3_TIME_CONF = DI_CLK / DISP3_IF_CLK_PER_WR = 133 MHz / 20 = 6.65MHz
    m_PixelClock = (currentPanel -> WIDTH + currentPanel -> HSTARTWIDTH + currentPanel -> HSYNCWIDTH + currentPanel -> HENDWIDTH) * \
                (currentPanel -> HEIGHT + currentPanel -> VSTARTWIDTH + currentPanel -> VSYNCWIDTH + currentPanel -> VENDWIDTH) * 60;

    DDKClockGetFreq(DDK_CLOCK_SIGNAL_IPU, &g_IPUClk);
    m_PixelDivider = (g_IPUClk << 4) / m_PixelClock;    // g_IPUClk is 0x3F6B5A0

    if (m_PixelDivider < 0x40) // Divider less than 4
    {
        DEBUGMSG(SDC_ERROR,
            (TEXT("InitPanel() - Pixel clock divider less than 1\r\n")));
        m_PixelDivider = 0x40;
    }

    switch (currentPanel -> TYPE)
    {

				case IPU_PANEL_SHARP_121SVGA:
					OUTREG32(&g_pIPU->DI_DISP3_TIME_CONF,
						  //.. period
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_PER_WR, m_PixelDivider )|						  
						  //..write strobe start
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_UP_WR, 0)|
						  //..write strobe end
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_DOWN_WR, 3 << 0 ));
				break;
				case IPU_PANEL_SHARP_104VGA:
				case IPU_PANEL_SHARP_64VGA:
					OUTREG32(&g_pIPU->DI_DISP3_TIME_CONF,
						  //.. period
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_PER_WR, m_PixelDivider )|
						  //..write strobe start
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_UP_WR, 0)|
						  //..write strobe end
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_DOWN_WR, 2 << 2 ));
					break;
				case IPU_PANEL_SHARP_57QVGA:
					OUTREG32(&g_pIPU->DI_DISP3_TIME_CONF,
						  //.. period
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_PER_WR, m_PixelDivider)|
						  //..write strobe start
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_UP_WR, 0)|
						  //..write strobe end
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_DOWN_WR, 0x1 << 2));
					break;
				case IPU_PANEL_SHARP_35HRQVGA:
					OUTREG32(&g_pIPU->DI_DISP3_TIME_CONF,
						  //..write strobe end
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_DOWN_WR, (m_PixelDivider / 8) - 1) |
						  //.. period
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_PER_WR, m_PixelDivider));
					break;

				case IPU_PANEL_SHARP_35QVGA:
					OUTREG32(&g_pIPU->DI_DISP3_TIME_CONF,
						  //..write strobe end
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_DOWN_WR, 2 << 2 ) |
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_DOWN_WR, 3 << 0 ) |
						  //..write strobe start
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_UP_WR,   0)|
						  //.. period
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_PER_WR, m_PixelDivider));
					break;

				case IPU_PANEL_SHARP_36QVGA:
					OUTREG32(&g_pIPU->DI_DISP3_TIME_CONF,
						  //.. period
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_PER_WR, m_PixelDivider)|
						  //..write strobe start
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_UP_WR, 0)|
						  //..write strobe end
						  CSP_BITFVAL( IPU_DI_DISP3_TIME_CONF_DISP3_IF_CLK_DOWN_WR, 0xa << 2));
					break;

		}

    //... DI_DISP_ACC_CC
    INSREG32BF(&g_pIPU->DI_DISP_ACC_CC,
                // display clock cycles number (data access)
                IPU_DI_DISP_ACC_CC_DISP3_IF_CLK_CNT_D, 0);

    //... DI_DISP3_B0_MAP
    OUTREG32(&g_pIPU->DI_DISP3_B0_MAP,
                // set0; data offset
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_OFFS0, 0x5)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_OFFS1, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_OFFS2, 0)|

                // set0; data maping
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M0, 3)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M1, 3)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M2, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M3, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M4, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M5, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M6, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B0_MAP_M30_M7, 0));



    //... DI_DISP3_B1_MAP
    OUTREG32(&g_pIPU->DI_DISP3_B1_MAP,
                // set1; data offset
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_OFFS0, 0xb)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_OFFS1, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_OFFS2, 0)|

                // set1; data maping
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M0, 3)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M1, 3)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M2, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M3, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M4, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M5, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M6, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B1_MAP_M31_M7, 0));


    //... DI_DISP3_B2_MAP
    OUTREG32(&g_pIPU->DI_DISP3_B2_MAP,
                // set2; data offset
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_OFFS0, 0x11)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_OFFS1, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_OFFS2, 0)|

                // set2; data maping
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M0, 3)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M1, 3)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M2, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M3, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M4, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M5, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M6, 0)|
                CSP_BITFVAL( IPU_DI_DISP3_B2_MAP_M32_M7, 0));

      OUTREG32(&g_pIPU->SDC_BG_POS,
                   CSP_BITFVAL( IPU_SDC_BG_POS_BGXP, currentPanel -> HSTARTWIDTH )|
                   CSP_BITFVAL( IPU_SDC_BG_POS_BGYP, currentPanel -> VSTARTWIDTH ));
      
      OUTREG32(&g_pIPU->SDC_FG_POS,
                   CSP_BITFVAL( IPU_SDC_FG_POS_FGXP, (currentPanel -> HSTARTWIDTH + 1) )|
                   CSP_BITFVAL( IPU_SDC_FG_POS_FGYP, currentPanel -> VSTARTWIDTH ));
   } //if(m_SkipLCDCInit)
   else {
      currentPanel -> WIDTH = width;
      currentPanel -> HEIGHT = height;
      currentPanel -> HSTARTWIDTH = (INREG32(&g_pIPU->SDC_BG_POS) >> 0x10) & 0xFFFF;
      currentPanel -> VSTARTWIDTH = INREG32(&g_pIPU->SDC_BG_POS) & 0xFFFF;
   }

    //----- SDC Configuration
    INSREG32BF(&g_pIPU->SDC_COM_CONF,
                IPU_SDC_COM_CONF_GWSEL, IPU_SDC_COM_CONF_GWSEL_BG);
    INSREG32BF(&g_pIPU->SDC_COM_CONF,
                IPU_SDC_COM_CONF_SDC_GLB_LOC_A, 1);

    g_iXValMax = currentPanel -> HSTARTWIDTH + currentPanel -> WIDTH;


   DEBUGMSG(1,
      (TEXT("LCDC Regs: \r\nSDC_COM_CONF:     0x%08x \r\n")
       TEXT("SDC_BG_POS:       0x%08x \r\n")
       TEXT("SDC_HOR_CONF:     0x%08x \r\n")
       TEXT("SDC_VER_CONF:     0x%08x \r\n")
       TEXT("SDC_SHARP_CONF_1: 0x%08x \r\n")
       TEXT("SDC_SHARP_CONF_2: 0x%08x \r\n")
       TEXT("DI_DISP_IF_CONF:  0x%08x \r\n")
       TEXT("DI_DISP_SIG_POL:  0x%08x \r\n")
       TEXT("DI_D3_TIME_CONF:  0x%08x \r\n"),
         INREG32(&g_pIPU->SDC_COM_CONF),
         INREG32(&g_pIPU->SDC_BG_POS),
         INREG32(&g_pIPU->SDC_HOR_CONF),
         INREG32(&g_pIPU->SDC_VER_CONF),
         INREG32(&g_pIPU->SDC_SHARP_CONF_1),
         INREG32(&g_pIPU->SDC_SHARP_CONF_2),
         INREG32(&g_pIPU->DI_DISP_IF_CONF),
         INREG32(&g_pIPU->DI_DISP_SIG_POL),
         INREG32(&g_pIPU->DI_DISP3_TIME_CONF)
   ));

    //----- IDMAC Configuration

    // Set no double-buffer, use buf0
    INSREG32BF(&g_pIPU->IPU_CHA_DB_MODE_SEL, IPU_DMA_CHA_DMASDC_0, IPU_SIG_BUF);
    INSREG32BF(&g_pIPU->IPU_CHA_DB_MODE_SEL, IPU_DMA_CHA_DMASDC_1, IPU_SIG_BUF);


    // Set buffer 0 as current buffer (non double buffered)
    INSREG32BF(&g_pIPU->IPU_CHA_CUR_BUF, IPU_DMA_CHA_DMASDC_0, IPU_SIG_BUF);
    INSREG32BF(&g_pIPU->IPU_CHA_CUR_BUF, IPU_DMA_CHA_DMASDC_1, IPU_SIG_BUF);

    // Set high priority for DMA SDC Channel 0
    INSREG32BF(&g_pIPU->IDMAC_CHA_PRI,
                IPU_DMA_CHA_DMASDC_0, 1);

    // Set high priority for DMA SDC Channel 1
    INSREG32BF(&g_pIPU->IDMAC_CHA_PRI,
                IPU_DMA_CHA_DMASDC_1, 1);

    // Set high priority for DMA SDC Channel 3
    INSREG32BF(&g_pIPU->IDMAC_CHA_PRI,
                IPU_DMA_CHA_DMASDC_3, 1);
                
    // Set max for consecutive bursts for each channel
#if 1
    // i.MX31 CE60
    INSREG32BF(&g_pIPU->IDMAC_CONF,
                IPU_IDMAC_CONF_SRCNT, 0);
#else
    // LPD_MX31 CE50
    INSREG32BF(&g_pIPU->IDMAC_CONF,
                IPU_IDMAC_CONF_SRCNT, 7);

    INSREG32BF(&g_pIPU->IDMAC_CONF,
                IPU_IDMAC_CONF_PRYM, 2);
#endif

    // Select source of SDC channel as ARM
    OUTREG32(&g_pIPU->IPU_FS_DISP_FLOW,
                CSP_BITFVAL( IPU_IPU_FS_DISP_FLOW_SDC0_SRC_SEL, FLOW_ARM)|
                CSP_BITFVAL( IPU_IPU_FS_DISP_FLOW_SDC1_SRC_SEL, FLOW_ARM));

    // Turn contrast fully on
    OUTREG32(&g_pIPU->SDC_CUR_BLINK_PWM_CTRL,
                CSP_BITFVAL( IPU_SDC_CUR_BLINK_PWM_CTRL_SCR, 1)|
                CSP_BITFVAL( IPU_SDC_CUR_BLINK_PWM_CTRL_CC_EN, 1)|
                CSP_BITFVAL( IPU_SDC_CUR_BLINK_PWM_CTRL_PWM, 0x8F));

    // Signal backlight driver to update as we just changed PWM value
    hBKEvent = CreateEvent(NULL, FALSE, FALSE,  L"BackLightLevelChangeEvent" );
    if(hBKEvent != NULL)
    {
        SetEvent(hBKEvent);
        CloseHandle(hBKEvent);
    }

   // this is fairly awkward - i'm trying to keep the older "currentPanel" system
   // intact for the case where predefined modes are used.  however, for the system
   // where the lcd is setup in the bootloader (e.g. skiplcdcinit:1), we need to use
   // the width and height of the panel as read from the hardware - not from the
   // currentPanel array.  in fact, the driver probably won't even have a valid
   // currentPanel if skiplcdcinit is set
   if (!m_SkipLCDCInit) {
      _init_dma(currentPanel -> WIDTH, currentPanel -> HEIGHT, bpp, (currentPanel -> WIDTH * bpp / 8), FALSE, SDC_DMA_CHANNEL, currentPanel->PIXEL_FMT);
   }
   else {
      _init_dma(width, height, bpp, (width * bpp / 8), FALSE, SDC_DMA_CHANNEL, currentPanel->PIXEL_FMT);
   }

    g_pCurrentPanel = currentPanel;

    ret = TRUE;
    return ret;
}


//------------------------------------------------------------------------------
//
// Function: EnableSDC
//
// This function enables SDC for normal opertion
//
// Parameters:
//      none
//
// Returns:
//      none.
//------------------------------------------------------------------------------
void EnableSDC(void)
{
    UINT32 iOldVal, iNewVal, iMask, iBitval;
    DWORD dwBytesTransferred;
    IPU_DRIVER driver = IPU_DRIVER_SDC;

    BSPDisplayIOMUXEnable(eIPU_SDC);

    // Enable DI and SDC

    // Call to IPU Base to turn on SDC_EN in IPU_CONF reg.
    // This will also turn on IPU clocks if no other IPU
    // modules have already turned them on.
    if (!DeviceIoControl(g_hIPUBase,    // file handle to the driver
             IPU_IOCTL_ENABLE_SDC,         // I/O control code
             NULL,                                       // in buffer
             0,                                            // in buffer size
             NULL,                                       // out buffer
             0,                                            // out buffer size
             &dwBytesTransferred,               // number of bytes returned
             NULL))                                     // ignored (=NULL)
    {
        DEBUGMSG (SDC_ERROR,
            (TEXT("%s: Failed to enable SDC!\r\n"), __WFUNCTION__));
    }

    // Call to IPU Base to turn on DI_EN in IPU_CONF reg.
    // This will also turn on IPU clocks if no other IPU
    // modules have already turned them on.
    if (!DeviceIoControl(g_hIPUBase,    // file handle to the driver
             IPU_IOCTL_ENABLE_DI,            // I/O control code
             &driver,                        // in buffer
             sizeof(IPU_DRIVER),             // in buffer size
             NULL,                                       // out buffer
             0,                                            // out buffer size
             &dwBytesTransferred,               // number of bytes returned
             NULL))                                     // ignored (=NULL)
    {
        DEBUGMSG (SDC_ERROR,
            (TEXT("%s: Failed to enable DI!\r\n"), __WFUNCTION__));
    }


    // Enable DMA SDC Channel 1

    // Compute bitmask and shifted bit value for IPU Conf register
    iMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_0);
    iBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, IPU_ENABLE);

    // Use interlocked function to Enable DMA SDC Channel 1.
    do
    {
        iOldVal = INREG32(&g_pIPU->IDMAC_CHA_EN);
        iNewVal = (iOldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IDMAC_CHA_EN,
                iOldVal, iNewVal) != iOldVal);

    // Enable SDC background
    // Set BG_EN = 1 (Background is enabled)
    INSREG32BF(&g_pIPU->SDC_COM_CONF,
                IPU_SDC_COM_CONF_BG_EN, IPU_ENABLE);

    // Set DMA SDC Channel 0 as ready
    SETREG32(&g_pIPU->IPU_CHA_BUF0_RDY,
                CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, IPU_DMA_CHA_READY));

}


//------------------------------------------------------------------------------
//
// Function: DisableSDC
//
// This function disables SDC
//
// Parameters:
//      none
//
// Returns:
//      none.
//------------------------------------------------------------------------------
void DisableSDC(void)
{
    UINT32 uTempReg1, uTempReg2, uCount = 0;
    UINT32 oldVal, newVal, iMask, iBitval;
    DWORD dwBytesTransferred;
    IPU_DRIVER driver = IPU_DRIVER_SDC;

    // Compute bitmask and shifted bit value for SDC_COM_CONF reg.
    iMask = CSP_BITFMASK(IPU_SDC_COM_CONF_BG_EN);
    iBitval = CSP_BITFVAL(IPU_SDC_COM_CONF_BG_EN, IPU_DISABLE);

    // Use interlocked function to Disable SDC FG and BG.
    do
    {
        oldVal = INREG32(&g_pIPU->SDC_COM_CONF);
        newVal = (oldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->SDC_COM_CONF,
                oldVal, newVal) != oldVal);

    // Can we do this, or perhaps not because a system
    // level call is required (WaitForSingleObject)?
    // DisplayPlaneWaitForNotBusy(DisplayPlane_0);

    // initalize ... for the first time through
    uTempReg1 = INREG32(&g_pIPU->IDMAC_CHA_BUSY);
    uTempReg2 = INREG32(&g_pIPU->IPU_CHA_BUF0_RDY);

    // We can't disable tasks until the active channel
    // has completed its current frames.  Make sure
    // that buffers aren't set as ready (indicating that
    // they are yet to start) and that channels are
    // not busy (indicating that channels are still running).
    while ((uTempReg1 & (1 << GRAPHICS_DMA_CHANNEL)) || (uTempReg2 & (1 << GRAPHICS_DMA_CHANNEL)))
    {
        if (uCount <= DELAYTIMEOUT)
        {
            uCount++;

            //.. need to check after the sleep delay
            uTempReg1 = INREG32(&g_pIPU->IDMAC_CHA_BUSY);
            uTempReg2 = INREG32(&g_pIPU->IPU_CHA_BUF0_RDY);
        }
        else
        {
            //.. there is something wrong ....break out
            break;
        }
    }

    // Compute bitmask and shifted bit value for idmac register
    iMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_0);
    iBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, IPU_DISABLE);

    // Use interlocked function to Disable DMA SDC Channel 0.
    do
    {
        oldVal = INREG32(&g_pIPU->IDMAC_CHA_EN);
        newVal = (oldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IDMAC_CHA_EN,
                oldVal, newVal) != oldVal);

    // Call to IPU Base to turn off SDC_EN in IPU_CONF reg.
    // This will also shut off IPU clocks if no other IPU
    // modules are enabled.
    if (!DeviceIoControl(g_hIPUBase,       // file handle to the driver
             IPU_IOCTL_DISABLE_SDC,          // I/O control code
             NULL,                                         // in buffer
             0,                                              // in buffer size
             NULL,                                         // out buffer
             0,                                              // out buffer size
             &dwBytesTransferred,                 // number of bytes returned
             NULL))                                       // ignored (=NULL)
    {
        DEBUGMSG (SDC_ERROR,
            (TEXT("%s: Failed to disable SDC!\r\n"), __WFUNCTION__));
    }

    // Call to IPU Base to turn off DI_EN in IPU_CONF reg.
    // This will also shut off IPU clocks if no other IPU
    // modules are enabled.
    if (!DeviceIoControl(g_hIPUBase,    // file handle to the driver
             IPU_IOCTL_DISABLE_DI,          // I/O control code
             &driver,                        // in buffer
             sizeof(IPU_DRIVER),             // in buffer size
             NULL,                                       // out buffer
             0,                                            // out buffer size
             &dwBytesTransferred,               // number of bytes returned
             NULL))                                     // ignored (=NULL)
    {
        DEBUGMSG (SDC_ERROR,
            (TEXT("%s: Failed to disable DI!\r\n"), __WFUNCTION__));
    }

    BSPDisplayIOMUXDisable(eIPU_SDC);
}

//------------------------------------------------------------------------------
//
// Function: BackgroundSetSrcBuffer
//
// This function sets the source buffer for the main background display window.
//
// Parameters:
//      pAddr
//          [in] Address of buffer to set as source for main background
//              display window.
//
// Returns:
//      none.
//------------------------------------------------------------------------------
void BackgroundSetSrcBuffer(PHYSICAL_ADDRESS *pAddr)
{
    SetSrcBuffer(SDC_DMA_CHANNEL, pAddr, eBUF_0);
}

//------------------------------------------------------------------------------
//
// Function: _init_dma
//
// Init the IPU DMA module
//
// Parameters:
//      None.
//
// Returns:
//      None.
//------------------------------------------------------------------------------
static void _init_dma(int width, int height, int bpp, int stride, BOOL vFlip, const UINT channel, IPU_PIXEL_FORMAT format)
{
    UINT32 bpp_code, npb_code, sat_code, bam_code, pfs_code, ofs[4], wid[4];
    UINT32 oldVal, newVal;

    //=================================
    // Configure First 132 bit word
    //=================================

    // Software-controlled access to IMA registers
    // IMA registers may only be accessed if IMA_ADDR is
    // set to 0.

    // Set IPU_IMA_ADDR (IPU Internal Memory Access Address)
    newVal = CSP_BITFVAL( IPU_IPU_IMA_ADDR_MEM_NU, IPU_IMA_ADDR_MEM_NU_CPM) |
                CSP_BITFVAL( IPU_IPU_IMA_ADDR_ROW_NU, (2 * channel))|
                CSP_BITFVAL( IPU_IPU_IMA_ADDR_WORD_NU, 0);

    for (;;)
    {
        oldVal = INREG32(&g_pIPU->IPU_IMA_ADDR);
        if (oldVal == 0)
        {
            // Try to set IPU_IMA registers.
            if ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IPU_IMA_ADDR,
                oldVal, newVal) == oldVal)
            {
                // Successfully set IMA_ADDR.
                break;
            }
        }
        // IPU_IMA controlled by another process.
        // Surrender CPU and then try again.
        Sleep(1);
    }

    //...0th 32 bit word
    // XV [9:0], YV [19:10], XB [31:20]
    OUTREG32(&g_pIPU->IPU_IMA_DATA,
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_XV, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_YV, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_XB, 0));

    //...1st 32 bit word
    // YB [11:0], SCE [12], RESERVED [13], NSB [14], LNPB [20:15], SX [30:21],
    // SY~ [31]
    // - Set NSB
    OUTREG32(&g_pIPU->IPU_IMA_DATA,
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_YB, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SCE, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_NSB, 1)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_LNPB, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SX, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_LOW_SY, 0));

    //...2nd 32 bit word
    // ~SY [8:0], NS [18:9], SM [28:10] SDX~ [31:29]
    OUTREG32(&g_pIPU->IPU_IMA_DATA,
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_HIGH_SY, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_NS, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SM, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_LOW_SDX, 0));

    //...3rd 32 bit word
    // ~SDX [1:0], SDY [6:2], SDRX [7], SDRY [8], SCRQ [9], RESERVED [11:10]
    // - FW [23:12], FH~ [31:24]
    // - Set FW & FH
    OUTREG32(&g_pIPU->IPU_IMA_DATA,
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_HIGH_SDX, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SDY, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SDRX, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SDRY, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SCRQ, 0)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_FW, (width - 1))|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_LOW_FH, (height - 1)));

    //...4th 32 bit word
    // ~FH [3:0]
    // NOTE: this takes care of the upper four bits in the FH field
    OUTREG32(&g_pIPU->IPU_IMA_DATA, ((height - 1) >> 8));


    //=================================
    // Configure Second 132 bit word
    //=================================
    //..skip over EBA0 and EBA1
    //.. Set IPU_IMA_ADDR (IPU Internal Memory Access Address)
    OUTREG32(&g_pIPU->IPU_IMA_ADDR,
            CSP_BITFVAL( IPU_IPU_IMA_ADDR_MEM_NU, IPU_IMA_ADDR_MEM_NU_CPM) |
            CSP_BITFVAL( IPU_IPU_IMA_ADDR_ROW_NU, (2 * channel + 1))|
            CSP_BITFVAL( IPU_IPU_IMA_ADDR_WORD_NU, 2));

    //...2nd 32 bit word

    // Default access type to 32-bit
    sat_code = 2;

    switch (bpp)
    {
        case 32:
            bpp_code = 0;
            npb_code = 8-1;
            ofs[0] = 0;
            ofs[1] = 8;
            ofs[2] = 16;
            ofs[3] = 24;
            wid[0] = 8-1;
            wid[1] = 8-1;
            wid[2] = 8-1;
            wid[3] = 8-1;
            break;

        case 24:
            bpp_code = 1;
            npb_code = 10-1;
            sat_code = 0;
            ofs[0] = 0;
            ofs[1] = 8;
            ofs[2] = 16;
            ofs[3] = 0;
            wid[0] = 8-1;
            wid[1] = 8-1;
            wid[2] = 8-1;
            wid[3] = 0;
            break;

        case 16:
            bpp_code = 2;
            npb_code = 16-1;
            ofs[0] = 0;
            ofs[1] = 5;
            ofs[2] = 11;
            ofs[3] = 0;
            wid[0] = 5-1;
            wid[1] = 6-1;
            wid[2] = 5-1;
            wid[3] = 0;
            break;

        case 8:
            bpp_code = 3;
            npb_code = 32-1;
            ofs[0] = 0;
            ofs[1] = 0;
            ofs[2] = 0;
            ofs[3] = 0;
            wid[0] = 8-1;
            wid[1] = 0;
            wid[2] = 0;
            wid[3] = 0;
            break;

        case 4:
            bpp_code = 4;
            npb_code = 32-1;
            ofs[0] = 0;
            ofs[1] = 0;
            ofs[2] = 0;
            ofs[3] = 0;
            wid[0] = 4-1;
            wid[1] = 0;
            wid[2] = 0;
            wid[3] = 0;
            break;

        case 1:
            bpp_code = 5;
            npb_code = 64-1;
            ofs[0] = 0;
            ofs[1] = 0;
            ofs[2] = 0;
            ofs[3] = 0;
            wid[0] = 1-1;
            wid[1] = 0;
            wid[2] = 0;
            wid[3] = 0;
            break;

        default:
            bpp_code = 7;
            bpp_code = 2;
            npb_code = 16-1;
            ofs[0] = 0;
            ofs[1] = 5;
            ofs[2] = 11;
            ofs[3] = 0;
            wid[0] = 5-1;
            wid[1] = 6-1;
            wid[2] = 5-1;
            wid[3] = 0;
        // TODO:  Should report error here.  bpp_code is reserved.
        break;
    }

    bam_code = vFlip ? 1 : 0;
    pfs_code = (IPU_PIX_FMT_YUV422  == format) ? 6 : 4;

    // - BPP [2:0], SL [16:3], PFS [19:17], BAM [24:20], NPB [30:25],
    // - RESERVED [31]
    // - Set BPP to 24bpp (1)
    // - Set SL (Scaling Factor) to bytes_pp * width
    // - Set PFS (Packing) to RGB (%100)
    OUTREG32(&g_pIPU->IPU_IMA_DATA,
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_BPP, bpp_code)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SL, (stride - 1))|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_PFS, pfs_code)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_BAM, bam_code)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_NPB, npb_code));

    //...3rd 32 bit word
    // SAT [1:0], SCC [2], OFS0 [7:3], 0FS1 [12:8], OFS2 [17:13], OFS3 [22:18]
    // - WID0 [25:23], WID1 [28:26], WID2 [31:29]
    OUTREG32(&g_pIPU->IPU_IMA_DATA,
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SAT, sat_code)|
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_SCC, 0)|

                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_OFS0, ofs[0]) |
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_OFS1, ofs[1]) |
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_OFS2, ofs[2]) |
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_OFS3, ofs[3]) |

                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_WID0, wid[0]) |
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_WID1, wid[1]) |
                CSP_BITFVAL( IPU_IPU_IMA_DATA_PARAM_WID2, wid[2]));

    //...4th 32 bit word
    // WID3 [2:0], DEC_SEL [3],
    // Set WID3 (7 - 8 bit size), Color component 3 width (Alpha)
    OUTREG32(&g_pIPU->IPU_IMA_DATA,
                CSP_BITFVAL(IPU_IPU_IMA_DATA_PARAM_WID3, wid[3]));

    // Cede control of IPU_IMA registers by writing 0 to IPU_IMA_ADDR
    OUTREG32(&g_pIPU->IPU_IMA_ADDR, 0);
}

//------------------------------------------------------------------------------
//
// Function: SetSrcBuffer
//
// Set the buffer for Init the IPU DMA module
//
// Parameters:
//      None.
//
// Returns:
//      None.
//------------------------------------------------------------------------------
static void SetSrcBuffer(int channel, PHYSICAL_ADDRESS *pAddr, DISP_BUF_TYPE bufNum)
{
    UINT32 wordNo = (bufNum == eBUF_0) ? 0 : 1;
    UINT32 oldVal, newVal;

    // Set IPU_IMA_ADDR (IPU Internal Memory Access Address)
    newVal = CSP_BITFVAL(IPU_IPU_IMA_ADDR_MEM_NU, IPU_IMA_ADDR_MEM_NU_CPM) |
            CSP_BITFVAL(IPU_IPU_IMA_ADDR_ROW_NU, (2 * channel + 1))|
            CSP_BITFVAL(IPU_IPU_IMA_ADDR_WORD_NU, wordNo);

    for (;;)
    {
        oldVal = INREG32(&g_pIPU->IPU_IMA_ADDR);
        if (oldVal == 0)
        {
            // Try to set IPU_IMA registers.
            if ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IPU_IMA_ADDR,
                oldVal, newVal) == oldVal)
            {
                // Successfully set IMA_ADDR.
                break;
            }
        }
        // IPU_IMA controlled by another process.
        // Surrender CPU and then try again.
        Sleep(1);
    }

    //..Set buffer to physical frame buffer address
    OUTREG32(&g_pIPU->IPU_IMA_DATA, (unsigned int) pAddr->QuadPart);

    // Cede control of IPU_IMA registers by writing 0 to IPU_IMA_ADDR
    OUTREG32(&g_pIPU->IPU_IMA_ADDR, 0);
}


//------------------------------------------------------------------------------
//
// Function: ForegroundWindowConfig
//
// Configure the foreground plane in the SDC.
//
// Parameters:
//      width
//          [in] Width of the foreground plane display area.
//
//      height
//          [in] Height of the foreground plane display area.
//
//      bpp
//          [in] BPP of foreground plane image for display.
//
// TODO: Support
//      verticalFlip
//          [in] Boolean indicating whether the displayed image
//          is vertically flipped.
//
// TODO: Support
//      alpha
//          [in] Alpha blending factor for  the graphics plane (indicated by the
//          plane parameter).  The following equation determines the output
//          pixel color:
//              OP = IGP * x + IVP * (1 - x)
//              where OP = Output Pixel
//                    IGP = Input Graphics Pixel
//                    IVP = Input Video Pixel
//                    x = (alpha + floor(alpha/128))/256
//
//      colorKey
//          [in] Color key for the graphics plane, indicated by the plane parameter.
//
//      plane
//          [in] Value indicating whether Plane 1 or Plane 0 should be
//          marked as the graphics (foreground) plane.
//
//
// Returns:
//      TRUE if success; FALSE if failure.
//------------------------------------------------------------------------------
BOOL ForegroundWindowConfig(PDISPLAY_SDC_FG_CONFIG_DATA pDispConfigData)
{
    UINT32 graphWindCtrl;

    // Build value for graphics window control and write it to register
    graphWindCtrl = (pDispConfigData->alpha << 24) | pDispConfigData->colorKey;
    OUTREG32(&g_pIPU->SDC_GRAPH_WIND_CTRL, graphWindCtrl);
    INSREG32BF(&g_pIPU->SDC_COM_CONF, IPU_SDC_COM_CONF_GWSEL, pDispConfigData->plane);
    if (pDispConfigData->colorKey != 0xFFFFFFFF)
    {
        INSREG32BF(&g_pIPU->SDC_COM_CONF, IPU_SDC_COM_CONF_SDC_KEY_COLOR_EN,
            IPU_ENABLE);
    }
    else
    {
        INSREG32BF(&g_pIPU->SDC_COM_CONF, IPU_SDC_COM_CONF_SDC_KEY_COLOR_EN,
            IPU_DISABLE);
    }

    // Determine if we need to crop Foreground window (i.e., change FG width)
    if ((g_iCurrentFGXP + pDispConfigData->width) > g_iXValMax)
    {
        // The foreground width plus FGXP exceeds the maximum, so
        // we must crop the foreground window.
        pDispConfigData->width = g_iXValMax - g_iCurrentFGXP - 1;
    }

    // go set up the IDMA
    _init_dma(pDispConfigData->width, pDispConfigData->height, pDispConfigData->bpp, pDispConfigData->stride, pDispConfigData->verticalFlip, GRAPHICS_DMA_CHANNEL, g_pCurrentPanel->PIXEL_FMT);

    return TRUE;
}


//------------------------------------------------------------------------------
//
// Function: ForegroundWindowSetSrcBuffer
//
// Set up the source buffer in the IPU DMA.  This takes the physical address
// passed as a parameter and configures the DMA to load the image from this
// buffer.
//
// Parameters:
//      pAddr
//          [in] PHYSICAL_ADDRESS for buffer containing frame to display
//          to the foreground plane.
//
//      bufNum
//          [in] Selects buffer 0 or buffer 1 in the DMA.
//
// Returns:
//      None.
//------------------------------------------------------------------------------
void ForegroundWindowSetSrcBuffer(PHYSICAL_ADDRESS *pAddr)
{
    // Set IPU_IMA_ADDR (IPU Internal Memory Access Address)
    if (g_iSDCFGNextBuffer == 0)
    {
        SetSrcBuffer(GRAPHICS_DMA_CHANNEL, pAddr, g_iSDCFGNextBuffer);

        // Set DMA VF Channel 0 ready
        SETREG32(&g_pIPU->IPU_CHA_BUF0_RDY,
                CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_DMA_CHA_READY));

        g_iSDCFGNextBuffer = 1;
    }
    else
    {
        SetSrcBuffer(GRAPHICS_DMA_CHANNEL, pAddr, g_iSDCFGNextBuffer);

        // Set DMA VF Channel 1 ready
        SETREG32(&g_pIPU->IPU_CHA_BUF1_RDY,
                CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_DMA_CHA_READY));

        g_iSDCFGNextBuffer = 0;
    }

	// Save last address in case we need to restore later.
	g_SDCFGBuf_Saved = (UINT32) pAddr->QuadPart;

}

void ForegroundWindowRestore()
{
	PHYSICAL_ADDRESS phyAddr;

    // Re-enable foreground
	ForegroundWindowEnable();

    // Restore last active buffer to foreground
	phyAddr.QuadPart = g_SDCFGBuf_Saved;
	ForegroundWindowSetSrcBuffer(&phyAddr);
}

//------------------------------------------------------------------------------
//
// Function: ForegroundWindowSetOffset
//
// This function sets up the window offset for the foreground plane.
//
// Parameters:
//      left
//          [in] X coordinate of the foreground plane in the
//          display window.
//
//      top
//          [in] Y coordinate of the foreground plane in the
//          display window.
//
// Returns:
//      None.
//------------------------------------------------------------------------------
void ForegroundWindowSetOffset(POINT *ptWinOffset)
{
    // Set the top or the Y coordinate of the foreground plane
    INSREG32BF(&g_pIPU->SDC_FG_POS,
                IPU_SDC_FG_POS_FGYP, g_pCurrentPanel->VSTARTWIDTH + ptWinOffset->y);

    // Set the left or the X coordinate of the foreground plane
    INSREG32BF(&g_pIPU->SDC_FG_POS,
                IPU_SDC_FG_POS_FGXP, g_pCurrentPanel->HSTARTWIDTH + ptWinOffset->x);

    g_iCurrentFGXP = g_pCurrentPanel->HSTARTWIDTH + ptWinOffset->x;
}

//------------------------------------------------------------------------------
//
// Function: ForegroundWindowEnable
//
// This function enables the foreground window.
//
// Parameters:
//      None.
//
// Returns:
//      None.
//------------------------------------------------------------------------------
void ForegroundWindowEnable(void)
{
    UINT32 oldVal, newVal, iMask, iBitval;

    // If FG_EN = 1, bail out
    if (EXTREG32BF(&g_pIPU->SDC_COM_CONF, IPU_SDC_COM_CONF_FG_EN) == IPU_ENABLE)
    {
        return;
    }

    // Set to double buffer mode

    // Compute bitmask and shifted bit value for DB mode sel register
    iMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_1);
    iBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_DUB_BUF);

    // Use interlocked function to set DB Mode sel to 1.
    do
    {
        oldVal = INREG32(&g_pIPU->IPU_CHA_DB_MODE_SEL);
        newVal = (oldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IPU_CHA_DB_MODE_SEL,
                oldVal, newVal) != oldVal);

    SETREG32(&g_pIPU->IPU_CHA_CUR_BUF,
            CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_IPU_CHA_CUR_BUF_CLEAR));

    // Enable DMA VF Channel 1

    // Compute bitmask and shifted bit value for IDMAC enable reg.
    iMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_1);
    iBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_ENABLE);

    // Use interlocked function to Enable DMA VF Channel 1.
    do
    {
        oldVal = INREG32(&g_pIPU->IDMAC_CHA_EN);
        newVal = (oldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IDMAC_CHA_EN,
                oldVal, newVal) != oldVal);

    // Enable VF foreground

    // Compute bitmask and shifted bit value for IDMAC enable reg.
    iMask = CSP_BITFMASK(IPU_SDC_COM_CONF_FG_EN);
    iBitval = CSP_BITFVAL(IPU_SDC_COM_CONF_FG_EN, IPU_ENABLE);

    // Use interlocked function to set FG_EN = 1 (Foreground is enabled)
    do
    {
        oldVal = INREG32(&g_pIPU->SDC_COM_CONF);
        newVal = (oldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->SDC_COM_CONF,
                oldVal, newVal) != oldVal);

    return;
}

//------------------------------------------------------------------------------
//
// Function: ForegroundWindowDisable
//
// This function disables the foreground window.
//
// Parameters:
//      None.
//
// Returns:
//      TRUE if success; FALSE if failure.
//------------------------------------------------------------------------------
BOOL ForegroundWindowDisable(void)
{
    UINT32 oldVal, newVal, iMask, iBitval;
	UINT32 uCount =0;
    // initalize ... for the first time through
    UINT32 uTempReg = INREG32(&g_pIPU->IDMAC_CHA_BUSY);
    UINT32 uTempReg1 = INREG32(&g_pIPU->IPU_CHA_BUF0_RDY);
    UINT32 uTempReg2 = INREG32(&g_pIPU->IPU_CHA_BUF1_RDY);

    // We can't disable tasks until the active channels
    // have completed their current frames.  Make sure
    // that buffers aren't set as ready (indicating that
    // they are yet to start) and that channels are
    // not busy (indicating that channels are still running).
    while ((uTempReg1 & (1 << GRAPHICS_DMA_CHANNEL)) || (uTempReg2 & (1 << GRAPHICS_DMA_CHANNEL))
        || (uTempReg & (1 << GRAPHICS_DMA_CHANNEL)))
    {
        if (uCount <= DELAYTIMEOUT)
        {
            //..give up the remainder of time slice
            Sleep(0);
            uCount++;

            //.. need to check after the sleep delay
            uTempReg = INREG32(&g_pIPU->IDMAC_CHA_BUSY);
            uTempReg1 = INREG32(&g_pIPU->IPU_CHA_BUF0_RDY);
            uTempReg2 = INREG32(&g_pIPU->IPU_CHA_BUF1_RDY);
        }
        else
        {
            //.. there is something wrong ....break out
            return FALSE;
        }
    }

    // Set FG_EN = 0 (Foreground is disabled)
    INSREG32BF(&g_pIPU->SDC_COM_CONF,
                IPU_SDC_COM_CONF_FG_EN, IPU_DISABLE);

    // Wait for the SDC Foreground DMA interrupt.
    // Timeout after 25ms...with a 60Hz refresh, we should receive
    // an interrupt after 18-20ms.
    DisplayPlaneWaitForVSync(DisplayPlane_1, 25);

    // Now, we can disable IDMAC channel.

    // Set up chaining register
    INSREG32BF(&g_pIPU->IPU_FS_DISP_FLOW,
                IPU_IPU_FS_DISP_FLOW_SDC1_SRC_SEL, 0);

    // Compute bitmask and shifted bit value for idmac register
    iMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_1);
    iBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_DISABLE);

    // Use interlocked function to Disable DMA SDC Channel 1.
    do
    {
        oldVal = INREG32(&g_pIPU->IDMAC_CHA_EN);
        newVal = (oldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IDMAC_CHA_EN,
                oldVal, newVal) != oldVal);

    // Return double-buffer mode to 0 so that we will restart correctly
    // upon next init.

    // Compute bitmask and shifted bit value for idmac register
    iMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_1);
    iBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_SIG_BUF);

    // Use interlocked function to set DB mode to 0.
    do
    {
        oldVal = INREG32(&g_pIPU->IPU_CHA_DB_MODE_SEL);
        newVal = (oldVal & (~iMask)) | iBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IPU_CHA_DB_MODE_SEL,
                oldVal, newVal) != oldVal);

	// Set next buffer to the BUF_0 for when FG is next started.
    g_iSDCFGNextBuffer = 0;

    return TRUE;

}

//------------------------------------------------------------------------------
//
// Function: ForegroundWindowGetCurBuf
//
// This function queries the current buffer for the SDC foreground.
//
// Parameters:
//      None.
//
// Returns:
//      0 if buffer 0 is currently the foreground source
//      1 if buffer 1 is currently the foreground source
//------------------------------------------------------------------------------
DWORD ForegroundWindowGetCurBuf()
{
    return (DWORD) EXTREG32BF(&g_pIPU->IPU_CHA_CUR_BUF, IPU_DMA_CHA_DMASDC_1);
}

//------------------------------------------------------------------------------
//
// Function: DisplayPlaneIsBusy
//
// This function queries whether or not the specified display
// plane is currently busy displaying data.
//
// Parameters:
//      dispPlane
//          [in] Specifies whether to query for the background
//          (DisplayPlane_0) or foreground plane (DisplayPlane_1).
//
// Returns:
//      TRUE if specified plane is busy; FALSE if not busy.
//------------------------------------------------------------------------------
BOOL DisplayPlaneIsBusy(DisplayPlane dispPlane)
{
    BOOL retval = FALSE;

    if (dispPlane == DisplayPlane_0)
    {
        // Poll Background Channel DMA channel busy bit.  If bit is set,
        // background window is busy.
        if (EXTREG32BF(&g_pIPU->IDMAC_CHA_BUSY, IPU_DMA_CHA_DMASDC_0))
        {
            retval = TRUE;
        }
    }
    else if (dispPlane == DisplayPlane_1)
    {
        // Poll Background Channel DMA channel busy bit.  If bit is set,
        // background window is busy.
        if (EXTREG32BF(&g_pIPU->IDMAC_CHA_BUSY, IPU_DMA_CHA_DMASDC_1))
        {
            retval = TRUE;
        }
    }
    else
    {
        DEBUGMSG(SDC_ERROR,
                 (TEXT("%s(): Invalid display plane specified.\r\n"), __WFUNCTION__));
    }

    return retval;
}

//------------------------------------------------------------------------------
//
// Function: DisplayPlaneWaitForNotBusy
//
// This function waits for the specified display
// plane to complete processing the current frame.  If
// the plane is not busy, this function returns immediately.
//
// Parameters:
//      dispPlane
//          [in] Specifies whether to query for the background
//          (DisplayPlane_0) or foreground plane (DisplayPlane_1).
//
// Returns:
//      None.
//------------------------------------------------------------------------------
void DisplayPlaneWaitForNotBusy(DisplayPlane dispPlane)
{
    DisplayPlaneWaitForVSync(dispPlane, 1000 * (1/50));
}

void VSyncInterruptEnable()
{
    UINT32 oldCtrl, newCtrl, ctrlMask, ctrlBitval;

    // Enable and wait for an EOF interrupt

    // Compute bitmask and shifted bit value for ctrl register
    ctrlMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_0);
    ctrlBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, IPU_ENABLE);

    // Use interlocked function to update control registers
    do
    {
         oldCtrl = INREG32(&g_pIPU->IPU_INT_CTRL_1);
         newCtrl = (oldCtrl & (~ctrlMask)) | ctrlBitval;
    } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IPU_INT_CTRL_1,
                        oldCtrl, newCtrl) != oldCtrl);

}


void VSyncInterruptClear()
{
    // Clear status bit (write-1-to-clear) to prepare for interrupt.
    OUTREG32(&g_pIPU->IPU_INT_STAT_1,
            CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, 1));
}

void WaitForVSyncInterrupt()
{
    WaitForSingleObject(g_hSDCBGIntrEvent, INFINITE);
}
//------------------------------------------------------------------------------
//
// Function: DisplayPlaneWaitForVSync
//
// This function waits for the specified display
// plane to complete processing the current frame
// and enter the Vertical Blanking Interval.
//
// Parameters:
//      dispPlane
//          [in] Specifies whether to query for the background
//          (DisplayPlane_0) or foreground plane (DisplayPlane_1).
//
//      timeout
//          [in] Timeout period for VSync interrupt.
//
// Returns:
//      None.
//------------------------------------------------------------------------------
void DisplayPlaneWaitForVSync(DisplayPlane dispPlane, UINT32 timeout)
{
    UINT32 oldCtrl, newCtrl, ctrlMask, ctrlBitval;

    if (dispPlane == DisplayPlane_0)
    {
        // Clear status bit (write-1-to-clear) to prepare
        // for interrupt.
        OUTREG32(&g_pIPU->IPU_INT_STAT_1,
            CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, 1));

        // Enable and wait for an EOF interrupt

            // Compute bitmask and shifted bit value for ctrl register
            ctrlMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_0);
            ctrlBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, IPU_ENABLE);

            // Use interlocked function to update control registers
            do
            {
                oldCtrl = INREG32(&g_pIPU->IPU_INT_CTRL_1);
                newCtrl = (oldCtrl & (~ctrlMask)) | ctrlBitval;
        } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IPU_INT_CTRL_1,
                        oldCtrl, newCtrl) != oldCtrl);

        if (WaitForSingleObject(g_hSDCBGIntrEvent, timeout) == WAIT_TIMEOUT)
            {
                DEBUGMSG(SDC_ERROR,
                         (TEXT("%s(): Waiting for SDC BG EOF interrupt time out!\r\n"), __WFUNCTION__));
            }

            // We have received our interrupt, so we can clear the
            // status bit (write-1-to-clear).
            OUTREG32(&g_pIPU->IPU_INT_STAT_1,
                CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, 1));

        return;
    }
    else if (dispPlane == DisplayPlane_1)
    {
        // Clear status bit (write-1-to-clear) to prepare
        // for interrupt.
        OUTREG32(&g_pIPU->IPU_INT_STAT_1,
            CSP_BITFVAL(IPU_DMA_CHA_DMASDC_0, 1));

            // Foreground plane is busy, so we must
            // wait for an EOF interrupt

            // Compute bitmask and shifted bit value for ctrl register
            ctrlMask = CSP_BITFMASK(IPU_DMA_CHA_DMASDC_1);
            ctrlBitval = CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, IPU_ENABLE);

            // Use interlocked function to update control registers
            do
            {
                oldCtrl = INREG32(&g_pIPU->IPU_INT_CTRL_1);
                newCtrl = (oldCtrl & (~ctrlMask)) | ctrlBitval;
        } while ((UINT32) InterlockedTestExchange((LPLONG)&g_pIPU->IPU_INT_CTRL_1,
                        oldCtrl, newCtrl) != oldCtrl);

        if (WaitForSingleObject(g_hSDCFGIntrEvent, timeout) == WAIT_TIMEOUT)
            {
                DEBUGMSG(SDC_ERROR,
                         (TEXT("%s(): Waiting for SDC FG EOF interrupt time out!\r\n"), __WFUNCTION__));
            }

            // We have received our interrupt, so we can clear the
            // status bit (write-1-to-clear).
            OUTREG32(&g_pIPU->IPU_INT_STAT_1,
                CSP_BITFVAL(IPU_DMA_CHA_DMASDC_1, 1));

        return;
    }
    else
    {
        DEBUGMSG(SDC_ERROR,
                 (TEXT("%s(): Invalid display plane specified.\r\n"), __WFUNCTION__));
    }
}


//------------------------------------------------------------------------------
//
// Function: PeekandPoke
//
// This function is a backdoor entrypoint into the driver. Since the driver can
// give you access to the information that you want.

// Parameters:
//        None
//
// Returns:
//      None.
//
//------------------------------------------------------------------------------
BOOL PeekandPoke( PDEBUG_INFO pvIn)
{
    if ( TRUE == pvIn->bWriteFlag )
    {
        OUTREG32( ((UINT8*)g_pIPU + pvIn->uReg), pvIn->uValue);
    }
    else
    {
        pvIn->uValue = INREG32((UINT8*)g_pIPU + pvIn->uReg);
    }

    return TRUE;
}
