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