1 /*
2  * Copyright 2021 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_epdc.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.epdc"
17 #endif
18 
19 #if defined(EPDC_RSTS)
20 #define EPDC_RESETS_ARRAY EPDC_RSTS
21 #endif
22 
23 typedef union
24 {
25     epdc_fifo_config_t _fifo_config;                 /* 32-bit */
26     epdc_autowave_map_t _autowave_map;               /* 32-bit */
27     epdc_gpio_config_t _gpio_config;                 /* 32-bit */
28     epdc_pigeon_cycle_config_t _pigeon_cycle_config; /* 64-bit */
29     epdc_sd_config_t _source_driver_config;          /* 64-bit */
30     epdc_pigeon_config_t _pigeon_config;             /* 96-bit */
31     epdc_update_config_t _update_config;             /* 192-bit */
32     uint32_t _u32;
33     uint64_t _u64;
34 } epdc_reg_convert_t;
35 
36 /*******************************************************************************
37  * Prototypes
38  ******************************************************************************/
39 
40 /*******************************************************************************
41  * Variables
42  ******************************************************************************/
43 /*! brief Pointers to EPDC bases for each instance. */
44 static EPDC_Type *const s_epdcBases[] = EPDC_BASE_PTRS;
45 
46 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
47 /*! brief Pointers to EPDC clocks for each EPDC submodule. */
48 static const clock_ip_name_t s_epdcClocks[] = EPDC_CLOCKS;
49 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
50 
51 #if defined(EPDC_RESETS_ARRAY)
52 /* Reset array */
53 static const reset_ip_name_t s_epdcResets[] = EPDC_RESETS_ARRAY;
54 #endif
55 
56 /*******************************************************************************
57  * Code
58  ******************************************************************************/
EPDC_GetInstance(EPDC_Type * base)59 static uint32_t EPDC_GetInstance(EPDC_Type *base)
60 {
61     uint32_t instance;
62 
63     /* Find the instance index from base address mappings. */
64     for (instance = 0; instance < ARRAY_SIZE(s_epdcBases); instance++)
65     {
66         if (s_epdcBases[instance] == base)
67         {
68             break;
69         }
70     }
71 
72     assert(instance < ARRAY_SIZE(s_epdcBases));
73 
74     return instance;
75 }
76 
77 /*!
78  * brief Resets the EPDC to initialized state.
79  *
80  * param base EPDC base pointer
81  */
EPDC_ResetToInit(EPDC_Type * base)82 void EPDC_ResetToInit(EPDC_Type *base)
83 {
84     /* Set software reset. */
85     base->CTRL.SET = EPDC_CTRL_SFTRST_MASK;
86     /* Wait for clock gate to set. */
87     while ((base->CTRL.RW & EPDC_CTRL_CLKGATE_MASK) == 0U)
88     {
89     }
90     /* Clear software reset and clock gate. */
91     base->CTRL.CLR = (EPDC_CTRL_SFTRST_MASK | EPDC_CTRL_CLKGATE_MASK);
92     /* Wait for these bits to be cleared */
93     while ((base->CTRL.RW & (EPDC_CTRL_CLKGATE_MASK | EPDC_CTRL_SFTRST_MASK)) != 0U)
94     {
95     }
96 }
97 
98 /*!
99  * brief Initializes the EPDC.
100  *
101  * This function enables the EPDC peripheral clock, and resets the EPDC registers
102  * to default status.
103  *
104  * param base EPDC base pointer
105  */
EPDC_Init(EPDC_Type * base)106 void EPDC_Init(EPDC_Type *base)
107 {
108 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
109     CLOCK_EnableClock(s_epdcClocks[EPDC_GetInstance(base)]);
110 #endif
111 
112 #if defined(EPDC_RESETS_ARRAY)
113     RESET_ReleasePeripheralReset(s_epdcResets[EPDC_GetInstance(base)]);
114 #endif
115 
116     EPDC_ResetToInit(base);
117 }
118 
119 /*!
120  * brief De-initializes the EPDC.
121  *
122  * This function disables the EPDC peripheral clock.
123  *
124  * param base EPDC base pointer
125  */
EPDC_Deinit(EPDC_Type * base)126 void EPDC_Deinit(EPDC_Type *base)
127 {
128 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
129     CLOCK_DisableClock(s_epdcClocks[EPDC_GetInstance(base)]);
130 #endif
131 }
132 
133 /*!
134  * brief Initializes the EPDC dispaly parameters.
135  *
136  * param base EPDC base pointer
137  * param config Pointer to EPDC display configuration structure
138  * retval kStatus_Success Successfully initialized the display parameters
139  * retval kStatus_InvalidArgument parameter(s) is(are) not valid
140  */
EPDC_InitDisplay(EPDC_Type * base,const epdc_display_config_t * config)141 status_t EPDC_InitDisplay(EPDC_Type *base, const epdc_display_config_t *config)
142 {
143     assert(config != NULL);
144 
145     /* waveform address and working buffer address must be 64-bit aligned. */
146     if (((config->waveformAddr & 0x3FUL) != 0U) || ((config->wbAddr & 0x3FUL) != 0U))
147     {
148         return kStatus_InvalidArgument;
149     }
150 
151     base->WVADDR    = config->waveformAddr;
152     base->WB_ADDR   = config->wbAddr;
153     base->TEMP      = config->tempIdx;
154     base->RES       = (uint32_t)config->resX | ((uint32_t)config->resY << 16U);
155     base->FORMAT.RW = EPDC_FORMAT_DEFAULT_TFT_PIXEL((uint32_t)config->defaltTftPixelValue) |
156                       EPDC_FORMAT_WB_TYPE((uint32_t)config->wbType) |
157                       EPDC_FORMAT_TFT_PIXEL_FORMAT((uint32_t)config->pixelFormat);
158     base->CTRL.RW = (base->CTRL.RW & ~(EPDC_CTRL_UPD_DATA_SWIZZLE_MASK | EPDC_CTRL_LUT_DATA_SWIZZLE_MASK)) |
159                     EPDC_CTRL_UPD_DATA_SWIZZLE((uint32_t)config->updSwizzle) |
160                     EPDC_CTRL_LUT_DATA_SWIZZLE((uint32_t)config->lutSwizzle);
161 
162     return kStatus_Success;
163 }
164 
165 /*!
166  * brief Configures the FIFO control parameters, including panic function and pre-fill level.
167  *
168  * param base EPDC base pointer
169  * param config Pointer to EPDC FIFO control configuration structure
170  * retval kStatus_Success Successfully configured the FIFO
171  * retval kStatus_InvalidArgument parameter(s) is(are) not valid
172  */
EPDC_ConfigFifo(EPDC_Type * base,const epdc_fifo_config_t * config)173 status_t EPDC_ConfigFifo(EPDC_Type *base, const epdc_fifo_config_t *config)
174 {
175     assert(config != NULL);
176     if (config->lowLevel >= config->highLevel)
177     {
178         return kStatus_InvalidArgument;
179     }
180 
181     epdc_reg_convert_t pid;
182 
183     pid._fifo_config  = *config;
184     base->FIFOCTRL.RW = pid._u32;
185 
186     return kStatus_Success;
187 }
188 
189 /*!
190  * brief Configures the TCE parameters before initiating the panel update.
191  *
192  * note Make sure to configure the display parameters by @ref EPDC_InitDisplay before calling this API.
193  *
194  * param base EPDC base pointer
195  * param config Pointer to EPDC TCE control configuration structure
196  * retval kStatus_Success Successfully configured the TCE
197  * retval kStatus_InvalidArgument parameter(s) is(are) not valid
198  */
EPDC_ConfigTCE(EPDC_Type * base,const epdc_tce_config_t * config)199 status_t EPDC_ConfigTCE(EPDC_Type *base, const epdc_tce_config_t *config)
200 {
201     assert(config != NULL);
202 
203     uint16_t resX = (uint16_t)((base->RES & EPDC_RES_HORIZONTAL_MASK) >> EPDC_RES_HORIZONTAL_SHIFT);
204 
205     /* The horizontal resolution must be evenly divided by the count of souce sriver control enable signal. */
206     if ((resX % config->sdConfig.sdceCount) != 0U)
207     {
208         return kStatus_InvalidArgument;
209     }
210 
211     if (config->sdConfig.pixelReverse > (uint32_t)kEPDC_DataReversed)
212     {
213         return kStatus_InvalidArgument;
214     }
215 
216     epdc_reg_convert_t pid;
217     pid._source_driver_config = config->sdConfig;
218     uint8_t piexelPerClk      = 2U; /* Default is 4pixel/clock, 2^2. */
219 
220     base->WB_ADDR_TCE = config->tceWbAddr;
221     base->TCE_CTRL.RW = EPDC_TCE_CTRL_VSCAN_HOLDOFF((uint32_t)config->vscanHoldoff) |
222                         EPDC_TCE_CTRL_VCOM_VAL((uint32_t)config->vcomVal) |
223                         EPDC_TCE_CTRL_VCOM_MODE((uint32_t)config->vcomMode) |
224                         ((uint32_t)config->outMode << EPDC_TCE_CTRL_SDDO_WIDTH_SHIFT) |
225                         EPDC_TCE_CTRL_SCAN_DIR_0((uint32_t)config->upperScanDirection) |
226                         EPDC_TCE_CTRL_SCAN_DIR_1((uint32_t)config->lowerScanDirection);
227     base->TCE_SDCFG.RW = ((uint32_t)pid._u64 & ~EPDC_TCE_SDCFG_PIXELS_PER_CE_MASK) |
228                          (EPDC_TCE_SDCFG_PIXELS_PER_CE(resX / config->sdConfig.sdceCount));
229     base->TCE_GDCFG.RW = EPDC_TCE_GDCFG_GDSP_MODE((uint32_t)config->gdConfig.gdspMode) |
230                          EPDC_TCE_GDCFG_GDOE_MODE((uint32_t)config->gdConfig.gdoeMode) |
231                          EPDC_TCE_GDCFG_GDRL((uint32_t)config->gdConfig.shiftDir);
232     base->TCE_HSCAN1.RW = ((uint32_t)config->scanConfig.lineSync << 16U) | (uint32_t)config->scanConfig.lineSync;
233     base->TCE_HSCAN2.RW = ((uint32_t)config->scanConfig.lineEnd << 16U) | (uint32_t)config->scanConfig.lineBegin;
234     base->TCE_VSCAN.RW  = ((uint32_t)config->scanConfig.frameEnd << 16U) |
235                          ((uint32_t)config->scanConfig.frameBegin << 8U) | (uint32_t)config->scanConfig.frameSync;
236     base->TCE_OE.RW       = (uint32_t)(pid._u64 >> 32U);
237     base->TCE_POLARITY.RW = ((uint32_t)pid._u64 & 0x7UL) |
238                             EPDC_TCE_POLARITY_GDOE_POL((uint32_t)config->gdConfig.gdoePol) |
239                             EPDC_TCE_POLARITY_GDSP_POL((uint32_t)config->gdConfig.gdspPol);
240     base->TCE_TIMING1.RW = ((uint32_t)pid._u64 >> 3U) & 0x3FUL;
241     base->TCE_TIMING2.RW = ((uint32_t)config->gdConfig.gdClkHigh << 16U) | (uint32_t)config->gdConfig.gdspOffset;
242     base->TCE_TIMING3.RW = ((uint32_t)config->gdConfig.gdoeOffset << 16U) | (uint32_t)config->gdConfig.gdClkOffset;
243 
244     /* Calculate the pixel per clock value. */
245     if ((base->TCE_CTRL.RW & EPDC_TCE_CTRL_DDR_MODE_MASK) != 0U)
246     {
247         piexelPerClk += 1U;
248     }
249     if ((base->TCE_CTRL.RW & EPDC_TCE_CTRL_SDDO_WIDTH_MASK) != 0U)
250     {
251         piexelPerClk += 1U;
252     }
253     if ((base->TCE_CTRL.RW & EPDC_TCE_CTRL_LVDS_MODE_MASK) != 0U)
254     {
255         piexelPerClk -= 1U;
256     }
257     if ((base->TCE_CTRL.RW & EPDC_TCE_CTRL_DUAL_SCAN_MASK) != 0U)
258     {
259         piexelPerClk -= 1U;
260     }
261     if (((base->FORMAT.RW & EPDC_FORMAT_TFT_PIXEL_FORMAT_MASK) >> EPDC_FORMAT_TFT_PIXEL_FORMAT_SHIFT) >=
262         (uint32_t)kEPDC_Pixel4bit)
263     {
264         piexelPerClk -= 1U;
265     }
266 
267     /* Pixel clock cannot be larger than 8. */
268     if (piexelPerClk > 3U)
269     {
270         return kStatus_InvalidArgument;
271     }
272 
273     base->TCE_CTRL.RW =
274         (base->TCE_CTRL.RW & ~EPDC_TCE_CTRL_PIXELS_PER_SDCLK_MASK) | EPDC_TCE_CTRL_PIXELS_PER_SDCLK(piexelPerClk);
275 
276     return kStatus_Success;
277 }
278 
279 /*!
280  * brief Configures the signal output format for signals that support pigeon mode.
281  *
282  * note Refer to the soc reference manual to check the configurable pigeon signal.
283  *       No need to call this API if not using the pigeon mode.
284  *
285  * param base EPDC base pointer
286  * param signalNum The number of the pigeon signal to be configured
287  * param config Pointer to EPDC pigeon mode configuration structure
288  */
EPDC_ConfigPigeon(EPDC_Type * base,uint8_t signalNum,const epdc_pigeon_config_t * config)289 void EPDC_ConfigPigeon(EPDC_Type *base, uint8_t signalNum, const epdc_pigeon_config_t *config)
290 {
291     assert(config != NULL);
292     assert(signalNum <= 16U);
293 
294     epdc_reg_convert_t pid;
295     pid._pigeon_config = *config;
296 
297     uint32_t dataAddr = (uint32_t) & (pid._u32);
298 
299     base->PIGEON_X[signalNum].PIGEON_0 = *(uint32_t *)dataAddr;
300     dataAddr += 4U;
301     base->PIGEON_X[signalNum].PIGEON_1 = *(uint32_t *)dataAddr;
302     dataAddr += 4U;
303     base->PIGEON_X[signalNum].PIGEON_2 = *(uint32_t *)dataAddr;
304 }
305 
306 /*!
307  * brief Configures the cycle's period.
308  *
309  * When selecting any of the pclk/line/frame cycle as global counter, call this API forst to set the proper cycle
310  * period. The configuraton is shared for all pigeon signals.
311  *
312  * param base EPDC base pointer
313  * param config Pointer to EPDC pigeon mode cycle configuration structure
314  */
EPDC_ConfigPigeonCycle(EPDC_Type * base,const epdc_pigeon_cycle_config_t * config)315 void EPDC_ConfigPigeonCycle(EPDC_Type *base, const epdc_pigeon_cycle_config_t *config)
316 {
317     assert(config != NULL);
318 
319     epdc_reg_convert_t pid;
320     pid._pigeon_cycle_config = *config;
321 
322     base->PIGEON_CTRL0.RW = (uint32_t)pid._u64;
323     base->PIGEON_CTRL1.RW = (uint32_t)(pid._u64 >> 32U);
324 }
325 
326 /*!
327  * brief Gets the number of the next available LUT.
328  *
329  * param base EPDC base pointer
330  * param lutNum Pointer to LUT number
331  * retval kStatus_Success Successfully got the LUT number
332  * retval kStatus_Fail no valid LUT present, all LUTs are busy
333  */
EPDC_GetNextAvailableLUT(EPDC_Type * base,uint8_t * lutNum)334 status_t EPDC_GetNextAvailableLUT(EPDC_Type *base, uint8_t *lutNum)
335 {
336     assert(lutNum != NULL);
337     if ((base->STATUS_NEXTLUT & EPDC_STATUS_NEXTLUT_NEXT_LUT_VALID_MASK) == 0U)
338     {
339         /* No idle LUT available */
340         return kStatus_Fail;
341     }
342 
343     *lutNum =
344         (uint8_t)((base->STATUS_NEXTLUT & EPDC_STATUS_NEXTLUT_NEXT_LUT_MASK) >> EPDC_STATUS_NEXTLUT_NEXT_LUT_SHIFT);
345     return kStatus_Success;
346 }
347 
348 /*!
349  * brief Initiates a panel display update.
350  *
351  * param base EPDC base pointer
352  * param config Pointer to update configuration structure
353  * retval kStatus_Success Successfully initiated an update
354  * retval kStatus_Fail update failed due to busy working buffer or LUT
355  * retval kStatus_InvalidArgument parameter(s) is(are) not valid
356  */
EPDC_UpdateDisplay(EPDC_Type * base,epdc_update_config_t * config)357 status_t EPDC_UpdateDisplay(EPDC_Type *base, epdc_update_config_t *config)
358 {
359     assert(config != NULL);
360 
361     uint32_t updateBits =
362         config->width * config->height * 2U *
363         (((base->FORMAT.RW & EPDC_FORMAT_TFT_PIXEL_FORMAT_MASK) >> (EPDC_FORMAT_TFT_PIXEL_FORMAT_SHIFT + 1U)) + 1U);
364     /* If stride disabled, the buffer address must start and end on 8 byte address. */
365     if ((((config->bufferAddress & 0x3FUL) != 0U) || ((updateBits & 0x3FUL) != 0U)) && (config->stride == 0U))
366     {
367         return kStatus_InvalidArgument;
368     }
369 
370     epdc_reg_convert_t pid;
371     pid._update_config = *config;
372 
373     uint32_t dataAddr = (uint32_t) & (pid._u32);
374 
375     base->UPD_ADDR = *(uint32_t *)dataAddr;
376     dataAddr += 4U;
377     base->UPD_STRIDE = *(uint32_t *)dataAddr;
378     dataAddr += 4U;
379     base->UPD_CORD = *(uint32_t *)dataAddr;
380     dataAddr += 4U;
381     base->UPD_SIZE = *(uint32_t *)dataAddr;
382     dataAddr += 4U;
383     base->UPD_FIXED.RW = *(uint32_t *)dataAddr;
384     dataAddr += 4U;
385 
386     /* Make sure the working buffer and lookup table are not busy. */
387     if ((base->STATUS.RW & (EPDC_STATUS_WB_BUSY_MASK | EPDC_STATUS_LUTS_BUSY_MASK)) != 0U)
388     {
389         return kStatus_Fail;
390     }
391     base->UPD_CTRL.RW = *(uint32_t *)dataAddr;
392 
393     return kStatus_Success;
394 }
395 
396 /*!
397  * brief Sets one map between a grey level and its waveform mode.
398  *
399  * Call this API multiple times until all the maps are set.
400  *
401  * param base EPDC base pointer
402  * param config Pointer to autowave configuration structure
403  */
EPDC_SetAutowaveMap(EPDC_Type * base,const epdc_autowave_map_t * config)404 void EPDC_SetAutowaveMap(EPDC_Type *base, const epdc_autowave_map_t *config)
405 {
406     assert(config != NULL);
407 
408     epdc_reg_convert_t pid;
409     pid._autowave_map = *config;
410 
411     base->AUTOWV_LUT = pid._u32;
412 }
413 
414 /*!
415  * brief Sets the GPIO output value for BDR(0,1), PWR_CTRL(0,1,2,3), PWR_COM and PWR_WAKE pins.
416  *
417  * param base EPDC base pointer
418  * param config Pointer to GPIO configuration structure
419  */
EPDC_SetGpioOutput(EPDC_Type * base,const epdc_gpio_config_t * config)420 void EPDC_SetGpioOutput(EPDC_Type *base, const epdc_gpio_config_t *config)
421 {
422     assert(config != NULL);
423 
424     epdc_reg_convert_t pid;
425     pid._gpio_config = *config;
426 
427     base->GPIO.RW = pid._u32;
428 }
429 
430 /*!
431  * brief Gets the status of the collision
432  *
433  * param base EPDC base pointer
434  * param status Pointer to collision status structure
435  */
EPDC_GetCollisionStatus(EPDC_Type * base,epdc_collision_status_t * status)436 void EPDC_GetCollisionStatus(EPDC_Type *base, epdc_collision_status_t *status)
437 {
438     assert(NULL != status);
439     /* Initializes the status structure to zero. */
440     (void)memset(status, 0, sizeof(*status));
441 
442     status->minX    = (uint16_t)base->UPD_COL_CORD;
443     status->minY    = (uint16_t)(base->UPD_COL_CORD >> 16U);
444     status->width   = (uint16_t)base->UPD_COL_SIZE;
445     status->height  = (uint16_t)(base->UPD_COL_SIZE >> 16U);
446     status->lutlist = (uint64_t)(base->STATUS_COL1.RW) | ((uint64_t)(base->STATUS_COL2.RW) << 32U);
447 }
448