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