1 /*
2  * Copyright (c) 2019-2021, NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_lcdif.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.lcdif"
18 #endif
19 
20 #define LCDIF_ALIGN_ADDR(addr, align) (((addr) + (align)-1U) & ~((align)-1U))
21 
22 #if defined(LCDIF_RSTS)
23 #define LCDIF_RESETS_ARRAY LCDIF_RSTS
24 #elif defined(DCNANO_RSTS)
25 #define LCDIF_RESETS_ARRAY DCNANO_RSTS
26 #endif
27 
28 /*******************************************************************************
29  * Prototypes
30  ******************************************************************************/
31 
32 /*!
33  * brief Get the instance from the base address
34  *
35  * param base LCDIF peripheral base address
36  *
37  * return The LCDIF module instance
38  */
39 static uint32_t LCDIF_GetInstance(LCDIF_Type *base);
40 
41 /*******************************************************************************
42  * Variables
43  ******************************************************************************/
44 /*! brief Pointers to LCDIF bases for each instance. */
45 static LCDIF_Type *const s_lcdifBases[] = LCDIF_BASE_PTRS;
46 
47 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
48 /*! brief Pointers to LCDIF clocks for each LCDIF submodule. */
49 static const clock_ip_name_t s_lcdifClocks[] = LCDIF_CLOCKS;
50 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
51 
52 #if defined(LCDIF_RESETS_ARRAY)
53 /* Reset array */
54 static const reset_ip_name_t s_lcdifResets[] = LCDIF_RESETS_ARRAY;
55 #endif
56 
57 /*******************************************************************************
58  * Code
59  ******************************************************************************/
LCDIF_GetInstance(LCDIF_Type * base)60 static uint32_t LCDIF_GetInstance(LCDIF_Type *base)
61 {
62     uint32_t instance;
63 
64     /* Find the instance index from base address mappings. */
65     for (instance = 0; instance < ARRAY_SIZE(s_lcdifBases); instance++)
66     {
67         if (s_lcdifBases[instance] == base)
68         {
69             break;
70         }
71     }
72 
73     assert(instance < ARRAY_SIZE(s_lcdifBases));
74 
75     return instance;
76 }
77 
78 /*!
79  * brief Initialize the LCDIF.
80  *
81  * This function initializes the LCDIF to work.
82  *
83  * param base LCDIF peripheral base address.
84  *
85  * retval kStatus_Success Initialize successfully.
86  */
LCDIF_Init(LCDIF_Type * base)87 status_t LCDIF_Init(LCDIF_Type *base)
88 {
89 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
90     uint32_t instance = LCDIF_GetInstance(base);
91     CLOCK_EnableClock(s_lcdifClocks[instance]);
92 #endif
93 
94 #if defined(LCDIF_RESETS_ARRAY)
95     RESET_ReleasePeripheralReset(s_lcdifResets[LCDIF_GetInstance(base)]);
96 #endif
97 
98     base->FRAMEBUFFERCONFIG0 = 0;
99     /* Clear interrupt status and disable interrupt. */
100     base->DISPLAYINTRENABLE = 0;
101     (void)(base->DISPLAYINTR);
102 
103     return kStatus_Success;
104 }
105 
106 /*!
107  * brief De-initialize the LCDIF.
108  *
109  * This function disables the LCDIF peripheral clock.
110  *
111  * param base LCDIF peripheral base address.
112  */
LCDIF_Deinit(LCDIF_Type * base)113 void LCDIF_Deinit(LCDIF_Type *base)
114 {
115 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
116     uint32_t instance = LCDIF_GetInstance(base);
117     CLOCK_DisableClock(s_lcdifClocks[instance]);
118 #endif
119 }
120 
121 /*!
122  * brief Get the default configuration for to initialize the LCDIF.
123  *
124  * The default configuration value is:
125  *
126  * code
127  config->panelWidth = 0;
128  config->panelHeight = 0;
129  config->hsw = 0;
130  config->hfp = 0;
131  config->hbp = 0;
132  config->vsw = 0;
133  config->vfp = 0;
134  config->vbp = 0;
135  config->polarityFlags = kLCDIF_VsyncActiveLow | kLCDIF_HsyncActiveLow | kLCDIF_DataEnableActiveHigh |
136  kLCDIF_DriveDataOnFallingClkEdge; config->format = kLCDIF_Output24Bit; endcode
137  *
138  * param config Pointer to the LCDIF configuration.
139  */
LCDIF_DpiModeGetDefaultConfig(lcdif_dpi_config_t * config)140 void LCDIF_DpiModeGetDefaultConfig(lcdif_dpi_config_t *config)
141 {
142     assert(NULL != config);
143 
144     config->panelWidth    = 0;
145     config->panelHeight   = 0;
146     config->hsw           = 0;
147     config->hfp           = 0;
148     config->hbp           = 0;
149     config->vsw           = 0;
150     config->vfp           = 0;
151     config->vbp           = 0;
152     config->polarityFlags = (uint32_t)kLCDIF_VsyncActiveLow | (uint32_t)kLCDIF_HsyncActiveLow |
153                             (uint32_t)kLCDIF_DataEnableActiveHigh | (uint32_t)kLCDIF_DriveDataOnFallingClkEdge;
154     config->format = kLCDIF_Output24Bit;
155 }
156 
157 /*!
158  * @brief Initialize the LCDIF to work in DPI mode.
159  *
160  * This function configures the LCDIF DPI display.
161  *
162  * param base LCDIF peripheral base address.
163  * param displayIndex Display index.
164  * param config Pointer to the configuration structure.
165  *
166  * retval kStatus_Success Initialize successfully.
167  * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
168  */
LCDIF_DpiModeSetConfig(LCDIF_Type * base,uint8_t displayIndex,const lcdif_dpi_config_t * config)169 status_t LCDIF_DpiModeSetConfig(LCDIF_Type *base, uint8_t displayIndex, const lcdif_dpi_config_t *config)
170 {
171     assert(NULL != config);
172 
173     uint32_t regHsync;
174     uint32_t regVsync;
175     uint32_t regPanelConfig;
176 
177     /* Reset the frame buffer. */
178     base->FRAMEBUFFERCONFIG0 = 0;
179 
180     /* Change to DPI mode. */
181     base->DBICONFIG0 &= ~LCDIF_DBICONFIG0_BUS_OUTPUT_SEL_MASK;
182 
183     base->DPICONFIG0 = (uint32_t)config->format;
184 
185     base->HDISPLAY0 =
186         ((uint32_t)config->panelWidth << LCDIF_HDISPLAY0_DISPLAY_END_SHIFT) |
187         (((uint32_t)config->panelWidth + config->hsw + config->hfp + config->hbp) << LCDIF_HDISPLAY0_TOTAL_SHIFT);
188 
189     base->VDISPLAY0 =
190         ((uint32_t)config->panelHeight << LCDIF_VDISPLAY0_DISPLAY_END_SHIFT) |
191         (((uint32_t)config->panelHeight + config->vsw + config->vfp + config->vbp) << LCDIF_VDISPLAY0_TOTAL_SHIFT);
192 
193     /* HSYNC */
194     regHsync = (((uint32_t)config->panelWidth + config->hfp) << LCDIF_HSYNC0_START_SHIFT) |
195                (((uint32_t)config->panelWidth + config->hfp + config->hsw) << LCDIF_HSYNC0_END_SHIFT) |
196                LCDIF_HSYNC0_PULSE_MASK;
197 
198     if ((uint32_t)kLCDIF_HsyncActiveHigh != (config->polarityFlags & (uint32_t)kLCDIF_HsyncActiveHigh))
199     {
200         regHsync |= LCDIF_HSYNC0_POLARITY_MASK;
201     }
202 
203     base->HSYNC0 = regHsync;
204 
205     /* VSYNC */
206     regVsync = (((uint32_t)config->panelHeight + config->vfp) << LCDIF_VSYNC0_START_SHIFT) |
207                (((uint32_t)config->panelHeight + config->vfp + config->vsw) << LCDIF_VSYNC0_END_SHIFT) |
208                LCDIF_VSYNC0_PULSE_MASK;
209 
210     if ((uint32_t)kLCDIF_VsyncActiveHigh != (config->polarityFlags & (uint32_t)kLCDIF_VsyncActiveHigh))
211     {
212         regVsync |= LCDIF_VSYNC0_POLARITY_MASK;
213     }
214 
215     base->VSYNC0 = regVsync;
216 
217     /* DE, Data, clock. */
218     regPanelConfig = LCDIF_PANELCONFIG0_DE_MASK | LCDIF_PANELCONFIG0_CLOCK_MASK;
219 
220     if ((uint32_t)kLCDIF_DataEnableActiveHigh != ((uint32_t)kLCDIF_DataEnableActiveHigh & config->polarityFlags))
221     {
222         regPanelConfig |= LCDIF_PANELCONFIG0_DE_POLARITY_MASK;
223     }
224 
225     if ((uint32_t)kLCDIF_DriveDataOnRisingClkEdge ==
226         ((uint32_t)kLCDIF_DriveDataOnRisingClkEdge & config->polarityFlags))
227     {
228         regPanelConfig |= LCDIF_PANELCONFIG0_CLOCK_POLARITY_MASK;
229     }
230 
231     base->PANELCONFIG0 = regPanelConfig | LCDIF_PANELCONFIG0_SEQUENCING_MASK;
232 
233     return kStatus_Success;
234 }
235 
236 /*!
237  * @brief Get default frame buffer configuration.
238  *
239  * The default configuration is
240  *   config->enable = true;
241  *   config->enableGamma = false;
242  *   config->format = kLCDIF_PixelFormatRGB565;
243  *
244  * @param config Pointer to the configuration structure.
245  */
LCDIF_FrameBufferGetDefaultConfig(lcdif_fb_config_t * config)246 void LCDIF_FrameBufferGetDefaultConfig(lcdif_fb_config_t *config)
247 {
248     assert(config != NULL);
249 
250     config->enable      = true;
251     config->enableGamma = false;
252     config->format      = kLCDIF_PixelFormatRGB565;
253 }
254 
255 /*!
256  * brief Configure the LCDIF frame buffer.
257  *
258  * param base LCDIF peripheral base address.
259  * param fbIndex Frame buffer index.
260  * param config Pointer to the configuration structure.
261  */
LCDIF_SetFrameBufferConfig(LCDIF_Type * base,uint8_t fbIndex,const lcdif_fb_config_t * config)262 void LCDIF_SetFrameBufferConfig(LCDIF_Type *base, uint8_t fbIndex, const lcdif_fb_config_t *config)
263 {
264     assert(NULL != config);
265     uint32_t reg;
266 
267     if (config->enable)
268     {
269         reg = LCDIF_FRAMEBUFFERCONFIG0_RESET_MASK | LCDIF_FRAMEBUFFERCONFIG0_OUTPUT_MASK | (uint32_t)config->format;
270         if (config->enableGamma)
271         {
272             reg |= LCDIF_FRAMEBUFFERCONFIG0_GAMMA_MASK;
273         }
274         base->FRAMEBUFFERCONFIG0 = reg;
275     }
276     else
277     {
278         base->FRAMEBUFFERCONFIG0 = 0U;
279     }
280 }
281 
282 /*
283  * @brief Set the frame buffer stride.
284  *
285  * @param base LCDIF peripheral base address.
286  * @param fbIndex Frame buffer index.
287  * @param strideBytes The stride in byte.
288  */
LCDIF_SetFrameBufferStride(LCDIF_Type * base,uint8_t fbIndex,uint32_t strideBytes)289 void LCDIF_SetFrameBufferStride(LCDIF_Type *base, uint8_t fbIndex, uint32_t strideBytes)
290 {
291     base->FRAMEBUFFERSTRIDE0 = LCDIF_ALIGN_ADDR(strideBytes, LCDIF_FB_ALIGN);
292 }
293 
294 /*!
295  * brief Set the dither configuration.
296  *
297  * param base LCDIF peripheral base address.
298  * param displayIndex Index to configure.
299  * param config Pointer to the configuration structure.
300  */
LCDIF_SetDitherConfig(LCDIF_Type * base,uint8_t displayIndex,const lcdif_dither_config_t * config)301 void LCDIF_SetDitherConfig(LCDIF_Type *base, uint8_t displayIndex, const lcdif_dither_config_t *config)
302 {
303     assert(NULL != config);
304 
305     if (config->enable)
306     {
307         base->DISPLAYDITHERTABLELOW0  = config->low;
308         base->DISPLAYDITHERTABLEHIGH0 = config->high;
309 
310         base->DISPLAYDITHERCONFIG0 = ((uint32_t)config->redSize << LCDIF_DISPLAYDITHERCONFIG0_RED_SIZE_SHIFT) |
311                                      ((uint32_t)config->greenSize << LCDIF_DISPLAYDITHERCONFIG0_GREEN_SIZE_SHIFT) |
312                                      ((uint32_t)config->blueSize << LCDIF_DISPLAYDITHERCONFIG0_BLUE_SIZE_SHIFT) |
313                                      LCDIF_DISPLAYDITHERCONFIG0_ENABLE_MASK;
314     }
315     else
316     {
317         base->DISPLAYDITHERCONFIG0    = 0U;
318         base->DISPLAYDITHERTABLELOW0  = 0U;
319         base->DISPLAYDITHERTABLEHIGH0 = 0U;
320     }
321 }
322 
323 /*!
324  * brief Set the gamma translation values to the LCDIF gamma table.
325  *
326  * param base LCDIF peripheral base address.
327  * param fbIndex The frame buffer index.
328  * param startIndex Start index in the gamma table that the value will be set to.
329  * param gamma The gamma values to set to the gamma table in LCDIF, could be defined using LCDIF_MAKE_GAMMA_VALUE.
330  * param gammaLen The length of the p gamma.
331  */
LCDIF_SetGammaData(LCDIF_Type * base,uint8_t fbIndex,uint16_t startIndex,const uint32_t * gamma,uint16_t gammaLen)332 void LCDIF_SetGammaData(
333     LCDIF_Type *base, uint8_t fbIndex, uint16_t startIndex, const uint32_t *gamma, uint16_t gammaLen)
334 {
335     assert(startIndex + gammaLen <= LCDIF_GAMMA_INDEX_MAX);
336 
337     base->GAMMAINDEX0 = startIndex;
338 
339     while (0U != (gammaLen--))
340     {
341         base->GAMMADATA0 = *(gamma++);
342     }
343 }
344 
345 /*!
346  * brief Get the hardware cursor default configuration
347  *
348  * The default configuration values are:
349  *
350  * code
351     config->enable = true;
352     config->format = kLCDIF_CursorMasked;
353     config->hotspotOffsetX = 0;
354     config->hotspotOffsetY = 0;
355    endcode
356  *
357  * param config Pointer to the hardware cursor configuration structure.
358  */
LCDIF_CursorGetDefaultConfig(lcdif_cursor_config_t * config)359 void LCDIF_CursorGetDefaultConfig(lcdif_cursor_config_t *config)
360 {
361     assert(NULL != config);
362 
363     config->enable         = true;
364     config->format         = kLCDIF_CursorMasked;
365     config->hotspotOffsetX = 0;
366     config->hotspotOffsetY = 0;
367 }
368 
369 /*!
370  * brief Configure the cursor.
371  *
372  * param base LCDIF peripheral base address.
373  * param config Cursor configuration.
374  */
LCDIF_SetCursorConfig(LCDIF_Type * base,const lcdif_cursor_config_t * config)375 void LCDIF_SetCursorConfig(LCDIF_Type *base, const lcdif_cursor_config_t *config)
376 {
377     assert(NULL != config);
378 
379     uint32_t regConfig = 0U;
380 
381     if (config->enable)
382     {
383         regConfig |= (uint32_t)(config->format) << LCDIF_CURSORCONFIG_FORMAT_SHIFT;
384         regConfig |= (((uint32_t)config->hotspotOffsetX << LCDIF_CURSORCONFIG_HOT_SPOT_X_SHIFT) |
385                       ((uint32_t)config->hotspotOffsetY << LCDIF_CURSORCONFIG_HOT_SPOT_Y_SHIFT));
386     }
387 
388     base->CURSORCONFIG = regConfig;
389 }
390 
391 /*!
392  * brief Set the cursor color
393  *
394  * param base LCDIF peripheral base address.
395  * param background  Background color, could be defined use ref LCDIF_MAKE_CURSOR_COLOR
396  * param foreground  Foreground color, could be defined use ref LCDIF_MAKE_CURSOR_COLOR
397  */
LCDIF_SetCursorColor(LCDIF_Type * base,uint32_t background,uint32_t foreground)398 void LCDIF_SetCursorColor(LCDIF_Type *base, uint32_t background, uint32_t foreground)
399 {
400     base->CURSORBACKGROUND = background;
401     base->CURSORFOREGROUND = foreground;
402 }
403