1 /*
2 * Copyright 2019-2021,2023 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_flexio_mculcd_smartdma.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.flexio_mculcd_smartdma"
17 #endif
18
19 #define FLEXIO_MCULCD_SMARTDMA_TX_START_SHIFTER 0U
20 #define FLEXIO_MCULCD_SMARTDMA_TX_END_SHIFTER 7U
21 #define FLEXIO_MCULCD_SMARTDMA_TX_SHIFTER_NUM \
22 (FLEXIO_MCULCD_SMARTDMA_TX_END_SHIFTER - FLEXIO_MCULCD_SMARTDMA_TX_START_SHIFTER + 1)
23
24 enum _MCULCD_transfer_state
25 {
26 kFLEXIO_MCULCD_StateIdle, /*!< No transfer in progress. */
27 kFLEXIO_MCULCD_StateReadArray, /*!< Reading array in progress. */
28 kFLEXIO_MCULCD_StateWriteArray, /*!< Writing array in progress. */
29 kFLEXIO_MCULCD_StateWriteSameValue, /*!< Writing the same value in progress.
30 */
31 };
32
33 /*******************************************************************************
34 * Prototypes
35 ******************************************************************************/
36
37 /*!
38 * @brief Get the TX chunk size.
39 *
40 * The SMARTDMA TX transfer memory must be 4Byte aligned, the transfer size must
41 * be multiple of 64Byte. So the transfer data is devided in to three part:
42 * part1 + part2 + part3.
43 * The part2 is transfered using SMARTDMA, it should be 4Byte aligned, multiple
44 * of 64Byte.
45 * The part1 and part3 are transfered using blocking method, each of them is
46 * less than 64Byte, and total of them is less than (64 + 4) bytes.
47 *
48 * This function gets the size of each part.
49 *
50 * @param totalLen The total TX size in byte.
51 * @param startAddr The start address of the TX data.
52 * @param part1Len Length of the part 1 in byte.
53 * @param part2Len Length of the part 2 in byte.
54 * @param part3Len Length of the part 3 in byte.
55 */
56 static void FLEXIO_MCULCD_SMARTDMA_GetTxChunkLen(
57 uint32_t totalLen, uint32_t startAddr, uint32_t *part1Len, uint32_t *part2Len, uint32_t *part3Len);
58
59 /*!
60 * @brief Convert RGB565 to RGB888.
61 *
62 * @param rgb565 Input RGB565.
63 * @param pixelCount Pixel count.
64 * @param rgb888 Output RGB888.
65 */
66 static void FLEXIO_MCULCD_RGB656ToRGB888(const uint16_t *rgb565, uint32_t pixelCount, uint8_t *rgb888);
67
68 /*!
69 * @brief Callback function registered to SMARTDMA driver.
70 */
71 static void FLEXIO_MCULCD_SMARTDMA_Callback(void *param);
72
73 /*******************************************************************************
74 * Variables
75 ******************************************************************************/
76
77 /*******************************************************************************
78 * Code
79 ******************************************************************************/
FLEXIO_MCULCD_SMARTDMA_GetTxChunkLen(uint32_t totalLen,uint32_t startAddr,uint32_t * part1Len,uint32_t * part2Len,uint32_t * part3Len)80 static void FLEXIO_MCULCD_SMARTDMA_GetTxChunkLen(
81 uint32_t totalLen, uint32_t startAddr, uint32_t *part1Len, uint32_t *part2Len, uint32_t *part3Len)
82 {
83 if (totalLen < FLEXIO_MCULCD_SMARTDMA_TX_LEN_ALIGN)
84 {
85 *part1Len = totalLen;
86 *part2Len = 0;
87 *part3Len = 0;
88 }
89 else
90 {
91 *part3Len = (startAddr + totalLen) & (FLEXIO_MCULCD_SMARTDMA_TX_ADDR_ALIGN - 1U);
92 *part2Len = ((uint32_t)(totalLen - *part3Len)) & (~(FLEXIO_MCULCD_SMARTDMA_TX_LEN_ALIGN - 1U));
93
94 if (FLEXIO_MCULCD_SMARTDMA_TX_LEN_ALIGN > *part2Len)
95 {
96 *part1Len = totalLen;
97 *part2Len = 0;
98 *part3Len = 0;
99 }
100 else
101 {
102 *part1Len = totalLen - *part2Len - *part3Len;
103 }
104 }
105 }
106
FLEXIO_MCULCD_RGB656ToRGB888(const uint16_t * rgb565,uint32_t pixelCount,uint8_t * rgb888)107 static void FLEXIO_MCULCD_RGB656ToRGB888(const uint16_t *rgb565, uint32_t pixelCount, uint8_t *rgb888)
108 {
109 while ((pixelCount--) != 0U)
110 {
111 *rgb888 = (uint8_t)(((*rgb565) & 0x001FU) << 3U);
112 rgb888++;
113 *rgb888 = (uint8_t)(((*rgb565) & 0x07E0U) >> 3U);
114 rgb888++;
115 *rgb888 = (uint8_t)(((*rgb565) & 0xF800U) >> 8U);
116 rgb888++;
117
118 rgb565++;
119 }
120 }
121
122 /*!
123 * brief Initializes the FLEXO MCULCD master SMARTDMA handle.
124 *
125 * This function initializes the FLEXO MCULCD master SMARTDMA handle which can be
126 * used for other FLEXO MCULCD transactional APIs. For a specified FLEXO MCULCD
127 * instance, call this API once to get the initialized handle.
128 *
129 * param base Pointer to FLEXIO_MCULCD_Type structure.
130 * param handle Pointer to flexio_mculcd_smartdma_handle_t structure to store the
131 * transfer state.
132 * param config Pointer to the configuration.
133 * param callback MCULCD transfer complete callback, NULL means no callback.
134 * param userData callback function parameter.
135 * retval kStatus_Success Successfully create the handle.
136 */
FLEXIO_MCULCD_TransferCreateHandleSMARTDMA(FLEXIO_MCULCD_Type * base,flexio_mculcd_smartdma_handle_t * handle,const flexio_mculcd_smartdma_config_t * config,flexio_mculcd_smartdma_transfer_callback_t callback,void * userData)137 status_t FLEXIO_MCULCD_TransferCreateHandleSMARTDMA(FLEXIO_MCULCD_Type *base,
138 flexio_mculcd_smartdma_handle_t *handle,
139 const flexio_mculcd_smartdma_config_t *config,
140 flexio_mculcd_smartdma_transfer_callback_t callback,
141 void *userData)
142 {
143 assert(handle != NULL);
144
145 /* The SMARTDMA firmware only support TX using shifter 0 to shifter 7 */
146 if (base->txShifterStartIndex != FLEXIO_MCULCD_SMARTDMA_TX_START_SHIFTER)
147 {
148 return kStatus_InvalidArgument;
149 }
150
151 if (base->txShifterEndIndex != FLEXIO_MCULCD_SMARTDMA_TX_END_SHIFTER)
152 {
153 return kStatus_InvalidArgument;
154 }
155
156 /* Zero the handle. */
157 (void)memset(handle, 0, sizeof(*handle));
158
159 if (NULL == config)
160 {
161 handle->smartdmaApi = (uint8_t)kSMARTDMA_FlexIO_DMA;
162 }
163 else
164 {
165 if (config->inputPixelFormat == config->outputPixelFormat)
166 {
167 handle->smartdmaApi = (uint8_t)kSMARTDMA_FlexIO_DMA;
168 }
169 else if (((config->inputPixelFormat == kFLEXIO_MCULCD_RGB565) &&
170 (config->outputPixelFormat == kFLEXIO_MCULCD_RGB888)) ||
171 ((config->inputPixelFormat == kFLEXIO_MCULCD_BGR565) &&
172 (config->outputPixelFormat == kFLEXIO_MCULCD_BGR888)))
173 {
174 handle->smartdmaApi = (uint8_t)kSMARTDMA_FlexIO_DMA_RGB565To888;
175 handle->needColorConvert = true;
176 }
177 else
178 {
179 return kStatus_InvalidArgument;
180 }
181 }
182
183 /* Initialize the state. */
184 handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
185
186 /* Register callback and userData. */
187 handle->completionCallback = callback;
188 handle->userData = userData;
189 handle->base = base;
190
191 SMARTDMA_InstallFirmware(SMARTDMA_DISPLAY_MEM_ADDR, s_smartdmaDisplayFirmware, SMARTDMA_DISPLAY_FIRMWARE_SIZE);
192
193 SMARTDMA_InstallCallback(FLEXIO_MCULCD_SMARTDMA_Callback, handle);
194
195 /* The shifter interrupt is used by the SMARTDMA. */
196 FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, (1UL << FLEXIO_MCULCD_SMARTDMA_TX_END_SHIFTER));
197
198 #if (defined(SMARTDMA_USE_FLEXIO_SHIFTER_DMA) && SMARTDMA_USE_FLEXIO_SHIFTER_DMA)
199 FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL, true);
200 #endif
201
202 return kStatus_Success;
203 }
204
205 /*!
206 * brief Performs a non-blocking FlexIO MCULCD transfer using SMARTDMA.
207 *
208 * This function returns immediately after transfer initiates. Use the callback
209 * function to check whether the transfer is completed.
210 *
211 * param base pointer to FLEXIO_MCULCD_Type structure.
212 * param handle pointer to flexio_mculcd_smartdma_handle_t structure to store the
213 * transfer state.
214 * param xfer Pointer to FlexIO MCULCD transfer structure.
215 * retval kStatus_Success Successfully start a transfer.
216 * retval kStatus_InvalidArgument Input argument is invalid.
217 * retval kStatus_FLEXIO_MCULCD_Busy FlexIO MCULCD is not idle, it is running another
218 * transfer.
219 */
FLEXIO_MCULCD_TransferSMARTDMA(FLEXIO_MCULCD_Type * base,flexio_mculcd_smartdma_handle_t * handle,flexio_mculcd_transfer_t * xfer)220 status_t FLEXIO_MCULCD_TransferSMARTDMA(FLEXIO_MCULCD_Type *base,
221 flexio_mculcd_smartdma_handle_t *handle,
222 flexio_mculcd_transfer_t *xfer)
223 {
224 assert(handle != NULL);
225 assert(xfer != NULL);
226
227 uint32_t part1Len, part2Len, part3Len;
228
229 /* Check if the device is busy. */
230 if ((uint32_t)kFLEXIO_MCULCD_StateIdle != handle->state)
231 {
232 return kStatus_FLEXIO_MCULCD_Busy;
233 }
234
235 /* Only support write array. */
236 if (kFLEXIO_MCULCD_WriteArray != xfer->mode)
237 {
238 return kStatus_InvalidArgument;
239 }
240
241 FLEXIO_MCULCD_SMARTDMA_GetTxChunkLen(xfer->dataSize, xfer->dataAddrOrSameValue, &part1Len, &part2Len, &part3Len);
242
243 handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteArray;
244
245 /* Start transfer. */
246 handle->remainingCount = xfer->dataSize;
247 handle->dataCount = xfer->dataSize;
248 handle->dataAddrOrSameValue = xfer->dataAddrOrSameValue;
249
250 /* Assert the nCS. */
251 FLEXIO_MCULCD_StartTransfer(base);
252
253 if (!xfer->dataOnly)
254 {
255 /* Send the command. */
256 FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
257 }
258
259 if (part1Len > 0U)
260 {
261 if (handle->needColorConvert)
262 {
263 FLEXIO_MCULCD_RGB656ToRGB888((uint16_t *)xfer->dataAddrOrSameValue, part1Len >> 1U,
264 handle->blockingXferBuffer);
265 FLEXIO_MCULCD_WriteDataArrayBlocking(base, handle->blockingXferBuffer, (part1Len >> 1U) * 3U);
266 }
267 else
268 {
269 FLEXIO_MCULCD_WriteDataArrayBlocking(base, (void *)(uint8_t *)xfer->dataAddrOrSameValue, (size_t)part1Len);
270 }
271 handle->remainingCount -= part1Len;
272 handle->dataAddrOrSameValue += part1Len;
273 }
274
275 if (0U == part2Len)
276 {
277 /* In this case, all data are sent out as part 1. Only notify upper layer here. */
278 FLEXIO_MCULCD_StopTransfer(base);
279 handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
280
281 /* Callback to inform upper layer. */
282 if (NULL != handle->completionCallback)
283 {
284 handle->completionCallback(base, handle, kStatus_FLEXIO_MCULCD_Idle, handle->userData);
285 }
286 }
287 else
288 {
289 /* For 6800, de-assert the RDWR pin. */
290 if (kFLEXIO_MCULCD_6800 == base->busType)
291 {
292 base->setRDWRPin(false);
293 }
294
295 FLEXIO_MCULCD_SetMultiBeatsWriteConfig(base);
296
297 /* Save the part 3 information. */
298 handle->dataCountUsingEzh = part2Len;
299 handle->dataAddrOrSameValue += part2Len;
300
301 /* The part 3 is transfered using blocking method in ISR, convert the color
302 to save time in ISR. */
303 if ((0U != part3Len) && (handle->needColorConvert))
304 {
305 FLEXIO_MCULCD_RGB656ToRGB888((uint16_t *)xfer->dataAddrOrSameValue, part3Len >> 1U,
306 handle->blockingXferBuffer);
307 }
308
309 handle->smartdmaParam.p_buffer = (uint32_t *)(xfer->dataAddrOrSameValue + part1Len);
310 handle->smartdmaParam.buffersize = part2Len;
311 handle->smartdmaParam.smartdma_stack = handle->smartdmaStack;
312
313 SMARTDMA_Reset();
314 SMARTDMA_Boot(handle->smartdmaApi, &(handle->smartdmaParam), 0);
315 }
316
317 return kStatus_Success;
318 }
319
320 /*!
321 * brief Aborts a FlexIO MCULCD transfer using SMARTDMA.
322 *
323 * param base pointer to FLEXIO_MCULCD_Type structure.
324 * param handle FlexIO MCULCD SMARTDMA handle pointer.
325 */
FLEXIO_MCULCD_TransferAbortSMARTDMA(FLEXIO_MCULCD_Type * base,flexio_mculcd_smartdma_handle_t * handle)326 void FLEXIO_MCULCD_TransferAbortSMARTDMA(FLEXIO_MCULCD_Type *base, flexio_mculcd_smartdma_handle_t *handle)
327 {
328 assert(handle != NULL);
329
330 SMARTDMA_Reset();
331
332 /* Set the handle state. */
333 handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
334 handle->dataCount = 0;
335 }
336
337 /*!
338 * brief Gets the remaining bytes for FlexIO MCULCD SMARTDMA transfer.
339 *
340 * param base pointer to FLEXIO_MCULCD_Type structure.
341 * param handle FlexIO MCULCD SMARTDMA handle pointer.
342 * param count Number of count transferred so far by the SMARTDMA transaction.
343 * retval kStatus_Success Get the transferred count Successfully.
344 * retval kStatus_NoTransferInProgress No transfer in process.
345 */
FLEXIO_MCULCD_TransferGetCountSMARTDMA(FLEXIO_MCULCD_Type * base,flexio_mculcd_smartdma_handle_t * handle,size_t * count)346 status_t FLEXIO_MCULCD_TransferGetCountSMARTDMA(FLEXIO_MCULCD_Type *base,
347 flexio_mculcd_smartdma_handle_t *handle,
348 size_t *count)
349 {
350 assert(handle != NULL);
351 assert(count != NULL);
352
353 uint32_t state = handle->state;
354
355 if ((uint32_t)kFLEXIO_MCULCD_StateIdle == state)
356 {
357 return kStatus_NoTransferInProgress;
358 }
359 else
360 {
361 *count = handle->dataCount - handle->remainingCount;
362 }
363
364 return kStatus_Success;
365 }
366
FLEXIO_MCULCD_SMARTDMA_Callback(void * param)367 static void FLEXIO_MCULCD_SMARTDMA_Callback(void *param)
368 {
369 flexio_mculcd_smartdma_handle_t *flexioMculcdSmartDmaHandle = (flexio_mculcd_smartdma_handle_t *)param;
370
371 FLEXIO_MCULCD_Type *flexioLcdMcuBase = flexioMculcdSmartDmaHandle->base;
372
373 FLEXIO_MCULCD_WaitTransmitComplete();
374
375 /* Disable the TX shifter and the timer. */
376 FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(flexioLcdMcuBase);
377
378 flexioMculcdSmartDmaHandle->remainingCount -= flexioMculcdSmartDmaHandle->dataCountUsingEzh;
379
380 /* Send the part 3 */
381 if (0U != flexioMculcdSmartDmaHandle->remainingCount)
382 {
383 if (flexioMculcdSmartDmaHandle->needColorConvert)
384 {
385 FLEXIO_MCULCD_WriteDataArrayBlocking(flexioLcdMcuBase, flexioMculcdSmartDmaHandle->blockingXferBuffer,
386 (flexioMculcdSmartDmaHandle->remainingCount >> 1U) * 3U);
387 }
388 else
389 {
390 FLEXIO_MCULCD_WriteDataArrayBlocking(flexioLcdMcuBase,
391 (void *)(uint8_t *)flexioMculcdSmartDmaHandle->dataAddrOrSameValue,
392 flexioMculcdSmartDmaHandle->remainingCount);
393 }
394 }
395
396 flexioMculcdSmartDmaHandle->remainingCount = 0;
397 FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
398 flexioMculcdSmartDmaHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
399
400 /* Callback to inform upper layer. */
401 if (NULL != flexioMculcdSmartDmaHandle->completionCallback)
402 {
403 flexioMculcdSmartDmaHandle->completionCallback(flexioLcdMcuBase, flexioMculcdSmartDmaHandle,
404 kStatus_FLEXIO_MCULCD_Idle,
405 flexioMculcdSmartDmaHandle->userData);
406 }
407 }
408