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