1 /*
2 * Copyright 2017-2021 NXP
3 * All rights reserved.
4 *
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_elcdif.h"
10
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.elcdif"
14 #endif
15
16 /*******************************************************************************
17 * Prototypes
18 ******************************************************************************/
19
20 /*!
21 * @brief Get instance number for ELCDIF module.
22 *
23 * @param base ELCDIF peripheral base address
24 */
25 static uint32_t ELCDIF_GetInstance(LCDIF_Type *base);
26
27 /*******************************************************************************
28 * Variables
29 ******************************************************************************/
30
31 /*! @brief Pointers to ELCDIF bases for each instance. */
32 static LCDIF_Type *const s_elcdifBases[] = LCDIF_BASE_PTRS;
33
34 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
35 /*! @brief Pointers to eLCDIF apb_clk for each instance. */
36 static const clock_ip_name_t s_elcdifApbClocks[] = LCDIF_CLOCKS;
37 #if defined(LCDIF_PERIPH_CLOCKS)
38 /*! @brief Pointers to eLCDIF pix_clk for each instance. */
39 static const clock_ip_name_t s_elcdifPixClocks[] = LCDIF_PERIPH_CLOCKS;
40 #endif
41 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
42
43 /*! @brief The control register value to select different pixel format. */
44 static const elcdif_pixel_format_reg_t s_pixelFormatReg[] = {
45 /* kELCDIF_PixelFormatRAW8 */
46 {/* Register CTRL. */
47 LCDIF_CTRL_WORD_LENGTH(1U),
48 /* Register CTRL1. */
49 LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
50 /* kELCDIF_PixelFormatRGB565 */
51 {/* Register CTRL. */
52 LCDIF_CTRL_WORD_LENGTH(0U),
53 /* Register CTRL1. */
54 LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
55 /* kELCDIF_PixelFormatRGB666 */
56 {/* Register CTRL. */
57 LCDIF_CTRL_WORD_LENGTH(3U) | LCDIF_CTRL_DATA_FORMAT_24_BIT(1U),
58 /* Register CTRL1. */
59 LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)},
60 /* kELCDIF_PixelFormatXRGB8888 */
61 {/* Register CTRL. 24-bit. */
62 LCDIF_CTRL_WORD_LENGTH(3U),
63 /* Register CTRL1. */
64 LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)},
65 /* kELCDIF_PixelFormatRGB888 */
66 {/* Register CTRL. 24-bit. */
67 LCDIF_CTRL_WORD_LENGTH(3U),
68 /* Register CTRL1. */
69 LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
70 };
71
72 /*******************************************************************************
73 * Codes
74 ******************************************************************************/
ELCDIF_GetInstance(LCDIF_Type * base)75 static uint32_t ELCDIF_GetInstance(LCDIF_Type *base)
76 {
77 uint32_t instance;
78
79 /* Find the instance index from base address mappings. */
80 for (instance = 0; instance < ARRAY_SIZE(s_elcdifBases); instance++)
81 {
82 if (s_elcdifBases[instance] == base)
83 {
84 break;
85 }
86 }
87
88 assert(instance < ARRAY_SIZE(s_elcdifBases));
89
90 return instance;
91 }
92
93 /*!
94 * brief Initializes the eLCDIF to work in RGB mode (DOTCLK mode).
95 *
96 * This function ungates the eLCDIF clock and configures the eLCDIF peripheral according
97 * to the configuration structure.
98 *
99 * param base eLCDIF peripheral base address.
100 * param config Pointer to the configuration structure.
101 */
ELCDIF_RgbModeInit(LCDIF_Type * base,const elcdif_rgb_mode_config_t * config)102 void ELCDIF_RgbModeInit(LCDIF_Type *base, const elcdif_rgb_mode_config_t *config)
103 {
104 assert(NULL != config);
105 assert((uint32_t)config->pixelFormat < ARRAY_SIZE(s_pixelFormatReg));
106
107 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
108 uint32_t instance = ELCDIF_GetInstance(base);
109 /* Enable the clock. */
110 (void)CLOCK_EnableClock(s_elcdifApbClocks[instance]);
111 #if defined(LCDIF_PERIPH_CLOCKS)
112 (void)CLOCK_EnableClock(s_elcdifPixClocks[instance]);
113 #endif
114 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
115
116 /* Reset. */
117 ELCDIF_Reset(base);
118
119 base->CTRL = s_pixelFormatReg[(uint32_t)config->pixelFormat].regCtrl | (uint32_t)(config->dataBus) |
120 LCDIF_CTRL_DOTCLK_MODE_MASK | /* RGB mode. */
121 LCDIF_CTRL_BYPASS_COUNT_MASK | /* Keep RUN bit set. */
122 LCDIF_CTRL_MASTER_MASK;
123
124 base->CTRL1 = s_pixelFormatReg[(uint32_t)config->pixelFormat].regCtrl1;
125
126 base->CTRL2 = (base->CTRL2 & ~LCDIF_CTRL2_OUTSTANDING_REQS_MASK) | (LCDIF_CTRL2_OUTSTANDING_REQS(4));
127
128 base->TRANSFER_COUNT = ((uint32_t)config->panelHeight << LCDIF_TRANSFER_COUNT_V_COUNT_SHIFT) |
129 ((uint32_t)config->panelWidth << LCDIF_TRANSFER_COUNT_H_COUNT_SHIFT);
130
131 base->VDCTRL0 = LCDIF_VDCTRL0_ENABLE_PRESENT_MASK | /* Data enable signal. */
132 LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT_MASK | /* VSYNC period in the unit of display clock. */
133 LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT_MASK | /* VSYNC pulse width in the unit of display clock. */
134 (uint32_t)config->polarityFlags | (uint32_t)config->vsw;
135
136 base->VDCTRL1 =
137 (uint32_t)config->vsw + (uint32_t)config->panelHeight + (uint32_t)config->vfp + (uint32_t)config->vbp;
138 base->VDCTRL2 =
139 ((uint32_t)config->hsw << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_SHIFT) |
140 (((uint32_t)config->hfp + (uint32_t)config->hbp + (uint32_t)config->panelWidth + (uint32_t)config->hsw))
141 << LCDIF_VDCTRL2_HSYNC_PERIOD_SHIFT;
142
143 base->VDCTRL3 = (((uint32_t)config->hbp + config->hsw) << LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_SHIFT) |
144 (((uint32_t)config->vbp + config->vsw) << LCDIF_VDCTRL3_VERTICAL_WAIT_CNT_SHIFT);
145
146 base->VDCTRL4 = LCDIF_VDCTRL4_SYNC_SIGNALS_ON_MASK |
147 ((uint32_t)config->panelWidth << LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT_SHIFT);
148
149 base->CUR_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
150 base->NEXT_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
151 }
152
153 /*!
154 * brief Gets the eLCDIF default configuration structure for RGB (DOTCLK) mode.
155 *
156 * This function sets the configuration structure to default values.
157 * The default configuration is set to the following values.
158 * code
159 config->panelWidth = 480U;
160 config->panelHeight = 272U;
161 config->hsw = 41;
162 config->hfp = 4;
163 config->hbp = 8;
164 config->vsw = 10;
165 config->vfp = 4;
166 config->vbp = 2;
167 config->polarityFlags = kELCDIF_VsyncActiveLow |
168 kELCDIF_HsyncActiveLow |
169 kELCDIF_DataEnableActiveLow |
170 kELCDIF_DriveDataOnFallingClkEdge;
171 config->bufferAddr = 0U;
172 config->pixelFormat = kELCDIF_PixelFormatRGB888;
173 config->dataBus = kELCDIF_DataBus24Bit;
174 code
175 *
176 * param config Pointer to the eLCDIF configuration structure.
177 */
ELCDIF_RgbModeGetDefaultConfig(elcdif_rgb_mode_config_t * config)178 void ELCDIF_RgbModeGetDefaultConfig(elcdif_rgb_mode_config_t *config)
179 {
180 assert(NULL != config);
181
182 /* Initializes the configure structure to zero. */
183 (void)memset(config, 0, sizeof(*config));
184
185 config->panelWidth = 480U;
186 config->panelHeight = 272U;
187 config->hsw = 41;
188 config->hfp = 4;
189 config->hbp = 8;
190 config->vsw = 10;
191 config->vfp = 4;
192 config->vbp = 2;
193 config->polarityFlags = (uint32_t)kELCDIF_VsyncActiveLow | (uint32_t)kELCDIF_HsyncActiveLow |
194 (uint32_t)kELCDIF_DataEnableActiveLow | (uint32_t)kELCDIF_DriveDataOnFallingClkEdge;
195 config->bufferAddr = 0U;
196 config->pixelFormat = kELCDIF_PixelFormatRGB888;
197 config->dataBus = kELCDIF_DataBus24Bit;
198 }
199
200 /*!
201 * brief Set the pixel format in RGB (DOTCLK) mode.
202 *
203 * param base eLCDIF peripheral base address.
204 * param pixelFormat The pixel format.
205 */
ELCDIF_RgbModeSetPixelFormat(LCDIF_Type * base,elcdif_pixel_format_t pixelFormat)206 void ELCDIF_RgbModeSetPixelFormat(LCDIF_Type *base, elcdif_pixel_format_t pixelFormat)
207 {
208 assert((uint32_t)pixelFormat < ARRAY_SIZE(s_pixelFormatReg));
209
210 base->CTRL = (base->CTRL & ~(LCDIF_CTRL_WORD_LENGTH_MASK | LCDIF_CTRL_DATA_FORMAT_24_BIT_MASK |
211 LCDIF_CTRL_DATA_FORMAT_18_BIT_MASK | LCDIF_CTRL_DATA_FORMAT_16_BIT_MASK)) |
212 s_pixelFormatReg[(uint32_t)pixelFormat].regCtrl;
213
214 base->CTRL1 = s_pixelFormatReg[(uint32_t)pixelFormat].regCtrl1;
215 }
216
217 /*!
218 * brief Deinitializes the eLCDIF peripheral.
219 *
220 * param base eLCDIF peripheral base address.
221 */
ELCDIF_Deinit(LCDIF_Type * base)222 void ELCDIF_Deinit(LCDIF_Type *base)
223 {
224 ELCDIF_Reset(base);
225
226 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
227 uint32_t instance = ELCDIF_GetInstance(base);
228 /* Disable the clock. */
229 #if defined(LCDIF_PERIPH_CLOCKS)
230 (void)CLOCK_DisableClock(s_elcdifPixClocks[instance]);
231 #endif
232 (void)CLOCK_DisableClock(s_elcdifApbClocks[instance]);
233 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
234 }
235
236 /*!
237 * brief Stop display in RGB (DOTCLK) mode and wait until finished.
238 *
239 * param base eLCDIF peripheral base address.
240 */
ELCDIF_RgbModeStop(LCDIF_Type * base)241 void ELCDIF_RgbModeStop(LCDIF_Type *base)
242 {
243 base->CTRL_CLR = LCDIF_CTRL_DOTCLK_MODE_MASK;
244
245 /* Wait for data transfer finished. */
246 while (0U != (base->CTRL & LCDIF_CTRL_DOTCLK_MODE_MASK))
247 {
248 }
249 }
250
251 /*!
252 * brief Reset the eLCDIF peripheral.
253 *
254 * param base eLCDIF peripheral base address.
255 */
ELCDIF_Reset(LCDIF_Type * base)256 void ELCDIF_Reset(LCDIF_Type *base)
257 {
258 /*
259 * ELCDIF reset workflow:
260 *
261 * 1. Ungate clock.
262 * 2. Trigger the software reset.
263 * 3. The software reset finished when clk_gate bit is set.
264 * 4. Ungate the clock.
265 * 5. Release the reset.
266 */
267
268 /* Ungate clock. */
269 base->CTRL_CLR = LCDIF_CTRL_CLKGATE_MASK;
270
271 /*
272 * If already in reset state, release the reset.
273 * If not, trigger reset.
274 */
275 if (0U == (base->CTRL & LCDIF_CTRL_SFTRST_MASK))
276 {
277 /* Trigger reset. */
278 base->CTRL_SET = LCDIF_CTRL_SFTRST_MASK;
279
280 /* Reset is not finished until CLK_GATE is set. */
281 while (0U == (base->CTRL & LCDIF_CTRL_CLKGATE_MASK))
282 {
283 }
284
285 /* Ungate the clock. */
286 base->CTRL_CLR = LCDIF_CTRL_CLKGATE_MASK;
287 }
288
289 /* Release the reset. */
290 base->CTRL_CLR = LCDIF_CTRL_SFTRST_MASK;
291 }
292
293 #if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && FSL_FEATURE_LCDIF_HAS_NO_AS)
294 /*!
295 * brief Set the configuration for alpha surface buffer.
296 *
297 * param base eLCDIF peripheral base address.
298 * param config Pointer to the configuration structure.
299 */
ELCDIF_SetAlphaSurfaceBufferConfig(LCDIF_Type * base,const elcdif_as_buffer_config_t * config)300 void ELCDIF_SetAlphaSurfaceBufferConfig(LCDIF_Type *base, const elcdif_as_buffer_config_t *config)
301 {
302 assert(NULL != config);
303
304 base->AS_CTRL = (base->AS_CTRL & ~LCDIF_AS_CTRL_FORMAT_MASK) | LCDIF_AS_CTRL_FORMAT(config->pixelFormat);
305 base->AS_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
306 base->AS_NEXT_BUF = ELCDIF_ADDR_CPU_2_IP(config->bufferAddr);
307 }
308
309 /*!
310 * brief Set the alpha surface blending configuration.
311 *
312 * param base eLCDIF peripheral base address.
313 * param config Pointer to the configuration structure.
314 */
ELCDIF_SetAlphaSurfaceBlendConfig(LCDIF_Type * base,const elcdif_as_blend_config_t * config)315 void ELCDIF_SetAlphaSurfaceBlendConfig(LCDIF_Type *base, const elcdif_as_blend_config_t *config)
316 {
317 assert(NULL != config);
318 uint32_t reg;
319
320 reg = base->AS_CTRL;
321 reg &= ~(LCDIF_AS_CTRL_ALPHA_INVERT_MASK | LCDIF_AS_CTRL_ROP_MASK | LCDIF_AS_CTRL_ALPHA_MASK |
322 LCDIF_AS_CTRL_ALPHA_CTRL_MASK);
323 reg |= (LCDIF_AS_CTRL_ROP(config->ropMode) | LCDIF_AS_CTRL_ALPHA(config->alpha) |
324 LCDIF_AS_CTRL_ALPHA_CTRL(config->alphaMode));
325
326 if (config->invertAlpha)
327 {
328 reg |= LCDIF_AS_CTRL_ALPHA_INVERT_MASK;
329 }
330
331 base->AS_CTRL = reg;
332 }
333 #endif /* FSL_FEATURE_LCDIF_HAS_NO_AS */
334
335 #if (defined(FSL_FEATURE_LCDIF_HAS_LUT) && FSL_FEATURE_LCDIF_HAS_LUT)
336 /*!
337 * brief Load the LUT value.
338 *
339 * This function loads the LUT value to the specific LUT memory, user can
340 * specify the start entry index.
341 *
342 * param base eLCDIF peripheral base address.
343 * param lut Which LUT to load.
344 * param startIndex The start index of the LUT entry to update.
345 * param lutData The LUT data to load.
346 * param count Count of p lutData.
347 * retval kStatus_Success Initialization success.
348 * retval kStatus_InvalidArgument Wrong argument.
349 */
ELCDIF_UpdateLut(LCDIF_Type * base,elcdif_lut_t lut,uint16_t startIndex,const uint32_t * lutData,uint16_t count)350 status_t ELCDIF_UpdateLut(
351 LCDIF_Type *base, elcdif_lut_t lut, uint16_t startIndex, const uint32_t *lutData, uint16_t count)
352 {
353 volatile uint32_t *regLutAddr;
354 volatile uint32_t *regLutData;
355 uint32_t i;
356 status_t status;
357
358 /* Only has 256 entries. */
359 if (startIndex + count > ELCDIF_LUT_ENTRY_NUM)
360 {
361 status = kStatus_InvalidArgument;
362 }
363 else
364 {
365 if (kELCDIF_Lut0 == lut)
366 {
367 regLutAddr = &(base->LUT0_ADDR);
368 regLutData = &(base->LUT0_DATA);
369 }
370 else
371 {
372 regLutAddr = &(base->LUT1_ADDR);
373 regLutData = &(base->LUT1_DATA);
374 }
375
376 *regLutAddr = startIndex;
377
378 for (i = 0; i < count; i++)
379 {
380 *regLutData = lutData[i];
381 }
382
383 status = kStatus_Success;
384 }
385
386 return status;
387 }
388 #endif /* FSL_FEATURE_LCDIF_HAS_LUT */
389