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