summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c527
1 files changed, 527 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c b/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c
new file mode 100644
index 0000000000..356a4625b0
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lcdifv2/fsl_lcdifv2.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2019-2022 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lcdifv2.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lcdifv2"
+#endif
+
+#define LCDIFV2_LUT_MEM(base) \
+ ((volatile uint32_t *)(((uint32_t)(base)) + (uint32_t)FSL_FEATURE_LCDIFV2_CLUT_RAM_OFFSET))
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for LCDIF module.
+ *
+ * @param base LCDIF peripheral base address
+ */
+static uint32_t LCDIFV2_GetInstance(const LCDIFV2_Type *base);
+
+/*!
+ * @brief Reset register value to default status.
+ *
+ * @param base LCDIF peripheral base address
+ */
+static void LCDIFV2_ResetRegister(LCDIFV2_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to LCDIF clock for each instance. */
+static const clock_ip_name_t s_lcdifv2Clocks[] = LCDIFV2_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t LCDIFV2_GetInstance(const LCDIFV2_Type *base)
+{
+ static LCDIFV2_Type *const s_lcdifv2Bases[] = LCDIFV2_BASE_PTRS;
+
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_lcdifv2Bases); instance++)
+ {
+ if (s_lcdifv2Bases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lcdifv2Bases));
+
+ return instance;
+}
+
+static void LCDIFV2_ResetRegister(LCDIFV2_Type *base)
+{
+ uint32_t i;
+
+ base->DISP_PARA = 0U;
+ base->CTRL = 0x80000000U;
+ base->DISP_SIZE = 0U;
+ base->HSYN_PARA = 0x00C01803U;
+ base->VSYN_PARA = 0x00C01803U;
+ base->INT[0].INT_ENABLE = 0U;
+ base->INT[1].INT_ENABLE = 0U;
+ base->PDI_PARA = 0x00001000U;
+
+ for (i = 0; i < (uint32_t)LCDIFV2_LAYER_COUNT; i++)
+ {
+ base->LAYER[i].CTRLDESCL5 = 0U;
+ base->LAYER[i].CTRLDESCL1 = 0U;
+ base->LAYER[i].CTRLDESCL2 = 0U;
+ base->LAYER[i].CTRLDESCL3 = 0U;
+ base->LAYER[i].CTRLDESCL4 = 0U;
+ base->LAYER[i].CTRLDESCL6 = 0U;
+ }
+
+ for (i = 0; i < (uint32_t)LCDIFV2_LAYER_CSC_COUNT; i++)
+ {
+ base->LAYER[i].CSC_COEF0 = 0x04000000U;
+ base->LAYER[i].CSC_COEF1 = 0x01230208U;
+ base->LAYER[i].CSC_COEF2 = 0x076B079CU;
+ }
+
+ /* Clear interrupt status. */
+ base->INT[0].INT_STATUS = 0xFFFFFFFFU;
+ base->INT[1].INT_STATUS = 0xFFFFFFFFU;
+}
+
+/*!
+ * brief Initializes the LCDIF v2.
+ *
+ * This function ungates the LCDIF v2 clock and release the peripheral reset.
+ *
+ * param base LCDIF v2 peripheral base address.
+ */
+void LCDIFV2_Init(LCDIFV2_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ uint32_t instance = LCDIFV2_GetInstance(base);
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_lcdifv2Clocks[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ LCDIFV2_ResetRegister(base);
+
+ /* Out of reset. */
+ base->CTRL = 0U;
+}
+
+/*!
+ * brief Deinitializes the LCDIF peripheral.
+ *
+ * param base LCDIF peripheral base address.
+ */
+void LCDIFV2_Deinit(LCDIFV2_Type *base)
+{
+ LCDIFV2_ResetRegister(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && (0 != FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL))
+ uint32_t instance = LCDIFV2_GetInstance(base);
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_lcdifv2Clocks[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Reset the LCDIF v2.
+ *
+ * param base LCDIF peripheral base address.
+ */
+void LCDIFV2_Reset(LCDIFV2_Type *base)
+{
+ LCDIFV2_ResetRegister(base);
+
+ /* Release and ready to work. */
+ base->CTRL = 0U;
+}
+
+/*!
+ * brief Gets the LCDIF display default configuration structure.
+ *
+ * param config Pointer to the LCDIF configuration structure.
+ */
+void LCDIFV2_DisplayGetDefaultConfig(lcdifv2_display_config_t *config)
+{
+ assert(NULL != config);
+
+ config->panelWidth = 0U;
+ config->panelHeight = 0U;
+ config->hsw = 3U;
+ config->hfp = 3U;
+ config->hbp = 3U;
+ config->vsw = 3U;
+ config->vfp = 3U;
+ config->vbp = 3U;
+ config->polarityFlags = (uint32_t)kLCDIFV2_VsyncActiveHigh | (uint32_t)kLCDIFV2_HsyncActiveHigh |
+ (uint32_t)kLCDIFV2_DataEnableActiveHigh | (uint32_t)kLCDIFV2_DriveDataOnRisingClkEdge |
+ (uint32_t)kLCDIFV2_DataActiveHigh;
+ config->lineOrder = kLCDIFV2_LineOrderRGB;
+}
+
+/*!
+ * brief Set the LCDIF v2 display configurations.
+ *
+ * param base LCDIF peripheral base address.
+ * param config Pointer to the LCDIF configuration structure.
+ */
+void LCDIFV2_SetDisplayConfig(LCDIFV2_Type *base, const lcdifv2_display_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Configure the parameters. */
+ base->DISP_SIZE = ((uint32_t)config->panelWidth << LCDIFV2_DISP_SIZE_DELTA_X_SHIFT) |
+ ((uint32_t)config->panelHeight << LCDIFV2_DISP_SIZE_DELTA_Y_SHIFT);
+
+ base->HSYN_PARA = ((uint32_t)config->hsw << LCDIFV2_HSYN_PARA_PW_H_SHIFT) |
+ ((uint32_t)config->hbp << LCDIFV2_HSYN_PARA_BP_H_SHIFT) |
+ ((uint32_t)config->hfp << LCDIFV2_HSYN_PARA_FP_H_SHIFT);
+
+ base->VSYN_PARA = ((uint32_t)config->vsw << LCDIFV2_VSYN_PARA_PW_V_SHIFT) |
+ ((uint32_t)config->vbp << LCDIFV2_VSYN_PARA_BP_V_SHIFT) |
+ ((uint32_t)config->vfp << LCDIFV2_VSYN_PARA_FP_V_SHIFT);
+
+ base->DISP_PARA = LCDIFV2_DISP_PARA_LINE_PATTERN((uint32_t)config->lineOrder);
+
+ base->CTRL = (uint32_t)(config->polarityFlags);
+}
+
+/*!
+ * brief Set the color space conversion mode.
+ *
+ * Supports YUV2RGB and YCbCr2RGB.
+ *
+ * param base LCDIFv2 peripheral base address.
+ * param layerIndex Index of the layer.
+ * param mode The conversion mode.
+ */
+void LCDIFV2_SetCscMode(LCDIFV2_Type *base, uint8_t layerIndex, lcdifv2_csc_mode_t mode)
+{
+ assert(layerIndex < (uint32_t)LCDIFV2_LAYER_CSC_COUNT);
+
+ /*
+ * The equations used for Colorspace conversion are:
+ *
+ * R = C0*(Y+Y_OFFSET) + C1(V+UV_OFFSET)
+ * G = C0*(Y+Y_OFFSET) + C3(U+UV_OFFSET) + C2(V+UV_OFFSET)
+ * B = C0*(Y+Y_OFFSET) + C4(U+UV_OFFSET)
+ */
+
+ if (kLCDIFV2_CscYUV2RGB == mode)
+ {
+ base->LAYER[layerIndex].CSC_COEF0 = LCDIFV2_CSC_COEF0_ENABLE_MASK | LCDIFV2_CSC_COEF0_C0(0x100U) /* 1.00. */
+ | LCDIFV2_CSC_COEF0_Y_OFFSET(0x0U) /* 0. */
+ | LCDIFV2_CSC_COEF0_UV_OFFSET(0x0U); /* 0. */
+
+ base->LAYER[layerIndex].CSC_COEF1 = LCDIFV2_CSC_COEF1_C1(0x0123U) /* 1.140. */
+ | LCDIFV2_CSC_COEF1_C4(0x0208U); /* 2.032. */
+ base->LAYER[layerIndex].CSC_COEF2 = LCDIFV2_CSC_COEF2_C2(0x076BU) /* -0.851. */
+ | LCDIFV2_CSC_COEF2_C3(0x079BU); /* -0.394. */
+ }
+ else if (kLCDIFV2_CscYCbCr2RGB == mode)
+ {
+ base->LAYER[layerIndex].CSC_COEF0 = LCDIFV2_CSC_COEF0_ENABLE_MASK | LCDIFV2_CSC_COEF0_YCBCR_MODE_MASK |
+ LCDIFV2_CSC_COEF0_C0(0x12AU) /* 1.164. */
+ | LCDIFV2_CSC_COEF0_Y_OFFSET(0x1F0U) /* -16. */
+ | LCDIFV2_CSC_COEF0_UV_OFFSET(0x180U); /* -128. */
+ base->LAYER[layerIndex].CSC_COEF1 = LCDIFV2_CSC_COEF1_C1(0x0198U) /* 1.596. */
+ | LCDIFV2_CSC_COEF1_C4(0x0204U); /* 2.017. */
+ base->LAYER[layerIndex].CSC_COEF2 = LCDIFV2_CSC_COEF2_C2(0x0730U) /* -0.813. */
+ | LCDIFV2_CSC_COEF2_C3(0x079CU); /* -0.392. */
+ }
+ else
+ {
+ base->LAYER[layerIndex].CSC_COEF0 = 0U;
+ base->LAYER[layerIndex].CSC_COEF1 = 0U;
+ base->LAYER[layerIndex].CSC_COEF2 = 0U;
+ }
+}
+
+/*!
+ * brief Set the layer source buffer configuration.
+ *
+ * param base LCDIFv2 peripheral base address.
+ * param layerIndex Layer layerIndex.
+ * param config Pointer to the configuration.
+ */
+void LCDIFV2_SetLayerBufferConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_buffer_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+
+ base->LAYER[layerIndex].CTRLDESCL3 = config->strideBytes;
+
+ reg = base->LAYER[layerIndex].CTRLDESCL5;
+ reg = (reg & ~(LCDIFV2_CTRLDESCL5_BPP_MASK | LCDIFV2_CTRLDESCL5_YUV_FORMAT_MASK)) | (uint32_t)config->pixelFormat;
+
+ if (0U == (reg & LCDIFV2_CTRLDESCL5_AB_MODE_MASK))
+ {
+ reg |= LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK;
+ }
+
+ base->LAYER[layerIndex].CTRLDESCL5 = reg;
+}
+
+/*!
+ * brief Set the LUT data.
+ *
+ * This function sets the specific layer LUT data, if useShadowLoad is true,
+ * call LCDIFV2_TriggerLayerShadowLoad after this function, the
+ * LUT will be loaded to the hardware during next vertical blanking period.
+ * If useShadowLoad is false, the LUT data is loaded to hardware directly.
+ *
+ * param base LCDIF v2 peripheral base address.
+ * param layerIndex Which layer to set.
+ * param lutData The LUT data to load.
+ * param count Count of lutData.
+ * retval kStatus_Success Set success.
+ * retval kStatus_Fail Previous LUT data is not loaded to hardware yet.
+ */
+status_t LCDIFV2_SetLut(
+ LCDIFV2_Type *base, uint8_t layerIndex, const uint32_t *lutData, uint16_t count, bool useShadowLoad)
+{
+ assert(count <= LCDIFV2_LUT_ENTRY_NUM);
+
+ uint16_t i;
+ status_t status;
+
+ /* Previous setting is not updated. */
+ if ((base->CLUT_LOAD & LCDIFV2_CLUT_LOAD_CLUT_UPDATE_EN_MASK) != 0U)
+ {
+ status = kStatus_Fail;
+ }
+ else
+ {
+ if (useShadowLoad)
+ {
+ base->CLUT_LOAD = LCDIFV2_CLUT_LOAD_SEL_CLUT_NUM(layerIndex) | LCDIFV2_CLUT_LOAD_CLUT_UPDATE_EN_MASK;
+ }
+ else
+ {
+ base->CLUT_LOAD = LCDIFV2_CLUT_LOAD_SEL_CLUT_NUM(layerIndex);
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ (LCDIFV2_LUT_MEM(base))[i + (LCDIFV2_LUT_ENTRY_NUM * layerIndex)] = lutData[i];
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Set the layer alpha blend mode.
+ *
+ * param base LCDIFv2 peripheral base address.
+ * param layerIndex Index of the CSC unit.
+ * param config Pointer to the blend configuration.
+ */
+void LCDIFV2_SetLayerBlendConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_blend_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t reg;
+
+ reg = base->LAYER[layerIndex].CTRLDESCL5;
+ reg &= ~(LCDIFV2_CTRLDESCL5_GLOBAL_ALPHA_MASK | LCDIFV2_CTRLDESCL5_AB_MODE_MASK |
+ LCDIFV2_CTRLDESCL5_PD_FACTOR_MODE_MASK | LCDIFV2_CTRLDESCL5_PD_ALPHA_MODE_MASK |
+ LCDIFV2_CTRLDESCL5_PD_COLOR_MODE_MASK | LCDIFV2_CTRLDESCL5_PD_GLOBAL_ALPHA_MODE_MASK |
+ LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK);
+
+ reg |=
+ (LCDIFV2_CTRLDESCL5_GLOBAL_ALPHA(config->globalAlpha) | LCDIFV2_CTRLDESCL5_AB_MODE(config->alphaMode) |
+ LCDIFV2_CTRLDESCL5_PD_FACTOR_MODE(config->pdFactorMode) |
+ LCDIFV2_CTRLDESCL5_PD_ALPHA_MODE(config->pdAlphaMode) | LCDIFV2_CTRLDESCL5_PD_COLOR_MODE(config->pdColorMode) |
+ LCDIFV2_CTRLDESCL5_PD_GLOBAL_ALPHA_MODE(config->pdGlobalAlphaMode));
+
+ if (config->alphaMode == kLCDIFV2_AlphaDisable)
+ {
+ reg |= LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK;
+ }
+
+ base->LAYER[layerIndex].CTRLDESCL5 = reg;
+}
+
+/*
+ * brief Get the blend configuration for Porter Duff blend.
+ *
+ * This is the basic Porter Duff blend configuration, user still could
+ * modify the configurations after this function.
+ *
+ * param mode Porter Duff blend mode.
+ * param layer The configuration for source layer or destination layer.
+ * param config Pointer to the configuration.
+ * retval kStatus_Success Get the configuration successfully.
+ * retval kStatus_InvalidArgument The argument is invalid.
+ */
+status_t LCDIFV2_GetPorterDuffConfig(lcdifv2_pd_blend_mode_t mode,
+ lcdifv2_pd_layer_t layer,
+ lcdifv2_blend_config_t *config)
+{
+ static const lcdifv2_pd_factor_mode_t s_lcdifv2PdLayerFactors[][2] = {
+ /* kLCDIFV2_PD_Src */
+ {
+ /* s1_s0_factor_mode. */
+ kLCDIFV2_PD_FactorZero,
+
+ /* s0_s1_factor_mode. */
+ kLCDIFV2_PD_FactorOne,
+ },
+
+ /* kLCDIFV2_PD_Atop */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorStraightAlpha},
+
+ /* kLCDIFV2_PD_Over */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorOne},
+
+ /* kLCDIFV2_PD_In */
+ {kLCDIFV2_PD_FactorZero, kLCDIFV2_PD_FactorStraightAlpha},
+
+ /* kLCDIFV2_PD_Out */
+ {kLCDIFV2_PD_FactorZero, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_Dst */
+ {kLCDIFV2_PD_FactorOne, kLCDIFV2_PD_FactorZero},
+
+ /* kLCDIFV2_PD_DstAtop */
+ {kLCDIFV2_PD_FactorStraightAlpha, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_DstOver */
+ {kLCDIFV2_PD_FactorOne, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_DstIn */
+ {kLCDIFV2_PD_FactorStraightAlpha, kLCDIFV2_PD_FactorZero},
+
+ /* kLCDIFV2_PD_DstOut */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorZero},
+
+ /* kLCDIFV2_PD_Xor */
+ {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorInversedAlpha},
+
+ /* kLCDIFV2_PD_Clear */
+ {
+ kLCDIFV2_PD_FactorZero,
+ kLCDIFV2_PD_FactorZero,
+ },
+ };
+
+ status_t status;
+
+ if ((NULL == config) || (mode >= kLCDIFV2_PD_Max) || (layer >= kLCDIFV2_PD_LayerMax))
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ config->pdAlphaMode = kLCDIFV2_PD_AlphaStraight;
+ config->pdColorMode = kLCDIFV2_PD_ColorWithAlpha;
+ config->pdGlobalAlphaMode = kLCDIFV2_PD_LocalAlpha;
+ config->pdFactorMode = s_lcdifv2PdLayerFactors[mode][(uint8_t)layer];
+ config->alphaMode = kLCDIFV2_AlphaPoterDuff;
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*
+ * brief Get the global alpha values for multiple layer blend.
+ *
+ * When all layers use the global alpha, the relationship blended alpha
+ * and global alpha of each layer is:
+ *
+ * Layer 7: ba7 = ga7
+ * Layer 6: ba6 = ga6 * (1-ga7)
+ * Layer 5: ba5 = ga5 * (1-ga6) * (1-ga7)
+ * Layer 4: ba4 = ga4 * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 3: ba3 = ga3 * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 2: ba2 = ga2 * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 1: ba1 = ga1 * (1-ga2) * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ * Layer 0: ba0 = 1 * (1-ga1) * (1-ga2) * (1-ga3) * (1-ga4) * (1-ga5) * (1-ga6) * (1-ga7)
+ *
+ * Here baN is the blended alpha of layer N, gaN is the global alpha configured to layer N.
+ *
+ * This function calculates the global alpha based on the blended alpha. The blendedAlpha and
+ * globalAlpha are all arrays of size layerCount. The first layer is a background layer,
+ * so blendedAlpha[0] is useless, globalAlpha[0] is always 255.
+ *
+ * param blendedAlpha The desired blended alpha value, alpha range 0~255.
+ * param globalAlpha Calculated global alpha set to each layer register.
+ * param layerCount Total layer count.
+ * retval kStatus_Success Get successfully.
+ * retval kStatus_InvalidArgument The argument is invalid.
+ */
+status_t LCDIFV2_GetMultiLayerGlobalAlpha(const uint8_t blendedAlpha[], uint8_t globalAlpha[], uint8_t layerCount)
+{
+ status_t status = kStatus_Success;
+ int16_t curLayer = (int16_t)layerCount - 1;
+ int left = 255;
+ int tmpAlpha;
+
+ assert((layerCount > 1U) && (layerCount <= (uint8_t)LCDIFV2_LAYER_COUNT));
+
+ /*
+ * Assume the layer counter is 7, and alpha range is 0~1, define:
+ *
+ * left_7 = 1
+ * left_i = (1-ga_(i+1)) * ... * (1-ga7)
+ *
+ * Then:
+ * ba_i = ga_i * left_i
+ * left_i = left_(i+1) - ba_i
+ * ga_i = ba_i / left_i
+ *
+ * Now change alpha range to 0~255, then:
+ *
+ * ga_i = ba_i * 255 / left_i
+ * left_i = left_(i+1) - ba_i
+ */
+
+ globalAlpha[0] = 255U;
+
+ while (curLayer > 0)
+ {
+ tmpAlpha = (int)blendedAlpha[curLayer] * 255 / left;
+ if (tmpAlpha > 255)
+ {
+ status = kStatus_InvalidArgument;
+ break;
+ }
+
+ globalAlpha[curLayer] = (uint8_t)tmpAlpha;
+ left -= (int)blendedAlpha[curLayer];
+
+ if (left <= 0)
+ {
+ status = kStatus_InvalidArgument;
+ break;
+ }
+
+ curLayer--;
+ }
+
+ return status;
+}