1 /*
2  * Copyright 2019-2021 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_lcdifv2.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.lcdifv2"
18 #endif
19 
20 #define LCDIFV2_LUT_MEM(base) \
21     ((volatile uint32_t *)(((uint32_t)(base)) + (uint32_t)FSL_FEATURE_LCDIFV2_CLUT_RAM_OFFSET))
22 
23 /*******************************************************************************
24  * Prototypes
25  ******************************************************************************/
26 
27 /*!
28  * @brief Get instance number for LCDIF module.
29  *
30  * @param base LCDIF peripheral base address
31  */
32 static uint32_t LCDIFV2_GetInstance(LCDIFV2_Type *base);
33 
34 /*!
35  * @brief Reset register value to default status.
36  *
37  * @param base LCDIF peripheral base address
38  */
39 static void LCDIFV2_ResetRegister(LCDIFV2_Type *base);
40 
41 /*******************************************************************************
42  * Variables
43  ******************************************************************************/
44 
45 /*! @brief Pointers to LCDIF bases for each instance. */
46 static LCDIFV2_Type *const s_lcdifv2Bases[] = LCDIFV2_BASE_PTRS;
47 
48 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
49 /*! @brief Pointers to LCDIF clock for each instance. */
50 static const clock_ip_name_t s_lcdifv2Clocks[] = LCDIFV2_CLOCKS;
51 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
52 
53 /*! @brief Porter Duff layer factors for different configuration. */
54 static const lcdifv2_pd_factor_mode_t s_lcdifv2PdLayerFactors[][2] = {
55     /* kLCDIFV2_PD_Src */
56     {
57         /* s1_s0_factor_mode. */
58         kLCDIFV2_PD_FactorZero,
59 
60         /* s0_s1_factor_mode. */
61         kLCDIFV2_PD_FactorOne,
62     },
63 
64     /* kLCDIFV2_PD_Atop */
65     {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorStraightAlpha},
66 
67     /* kLCDIFV2_PD_Over */
68     {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorOne},
69 
70     /* kLCDIFV2_PD_In */
71     {kLCDIFV2_PD_FactorZero, kLCDIFV2_PD_FactorStraightAlpha},
72 
73     /* kLCDIFV2_PD_Out */
74     {kLCDIFV2_PD_FactorZero, kLCDIFV2_PD_FactorInversedAlpha},
75 
76     /* kLCDIFV2_PD_Dst */
77     {kLCDIFV2_PD_FactorOne, kLCDIFV2_PD_FactorZero},
78 
79     /* kLCDIFV2_PD_DstAtop */
80     {kLCDIFV2_PD_FactorStraightAlpha, kLCDIFV2_PD_FactorInversedAlpha},
81 
82     /* kLCDIFV2_PD_DstOver */
83     {kLCDIFV2_PD_FactorOne, kLCDIFV2_PD_FactorInversedAlpha},
84 
85     /* kLCDIFV2_PD_DstIn */
86     {kLCDIFV2_PD_FactorStraightAlpha, kLCDIFV2_PD_FactorZero},
87 
88     /* kLCDIFV2_PD_DstOut */
89     {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorZero},
90 
91     /* kLCDIFV2_PD_Xor */
92     {kLCDIFV2_PD_FactorInversedAlpha, kLCDIFV2_PD_FactorInversedAlpha},
93 
94     /* kLCDIFV2_PD_Clear */
95     {
96         kLCDIFV2_PD_FactorZero,
97         kLCDIFV2_PD_FactorZero,
98     },
99 };
100 
101 /*******************************************************************************
102  * Codes
103  ******************************************************************************/
LCDIFV2_GetInstance(LCDIFV2_Type * base)104 static uint32_t LCDIFV2_GetInstance(LCDIFV2_Type *base)
105 {
106     uint32_t instance;
107 
108     /* Find the instance index from base address mappings. */
109     for (instance = 0; instance < ARRAY_SIZE(s_lcdifv2Bases); instance++)
110     {
111         if (s_lcdifv2Bases[instance] == base)
112         {
113             break;
114         }
115     }
116 
117     assert(instance < ARRAY_SIZE(s_lcdifv2Bases));
118 
119     return instance;
120 }
121 
LCDIFV2_ResetRegister(LCDIFV2_Type * base)122 static void LCDIFV2_ResetRegister(LCDIFV2_Type *base)
123 {
124     uint32_t i;
125 
126     base->DISP_PARA         = 0U;
127     base->CTRL              = 0x80000000U;
128     base->DISP_SIZE         = 0U;
129     base->HSYN_PARA         = 0x00C01803U;
130     base->VSYN_PARA         = 0x00C01803U;
131     base->INT[0].INT_ENABLE = 0U;
132     base->INT[1].INT_ENABLE = 0U;
133     base->PDI_PARA          = 0x00001000U;
134 
135     for (i = 0; i < (uint32_t)LCDIFV2_LAYER_COUNT; i++)
136     {
137         base->LAYER[i].CTRLDESCL5 = 0U;
138         base->LAYER[i].CTRLDESCL1 = 0U;
139         base->LAYER[i].CTRLDESCL2 = 0U;
140         base->LAYER[i].CTRLDESCL3 = 0U;
141         base->LAYER[i].CTRLDESCL4 = 0U;
142         base->LAYER[i].CTRLDESCL6 = 0U;
143     }
144 
145     for (i = 0; i < (uint32_t)LCDIFV2_LAYER_CSC_COUNT; i++)
146     {
147         base->LAYER[i].CSC_COEF0 = 0x04000000U;
148         base->LAYER[i].CSC_COEF1 = 0x01230208U;
149         base->LAYER[i].CSC_COEF2 = 0x076B079CU;
150     }
151 
152     /* Clear interrupt status. */
153     base->INT[0].INT_STATUS = 0xFFFFFFFFU;
154     base->INT[1].INT_STATUS = 0xFFFFFFFFU;
155 }
156 
157 /*!
158  * brief Initializes the LCDIF v2.
159  *
160  * This function ungates the LCDIF v2 clock and release the peripheral reset.
161  *
162  * param base LCDIF v2 peripheral base address.
163  */
LCDIFV2_Init(LCDIFV2_Type * base)164 void LCDIFV2_Init(LCDIFV2_Type *base)
165 {
166 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
167     uint32_t instance = LCDIFV2_GetInstance(base);
168     /* Enable the clock. */
169     CLOCK_EnableClock(s_lcdifv2Clocks[instance]);
170 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
171 
172     LCDIFV2_ResetRegister(base);
173 
174     /* Out of reset. */
175     base->CTRL = 0U;
176 }
177 
178 /*!
179  * brief Deinitializes the LCDIF peripheral.
180  *
181  * param base LCDIF peripheral base address.
182  */
LCDIFV2_Deinit(LCDIFV2_Type * base)183 void LCDIFV2_Deinit(LCDIFV2_Type *base)
184 {
185     LCDIFV2_ResetRegister(base);
186 
187 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
188     uint32_t instance = LCDIFV2_GetInstance(base);
189     /* Disable the clock. */
190     CLOCK_DisableClock(s_lcdifv2Clocks[instance]);
191 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
192 }
193 
194 /*!
195  * brief Reset the LCDIF v2.
196  *
197  * param base LCDIF peripheral base address.
198  */
LCDIFV2_Reset(LCDIFV2_Type * base)199 void LCDIFV2_Reset(LCDIFV2_Type *base)
200 {
201     LCDIFV2_ResetRegister(base);
202 
203     /* Release and ready to work. */
204     base->CTRL = 0U;
205 }
206 
207 /*!
208  * brief Gets the LCDIF display default configuration structure.
209  *
210  * param config Pointer to the LCDIF configuration structure.
211  */
LCDIFV2_DisplayGetDefaultConfig(lcdifv2_display_config_t * config)212 void LCDIFV2_DisplayGetDefaultConfig(lcdifv2_display_config_t *config)
213 {
214     assert(NULL != config);
215 
216     config->panelWidth    = 0U;
217     config->panelHeight   = 0U;
218     config->hsw           = 3U;
219     config->hfp           = 3U;
220     config->hbp           = 3U;
221     config->vsw           = 3U;
222     config->vfp           = 3U;
223     config->vbp           = 3U;
224     config->polarityFlags = (uint32_t)kLCDIFV2_VsyncActiveHigh | (uint32_t)kLCDIFV2_HsyncActiveHigh |
225                             (uint32_t)kLCDIFV2_DataEnableActiveHigh | (uint32_t)kLCDIFV2_DriveDataOnRisingClkEdge |
226                             (uint32_t)kLCDIFV2_DataActiveHigh;
227     config->lineOrder = kLCDIFV2_LineOrderRGB;
228 }
229 
230 /*!
231  * brief Set the LCDIF v2 display configurations.
232  *
233  * param base LCDIF peripheral base address.
234  * param config Pointer to the LCDIF configuration structure.
235  */
LCDIFV2_SetDisplayConfig(LCDIFV2_Type * base,const lcdifv2_display_config_t * config)236 void LCDIFV2_SetDisplayConfig(LCDIFV2_Type *base, const lcdifv2_display_config_t *config)
237 {
238     assert(NULL != config);
239 
240     /* Configure the parameters. */
241     base->DISP_SIZE = ((uint32_t)config->panelWidth << LCDIFV2_DISP_SIZE_DELTA_X_SHIFT) |
242                       ((uint32_t)config->panelHeight << LCDIFV2_DISP_SIZE_DELTA_Y_SHIFT);
243 
244     base->HSYN_PARA = ((uint32_t)config->hsw << LCDIFV2_HSYN_PARA_PW_H_SHIFT) |
245                       ((uint32_t)config->hbp << LCDIFV2_HSYN_PARA_BP_H_SHIFT) |
246                       ((uint32_t)config->hfp << LCDIFV2_HSYN_PARA_FP_H_SHIFT);
247 
248     base->VSYN_PARA = ((uint32_t)config->vsw << LCDIFV2_VSYN_PARA_PW_V_SHIFT) |
249                       ((uint32_t)config->vbp << LCDIFV2_VSYN_PARA_BP_V_SHIFT) |
250                       ((uint32_t)config->vfp << LCDIFV2_VSYN_PARA_FP_V_SHIFT);
251 
252     base->DISP_PARA = LCDIFV2_DISP_PARA_LINE_PATTERN(config->lineOrder);
253 
254     base->CTRL = (uint32_t)(config->polarityFlags);
255 }
256 
257 /*!
258  * brief Set the color space conversion mode.
259  *
260  * Supports YUV2RGB and YCbCr2RGB.
261  *
262  * param base LCDIFv2 peripheral base address.
263  * param layerIndex Index of the layer.
264  * param mode The conversion mode.
265  */
LCDIFV2_SetCscMode(LCDIFV2_Type * base,uint8_t layerIndex,lcdifv2_csc_mode_t mode)266 void LCDIFV2_SetCscMode(LCDIFV2_Type *base, uint8_t layerIndex, lcdifv2_csc_mode_t mode)
267 {
268     assert(layerIndex < (uint32_t)LCDIFV2_LAYER_CSC_COUNT);
269 
270     /*
271      * The equations used for Colorspace conversion are:
272      *
273      * R = C0*(Y+Y_OFFSET)                   + C1(V+UV_OFFSET)
274      * G = C0*(Y+Y_OFFSET) + C3(U+UV_OFFSET) + C2(V+UV_OFFSET)
275      * B = C0*(Y+Y_OFFSET) + C4(U+UV_OFFSET)
276      */
277 
278     if (kLCDIFV2_CscYUV2RGB == mode)
279     {
280         base->LAYER[layerIndex].CSC_COEF0 = LCDIFV2_CSC_COEF0_ENABLE_MASK | LCDIFV2_CSC_COEF0_C0(0x100U) /* 1.00. */
281                                             | LCDIFV2_CSC_COEF0_Y_OFFSET(0x0U)                           /* 0. */
282                                             | LCDIFV2_CSC_COEF0_UV_OFFSET(0x0U);                         /* 0. */
283 
284         base->LAYER[layerIndex].CSC_COEF1 = LCDIFV2_CSC_COEF1_C1(0x0123U)    /* 1.140. */
285                                             | LCDIFV2_CSC_COEF1_C4(0x0208U); /* 2.032. */
286         base->LAYER[layerIndex].CSC_COEF2 = LCDIFV2_CSC_COEF2_C2(0x076BU)    /* -0.851. */
287                                             | LCDIFV2_CSC_COEF2_C3(0x079BU); /* -0.394. */
288     }
289     else if (kLCDIFV2_CscYCbCr2RGB == mode)
290     {
291         base->LAYER[layerIndex].CSC_COEF0 = LCDIFV2_CSC_COEF0_ENABLE_MASK | LCDIFV2_CSC_COEF0_YCBCR_MODE_MASK |
292                                             LCDIFV2_CSC_COEF0_C0(0x12AU)           /* 1.164. */
293                                             | LCDIFV2_CSC_COEF0_Y_OFFSET(0x1F0U)   /* -16. */
294                                             | LCDIFV2_CSC_COEF0_UV_OFFSET(0x180U); /* -128. */
295         base->LAYER[layerIndex].CSC_COEF1 = LCDIFV2_CSC_COEF1_C1(0x0198U)          /* 1.596. */
296                                             | LCDIFV2_CSC_COEF1_C4(0x0204U);       /* 2.017. */
297         base->LAYER[layerIndex].CSC_COEF2 = LCDIFV2_CSC_COEF2_C2(0x0730U)          /* -0.813. */
298                                             | LCDIFV2_CSC_COEF2_C3(0x079CU);       /* -0.392. */
299     }
300     else
301     {
302         base->LAYER[layerIndex].CSC_COEF0 = 0U;
303         base->LAYER[layerIndex].CSC_COEF1 = 0U;
304         base->LAYER[layerIndex].CSC_COEF2 = 0U;
305     }
306 }
307 
308 /*!
309  * brief Set the layer source buffer configuration.
310  *
311  * param base LCDIFv2 peripheral base address.
312  * param layerIndex Layer layerIndex.
313  * param config Pointer to the configuration.
314  */
LCDIFV2_SetLayerBufferConfig(LCDIFV2_Type * base,uint8_t layerIndex,const lcdifv2_buffer_config_t * config)315 void LCDIFV2_SetLayerBufferConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_buffer_config_t *config)
316 {
317     assert(NULL != config);
318     uint32_t reg;
319 
320     base->LAYER[layerIndex].CTRLDESCL3 = config->strideBytes;
321 
322     reg = base->LAYER[layerIndex].CTRLDESCL5;
323     reg = (reg & ~(LCDIFV2_CTRLDESCL5_BPP_MASK | LCDIFV2_CTRLDESCL5_YUV_FORMAT_MASK)) | (uint32_t)config->pixelFormat;
324 
325     if (0U == (reg & LCDIFV2_CTRLDESCL5_AB_MODE_MASK))
326     {
327         reg |= LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK;
328     }
329 
330     base->LAYER[layerIndex].CTRLDESCL5 = reg;
331 }
332 
333 /*!
334  * brief Set the LUT data.
335  *
336  * This function sets the specific layer LUT data, if useShadowLoad is true,
337  * call LCDIFV2_TriggerLayerShadowLoad after this function, the
338  * LUT will be loaded to the hardware during next vertical blanking period.
339  * If useShadowLoad is false, the LUT data is loaded to hardware directly.
340  *
341  * param base LCDIF v2 peripheral base address.
342  * param layerIndex Which layer to set.
343  * param lutData The LUT data to load.
344  * param count Count of lutData.
345  * retval kStatus_Success Set success.
346  * retval kStatus_Fail Previous LUT data is not loaded to hardware yet.
347  */
LCDIFV2_SetLut(LCDIFV2_Type * base,uint8_t layerIndex,const uint32_t * lutData,uint16_t count,bool useShadowLoad)348 status_t LCDIFV2_SetLut(
349     LCDIFV2_Type *base, uint8_t layerIndex, const uint32_t *lutData, uint16_t count, bool useShadowLoad)
350 {
351     assert(count <= LCDIFV2_LUT_ENTRY_NUM);
352 
353     uint16_t i;
354     status_t status;
355 
356     /* Previous setting is not updated. */
357     if ((base->CLUT_LOAD & LCDIFV2_CLUT_LOAD_CLUT_UPDATE_EN_MASK) != 0U)
358     {
359         status = kStatus_Fail;
360     }
361     else
362     {
363         if (useShadowLoad)
364         {
365             base->CLUT_LOAD = LCDIFV2_CLUT_LOAD_SEL_CLUT_NUM(layerIndex) | LCDIFV2_CLUT_LOAD_CLUT_UPDATE_EN_MASK;
366         }
367         else
368         {
369             base->CLUT_LOAD = LCDIFV2_CLUT_LOAD_SEL_CLUT_NUM(layerIndex);
370         }
371 
372         for (i = 0; i < count; i++)
373         {
374             (LCDIFV2_LUT_MEM(base))[i + LCDIFV2_LUT_ENTRY_NUM * layerIndex] = lutData[i];
375         }
376 
377         status = kStatus_Success;
378     }
379 
380     return status;
381 }
382 
383 /*!
384  * brief Set the layer alpha blend mode.
385  *
386  * param base LCDIFv2 peripheral base address.
387  * param layerIndex Index of the CSC unit.
388  * param config Pointer to the blend configuration.
389  */
LCDIFV2_SetLayerBlendConfig(LCDIFV2_Type * base,uint8_t layerIndex,const lcdifv2_blend_config_t * config)390 void LCDIFV2_SetLayerBlendConfig(LCDIFV2_Type *base, uint8_t layerIndex, const lcdifv2_blend_config_t *config)
391 {
392     assert(NULL != config);
393 
394     uint32_t reg;
395 
396     reg = base->LAYER[layerIndex].CTRLDESCL5;
397     reg &= ~(LCDIFV2_CTRLDESCL5_GLOBAL_ALPHA_MASK | LCDIFV2_CTRLDESCL5_AB_MODE_MASK |
398              LCDIFV2_CTRLDESCL5_PD_FACTOR_MODE_MASK | LCDIFV2_CTRLDESCL5_PD_ALPHA_MODE_MASK |
399              LCDIFV2_CTRLDESCL5_PD_COLOR_MODE_MASK | LCDIFV2_CTRLDESCL5_PD_GLOBAL_ALPHA_MODE_MASK |
400              LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK);
401 
402     reg |=
403         (LCDIFV2_CTRLDESCL5_GLOBAL_ALPHA(config->globalAlpha) | LCDIFV2_CTRLDESCL5_AB_MODE(config->alphaMode) |
404          LCDIFV2_CTRLDESCL5_PD_FACTOR_MODE(config->pdFactorMode) |
405          LCDIFV2_CTRLDESCL5_PD_ALPHA_MODE(config->pdAlphaMode) | LCDIFV2_CTRLDESCL5_PD_COLOR_MODE(config->pdColorMode) |
406          LCDIFV2_CTRLDESCL5_PD_GLOBAL_ALPHA_MODE(config->pdGlobalAlphaMode));
407 
408     if (config->alphaMode == kLCDIFV2_AlphaDisable)
409     {
410         reg |= LCDIFV2_CTRLDESCL5_SAFETY_EN_MASK;
411     }
412 
413     base->LAYER[layerIndex].CTRLDESCL5 = reg;
414 }
415 
416 /*
417  * brief Get the blend configuration for Porter Duff blend.
418  *
419  * This is the basic Porter Duff blend configuration, user still could
420  * modify the configurations after this function.
421  *
422  * param mode Porter Duff blend mode.
423  * param layer The configuration for source layer or destination layer.
424  * param config Pointer to the configuration.
425  * retval kStatus_Success Get the configuration successfully.
426  * retval kStatus_InvalidArgument The argument is invalid.
427  */
LCDIFV2_GetPorterDuffConfig(lcdifv2_pd_blend_mode_t mode,lcdifv2_pd_layer_t layer,lcdifv2_blend_config_t * config)428 status_t LCDIFV2_GetPorterDuffConfig(lcdifv2_pd_blend_mode_t mode,
429                                      lcdifv2_pd_layer_t layer,
430                                      lcdifv2_blend_config_t *config)
431 {
432     status_t status;
433 
434     if ((NULL == config) || (mode >= kLCDIFV2_PD_Max) || (layer >= kLCDIFV2_PD_LayerMax))
435     {
436         status = kStatus_InvalidArgument;
437     }
438     else
439     {
440         config->pdAlphaMode       = kLCDIFV2_PD_AlphaStraight;
441         config->pdColorMode       = kLCDIFV2_PD_ColorWithAlpha;
442         config->pdGlobalAlphaMode = kLCDIFV2_PD_LocalAlpha;
443         config->pdFactorMode      = s_lcdifv2PdLayerFactors[mode][(uint8_t)layer];
444         config->alphaMode         = kLCDIFV2_AlphaPoterDuff;
445 
446         status = kStatus_Success;
447     }
448 
449     return status;
450 }
451