1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2019 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_lcdc.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.lpc_lcdc"
18 #endif
19 
20 /* Max value of LCD_POL[PCD]. */
21 #define LCD_PCD_MAX                                                                 \
22     ((uint32_t)(((uint32_t)LCD_POL_PCD_LO_MASK >> (uint32_t)LCD_POL_PCD_LO_SHIFT) | \
23                 ((uint32_t)LCD_POL_PCD_HI_MASK >> ((uint32_t)LCD_POL_PCD_HI_SHIFT - (uint32_t)LCD_POL_PCD_LO_SHIFT))))
24 
25 /* Macro to contruct the LCD_POL[PCD]. */
26 #if (LCD_POL_PCD_LO_MASK != 0x1F)
27 #error LCD_POL_PCD_LO is not 5-bit. The macro LCD_POL_PCD_LO_WIDTH should be updated.
28 #endif
29 #define LCD_POL_PCD_LO_WIDTH 5U
30 #define LCD_POL_PCD(pcd)     (LCD_POL_PCD_LO(pcd) | LCD_POL_PCD_HI((pcd) >> LCD_POL_PCD_LO_WIDTH))
31 
32 /* Cursor interrupt. */
33 #define LCDC_CURSOR_INT_MASK LCD_CRSR_INTMSK_CRSRIM_MASK
34 
35 /* Interrupts except cursor interrupt. */
36 #define LCDC_NORMAL_INT_MASK \
37     (LCD_INTMSK_FUFIM_MASK | LCD_INTMSK_LNBUIM_MASK | LCD_INTMSK_VCOMPIM_MASK | LCD_INTMSK_BERIM_MASK)
38 
39 /* Detect the cursor interrupt and normal interrupt bits overlap. */
40 #if (LCDC_CURSOR_INT_MASK & LCDC_NORMAL_INT_MASK)
41 #error Cursor interrupt and normal interrupt overlap. The driver should be updated.
42 #endif
43 
44 /* The max cursor clip value. */
45 #define LCDC_CLIP_MAX (LCD_CRSR_CLIP_CRSRCLIPX_MASK >> LCD_CRSR_CLIP_CRSRCLIPX_SHIFT)
46 
47 /*******************************************************************************
48  * Variables
49  ******************************************************************************/
50 static LCD_Type *const s_lcdBases[] = LCD_BASE_PTRS;
51 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
52 static const clock_ip_name_t s_lcdClocks[] = LCD_CLOCKS;
53 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
54 
55 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
56 static const reset_ip_name_t s_lcdResets[] = LCD_RSTS;
57 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
58 
59 /*******************************************************************************
60  * Prototypes
61  ******************************************************************************/
62 
63 /*!
64  * @brief Gets the LCD instance according to the LCD base
65  *
66  * @param base LCD peripheral base address.
67  * @return LCD instance.
68  */
69 static uint32_t LCDC_GetInstance(LCD_Type *base);
70 
71 /*!
72  * @brief Calculate the clock divider to generate desired panel clock.
73  *
74  * @param config Pointer to the LCD configuration.
75  * @param srcClock_Hz The LCD input clock (LCDCLK) frequency in Hz.
76  * @param divider The divider result.
77  * @return Return false if no divider available to generate the desired clock,
78  * otherwise return true;
79  */
80 static bool LCDC_GetClockDivider(const lcdc_config_t *config, uint32_t srcClock_Hz, uint32_t *divider);
81 
82 /*******************************************************************************
83  * Code
84  ******************************************************************************/
LCDC_GetInstance(LCD_Type * base)85 static uint32_t LCDC_GetInstance(LCD_Type *base)
86 {
87     uint32_t instance;
88 
89     /* Find the instance index from base address mappings. */
90     for (instance = 0; instance < ARRAY_SIZE(s_lcdBases); instance++)
91     {
92         if (s_lcdBases[instance] == base)
93         {
94             break;
95         }
96     }
97 
98     assert(instance < ARRAY_SIZE(s_lcdBases));
99 
100     return instance;
101 }
102 
LCDC_GetClockDivider(const lcdc_config_t * config,uint32_t srcClock_Hz,uint32_t * divider)103 static bool LCDC_GetClockDivider(const lcdc_config_t *config, uint32_t srcClock_Hz, uint32_t *divider)
104 {
105     uint16_t cpl;
106     uint32_t pcd;
107 
108     *divider = 0U;
109 
110     /* Find the PCD. */
111     pcd = (srcClock_Hz + (config->panelClock_Hz / 2U)) / config->panelClock_Hz;
112 
113     if (pcd <= 1U)
114     {
115         if (kLCDC_DisplayTFT == config->display)
116         {
117             pcd      = 0U;
118             *divider = LCD_POL_BCD_MASK;
119         }
120         else
121         {
122             return false;
123         }
124     }
125     else
126     {
127         pcd -= 2U;
128 
129         /* Verify the PCD value. */
130         if (pcd > LCD_PCD_MAX)
131         {
132             return false;
133         }
134 
135         if (((kLCDC_DisplaySingleColorSTN8Bit == config->display) && (pcd < 1U)) ||
136             ((kLCDC_DisplayDualColorSTN8Bit == config->display) && (pcd < 4U)) ||
137             ((kLCDC_DisplaySingleMonoSTN4Bit == config->display) && (pcd < 2U)) ||
138             ((kLCDC_DisplaySingleMonoSTN8Bit == config->display) && (pcd < 6U)) ||
139             ((kLCDC_DisplayDualMonoSTN4Bit == config->display) && (pcd < 6U)) ||
140             ((kLCDC_DisplayDualMonoSTN8Bit == config->display) && (pcd < 14U)))
141         {
142             return false;
143         }
144     }
145 
146     if (0U != ((uint32_t)(config->display) & LCD_CTRL_LCDTFT_MASK))
147     {
148         /* TFT panel. */
149         cpl = config->ppl - 1U;
150     }
151     else
152     {
153         if (0U != ((uint32_t)(config->display) & LCD_CTRL_LCDBW_MASK))
154         {
155             if (0U != ((uint32_t)(config->display) & LCD_CTRL_LCDMONO8_MASK))
156             {
157                 /* 8-bit monochrome STN panel. */
158                 cpl = (config->ppl / 8U) - 1U;
159             }
160             else
161             {
162                 /* 4-bit monochrome STN panel. */
163                 cpl = (config->ppl / 4U) - 1U;
164             }
165         }
166         else
167         {
168             /* Color STN panel. */
169             cpl = ((config->ppl * 3U) / 8U) - 1U;
170         }
171     }
172 
173     *divider |= (LCD_POL_CPL(cpl) | LCD_POL_PCD(pcd));
174 
175     return true;
176 }
177 
178 /*!
179  * brief Initialize the LCD module.
180  *
181  * param base LCD peripheral base address.
182  * param config Pointer to configuration structure, see to ref lcdc_config_t.
183  * param srcClock_Hz The LCD input clock (LCDCLK) frequency in Hz.
184  * retval kStatus_Success LCD is initialized successfully.
185  * retval kStatus_InvalidArgument Initlialize failed because of invalid argument.
186  */
LCDC_Init(LCD_Type * base,const lcdc_config_t * config,uint32_t srcClock_Hz)187 status_t LCDC_Init(LCD_Type *base, const lcdc_config_t *config, uint32_t srcClock_Hz)
188 {
189     assert(NULL != config);
190     assert(0U != srcClock_Hz);
191     assert((config->ppl & 0xFU) == 0U);
192     assert((config->upperPanelAddr & 0x07U) == 0U);
193     assert((config->lowerPanelAddr & 0x07U) == 0U);
194 
195     uint32_t reg;
196     uint32_t divider;
197     uint32_t instance;
198 
199     /* Verify the clock here. */
200     if (!LCDC_GetClockDivider(config, srcClock_Hz, &divider))
201     {
202         return kStatus_InvalidArgument;
203     }
204 
205     instance = LCDC_GetInstance(base);
206 
207 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
208     CLOCK_EnableClock(s_lcdClocks[instance]);
209 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
210 
211 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
212     /* Reset the module. */
213     RESET_PeripheralReset(s_lcdResets[instance]);
214 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
215 
216     /* Set register CTRL. */
217     reg = base->CTRL & (LCD_CTRL_LCDVCOMP_MASK | LCD_CTRL_WATERMARK_MASK);
218     reg |= (uint32_t)(config->dataFormat) | (uint32_t)(config->display) | LCD_CTRL_LCDBPP(config->bpp);
219 
220     if (config->swapRedBlue)
221     {
222         reg |= LCD_CTRL_BGR_MASK;
223     }
224 
225     base->CTRL = reg;
226 
227     /* Clean pending interrupts and disable all interrupts. */
228     base->INTCLR      = LCDC_NORMAL_INT_MASK;
229     base->CRSR_INTCLR = LCDC_CURSOR_INT_MASK;
230     base->INTMSK      = 0U;
231     base->CRSR_INTMSK = 0U;
232 
233     /* Configure timing. */
234     base->TIMH = LCD_TIMH_PPL(((uint32_t)config->ppl / 16U) - 1U) | LCD_TIMH_HSW((uint32_t)config->hsw - 1U) |
235                  LCD_TIMH_HFP((uint32_t)config->hfp - 1U) | LCD_TIMH_HBP((uint32_t)config->hbp - 1U);
236 
237     base->TIMV = LCD_TIMV_LPP((uint32_t)config->lpp - 1U) | LCD_TIMV_VSW((uint32_t)config->vsw - 1U) |
238                  LCD_TIMV_VFP((uint32_t)config->vfp - 1U) | LCD_TIMV_VBP((uint32_t)config->vbp - 1U);
239 
240     base->POL = (uint32_t)(config->polarityFlags) | LCD_POL_ACB((uint32_t)config->acBiasFreq - 1U) | divider;
241 
242     /* Line end configuration. */
243     if (config->enableLineEnd)
244     {
245         base->LE = LCD_LE_LED((uint32_t)config->lineEndDelay - 1U) | LCD_LE_LEE_MASK;
246     }
247     else
248     {
249         base->LE = 0U;
250     }
251 
252     /* Set panel frame base address. */
253     base->UPBASE = config->upperPanelAddr;
254     base->LPBASE = config->lowerPanelAddr;
255 
256     return kStatus_Success;
257 }
258 
259 /*!
260  * brief Deinitialize the LCD module.
261  *
262  * param base LCD peripheral base address.
263  */
LCDC_Deinit(LCD_Type * base)264 void LCDC_Deinit(LCD_Type *base)
265 {
266 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
267     CLOCK_EnableClock(s_lcdClocks[LCDC_GetInstance(base)]);
268 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
269 }
270 
271 /*!
272  * brief Gets default pre-defined settings for initial configuration.
273  *
274  * This function initializes the configuration structure. The default values are:
275  *
276    code
277     config->panelClock_Hz = 0U;
278     config->ppl = 0U;
279     config->hsw = 0U;
280     config->hfp = 0U;
281     config->hbp = 0U;
282     config->lpp = 0U;
283     config->vsw = 0U;
284     config->vfp = 0U;
285     config->vbp = 0U;
286     config->acBiasFreq = 1U;
287     config->polarityFlags = 0U;
288     config->enableLineEnd = false;
289     config->lineEndDelay = 0U;
290     config->upperPanelAddr = 0U;
291     config->lowerPanelAddr = 0U;
292     config->bpp = kLCDC_1BPP;
293     config->dataFormat = kLCDC_LittleEndian;
294     config->swapRedBlue = false;
295     config->display = kLCDC_DisplayTFT;
296    endcode
297  *
298  * param config Pointer to configuration structure.
299  */
LCDC_GetDefaultConfig(lcdc_config_t * config)300 void LCDC_GetDefaultConfig(lcdc_config_t *config)
301 {
302     /* Initializes the configure structure to zero. */
303     (void)memset(config, 0, sizeof(*config));
304 
305     config->panelClock_Hz  = 0U;
306     config->ppl            = 0U;
307     config->hsw            = 0U;
308     config->hfp            = 0U;
309     config->hbp            = 0U;
310     config->lpp            = 0U;
311     config->vsw            = 0U;
312     config->vfp            = 0U;
313     config->vbp            = 0U;
314     config->acBiasFreq     = 1U;
315     config->polarityFlags  = 0U;
316     config->enableLineEnd  = false;
317     config->lineEndDelay   = 0U;
318     config->upperPanelAddr = 0U;
319     config->lowerPanelAddr = 0U;
320     config->bpp            = kLCDC_1BPP;
321     config->dataFormat     = kLCDC_LittleEndian;
322     config->swapRedBlue    = false;
323     config->display        = kLCDC_DisplayTFT;
324 }
325 
326 /*!
327  * brief Sets panel frame base address
328  *
329  * param base LCD peripheral base address.
330  * param panel Which panel to set.
331  * param addr Frame base address, must be doubleword(64-bit) aligned.
332  */
LCDC_SetPanelAddr(LCD_Type * base,lcdc_panel_t panel,uint32_t addr)333 void LCDC_SetPanelAddr(LCD_Type *base, lcdc_panel_t panel, uint32_t addr)
334 {
335     /* The base address must be doubleword aligned. */
336     assert((addr & 0x07U) == 0U);
337 
338     if (kLCDC_UpperPanel == panel)
339     {
340         base->UPBASE = addr;
341     }
342     else
343     {
344         base->LPBASE = addr;
345     }
346 }
347 
348 /*!
349  * brief Sets palette
350  *
351  * param base LCD peripheral base address.
352  * param palette Pointer to the palette array.
353  * param count_words Length of the palette array to set (how many words), it should
354  * not be larger than LCDC_PALETTE_SIZE_WORDS.
355  */
LCDC_SetPalette(LCD_Type * base,const uint32_t * palette,uint8_t count_words)356 void LCDC_SetPalette(LCD_Type *base, const uint32_t *palette, uint8_t count_words)
357 {
358     assert(count_words <= ARRAY_SIZE(base->PAL));
359 
360     uint32_t i;
361 
362     for (i = 0; i < count_words; i++)
363     {
364         base->PAL[i] = palette[i];
365     }
366 }
367 
368 /*!
369  * brief Enable LCD interrupts.
370  *
371  * Example to enable LCD base address update interrupt and vertical compare
372  * interrupt:
373  *
374  * code
375    LCDC_EnableInterrupts(LCD, kLCDC_BaseAddrUpdateInterrupt | kLCDC_VerticalCompareInterrupt);
376    endcode
377  *
378  * param base LCD peripheral base address.
379  * param mask Interrupts to enable, it is OR'ed value of ref _lcdc_interrupts.
380  */
LCDC_EnableInterrupts(LCD_Type * base,uint32_t mask)381 void LCDC_EnableInterrupts(LCD_Type *base, uint32_t mask)
382 {
383     uint32_t reg;
384 
385     reg = mask & LCDC_CURSOR_INT_MASK;
386     if (0U != reg)
387     {
388         base->CRSR_INTMSK |= reg;
389     }
390 
391     reg = mask & LCDC_NORMAL_INT_MASK;
392     if (0U != reg)
393     {
394         base->INTMSK |= reg;
395     }
396 }
397 
398 /*!
399  * brief Disable LCD interrupts.
400  *
401  * Example to disable LCD base address update interrupt and vertical compare
402  * interrupt:
403  *
404  * code
405    LCDC_DisableInterrupts(LCD, kLCDC_BaseAddrUpdateInterrupt | kLCDC_VerticalCompareInterrupt);
406    endcode
407  *
408  * param base LCD peripheral base address.
409  * param mask Interrupts to disable, it is OR'ed value of ref _lcdc_interrupts.
410  */
LCDC_DisableInterrupts(LCD_Type * base,uint32_t mask)411 void LCDC_DisableInterrupts(LCD_Type *base, uint32_t mask)
412 {
413     uint32_t reg;
414 
415     reg = mask & LCDC_CURSOR_INT_MASK;
416     if (0U != reg)
417     {
418         base->CRSR_INTMSK &= ~reg;
419     }
420 
421     reg = mask & LCDC_NORMAL_INT_MASK;
422     if (0U != reg)
423     {
424         base->INTMSK &= ~reg;
425     }
426 }
427 
428 /*!
429  * brief Get LCD interrupt pending status.
430  *
431  * Example:
432  *
433  * code
434    uint32_t status;
435 
436    status = LCDC_GetInterruptsPendingStatus(LCD);
437 
438    if (kLCDC_BaseAddrUpdateInterrupt & status)
439    {
440        LCD base address update interrupt occurred.
441    }
442 
443    if (kLCDC_VerticalCompareInterrupt & status)
444    {
445        LCD vertical compare interrupt occurred.
446    }
447    endcode
448  *
449  * param base LCD peripheral base address.
450  * return Interrupts pending status, it is OR'ed value of ref _lcdc_interrupts.
451  */
LCDC_GetInterruptsPendingStatus(LCD_Type * base)452 uint32_t LCDC_GetInterruptsPendingStatus(LCD_Type *base)
453 {
454     uint32_t reg;
455 
456     reg = base->CRSR_INTRAW;
457     reg |= base->INTRAW;
458 
459     return reg;
460 }
461 
462 /*!
463  * brief Get LCD enabled interrupt pending status.
464  *
465  * This function is similar with ref LCDC_GetInterruptsPendingStatus, the only
466  * difference is, this function only returns the pending status of the
467  * interrupts that have been enabled using ref LCDC_EnableInterrupts.
468  *
469  * param base LCD peripheral base address.
470  * return Interrupts pending status, it is OR'ed value of ref _lcdc_interrupts.
471  */
LCDC_GetEnabledInterruptsPendingStatus(LCD_Type * base)472 uint32_t LCDC_GetEnabledInterruptsPendingStatus(LCD_Type *base)
473 {
474     uint32_t reg;
475 
476     reg = base->CRSR_INTSTAT;
477     reg |= base->INTSTAT;
478 
479     return reg;
480 }
481 
482 /*!
483  * brief Clear LCD interrupts pending status.
484  *
485  * Example to clear LCD base address update interrupt and vertical compare
486  * interrupt pending status:
487  *
488  * code
489    LCDC_ClearInterruptsStatus(LCD, kLCDC_BaseAddrUpdateInterrupt | kLCDC_VerticalCompareInterrupt);
490    endcode
491  *
492  * param base LCD peripheral base address.
493  * param mask Interrupts to disable, it is OR'ed value of ref _lcdc_interrupts.
494  */
LCDC_ClearInterruptsStatus(LCD_Type * base,uint32_t mask)495 void LCDC_ClearInterruptsStatus(LCD_Type *base, uint32_t mask)
496 {
497     uint32_t reg;
498 
499     reg = mask & LCDC_CURSOR_INT_MASK;
500     if (0U != reg)
501     {
502         base->CRSR_INTCLR = reg;
503     }
504 
505     reg = mask & LCDC_NORMAL_INT_MASK;
506     if (0U != reg)
507     {
508         base->INTCLR = reg;
509     }
510 }
511 
512 /*!
513  * brief Set the hardware cursor configuration
514  *
515  * This function should be called before enabling the hardware cursor.
516  * It supports initializing multiple cursor images at a time when using
517  * 32x32 pixels cursor.
518  *
519  * For example:
520  *
521  * code
522    uint32_t cursor0Img[LCDC_CURSOR_IMG_32X32_WORDS] = {...};
523    uint32_t cursor2Img[LCDC_CURSOR_IMG_32X32_WORDS] = {...};
524 
525    lcdc_cursor_config_t cursorConfig;
526 
527    LCDC_CursorGetDefaultConfig(&cursorConfig);
528 
529    cursorConfig.image[0] = cursor0Img;
530    cursorConfig.image[2] = cursor2Img;
531 
532    LCDC_SetCursorConfig(LCD, &cursorConfig);
533 
534    LCDC_ChooseCursor(LCD, 0);
535    LCDC_SetCursorPosition(LCD, 0, 0);
536 
537    LCDC_EnableCursor(LCD);
538    endcode
539  *
540  * In this example, cursor 0 and cursor 2 image data are initialized, but cursor 1
541  * and cursor 3 image data are not initialized because image[1] and image[2] are
542  * all NULL. With this, application could initializes all cursor images it will
543  * use at the beginning and call ref LCDC_SetCursorImage directly to display the
544  * one which it needs.
545  *
546  * param base LCD peripheral base address.
547  * param config Pointer to the hardware cursor configuration structure.
548  */
LCDC_SetCursorConfig(LCD_Type * base,const lcdc_cursor_config_t * config)549 void LCDC_SetCursorConfig(LCD_Type *base, const lcdc_cursor_config_t *config)
550 {
551     assert(NULL != config);
552 
553     uint8_t i;
554 
555     base->CRSR_CFG = LCD_CRSR_CFG_CRSRSIZE(config->size) | LCD_CRSR_CFG_FRAMESYNC(config->syncMode);
556 
557     /* Set position. */
558     LCDC_SetCursorPosition(base, 0, 0);
559 
560     /* Palette. */
561     base->CRSR_PAL0 = ((uint32_t)config->palette0.red << LCD_CRSR_PAL0_RED_SHIFT) |
562                       ((uint32_t)config->palette0.blue << LCD_CRSR_PAL0_BLUE_SHIFT) |
563                       ((uint32_t)config->palette0.green << LCD_CRSR_PAL0_GREEN_SHIFT);
564     base->CRSR_PAL1 = ((uint32_t)config->palette1.red << LCD_CRSR_PAL1_RED_SHIFT) |
565                       ((uint32_t)config->palette1.blue << LCD_CRSR_PAL1_BLUE_SHIFT) |
566                       ((uint32_t)config->palette1.green << LCD_CRSR_PAL1_GREEN_SHIFT);
567 
568     /* Image of cursors. */
569     if (kLCDC_CursorSize64 == config->size)
570     {
571         assert(NULL != config->image[0]);
572         LCDC_SetCursorImage(base, config->size, 0, config->image[0]);
573     }
574     else
575     {
576         for (i = 0; i < LCDC_CURSOR_COUNT; i++)
577         {
578             if (NULL != config->image[i])
579             {
580                 LCDC_SetCursorImage(base, config->size, i, config->image[i]);
581             }
582         }
583     }
584 }
585 
586 /*!
587  * brief Get the hardware cursor default configuration
588  *
589  * The default configuration values are:
590  *
591  * code
592     config->size = kLCDC_CursorSize32;
593     config->syncMode = kLCDC_CursorAsync;
594     config->palette0.red = 0U;
595     config->palette0.green = 0U;
596     config->palette0.blue = 0U;
597     config->palette1.red = 255U;
598     config->palette1.green = 255U;
599     config->palette1.blue = 255U;
600     config->image[0] = (uint32_t *)0;
601     config->image[1] = (uint32_t *)0;
602     config->image[2] = (uint32_t *)0;
603     config->image[3] = (uint32_t *)0;
604    endcode
605  *
606  * param config Pointer to the hardware cursor configuration structure.
607  */
LCDC_CursorGetDefaultConfig(lcdc_cursor_config_t * config)608 void LCDC_CursorGetDefaultConfig(lcdc_cursor_config_t *config)
609 {
610     uint32_t i;
611 
612     /* Initializes the configure structure to zero. */
613     (void)memset(config, 0, sizeof(*config));
614 
615     config->size           = kLCDC_CursorSize32;
616     config->syncMode       = kLCDC_CursorAsync;
617     config->palette0.red   = 0U;
618     config->palette0.green = 0U;
619     config->palette0.blue  = 0U;
620     config->palette1.red   = 255U;
621     config->palette1.green = 255U;
622     config->palette1.blue  = 255U;
623 
624     for (i = 0; i < LCDC_CURSOR_COUNT; i++)
625     {
626         config->image[i] = (uint32_t *)0;
627     }
628 }
629 
630 /*!
631  * brief Set the position of cursor
632  *
633  * When synchronization mode is ref kLCDC_CursorSync, position change effects
634  * in the next frame. When synchronization mode is ref kLCDC_CursorAsync,
635  * position change effects immediately.
636  *
637  * param base LCD peripheral base address.
638  * param positionX X ordinate of the cursor top-left measured in pixels
639  * param positionY Y ordinate of the cursor top-left measured in pixels
640  */
LCDC_SetCursorPosition(LCD_Type * base,int32_t positionX,int32_t positionY)641 void LCDC_SetCursorPosition(LCD_Type *base, int32_t positionX, int32_t positionY)
642 {
643     uint32_t clipX;
644     uint32_t clipY;
645 
646     if (positionX < 0)
647     {
648         clipX     = (uint32_t)(-positionX);
649         positionX = 0;
650 
651         /* If clip value too large, set to the max value. */
652         if (clipX > LCDC_CLIP_MAX)
653         {
654             clipX = LCDC_CLIP_MAX;
655         }
656     }
657     else
658     {
659         clipX = 0U;
660     }
661 
662     if (positionY < 0)
663     {
664         clipY     = (uint32_t)-positionY;
665         positionY = 0;
666 
667         /* If clip value too large, set to the max value. */
668         if (clipY > LCDC_CLIP_MAX)
669         {
670             clipY = LCDC_CLIP_MAX;
671         }
672     }
673     else
674     {
675         clipY = 0U;
676     }
677 
678     base->CRSR_CLIP = LCD_CRSR_CLIP_CRSRCLIPX(clipX) | LCD_CRSR_CLIP_CRSRCLIPY(clipY);
679     base->CRSR_XY   = LCD_CRSR_XY_CRSRX(positionX) | LCD_CRSR_XY_CRSRY(positionY);
680 }
681 
682 /*!
683  * brief Set the cursor image.
684  *
685  * The interrupt ref kLCDC_CursorInterrupt indicates that last cursor pixel is
686  * displayed. When the hardware cursor is enabled,
687  *
688  * param base LCD peripheral base address.
689  * param size The cursor size.
690  * param index Index of the cursor to set when using 32x32 cursor.
691  * param image Pointer to the cursor image. When using 32x32 cursor, the image
692  * size should be LCDC_CURSOR_IMG_32X32_WORDS. When using 64x64 cursor, the image
693  * size should be LCDC_CURSOR_IMG_64X64_WORDS.
694  */
LCDC_SetCursorImage(LCD_Type * base,lcdc_cursor_size_t size,uint8_t index,const uint32_t * image)695 void LCDC_SetCursorImage(LCD_Type *base, lcdc_cursor_size_t size, uint8_t index, const uint32_t *image)
696 {
697     uint32_t regStart;
698     uint32_t i;
699     uint32_t len;
700 
701     if (kLCDC_CursorSize64 == size)
702     {
703         regStart = 0U;
704         len      = LCDC_CURSOR_IMG_64X64_WORDS;
705     }
706     else
707     {
708         regStart = (uint32_t)index * LCDC_CURSOR_IMG_32X32_WORDS;
709         len      = LCDC_CURSOR_IMG_32X32_WORDS;
710     }
711 
712     for (i = 0U; i < len; i++)
713     {
714         base->CRSR_IMG[regStart + i] = image[i];
715     }
716 }
717