⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpc32xx_lcd.cpp

📁 NXP LPC3000系列 wince BSP包
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//*********************************************************************
//* Software that is described herein is for illustrative purposes only  
//* which provides customers with programming information regarding the  
//* products. This software is supplied "AS IS" without any warranties.  
//* NXP Semiconductors assumes no responsibility or liability for the 
//* use of the software, conveys no license or title under any patent, 
//* copyright, or mask work right to the product. NXP Semiconductors 
//* reserves the right to make changes in the software without 
//* notification. NXP Semiconductors also make no representation or 
//* warranty that such application will be suitable for the specified 
//* use without further testing or modification. 
//*
//* Copyright NXP Semiconductors
//*********************************************************************
//
// lpc32xx_lcd.cpp
//
// This file implements basic flat display driver. Informations about
// supported display modes and switching between them are offloaded to kernel
// via KernelIoControl calls.
//

#define DDI 1
#include "precomp.h"
#include <windows.h>
#include <types.h>
#include <winddi.h>
#include <gpe.h>
#include <emul.h>
#include <ceddk.h>
#include <dispperf.h>
#include <pkfuncs.h>
#include <ddhal.h>
#include "lpc32xx_lcd.h"
#include "lcd_panel_types.h"
#include "lpc32xx_gpio.h"
#include "bsp.h"

#define dim(x) (sizeof(x) / sizeof(x[0]))

//------------------------------------------------------------------------------
// Debug Zones (only for retail)
//#ifndef SHIP_BUILD
INSTANTIATE_GPE_ZONES(0x03, "MGDI Driver", "error", "warn")
#undef  ZONE_ERROR
#undef  ZONE_WARN
#undef  ZONE_FUNCTION
#undef  ZONE_INIT
#undef  ZONE_INFO

#define ZONE_ERROR          DEBUGZONE(0)
#define ZONE_WARN           DEBUGZONE(1)
#define ZONE_FUNCTION       DEBUGZONE(2)
#define ZONE_INIT           DEBUGZONE(3)
#define ZONE_INFO           DEBUGZONE(4)
//#endif

//------------------------------------------------------------------------------
// Static variables
static GPE *g_pGPE = (GPE *) NULL;
static TCHAR gszBaseInstance[256] = _T("Drivers\\Display\\LPC32XX\\CONFIG");
static DWORD PanelType = 0;

//------------------------------------------------------------------------------
// External functions
BOOL APIENTRY GPEEnableDriver(
   ULONG version, ULONG cj, DRVENABLEDATA *pData, ENGCALLBACKS *pCallbacks
);

//------------------------------------------------------------------------------
//
//  Function:  DisplayInit
//
//  The GWES will invoke this routine once prior to making any other calls
//  into the driver. This routine needs to save its instance path information
//  and return TRUE.  If it returns FALSE, GWES will abort the display
//  initialization.
//
BOOL DisplayInit(LPCTSTR pszInstance, DWORD monitors)
{
	// Save copy of instance base
    if(pszInstance != NULL) {
        _tcsncpy(gszBaseInstance, pszInstance, dim(gszBaseInstance));
    }

    g_pGPE = new LPC32XXLCD;

    return TRUE;
}

