Wayne 0d1c709fa5
Sync upstream (#6793)
Co-authored-by: Wayne Lin <wclin@nuvoton.com>
2022-12-29 15:15:13 +08:00

578 lines
16 KiB
C

/**************************************************************************//**
* @file nu_disp.c
* @brief DISP driver source file
*
* SPDX-License-Identifier: Apache-2.0
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NuMicro.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup DISP_Driver DISP Driver
@{
*/
/** @addtogroup DISP_EXPORTED_FUNCTIONS DISP Exported Functions
@{
*/
static const DISP_LCD_INFO *g_psDispLcdInfo_Curr = NULL;
const static DISP_LCD_INFO g_sLcdInfo_arr [eDispLcd_Cnt] =
{
{
/* eDispLcd_1024x600 */
.u32ResolutionWidth = 1024,
.u32ResolutionHeight = 600,
.sLcdTiming =
{
.u32PCF = 51000000,
.u32HA = 1024,
.u32HSL = 1,
.u32HFP = 160,
.u32HBP = 160,
.u32VA = 600,
.u32VSL = 1,
.u32VFP = 23,
.u32VBP = 12,
.eHSPP = ePolarity_Positive,
.eVSPP = ePolarity_Positive
},
.sPanelConf =
{
.eDpiFmt = eDPIFmt_D24,
.eDEP = ePolarity_Positive,
.eDP = ePolarity_Positive,
.eCP = ePolarity_Positive
},
},
{
/* eDispLcd_800x480 */
.u32ResolutionWidth = 800,
.u32ResolutionHeight = 480,
.sLcdTiming =
{
.u32PCF = 45000000,
.u32HA = 800,
.u32HSL = 1,
.u32HFP = 210,
.u32HBP = 46,
.u32VA = 480,
.u32VSL = 1,
.u32VFP = 22,
.u32VBP = 23,
.eHSPP = ePolarity_Positive,
.eVSPP = ePolarity_Positive
},
.sPanelConf =
{
.eDpiFmt = eDPIFmt_D24,
.eDEP = ePolarity_Positive,
.eDP = ePolarity_Positive,
.eCP = ePolarity_Positive
},
},
{
/* eDispLcd_1920x1080 */
.u32ResolutionWidth = 1920,
.u32ResolutionHeight = 1080,
.sLcdTiming =
{
.u32PCF = 125000000,
.u32HA = 1920,
.u32HSL = 32,
.u32HFP = 120,
.u32HBP = 128,
.u32VA = 1080,
.u32VSL = 14,
.u32VFP = 21,
.u32VBP = 10,
.eHSPP = ePolarity_Positive,
.eVSPP = ePolarity_Positive
},
.sPanelConf =
{
.eDpiFmt = eDPIFmt_D24,
.eDEP = ePolarity_Positive,
.eDP = ePolarity_Positive,
.eCP = ePolarity_Positive
},
},
};
static uint32_t DISP_GetBitPerPixel(E_FB_FMT eFbFmt)
{
uint32_t u32bpp;
switch (eFbFmt)
{
case eFBFmt_MONOCHROME:
case eFBFmt_R8:
case eFBFmt_INDEX8:
case eFBFmt_NV12:
case eFBFmt_NV16:
u32bpp = 8U;
break;
case eFBFmt_X4R4G4B4:
case eFBFmt_A4R4G4B4:
case eFBFmt_X1R5G5B5:
case eFBFmt_A1R5G5B5:
case eFBFmt_R5G6B5:
case eFBFmt_YUY2:
case eFBFmt_UYVY:
case eFBFmt_YV12:
case eFBFmt_RG16:
u32bpp = 16U;
break;
case eFBFmt_INDEX1:
u32bpp = 1U;
break;
case eFBFmt_INDEX2:
u32bpp = 2U;
break;
case eFBFmt_INDEX4:
u32bpp = 4U;
break;
default:
u32bpp = 32U;
break;
}
return u32bpp;
}
uint64_t DISP_GeneratePixelClk(uint32_t u32PixClkInHz)
{
uint64_t u64PixClkOut;
/* Set new VPLL clock frequency. */
u32PixClkInHz <<= 1U;
u64PixClkOut = CLK_SetPLLFreq(VPLL, PLL_OPMODE_INTEGER, __HXT, (uint64_t)u32PixClkInHz);
/* Waiting clock ready */
CLK_WaitClockReady(CLK_STATUS_VPLLSTB_Msk);
return u64PixClkOut;
}
void DISP_SuspendPixelClk(void)
{
/* Stop VPLL forcely. */
CLK_SetPLLPowerDown(VPLL);
}
void DISP_SetTiming(DISP_LCD_TIMING *psLCDTiming)
{
uint32_t u32HEnd, u32HTotal, u32HSyncStart, u32HSyncEnd;
uint32_t u32VEnd, u32VTotal, u32VSyncStart, u32VSyncEnd;
uint32_t u32Value;
/* Set H- timing */
u32HEnd = psLCDTiming->u32HA;
u32HTotal = u32HEnd + psLCDTiming->u32HFP + psLCDTiming->u32HBP + psLCDTiming->u32HSL;
u32HSyncStart = u32HEnd + psLCDTiming->u32HFP;
u32HSyncEnd = u32HSyncStart + psLCDTiming->u32HSL;
u32Value = (u32HTotal << DISP_HDisplay0_TOTAL_Pos) | (u32HEnd << DISP_HDisplay0_DISPLAY_END_Pos);
DISP->HDisplay0 = u32Value;
u32Value = 0U;
if (psLCDTiming->eHSPP != ePolarity_Disable)
{
u32Value = (psLCDTiming->eHSPP << DISP_HSync0_POLARITY_Pos) | DISP_HSync0_PULSE_Msk;
}
u32Value |= (u32HSyncEnd << DISP_HSync0_END_Pos) | (u32HSyncStart << DISP_HSync0_START_Pos);
DISP->HSync0 = u32Value;
/* Set V- timing */
u32VEnd = psLCDTiming->u32VA;
u32VTotal = u32VEnd + psLCDTiming->u32VFP + psLCDTiming->u32VBP + psLCDTiming->u32VSL;
u32VSyncStart = u32VEnd + psLCDTiming->u32VFP;
u32VSyncEnd = u32VSyncStart + psLCDTiming->u32VSL;
u32Value = (u32VTotal << DISP_VDisplay0_TOTAL_Pos) | (u32VEnd << DISP_VDisplay0_DISPLAY_END_Pos);
DISP->VDisplay0 = u32Value;
u32Value = 0U;
if (psLCDTiming->eVSPP != ePolarity_Disable)
{
u32Value = (psLCDTiming->eVSPP << DISP_VSync0_POLARITY_Pos) | DISP_VSync0_PULSE_Msk;
}
u32Value |= (u32VSyncEnd << DISP_VSync0_END_Pos) | (u32VSyncStart << DISP_VSync0_START_Pos);
DISP->VSync0 = u32Value;
}
void DISP_SetPanelConf(DISP_PANEL_CONF *psPanelConf)
{
uint32_t u32Value = 0U;
if (psPanelConf->eDEP != ePolarity_Disable)
{
u32Value = (psPanelConf->eDEP << DISP_PanelConfig0_DE_POLARITY_Pos) | DISP_PanelConfig0_DE_Msk;
}
if (psPanelConf->eDP != ePolarity_Disable)
{
u32Value |= ((psPanelConf->eDP << DISP_PanelConfig0_DATA_POLARITY_Pos) | DISP_PanelConfig0_DATA_ENABLE_Msk);
}
if (psPanelConf->eCP != ePolarity_Disable)
{
u32Value |= ((psPanelConf->eCP << DISP_PanelConfig0_CLOCK_POLARITY_Pos) | DISP_PanelConfig0_CLOCK_Msk);
}
DISP->DbiConfig0 = 0x00000080U;
DISP->DpiConfig0 = psPanelConf->eDpiFmt << DISP_DpiConfig0_DPI_DATA_FORMAT_Pos;
DISP->PanelConfig0 = u32Value;
}
int DISP_SetTransparencyMode(E_DISP_LAYER eLayer, E_TRANSPARENCY_MODE eTM)
{
switch (eLayer)
{
case eLayer_Video:
DISP->FrameBufferConfig0 &= ~DISP_FrameBufferConfig0_TRANSPARENCY_Msk;
DISP->FrameBufferConfig0 |= (eTM << DISP_FrameBufferConfig0_TRANSPARENCY_Pos);
break;
case eLayer_Overlay:
DISP->OverlayConfig0 &= ~DISP_OverlayConfig0_TRANSPARENCY_Msk;
DISP->OverlayConfig0 |= (eTM << DISP_OverlayConfig0_TRANSPARENCY_Pos);
break;
default:
return -1;
}
return 0;
}
uint32_t DISP_LCDTIMING_GetFPS(const DISP_LCD_TIMING* psDispLCDTiming)
{
static uint32_t u32FPS = 0;
if ( psDispLCDTiming != NULL )
{
uint32_t u32HTotal, u32VTotal;
u32HTotal = psDispLCDTiming->u32HA + psDispLCDTiming->u32HBP + psDispLCDTiming->u32HFP + psDispLCDTiming->u32HSL;
u32VTotal = psDispLCDTiming->u32VA + psDispLCDTiming->u32VBP + psDispLCDTiming->u32VFP + psDispLCDTiming->u32VSL;
u32FPS = psDispLCDTiming->u32PCF / u32HTotal / u32VTotal;
}
return u32FPS;
}
int DISP_Trigger(E_DISP_LAYER eLayer, uint32_t u32Action)
{
switch (eLayer)
{
case eLayer_Video:
if (u32Action)
{
/* Start engine clock. */
CLK_EnableModuleClock(DCU_MODULE);
/* Generate Pixel clock */
DISP_GeneratePixelClk(g_psDispLcdInfo_Curr->sLcdTiming.u32PCF);
DISP->FrameBufferConfig0 |= DISP_FrameBufferConfig0_OUTPUT_Msk;
}
else
{
DISP->FrameBufferConfig0 &= ~DISP_FrameBufferConfig0_OUTPUT_Msk;
/* Stop pixel clock. */
DISP_SuspendPixelClk();
/* Stop engine clock. */
CLK_DisableModuleClock(DCU_MODULE);
}
break;
case eLayer_Overlay:
if (u32Action)
{
DISP->OverlayConfig0 = (DISP->OverlayConfig0 & ~DISP_OverlayConfig0_ENABLE_Msk) | DISP_OverlayConfig0_ENABLE_Msk;
}
else
{
DISP->OverlayConfig0 &= ~DISP_OverlayConfig0_ENABLE_Msk;
}
break;
default:
return -1;
}
return 0;
}
int DISP_SetBlendOpMode(E_DC_BLEND_MODE eDCBM, E_GLOBAL_ALPHA_MODE eGloAM_Src, E_GLOBAL_ALPHA_MODE eGloAM_Dst)
{
uint32_t u32Value;
u32Value = (eGloAM_Dst << DISP_OverlayAlphaBlendConfig0_DST_GLOBAL_ALPHA_MODE_Pos) |
(eGloAM_Src << DISP_OverlayAlphaBlendConfig0_SRC_GLOBAL_ALPHA_MODE_Pos);
switch (eDCBM)
{
case DC_BLEND_MODE_CLEAR:
u32Value |= (eBM_ZERO << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_ZERO << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
case DC_BLEND_MODE_SRC:
u32Value |= (eBM_ONE << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_ZERO << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
case DC_BLEND_MODE_DST:
u32Value |= (eBM_ZERO << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_ONE << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
case DC_BLEND_MODE_SRC_OVER:
u32Value |= (eBM_ONE << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_INVERSED << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
case DC_BLEND_MODE_DST_OVER:
u32Value |= (eBM_INVERSED << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_ONE << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
case DC_BLEND_MODE_SRC_IN:
u32Value |= (eBM_NORMAL << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_ZERO << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
case DC_BLEND_MODE_DST_IN:
u32Value |= (eBM_ZERO << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_NORMAL << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
case DC_BLEND_MODE_SRC_OUT:
u32Value |= (eBM_INVERSED << DISP_OverlayAlphaBlendConfig0_SRC_BLENDING_MODE_Pos) |
(eBM_ZERO << DISP_OverlayAlphaBlendConfig0_DST_BLENDING_MODE_Pos);
break;
default:
return -1;
}
DISP->OverlayAlphaBlendConfig0 = u32Value;
return 0;
}
void DISP_SetBlendValue(uint32_t u32GloAV_Src, uint32_t u32GloAV_Dst)
{
DISP->OverlaySrcGlobalColor0 = u32GloAV_Src;
DISP->OverlayDstGlobalColor0 = u32GloAV_Dst;
}
void DISP_SetColorKeyValue(uint32_t u32ColorKeyLow, uint32_t u32ColorKeyHigh)
{
DISP->OverlayColorKey0 = u32ColorKeyLow;
DISP->OverlayColorKeyHigh0 = u32ColorKeyHigh;
}
int DISP_SetFBAddr(E_DISP_LAYER eLayer, uint32_t u32DMAFBStartAddr)
{
/* Check Start address is 128B alignment. */
if ((u32DMAFBStartAddr % 128) != 0)
return -1;
switch (eLayer)
{
case eLayer_Video:
/* Set frame buffer address registers */
DISP->FrameBufferAddress0 = u32DMAFBStartAddr;
break;
case eLayer_Overlay:
/* Set frame buffer address registers */
DISP->OverlayAddress0 = u32DMAFBStartAddr;
break;
default:
return -1;
}
return 0;
}
int DISP_SetFBFmt(E_DISP_LAYER eLayer, E_FB_FMT eFbFmt, uint32_t u32Pitch)
{
switch (eLayer)
{
case eLayer_Video:
{
uint32_t u32FBConf = DISP->FrameBufferConfig0;
DISP->FrameBufferConfig0 = 0;
DISP->FrameBufferStride0 = u32Pitch;
u32FBConf = (u32FBConf & ~DISP_FrameBufferConfig0_FORMAT_Msk) |
(eFbFmt << DISP_FrameBufferConfig0_FORMAT_Pos) |
DISP_FrameBufferConfig0_RESET_Msk;
DISP->FrameBufferConfig0 = u32FBConf;
break;
}
default:
return -2;
}
return 0;
}
int DISP_SetFBConfig(E_DISP_LAYER eLayer, E_FB_FMT eFbFmt, uint32_t u32ResWidth, uint32_t u32ResHeight, uint32_t u32DMAFBStartAddr)
{
uint32_t u32bpp;
/* Check Start address is 128B alignment. */
if ((u32DMAFBStartAddr % 128) != 0)
return -1;
u32bpp = DISP_GetBitPerPixel(eFbFmt);
switch (eLayer)
{
case eLayer_Video:
DISP->FrameBufferUPlanarAddress0 = 0U;
DISP->FrameBufferVPlanarAddress0 = 0U;
DISP->FrameBufferUStride0 = 0U;
DISP->FrameBufferVStride0 = 0U;
DISP->IndexColorTableIndex0 = 0U;
DISP->FrameBufferSize0 = (u32ResHeight << DISP_FrameBufferSize0_HEIGHT_Pos) |
(u32ResWidth << DISP_FrameBufferSize0_WIDTH_Pos);
DISP->FrameBufferStride0 = u32ResWidth * (u32bpp >> 3U);
/* Set frame buffer address registers */
DISP->FrameBufferAddress0 = u32DMAFBStartAddr;
DISP->FrameBufferConfig0 = (eFbFmt << DISP_FrameBufferConfig0_FORMAT_Pos) |
(eYUV_709_BT709 << DISP_FrameBufferConfig0_YUV_Pos) |
(DISP_FrameBufferConfig0_RESET_Msk);
break;
case eLayer_Overlay:
DISP->OverlayStride0 = u32ResWidth * (u32bpp >> 3U);
/*
* eFbFmt is fixed in eFBFmt_A8R8G8B8.
*/
DISP->OverlayConfig0 = (eFBFmt_A8R8G8B8 << DISP_OverlayConfig0_FORMAT_Pos) |
(0 << DISP_OverlayConfig0_SWIZZLE_Pos) |
(0 << DISP_OverlayConfig0_TRANSPARENCY_Pos) |
(eYUV_709_BT709 << DISP_OverlayConfig0_YUV_Pos) |
(0 << DISP_OverlayConfig0_CLEAR_Pos);
/* Set frame buffer address registers */
DISP->OverlayAddress0 = u32DMAFBStartAddr;
DISP->OverlayVStride0 = 0U;
DISP->OverlayUStride0 = 0U;
DISP->OverlayVStride0 = 0U;
DISP->OverlaySize0 = (u32ResHeight << DISP_OverlaySize0_HEIGHT_Pos) |
(u32ResWidth << DISP_OverlaySize0_WIDTH_Pos);
DISP->OverlayTL0 = (0U << DISP_OverlayTL0_Y_Pos) | (0 << DISP_OverlayTL0_X_Pos);
DISP->OverlayBR0 = (u32ResHeight << DISP_OverlayBR0_Y_Pos) | (u32ResWidth << DISP_OverlayBR0_X_Pos);
/* Default setting */
DISP_SetBlendOpMode(DC_BLEND_MODE_SRC_OVER, eGloAM_NORMAL, eGloAM_NORMAL);
DISP->OverlayClearValue0 = 0U;
DISP_SetColorKeyValue(0U, 0U);
DISP->OverlayUPlanarAddress0 = 0U;
DISP->OverlayVPlanarAddress0 = 0U;
break;
default:
return -2;
}
return 0;
}
int32_t DISP_LCDInit(const DISP_LCD_INFO *psLCDInfo)
{
vu32 vu32UsDelay = CLK_GetPLLClockFreq(CAPLL) / 1000000;
vu32 vu32Timeout;
DISP_LCD_TIMING *psLCDTiming = (DISP_LCD_TIMING *)&psLCDInfo->sLcdTiming;
DISP_PANEL_CONF *psPanelConf = (DISP_PANEL_CONF *)&psLCDInfo->sPanelConf;
/* Store to current. */
g_psDispLcdInfo_Curr = psLCDInfo;
/* Start engine clock. */
DISP_SuspendPixelClk();
/* Reset */
SYS->IPRST0 |= SYS_IPRST0_DISPCRST_Msk;
vu32Timeout = 100 * vu32UsDelay;
while (vu32Timeout--);
SYS->IPRST0 &= ~SYS_IPRST0_DISPCRST_Msk;
vu32Timeout = 100 * vu32UsDelay;
while (vu32Timeout--);
DISP->FrameBufferConfig0 = 0U;
DISP->AQHiClockControl = 0x00071900U;
DISP->AQHiClockControl = 0x00070900U;
/* Delay 5ms */
vu32Timeout = 5000 * vu32UsDelay;
while (vu32Timeout--);
/* Set timing */
DISP_SetTiming(psLCDTiming);
/* Set Panel config */
DISP_SetPanelConf(psPanelConf);
return 0;
}
int32_t DISP_LCDDeinit(void)
{
/* Stop engine clock */
DISP_SuspendPixelClk();
/* Stop engine clock. */
CLK_DisableModuleClock(DCU_MODULE);
g_psDispLcdInfo_Curr = NULL;
return 0;
}
const DISP_LCD_INFO *DISP_GetLCDInst(E_DISP_LCD eDispLcd)
{
if (eDispLcd < eDispLcd_Cnt)
return &g_sLcdInfo_arr[eDispLcd];
return (const DISP_LCD_INFO *)NULL;
}
/*@}*/ /* end of group DISP_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group DISP_Driver */
/*@}*/ /* end of group Standard_Driver */