rt-thread/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_lcd.c

960 lines
32 KiB
C

/**************************************************************************//**
* @file lcd.c
* @brief N9H30 LCD driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "N9H30.h"
#include "nu_sys.h"
#include "nu_lcd.h"
/** @addtogroup N9H30_Device_Driver N9H30 Device Driver
@{
*/
/** @addtogroup N9H30_LCD_Driver LCD Driver
@{
*/
/** @addtogroup N9H30_LCD_EXPORTED_CONSTANTS LCD Exported Constants
@{
*/
/// @cond HIDDEN_SYMBOLS
/* LCD attributes */
static VPOST_T DEF_E50A2V1 =
{
800, /*!< Panel width */
480, /*!< Panel height */
0, /*!< MPU command line low indicator */
0, /*!< MPU command width */
0, /*!< MPU bus width */
VPOSTB_DATA16or18, /*!< Display bus width */
0, /*!< MPU mode */
VPOSTB_COLORTYPE_64K, /*!< Display colors */
VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */
0x020d03a0, /*!< CRTCSIZE register value */
0x01e00320, /*!< CRTCDEND register value */
0x03250321, /*!< CRTCHR register value */
0x03780348, /*!< CRTCHSYNC register value */
0x01f001ed /*!< CRTCVR register value */
};
static VPOST_T DEF_ILI9341_MPU80 =
{
240, /*!< Panel width */
320, /*!< Panel height */
VPOSTB_CMDLOW, /*!< MPU command line low indicator */
VPOSTB_CM16t18HIGH, /*!< MPU command width */
VPOSTB_CMD8, /*!< MPU bus width */
VPOSTB_DATA16or18, /*!< Display bus width */
VPOSTB_MPU80, /*!< MPU mode */
VPOSTB_COLORTYPE_64K, /*!< Display colors */
VPOSTB_DEVICE_MPU, /*!< Type of display panel */
0x01600100, /*!< CRTCSIZE register value */
0x014000F0, /*!< CRTCDEND register value */
0x00FA00F5, /*!< CRTCHR register value */
0x00FC00FA, /*!< CRTCHSYNC register value */
0x01500145 /*!< CRTCVR register value */
};
static VPOST_T DEF_LSA40AT9001 =
{
800, /*!< Panel width */
600, /*!< Panel height */
0, /*!< MPU command line low indicator */
0, /*!< MPU command width */
0, /*!< MPU bus width */
VPOSTB_DATA16or18, /*!< Display bus width */
0, /*!< MPU mode */
VPOSTB_COLORTYPE_64K, /*!< Display colors */
VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */
0x02800425, /*!< CRTCSIZE register value */
0x02580320, /*!< CRTCDEND register value */
0x032F032A, /*!< CRTCHR register value */
0x0334032A, /*!< CRTCHSYNC register value */
0x026C0262 /*!< CRTCVR register value */
};
static VPOST_T DEF_FW070TFT =
{
800, /*!< Panel width */
480, /*!< Panel height */
0, /*!< MPU command line low indicator */
0, /*!< MPU command width */
0, /*!< MPU bus width */
VPOSTB_DATA16or18, /*!< Display bus width */
0, /*!< MPU mode */
VPOSTB_COLORTYPE_16M, /*!< Display colors */
VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */
0x020d0420, /*!< CRTCSIZE register value */
0x01e00320, /*!< CRTCDEND register value */
0x033e0339, /*!< CRTCHR register value */
0x040c03f8, /*!< CRTCHSYNC register value */
0x020001f6 /*!< CRTCVR register value */
};
#define FW043TFT_WIDTH 480 /*!< XRES */
#define FW043TFT_HEIGHT 272 /*!< YRES */
#define FW043TFT_MARGIN_LEFT 30 /*!< HBP (Horizontal Back Porch) */
#define FW043TFT_MARGIN_RIGHT 5 /*!< HFP (Horizontal Front Porch) */
#define FW043TFT_MARGIN_UPPER 2 /*!< VBP (Vertical Back Porch) */
#define FW043TFT_MARGIN_LOWER 27 /*!< VFP (Vertical Front Porch) */
#define FW043TFT_HSYNC_LEN 41 /*!< HPW (HSYNC plus width) */
#define FW043TFT_VSYNC_LEN 10 /*!< VPW (VSYNC width) */
static VPOST_T DEF_FW043TFT =
{
FW043TFT_WIDTH, /*!< Panel width */
FW043TFT_HEIGHT, /*!< Panel height */
0, /*!< MPU command line low indicator */
0, /*!< MPU command width */
0, /*!< MPU bus width */
VPOSTB_DATA16or18, /*!< Display bus width */
0, /*!< MPU mode */
VPOSTB_COLORTYPE_16M, /*!< Display colors */
VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */
.sCRTCSIZE =
{
/*!< Horizontal Total */
.HTT = FW043TFT_MARGIN_LEFT + FW043TFT_WIDTH + FW043TFT_MARGIN_RIGHT,
/*!< Vertical Total */
.VTT = FW043TFT_MARGIN_UPPER + FW043TFT_HEIGHT + FW043TFT_MARGIN_LOWER,
},
.sCRTCDEND =
{
/*!< Horizontal Display Enable End */
.HDEND = FW043TFT_WIDTH,
/*!< Vertical Display Enable End */
.VDEND = FW043TFT_HEIGHT,
},
.sCRTCHR =
{
/*!< Internal Horizontal Retrace Start Timing */
.HRS = FW043TFT_WIDTH + 1,
/*!< Internal Horizontal Retrace End Low */
.HRE = FW043TFT_WIDTH + 5,
},
.sCRTCHSYNC =
{
/*!< Horizontal Sync Start Timing */
.HSYNC_S = FW043TFT_WIDTH + FW043TFT_MARGIN_LEFT,
/*!< Horizontal Sync End Timing */
.HSYNC_E = FW043TFT_WIDTH + FW043TFT_MARGIN_LEFT + FW043TFT_HSYNC_LEN,
/*!< Hsync Signal Adjustment For Multi-Cycles Per Pixel Mode Of Sync-Based Unipac-LCD */
.HSYNC_SHIFT = 0,
},
.sCRTCVR =
{
/*!< Vertical Internal Retrace Start Timing */
.VRS = FW043TFT_HEIGHT + FW043TFT_MARGIN_UPPER,
/*!< Vertical Internal Retrace End Low */
.VRE = FW043TFT_HEIGHT + FW043TFT_MARGIN_UPPER + FW043TFT_VSYNC_LEN,
}
};
#define FW070TFT_WSVGA_WIDTH 1024 /*!< XRES */
#define FW070TFT_WSVGA_HEIGHT 600 /*!< YRES */
#define FW070TFT_WSVGA_MARGIN_LEFT 160 /*!< HBP (Horizontal Back Porch) */
#define FW070TFT_WSVGA_MARGIN_RIGHT 160 /*!< HFP (Horizontal Front Porch) */
#define FW070TFT_WSVGA_MARGIN_UPPER 12 /*!< VBP (Vertical Back Porch) */
#define FW070TFT_WSVGA_MARGIN_LOWER 23 /*!< VFP (Vertical Front Porch) */
#define FW070TFT_WSVGA_HSYNC_LEN 1 /*!< HPW (HSYNC plus width) */
#define FW070TFT_WSVGA_VSYNC_LEN 1 /*!< VPW (VSYNC width) */
static VPOST_T DEF_FW070TFT_WSVGA =
{
FW070TFT_WSVGA_WIDTH, /*!< Panel width */
FW070TFT_WSVGA_HEIGHT, /*!< Panel height */
0, /*!< MPU command line low indicator */
0, /*!< MPU command width */
0, /*!< MPU bus width */
VPOSTB_DATA16or18, /*!< Display bus width */
0, /*!< MPU mode */
VPOSTB_COLORTYPE_16M, /*!< Display colors */
VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */
.sCRTCSIZE =
{
/*!< Horizontal Total */
.HTT = FW070TFT_WSVGA_MARGIN_LEFT + FW070TFT_WSVGA_WIDTH + FW070TFT_WSVGA_MARGIN_RIGHT,
/*!< Vertical Total */
.VTT = FW070TFT_WSVGA_MARGIN_UPPER + FW070TFT_WSVGA_HEIGHT + FW070TFT_WSVGA_MARGIN_LOWER,
},
.sCRTCDEND =
{
/*!< Horizontal Display Enable End */
.HDEND = FW070TFT_WSVGA_WIDTH,
/*!< Vertical Display Enable End */
.VDEND = FW070TFT_WSVGA_HEIGHT,
},
.sCRTCHR =
{
/*!< Internal Horizontal Retrace Start Timing */
.HRS = FW070TFT_WSVGA_WIDTH + 1,
/*!< Internal Horizontal Retrace End Low */
.HRE = FW070TFT_WSVGA_WIDTH + 5,
},
.sCRTCHSYNC =
{
/*!< Horizontal Sync Start Timing */
.HSYNC_S = FW070TFT_WSVGA_WIDTH + FW070TFT_WSVGA_MARGIN_LEFT,
/*!< Horizontal Sync End Timing */
.HSYNC_E = FW070TFT_WSVGA_WIDTH + FW070TFT_WSVGA_MARGIN_LEFT + FW070TFT_WSVGA_HSYNC_LEN,
/*!< Hsync Signal Adjustment For Multi-Cycles Per Pixel Mode Of Sync-Based Unipac-LCD */
.HSYNC_SHIFT = 0,
},
.sCRTCVR =
{
/*!< Vertical Internal Retrace Start Timing */
.VRS = FW070TFT_WSVGA_HEIGHT + FW070TFT_WSVGA_MARGIN_UPPER,
/*!< Vertical Internal Retrace End Low */
.VRE = FW070TFT_WSVGA_HEIGHT + FW070TFT_WSVGA_MARGIN_UPPER + FW070TFT_WSVGA_VSYNC_LEN,
}
};
/* LCD build-in support list */
static VPOST_T *DisplayDevList[DIS_PANEL_CNT] =
{
&DEF_E50A2V1,
&DEF_ILI9341_MPU80,
&DEF_LSA40AT9001,
&DEF_FW070TFT,
&DEF_FW043TFT,
&DEF_FW070TFT_WSVGA
};
static VPOST_T curDisplayDev;
static OSDFORMATEX curOSDDev = {0};
static LCDFORMATEX curVADev = {0};
/// @endcond /* HIDDEN_SYMBOLS */
/*@}*/ /* end of group N9H30_I2C_EXPORTED_CONSTANTS */
/** @addtogroup N9H30_LCD_EXPORTED_FUNCTIONS LCD Exported Functions
@{
*/
/// @cond HIDDEN_SYMBOLS
/* For align 32 */
static uint32_t shift_pointer(uint32_t ptr, uint32_t align)
{
uint32_t alignedPTR;
uint32_t remain;
//printf("pointer position is %x\n",ptr);
if ((ptr % align) != 0)
{
remain = ptr % align;
alignedPTR = ptr + (align - remain);
return alignedPTR;
}
return ptr;
}
/// @endcond /* HIDDEN_SYMBOLS */
/**
* @brief Configure attributes of LCD panel,install interrupt handler and enable LCD engine clock
* @param[in] u32DisplayPanelID is panel id to configure.
* @return none
*/
void vpostLCMInit(uint32_t u32DisplayPanelID)
{
// enable lcd engine clock
outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | (1 << 25));
memset((void *)&curDisplayDev, 0, sizeof(curDisplayDev));
memcpy((void *)&curDisplayDev, DisplayDevList[u32DisplayPanelID], sizeof(curDisplayDev));
outpw(REG_LCM_DEV_CTRL, curDisplayDev.u32CmdLow
| curDisplayDev.u32Cmd16t18
| curDisplayDev.u32CmdBusWidth
| curDisplayDev.u32DataBusWidth
| curDisplayDev.u32MPU_Mode
| curDisplayDev.u32DisplayColors
| curDisplayDev.u32DevType);
outpw(REG_LCM_CRTC_SIZE, curDisplayDev.u32Reg_CRTCSIZE);
outpw(REG_LCM_CRTC_DEND, curDisplayDev.u32Reg_CRTCDEND);
outpw(REG_LCM_CRTC_HR, curDisplayDev.u32Reg_CRTCHR);
outpw(REG_LCM_CRTC_HSYNC, curDisplayDev.u32Reg_CRTCHSYNC);
outpw(REG_LCM_CRTC_VR, curDisplayDev.u32Reg_CRTCVR);
}
/**
* @brief Query LCM capacity and configuration by ID
* @param[in] u32DisplayPanelID is panel id to configure.
* @return LCM instance
*/
VPOST_T *vpostLCMGetInstance(uint32_t u32DisplayPanelID)
{
if (u32DisplayPanelID > (sizeof(DisplayDevList) / sizeof(VPOST_T *)))
return NULL;
return DisplayDevList[u32DisplayPanelID];
}
/**
* @brief Disable LCD engine
* @param none
* @return none
*/
void vpostLCMDeinit(void)
{
// disable lcd engine clock
outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) & ~(1 << 25));
//sysDisableInterrupt(LCD_IRQn);
}
/**
* @brief Get the pointer of frame buffer
* @param none
* @return pointer of frame buffer
* @retval NULL fail.
* @note before calling this function, display width, height and source format must be set first.
*/
uint8_t *vpostGetFrameBuffer(void)
{
uint8_t *u8BufPtr;
uint8_t u32BytePerPixel;
if ((curDisplayDev.u32DevWidth == 0) || (curDisplayDev.u32DevHeight == 0))
return NULL;
switch (curVADev.ucVASrcFormat)
{
case VA_SRC_YUV422:
case VA_SRC_YCBCR422:
case VA_SRC_RGB565:
u32BytePerPixel = 2;
break;
case VA_SRC_RGB666:
case VA_SRC_RGB888:
u32BytePerPixel = 4;
break;
default:
u32BytePerPixel = 2;
}
u8BufPtr = (uint8_t *)malloc((curDisplayDev.u32DevWidth * curDisplayDev.u32DevHeight * u32BytePerPixel) + 32);
if (u8BufPtr == NULL)
return NULL;
u8BufPtr = (uint8_t *)shift_pointer((uint32_t)u8BufPtr, 32);
outpw(REG_LCM_VA_BADDR0, (uint32_t)((uint32_t)u8BufPtr | 0x80000000));
outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~(1 << 30) & ~VPOSTB_DB_EN);
return (uint8_t *)((uint32_t)u8BufPtr | 0x80000000);
}
void vpostSetFrameBuffer(uint8_t *pu8BufPtr)
{
outpw(REG_LCM_VA_BADDR0, (uint32_t)((uint32_t)pu8BufPtr | 0x80000000));
outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~(1 << 30) & ~VPOSTB_DB_EN);
}
/**
* @brief Get the pointer of frame buffer
* @param[in] u32Cnt is the frame buffer count to allocate. Min value is 1.
* @return pointer of frame buffer
* @retval NULL fail.
* @note before calling this function, display width, height and source format must be set first.
*/
uint8_t *vpostGetMultiFrameBuffer(uint32_t u32Cnt)
{
uint8_t *u8BufPtr;
uint8_t u32BytePerPixel;
if ((curDisplayDev.u32DevWidth == 0) || (curDisplayDev.u32DevHeight == 0) || (u32Cnt == 0))
return NULL;
switch (curVADev.ucVASrcFormat)
{
case VA_SRC_YUV422:
case VA_SRC_YCBCR422:
case VA_SRC_RGB565:
u32BytePerPixel = 2;
break;
case VA_SRC_RGB666:
case VA_SRC_RGB888:
u32BytePerPixel = 4;
break;
default:
u32BytePerPixel = 2;
}
u8BufPtr = (uint8_t *)malloc((curDisplayDev.u32DevWidth * curDisplayDev.u32DevHeight * u32BytePerPixel) * u32Cnt + 32);
if (u8BufPtr == NULL)
return NULL;
u8BufPtr = (uint8_t *)shift_pointer((uint32_t)u8BufPtr, 32);
outpw(REG_LCM_VA_BADDR0, (uint32_t)((uint32_t)u8BufPtr | 0x80000000));
outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~(1 << 30) & ~VPOSTB_DB_EN);
return (uint8_t *)((uint32_t)u8BufPtr | 0x80000000);
}
/**
* @brief Set active display window
* @param[in] u16StartY is y start position
* @param[in] u16EndY is y end position
* @param[in] u8BGColorR is background R color
* @param[in] u8BGColorG is background G color
* @param[in] u8BGColorB is background B color
* @return none
*/
void vpostSetActiveWindow(uint16_t u16StartY, uint16_t u16EndY, uint8_t u8BGColorR, uint8_t u8BGColorG, uint8_t u8BGColorB)
{
outpw(REG_LCM_VA_WIN, (u16StartY << 16) | u16EndY);
outpw(REG_LCM_VA_STUFF, (u8BGColorR << 16) | (u8BGColorG << 8) | u8BGColorB);
}
/**
* @brief Configure LCD display mode
* @param[in] u8DisplayMode is display mode, value could be
* - \ref VPOST_DISPLAY_SINGLE
* - \ref VPOST_DISPLAY_CONTINUOUS
* @return none
*/
void vpostSetDisplayMode(uint8_t u8DisplayMode)
{
if (u8DisplayMode == 0)
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(1 << 7)); //clear setting
else
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | (u8DisplayMode) << 7);
}
/**
* @brief Configure display attributes of video interface,
* @param[in] u32VASrcType is display type, value could be
* - \ref VA_SRC_YUV422
* - \ref VA_SRC_YCBCR422
* - \ref VA_SRC_RGB888
* - \ref VA_SRC_RGB666
* - \ref VA_SRC_RGB565
* - \ref VA_SRC_RGB444_LOW
* - \ref VA_SRC_RGB444_HIGH
* @return none
*/
void vpostSetVASrc(uint32_t u32VASrcType)
{
uint32_t u32BytePerPixel, VA_FF, VA_Sride;
curVADev.ucVASrcFormat = u32VASrcType;
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(7 << 8));
if (u32VASrcType != 0)
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | u32VASrcType);
else
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(7 << 8));
if ((u32VASrcType == VA_SRC_RGB888) || (u32VASrcType == VA_SRC_RGB666))
outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~0x7ff07ff | (curDisplayDev.u32DevWidth << 16) | curDisplayDev.u32DevWidth);
else
outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~0x7ff07ff | ((curDisplayDev.u32DevWidth / 2) << 16) | (curDisplayDev.u32DevWidth / 2));
switch (u32VASrcType)
{
case VA_SRC_YUV422:
case VA_SRC_YCBCR422:
case VA_SRC_RGB565:
u32BytePerPixel = 2;
break;
case VA_SRC_RGB666:
case VA_SRC_RGB888:
u32BytePerPixel = 4;
break;
default:
u32BytePerPixel = 2;
}
/* set video stream frame buffer control */
VA_FF = curDisplayDev.u32DevWidth * u32BytePerPixel / 4;
VA_Sride = curDisplayDev.u32DevWidth * u32BytePerPixel / 4;
outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~0x7ff07ff | (VA_FF << 16) | VA_Sride);
}
/**
* @brief Start to display
* @param none
* @return none
*/
void vpostVAStartTrigger(void)
{
if ((inpw(REG_LCM_DCCS) & VPOSTB_SINGLE) == VPOSTB_SINGLE)
while ((inpw(REG_LCM_DCCS) & VPOSTB_VA_EN) == VPOSTB_VA_EN); //wait VA_EN low
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_DISP_OUT_EN); //display_out-enable
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_VA_EN); //va-enable
}
/**
* @brief Stop to display
* @param none
* @return none
*/
void vpostVAStopTrigger(void)
{
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(VPOSTB_DISP_OUT_EN | VPOSTB_VA_EN)); //OSD disable
}
/**
* @brief Configure LCD scaling attribute
* @param[in] u8HIntegral is horizontal integral
* @param[in] u16HDecimal is horizontal decimal
* @param[in] u8VIntegral is vertical integral
* @param[in] u16VDecimal is vertical decimal
* @param[in] u32Mode is scale mode, value could be
* - \ref VA_SCALE_INTERPOLATION
* - \ref VA_SCALE_DUPLICATION
* @return none
*/
void vpostVAScalingCtrl(uint8_t u8HIntegral, uint16_t u16HDecimal, uint8_t u8VIntegral, uint16_t u16VDecimal, uint32_t u32Mode)
{
outpw(REG_LCM_VA_SCALE, ((((uint32_t)u8VIntegral << 10) + ((uint32_t)ceil((double)1024 / 10)*u16VDecimal)) << 16)
| (((uint32_t)u8HIntegral << 10) + ((uint32_t)ceil((double)1024 / 10)*u16HDecimal)) | u32Mode);
}
/**
* @brief Set OSD color key
* @param[in] u8CKeyColorR is color key R color
* @param[in] u8CKeyColorG is color key G color
* @param[in] u8CKeyColorB is color key B color
* @return none
*/
void vpostOSDSetColKey(uint8_t u8CKeyColorR, uint8_t u8CKeyColorG, uint8_t u8CKeyColorB)
{
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & ~(VPOSTB_BLI_ON | VPOSTB_CKEY_ON)); //blinking disable, color-key disable
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | VPOSTB_CKEY_ON);//color-key enable
outpw(REG_LCM_OSD_CKEY, ((uint32_t)(u8CKeyColorR << 16) | (uint32_t)(u8CKeyColorG << 8) | u8CKeyColorB));
}
/**
* @brief Set OSD color mask, OSD data only will be displayed if the mask bit is set as 1.
* @param[in] u8MaskColorR is color key R color
* @param[in] u8MaskColorG is color key G color
* @param[in] u8MaskColorB is color key B color
* @return none
*/
void vpostOSDSetColMask(uint8_t u8MaskColorR, uint8_t u8MaskColorG, uint8_t u8MaskColorB)
{
outpw(REG_LCM_OSD_CMASK, ((u8MaskColorR << 16) | (u8MaskColorG << 8) | u8MaskColorB));
}
/**
* @brief Set OSD blinking function
* @param[in] u8OSDBlinkVcnt is blinking cycle time, unit is VSync
* @return none
*/
void vpostOSDSetBlinking(uint8_t u8OSDBlinkVcnt)
{
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & ~(VPOSTB_BLI_ON | VPOSTB_CKEY_ON)); //blinking disable, color-key disable
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | VPOSTB_BLI_ON);
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | ((uint32_t)(u8OSDBlinkVcnt) << 16));
}
/**
* @brief Disable OSD blinking function
* @param none
* @return none
*/
void vpostOSDDisableBlinking(void)
{
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & ~ VPOSTB_BLI_ON);
}
/**
* @brief Configure display attributes of OSD
* @param[in] u32OSDSrcType is display type, value could be
* - \ref OSD_SRC_YUV422
* - \ref OSD_SRC_YCBCR422
* - \ref OSD_SRC_RGB888
* - \ref OSD_SRC_RGB666
* - \ref OSD_SRC_RGB565
* - \ref OSD_SRC_RGB444_LOW
* - \ref OSD_SRC_RGB444_HIGH
* - \ref OSD_SRC_RGB332
* @return none
*/
void vpostSetOSDSrc(uint32_t u32OSDSrcType)
{
uint32_t u32BytePerPixel, VA_FF, VA_Sride;
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(7 << 12) | u32OSDSrcType);
curOSDDev.ucOSDSrcFormat = u32OSDSrcType;
switch (u32OSDSrcType)
{
case OSD_SRC_YUV422:
case OSD_SRC_YCBCR422:
case OSD_SRC_RGB565:
u32BytePerPixel = 2;
break;
case OSD_SRC_RGB666:
case OSD_SRC_RGB888:
u32BytePerPixel = 4;
break;
default:
u32BytePerPixel = 2;
}
/* set video stream frame buffer control */
VA_FF = curOSDDev.nOSDWidth * u32BytePerPixel / 4;
VA_Sride = curOSDDev.nOSDWidth * u32BytePerPixel / 4;
outpw(REG_LCM_OSD_FBCTRL, inpw(REG_LCM_OSD_FBCTRL) & ~0x7ff07ff | (VA_FF << 16) | VA_Sride);
}
/**
* @brief Get the pointer of OSD frame buffer
* @param none
* @return pointer of OSD frame buffer
* @retval NULL fail.
* @note Must call \ref vpostOSDSetWindow and \ref vpostSetOSDSrc before calling this function
*/
uint8_t *vpostGetOSDBuffer(void)
{
uint32_t u32BytePerPixel;
uint8_t *u8BufPtr;
if ((curOSDDev.nOSDWidth == 0) || (curOSDDev.nOSDHeight == 0))
{
return NULL;
}
switch (curOSDDev.ucOSDSrcFormat)
{
case OSD_SRC_YUV422:
case OSD_SRC_YCBCR422:
case OSD_SRC_RGB565:
u32BytePerPixel = 2;
break;
case OSD_SRC_RGB666:
case OSD_SRC_RGB888:
u32BytePerPixel = 4;
break;
default:
u32BytePerPixel = 2;
}
u8BufPtr = (uint8_t *)malloc((curOSDDev.nOSDWidth * curOSDDev.nOSDHeight * u32BytePerPixel) + 32);
if (u8BufPtr == NULL)
return NULL;
u8BufPtr = (uint8_t *)shift_pointer((uint32_t)u8BufPtr, 32);
outpw(REG_LCM_OSD_BADDR, (uint32_t)((uint32_t)u8BufPtr | 0x80000000));
return (uint8_t *)((uint32_t)u8BufPtr | 0x80000000);
}
/**
* @brief Get the pointer of OSD buffer
* @param[in] u32Cnt is the frame buffer count to allocate. Min value is 1.
* @return pointer of frame buffer
* @retval NULL fail.
* @note before calling this function, display width, height and source format must be set first.
*/
uint8_t *vpostGetMultiOSDBuffer(uint32_t u32Cnt)
{
uint32_t u32BytePerPixel;
uint8_t *u8BufPtr;
if ((curOSDDev.nOSDWidth == 0) || (curOSDDev.nOSDHeight == 0))
{
return NULL;
}
switch (curOSDDev.ucOSDSrcFormat)
{
case OSD_SRC_YUV422:
case OSD_SRC_YCBCR422:
case OSD_SRC_RGB565:
u32BytePerPixel = 2;
break;
case OSD_SRC_RGB666:
case OSD_SRC_RGB888:
u32BytePerPixel = 4;
break;
default:
u32BytePerPixel = 2;
}
u8BufPtr = (uint8_t *)malloc((curOSDDev.nOSDWidth * curOSDDev.nOSDHeight * u32BytePerPixel) * u32Cnt + 32);
if (u8BufPtr == NULL)
return NULL;
u8BufPtr = (uint8_t *)shift_pointer((uint32_t)u8BufPtr, 32);
outpw(REG_LCM_OSD_BADDR, (uint32_t)((uint32_t)u8BufPtr | 0x80000000));
return (uint8_t *)((uint32_t)u8BufPtr | 0x80000000);
}
void vpostSetOSDBuffer(uint8_t *u8BufPtr)
{
outpw(REG_LCM_OSD_BADDR, (uint32_t)((uint32_t)u8BufPtr | 0x80000000));
}
/**
* @brief Enable OSD function
* @param none
* @return none
*/
void vpostOSDEnable(void)
{
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_OSD_EN); //OSD enable
}
/**
* @brief Disable OSD function
* @param none
* @return none
*/
void vpostOSDDisable(void)
{
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~VPOSTB_OSD_EN); //OSD disable
}
/**
* @brief Configure OSD scaling attribute
* @param[in] u8HIntegral is horizontal integral
* @param[in] u16HDecimal is horizontal decimal
* @param[in] u8VScall is scale mode, value could be
* - \ref VPOSTB_OSD_VUP_1X
* - \ref VPOSTB_OSD_VUP_2X
* - \ref VPOSTB_OSD_VUP_4X
* @return none
*/
void vpostOSDScalingCtrl(uint8_t u8HIntegral, uint16_t u16HDecimal, uint8_t u8VScall)
{
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & 0xfff0ffff); //clear OSD scaling setting
if (u8VScall != 0)
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | (u8VScall << 16));
outpw(REG_LCM_OSD_SCALE, ((uint32_t)u8HIntegral << 10) | ((uint32_t)ceil((double)1024 / 10 * u16HDecimal)) << 6);
}
/**
* @brief Set OSD display window, including start position, width and height.
* @param[in] u32XStart is X start position
* @param[in] u32YStart is Y start position
* @param[in] u32Width is OSD display width
* @param[in] u32Height is OSD display height
* @return none
*/
void vpostOSDSetWindow(uint32_t u32XStart, uint32_t u32YStart, uint32_t u32Width, uint32_t u32Height)
{
outpw(REG_LCM_OSD_WINS, ((u32YStart + 1) << 16) | (u32XStart + 1));
outpw(REG_LCM_OSD_WINE, ((u32YStart + u32Height) << 16) | (u32XStart + u32Width));
curOSDDev.nOSDWidth = u32Width;
curOSDDev.nOSDHeight = u32Height;
}
/**
* @brief Initialize hardware cursor function
* @param[in] u32CursorBMPBuff is pointer of hardware cursor image
* @param[in] ucMode is hardware cursor mode, value could be
* - \ref HC_MODE0
* - \ref HC_MODE1
* - \ref HC_MODE2
* - \ref HC_MODE3
* - \ref HC_MODE4
* - \ref HC_MODE5
* @return none
*/
void vpostHCInit(uint32_t *u32CursorBMPBuff, VA_HCMODE_E ucMode)
{
int bpp = 2;
int BlockWidth = 32;
int bpw = 32;
outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x003f3f00 | (0x00 << 8) | (0x00 << 16)); //set TIP
if (ucMode == HC_MODE0)
{
bpp = 2;
BlockWidth = 32;
outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7); //set mode 0 32X32X2bpp 4 color
}
else if (ucMode == HC_MODE1)
{
bpp = 2;
BlockWidth = 32;
outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x1); //set mode 1 32X32X2bpp 3 color and 1 transparent
}
else if (ucMode == HC_MODE2)
{
bpp = 2;
BlockWidth = 64;
outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x2); //set mode 2 64X64X2bpp 4 color
}
else if (ucMode == HC_MODE3)
{
bpp = 2;
BlockWidth = 64;
outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x3); //set mode 3 64X64X2bpp 3 color and 1 transparent
}
else if (ucMode == HC_MODE4)
{
bpp = 1;
BlockWidth = 128;
outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x4); //set mode 4 128X128X1bpp 2 color
}
else if (ucMode == HC_MODE5)
{
bpp = 1;
BlockWidth = 128;
outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x5); //set mode 5 128X128X1bpp 1 color and 1 transparent
}
outpw(REG_LCM_HC_WBCTRL, ((bpp * BlockWidth / bpw) << 16) | (bpp * BlockWidth / bpw));
outpw(REG_LCM_HC_BADDR, (uint32_t)u32CursorBMPBuff);
outpw(REG_LCM_HC_COLOR0, 0x00ff0000); // RED color
outpw(REG_LCM_HC_COLOR1, 0x0000ff00); // GREEN color
outpw(REG_LCM_HC_COLOR2, 0x000000ff); // BLUE color
outpw(REG_LCM_HC_COLOR3, 0x00ffff00); // YELLOW color
outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_HC_EN);
}
/**
* @brief Set the position of hardware cursor
* @param[in] u32CursorX is X position
* @param[in] u32CursorY is Y position
* @return none
*/
void vpostHCPosCtrl(uint32_t u32CursorX, uint32_t u32CursorY)
{
outpw(REG_LCM_HC_POS, (u32CursorY << 16) | u32CursorX); //set Cursor position
}
/**
* @brief Set OSD overlay condition
* @param[in] u8OSDDisplayMatch is display method when mask bit is matched, value could be
* - \ref DISPLAY_VIDEO
* - \ref DISPLAY_OSD
* - \ref DISPLAY_SYNTHESIZED
* @param[in] u8OSDDisplayUnMatch is display method when mask bit is unmatched
* - \ref DISPLAY_VIDEO
* - \ref DISPLAY_OSD
* - \ref DISPLAY_SYNTHESIZED
* @param[in] u8OSDSynW is synthesis video weighting, based on match condition
* @return none
*/
void vpostOSDSetOverlay(uint8_t u8OSDDisplayMatch, uint8_t u8OSDDisplayUnMatch, uint8_t u8OSDSynW)
{
/* clear OCR0 and OCR1 */
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & 0xfffffff0);
/* match condition */
if (u8OSDDisplayMatch != 0)
{
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | (u8OSDDisplayMatch << 2));
}
/* unmatch condition */
if (u8OSDDisplayUnMatch != 0)
{
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | (u8OSDDisplayUnMatch));
}
/* synthesized weight */
if (u8OSDDisplayMatch == DISPLAY_SYNTHESIZED || u8OSDDisplayUnMatch == DISPLAY_SYNTHESIZED)
{
outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | (u8OSDSynW << 4));
}
}
/**
* @brief Write MPU command
* @param[in] uscmd MPU command code
* @return none
*/
void vpostMPUWriteAddr(uint16_t uscmd)
{
outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & ~(1 << 30)); //RS=0
outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & ~(1 << 29)); //w
outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) | (1 << 5))); //CMD ON
outpw(REG_LCM_MPU_CMD, (inpw(REG_LCM_MPU_CMD) & 0xffff0000 | uscmd));
while (inpw(REG_LCM_MPU_CMD) & (1UL << 31));
outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) & ~(1 << 5))); //CMD OFF
}
/**
* @brief Write MPU data
* @param[in] usdata MPU data
* @return none
*/
void vpostMPUWriteData(uint16_t usdata)
{
outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) | (1 << 30)); //RS=1
outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & ~(1 << 29)); //w
outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) | (1 << 5))); //CMD ON
outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & 0xffff0000 | usdata);
while (inpw(REG_LCM_MPU_CMD) & (1UL << 31));
outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) & ~(1 << 5))); //CMD OFF
}
/**
* @brief Read MPU data
* @param none
* @return MPU data
*/
uint32_t vpostMPUReadData(void)
{
uint32_t udata;
outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) | (1 << 30)); //RS=1
outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) | (1 << 5))); //CMD ON
outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) | (1 << 29)); //r
while (inpw(REG_LCM_MPU_CMD) & (1UL << 31));
udata = inpw(REG_LCM_MPU_CMD) & 0xffff;
outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) & ~(1 << 5))); //CMD OFF
return udata;
}
/*@}*/ /* end of group N9H30_LCD_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group N9H30_LCD_Driver */
/*@}*/ /* end of group N9H30_Device_Driver */
/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/