//------------------------------------------------------------------------------
//
//  Function:  DrvEnableDriver
//
//  This function must be exported from display driver. As long as we use
//  GPE class implementation we don't need do anything else than call
//  GPEEnableDriver library function.
//
BOOL DrvEnableDriver(
    ULONG version, ULONG cj, DRVENABLEDATA *pData, ENGCALLBACKS *pCallbacks
) {
    BOOL rc;

    rc = GPEEnableDriver(version, cj, pData, pCallbacks);

    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  DrvGetMasks
//
ULONG *APIENTRY DrvGetMasks(DHPDEV dhpdev)
{
    return LCDPanelList[PanelType].m_BitMasks;
}

//------------------------------------------------------------------------------
//
//  Function:  RegisterDDHALAPI
//
VOID RegisterDDHALAPI()
{
    DEBUGMSG(ZONE_FUNCTION, (L"+RegisterDDHALAPI\r\n"));
}

//------------------------------------------------------------------------------
//
//  Function:  GetGPE
//
//  This function is called from GPE class library to get pointer to class
//  deriver from GPE.
//
GPE* GetGPE()
{
    return g_pGPE;
}    

//------------------------------------------------------------------------------
//
//  Function:  lcd_update_clock
//
//  Sets the LCD clock.
//
void LPC32XXLCD::lcd_update_clock(UINT32 desired_clock)
{
    UINT32 pixel_div, tmp;
    DWORD clk, bytesret;

	// Get base clock for LCD (HCLK)
	if (KernelIoControl(IOCTL_LPC32XX_GETHCLK, NULL, 0, &clk,
		sizeof (clk), &bytesret) == FALSE)
	{
		// Cannot get clock
        RETAILMSG(1, (_T("lcd_update_clock: lcd_update_clock: Error getting LCD base clock\r\n")));
        RETAILMSG(1, (_T("lcd_update_clock: Using 104MHz for the base clock\r\n")));
        clk = 104000000;
	}

	// Find closest clock divider to get clock rate
	pixel_div = 1;
	while (((clk / pixel_div) > desired_clock) && (pixel_div < 0x3F)) {
		pixel_div++;
	}

   DEBUGMSG(ZONE_INFO, (_T("LCD: lcd_update_clock: Base clock %d, divider %d, LCD clock %d\r\n"),
	   clk, pixel_div, clk/pixel_div));

	tmp = pLCDRegs->lcdpol;

	if (pixel_div <= 1)
    {
        /* Pixel clock divider is 1, skip divider logic */
        tmp |= CLCDC_LCDTIMING2_BCD;
    }
    else
    {
        // Add in new divider
        tmp &= ~(CLCDC_LCDTIMING2_BCD | CLCDC_LCDTIMING2_PCD(0x1F) | 0xF8000000);
		tmp |= (pixel_div & 0x1F);
		tmp |= (((pixel_div >> 5) & 0x1F) << 27);
    }

    pLCDRegs->lcdpol = tmp;
}

//------------------------------------------------------------------------------
//
//  Constructor
//
void LPC32XXLCD::lpc32xx_hw_init(void)
{
    HKEY hkDisplay = NULL;
    DWORD dwStatus, dwType, dwSize, tmp, bsize, UseIRAM, phya;
    PHYSICAL_ADDRESS pa;
	GPIO_REGS_T *pGPIOREGs;

	// Open the registry key and read our configuration
    dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, gszBaseInstance, 0, 0, &hkDisplay);
    if (dwStatus != ERROR_SUCCESS) {
        RETAILMSG(1, (_T("LCD: lpc32xx_hw_init: Error opening registry!\r\n")));
        return;
    }
	else
	{
		// Get panel type from the register, the panel type matches the panels
		// index specified in the panels.cpp list.
		PanelType = 0xffff;
        dwSize = sizeof(DWORD);
	    dwType = REG_DWORD;
        dwStatus = RegQueryValueEx(hkDisplay, _T("LCDPanelType"), NULL, &dwType, 
            (LPBYTE) &PanelType, &dwSize);

	    // Sanity checks
		if (dwStatus != ERROR_SUCCESS) {
	        DEBUGMSG(ZONE_WARN,
				(_T("LCD: lpc32xx_hw_init: No panel type found, using 0!\r\n")));
			PanelType = 0;
		}
		if (PanelType > (LCD_MAX_PANELS - 1)) {
		    RETAILMSG(1,
				(_T("LCD: lpc32xx_hw_init: Invalid panel type, use 0!\r\n")));
			PanelType = 0;
	    }

		// Get IRAM use flag
		// Get panel type from the register, the panel type matches the panels
		// index specified in the panels.cpp list.
		UseIRAM = 1;
        dwSize = sizeof(DWORD);
	    dwType = REG_DWORD;
        dwStatus = RegQueryValueEx(hkDisplay, _T("UseIRAM"), NULL, &dwType, 
            (LPBYTE) &UseIRAM, &dwSize);

		if (dwStatus != ERROR_SUCCESS) {
	        DEBUGMSG(ZONE_WARN,
				(_T("LCD: lpc32xx_hw_init: Using IRAM for LCD buffer\r\n")));
			UseIRAM = 1;
		}
	}
    
    // Close the registry key
    if (hkDisplay != NULL) {
        RegCloseKey(hkDisplay);
    }

	// Only TFT panels on 16bpp and 24bpp are supported
	if (LCDPanelList[PanelType].lcd_panel_type != TFT) {
        RETAILMSG(1, (_T("LCD: lpc32xx_hw_init: Not a TFT panel!\r\n")));
        return;
    }

	// Get pointer to registers used in this driver
    pa.QuadPart = LCD_BASE;
	pLCDRegs = (CLCDC_REGS_T *) MmMapIoSpace(pa, sizeof (CLCDC_REGS_T), FALSE);
    pa.QuadPart = CLK_PM_BASE;
	pCLKPWRRegs = (CLKPWR_REGS_T *)
		MmMapIoSpace(pa, sizeof (CLKPWR_REGS_T), FALSE);
	if ((pLCDRegs == NULL) || (pCLKPWRRegs == NULL))
	{
		RETAILMSG(1, (_T("LCD: lpc32xx_hw_init: Critcal error: cannot map registers!\r\n")));
		if (pLCDRegs != NULL)
		{
			MmUnmapIoSpace(pLCDRegs, sizeof(CLCDC_REGS_T));
		}
		if (pCLKPWRRegs != NULL)
		{
			MmUnmapIoSpace(pCLKPWRRegs, sizeof(CLKPWR_REGS_T));
		}

		return;
	}

	if (LCDPanelList[PanelType].bits_per_pixel == 16) {
		tmp = CLKPWR_LCDCTRL_LCDTYPE_TFT16;
		bsize = 2;
	}
	else if (LCDPanelList[PanelType].bits_per_pixel == 24) {
		tmp = CLKPWR_LCDCTRL_LCDTYPE_TFT24;
		bsize = 4;
	}
	else {
        RETAILMSG(1, (_T("LCD: lpc32xx_hw_init: Unsupported color depth!\r\n")));
        return;
	}

	// Enough memory for frame buffer?
	if ((LCDPanelList[PanelType].pixels_per_line *
		LCDPanelList[PanelType].lines_per_panel * bsize) >
		IMAGE_WINCE_LCD_BUFFERS_SIZE) {
        RETAILMSG(1, (_T("LCD: lpc32xx_hw_init: Frame buffer not big enough!\r\n")));
        return;
	}

	// Enable LCD clocks and setup prescaler to 1
	pCLKPWRRegs->clkpwr_lcdclk_ctrl = (tmp | CLKPWR_LCDCTRL_CLK_EN);

	// Configure LCD based on selected panel type
    pLCDRegs->lcdctrl &= ~CLCDC_LCDCTRL_ENABLE;

    // Generate the timing 0 word
    tmp = (CLCDC_LCDTIMING0_PPL(LCDPanelList[PanelType].pixels_per_line) |
        CLCDC_LCDTIMING0_HSW(LCDPanelList[PanelType].h_sync_pulse_width) |
        CLCDC_LCDTIMING0_HFP(LCDPanelList[PanelType].h_front_porch) |
        CLCDC_LCDTIMING0_HBP(LCDPanelList[PanelType].h_back_porch));
    pLCDRegs->lcdtimh = tmp;

    // Generate the timing 1 word
    tmp = (CLCDC_LCDTIMING1_LPP(LCDPanelList[PanelType].lines_per_panel) |
        CLCDC_LCDTIMING1_VSW(LCDPanelList[PanelType].v_sync_pulse_width) |
        CLCDC_LCDTIMING1_VFP(LCDPanelList[PanelType].v_front_porch) |
        CLCDC_LCDTIMING1_VBP(LCDPanelList[PanelType].v_back_porch));
    pLCDRegs->lcdtimv = tmp;

    // Generate the timing 2 word
    tmp = CLCDC_LCDTIMING2_ACB(LCDPanelList[PanelType].ac_bias_frequency);
    if (LCDPanelList[PanelType].invert_output_enable != 0)
    {
        tmp |= CLCDC_LCDTIMING2_IOE;
    }
    if (LCDPanelList[PanelType].invert_panel_clock != 0)
    {
        tmp |= CLCDC_LCDTIMING2_IPC;
    }
    if (LCDPanelList[PanelType].invert_hsync != 0)
    {
        tmp |= CLCDC_LCDTIMING2_IHS;
    }
    if (LCDPanelList[PanelType].invert_vsync != 0)
    {
        tmp |= CLCDC_LCDTIMING2_IVS;
    }

    // Clocks per line and pixels per line are the same
    tmp = tmp | CLCDC_LCDTIMING2_CPL(
		LCDPanelList[PanelType].pixels_per_line - 1);
    pLCDRegs->lcdpol = tmp;

    // Update timing 2 word with correct clock data
    lcd_update_clock(LCDPanelList[PanelType].optimal_clock);

    // Skip timing 3 word - just set to 0x0
    pLCDRegs->lcdle = 0x00000000;

    // Default with all interrupts off
    pLCDRegs->lcdintrenable = 0x00000000; 

#if 0 // SDRAM only version
    // Default configuration is 16 bits per pixel with blue and
    // green not swapped
	if (LCDPanelList[PanelType].bits_per_pixel == 16) {
		tmp = CLCDC_LCDCTRL_BPP16_565;
	}
	else
	{
		tmp = CLCDC_LCDCTRL_BPP24;
	}
    pLCDRegs->lcdctrl = (tmp | CLCDC_LCDCTRL_RGB | CLCDC_LCDCTRL_TFT);

	// Setup frame buffer
	pLCDRegs->lcdupbase = IMAGE_WINCE_LCD_BUFFERS_PA;

	// Enable LCD
	pLCDRegs->lcdctrl |= (CLCDC_LCDCTRL_ENABLE | CLCDC_LCDCTRL_PWR);

	// Enable LCD and backlight power
    pa.QuadPart = GPIO_BASE;
	pGPIOREGs = (GPIO_REGS_T *) MmMapIoSpace(pa, sizeof (GPIO_REGS_T), FALSE);
	pGPIOREGs->pio_outp_set = _BIT(0);
#if BSP_BOARD_PHY3250_QVGA_LCD1307 > 0
	pGPIOREGs->pio_outp_set = _BIT(4);
#else
	pGPIOREGs->pio_outp_clr = _BIT(4);
#endif
    MmUnmapIoSpace((PVOID) pGPIOREGs, 0);

    // Setup up display mode related constants
    m_nScreenWidth = LCDPanelList[PanelType].pixels_per_line;
    m_nScreenHeight = LCDPanelList[PanelType].lines_per_panel;
    m_colorDepth = LCDPanelList[PanelType].bits_per_pixel;
    m_cbScanLineLength = LCDPanelList[PanelType].pixels_per_line * bsize;
    m_FrameBufferSize = m_nScreenHeight * m_cbScanLineLength;

	// Allocate virtual memory for frame buffer
    m_VirtualFrameBuffer = (DWORD) VirtualAlloc(NULL, m_FrameBufferSize,
		MEM_RESERVE, (PAGE_READWRITE | PAGE_NOCACHE));
    if (!m_VirtualFrameBuffer)
    {
        RETAILMSG(1, (TEXT("m_VirtualFrameBuffer is not allocated\n\r")));
        return;
    }
    if (!VirtualCopy((PVOID)m_VirtualFrameBuffer, (PVOID) (IMAGE_WINCE_LCD_BUFFERS_PA >> 8),
		m_FrameBufferSize, (PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL)))
    {
        RETAILMSG(1, (TEXT("m_VirtualFrameBuffer is not mapped\n\r")));
        VirtualFree((PVOID)m_VirtualFrameBuffer, 0, MEM_RELEASE);
        return;
    }

    DEBUGMSG(ZONE_FUNCTION, (TEXT("m_VirtualFrameBuffer is mapped at %x(PHY : %x)\n\r"),
		m_VirtualFrameBuffer, IMAGE_WINCE_LCD_BUFFERS_PA));

#else // SDRAM and IRAM version
    // Default configuration is 16 bits per pixel with blue and

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -