1 /*
2 * Copyright 2021-2022, 2024 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_lcdic_dma.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.lcdic_dma"
17 #endif
18
19 /* Max transfer byte count in each DMA transfer. */
20 #define LCDIC_MAX_DMA_XFER_COUNT (DMA_MAX_TRANSFER_COUNT * 4U)
21
22 /*******************************************************************************
23 * Prototypes
24 ******************************************************************************/
25 /*!
26 * @brief LCDIC TX DMA callback.
27 *
28 * @param dmaHandle DMA handle.
29 * @param param Callback parameter.
30 * @param dmaXferDone DMA transfer done or not.
31 * @param intmode Interrupt mode, kDMA_IntA, kDMA_IntB, or kDMA_IntError.
32 */
33 static void LCDIC_TransferSendDMACallback(dma_handle_t *dmaHandle, void *param, bool dmaXferDone, uint32_t intmode);
34
35 /*!
36 * @brief LCDIC RX DMA callback.
37 *
38 * @param dmaHandle DMA handle.
39 * @param param Callback parameter.
40 * @param dmaXferDone DMA transfer done or not.
41 * @param intmode Interrupt mode, kDMA_IntA, kDMA_IntB, or kDMA_IntError.
42 */
43 static void LCDIC_TransferReceiveDMACallback(dma_handle_t *dmaHandle, void *param, bool dmaXferDone, uint32_t intmode);
44
45 /*!
46 * @brief Handle the LCDIC DMA transfer done.
47 *
48 * Disables the related interrupts, disable DMA, calling user callback.
49 *
50 * @param base LCDIC peripheral base address.
51 * @param handle LCDIC DMA driver handle.
52 * @param status The status passing to user callback.
53 */
54 static void LCDIC_TransferDoneDMA(lcdic_dma_handle_t *handle, status_t status);
55
56 /*!
57 * @brief Send data array using DMA way.
58 *
59 * @param base LCDIC peripheral base address.
60 * @param handle LCDIC DMA driver handle.
61 * @param xfer Pointer to the transfer structure.
62 * @retval kStatus_Success Successfully start a transfer.
63 * @retval kStatus_InvalidArgument Input argument is invalid.
64 */
65 static status_t LCDIC_TransferSendDataArrayDMA(LCDIC_Type *base,
66 lcdic_dma_handle_t *handle,
67 const lcdic_tx_xfer_t *xfer);
68
69 /*!
70 * @brief Read data array using DMA way.
71 *
72 * @param base LCDIC peripheral base address.
73 * @param handle LCDIC DMA driver handle.
74 * @param xfer Pointer to the transfer structure.
75 * @retval kStatus_Success Successfully start a transfer.
76 * @retval kStatus_InvalidArgument Input argument is invalid.
77 */
78 static status_t LCDIC_TransferReceiveDataArrayDMA(LCDIC_Type *base,
79 lcdic_dma_handle_t *handle,
80 const lcdic_rx_xfer_t *xfer);
81
82 /*!
83 * @brief Submit RX transfer request to DMA.
84 *
85 * Submit the data transfer request saved in LCDIC DMA driver handle to DMA.
86 *
87 * @param handle LCDIC DMA driver handle.
88 */
89 static void LCDIC_TransferSubmitRxDataDMA(lcdic_dma_handle_t *handle);
90
91 /*!
92 * @brief Submit TX transfer request to DMA.
93 *
94 * Submit the data transfer request saved in LCDIC DMA driver handle to DMA.
95 *
96 * @param handle LCDIC DMA driver handle.
97 */
98 static void LCDIC_TransferSubmitTxDataDMA(lcdic_dma_handle_t *handle);
99
100 /*******************************************************************************
101 * Variables
102 ******************************************************************************/
103
104 /*******************************************************************************
105 * Code
106 ******************************************************************************/
107
108 /*
109 * brief LCDIC TX DMA callback.
110 *
111 * param handle DMA handle.
112 * param param Callback parameter.
113 * param dmaXferDone DMA transfer done or not.
114 * param intmode Interrupt mode, kDMA_IntA, kDMA_IntB, or kDMA_IntError.
115 */
LCDIC_TransferSendDMACallback(dma_handle_t * dmaHandle,void * param,bool dmaXferDone,uint32_t intmode)116 static void LCDIC_TransferSendDMACallback(dma_handle_t *dmaHandle, void *param, bool dmaXferDone, uint32_t intmode)
117 {
118 assert(dmaHandle != NULL);
119 assert(param != NULL);
120
121 lcdic_dma_handle_t *lcdicDmaHandle = (lcdic_dma_handle_t *)param;
122
123 if (dmaXferDone)
124 {
125 LCDIC_TransferSubmitTxDataDMA(lcdicDmaHandle);
126 }
127 }
128
129 /*
130 * brief LCDIC RX DMA callback.
131 *
132 * param handle DMA handle.
133 * param param Callback parameter.
134 * param dmaXferDone DMA transfer done or not.
135 * param intmode Interrupt mode, kDMA_IntA, kDMA_IntB, or kDMA_IntError.
136 */
LCDIC_TransferReceiveDMACallback(dma_handle_t * dmaHandle,void * param,bool dmaXferDone,uint32_t intmode)137 static void LCDIC_TransferReceiveDMACallback(dma_handle_t *dmaHandle, void *param, bool dmaXferDone, uint32_t intmode)
138 {
139 assert(dmaHandle != NULL);
140 assert(param != NULL);
141
142 lcdic_dma_handle_t *lcdicDmaHandle = (lcdic_dma_handle_t *)param;
143
144 if (dmaXferDone)
145 {
146 LCDIC_TransferSubmitRxDataDMA(lcdicDmaHandle);
147 }
148 }
149
150 /*
151 * brief Submit RX transfer request to DMA.
152 *
153 * Submit the data transfer request saved in LCDIC DMA driver handle to DMA.
154 *
155 * param handle LCDIC DMA driver handle.
156 */
LCDIC_TransferSubmitRxDataDMA(lcdic_dma_handle_t * handle)157 static void LCDIC_TransferSubmitRxDataDMA(lcdic_dma_handle_t *handle)
158 {
159 dma_handle_t *dmaHandle = handle->rxDmaHandle;
160 dma_descriptor_t *dmaDesc, *nextDmaDesc;
161 bool startDMA = true;
162 bool reloadDmaXferCfg;
163 uint8_t xferSizeWordUnaligned = handle->xferSizeWordUnaligned;
164 uint32_t xferSizeWordAligned = handle->xferSizeWordAligned;
165
166 LCDIC_EnableDMA(handle->lcdic, false);
167 /*
168 * If left word-size aligned data is more than LCDIC_MAX_DMA_XFER_COUNT,
169 * start DMA to handle the first LCDIC_MAX_DMA_XFER_COUNT part.
170 */
171 if (xferSizeWordAligned > LCDIC_MAX_DMA_XFER_COUNT)
172 {
173 dmaDesc = &handle->dmaDesc[0];
174
175 dmaDesc->xfercfg = DMA_SetChannelXferConfig(false, /* Reload */
176 true, /* Clear Trigger. */
177 true, /* intA */
178 false, /* intB */
179 4U, /* Width */
180 (uint8_t)kDMA_AddressInterleave0xWidth, /* Source increase. */
181 (uint8_t)kDMA_AddressInterleave1xWidth, /* Destination increase. */
182 LCDIC_MAX_DMA_XFER_COUNT);
183 dmaDesc->srcEndAddr = (uint32_t *)(uintptr_t) & (handle->lcdic->RFIFO_RDATA);
184 dmaDesc->dstEndAddr = DMA_DESCRIPTOR_END_ADDRESS(handle->rxData, 1U, LCDIC_MAX_DMA_XFER_COUNT, 4U);
185
186 dmaDesc->linkToNextDesc = NULL;
187
188 handle->xferSizeWordAligned = xferSizeWordAligned - LCDIC_MAX_DMA_XFER_COUNT;
189 handle->txData += LCDIC_MAX_DMA_XFER_COUNT;
190 }
191 /*
192 * If left word-size aligned data is equal or less than LCDIC_MAX_DMA_XFER_COUNT,
193 * besides the word-size aligned part, a descriptor is setup to handle the
194 * word-size unaligned part.
195 */
196 else if (xferSizeWordAligned > 0U)
197 {
198 if (xferSizeWordUnaligned > 0U)
199 {
200 /* If there is unaligned part, using transfer link. */
201 reloadDmaXferCfg = true;
202 nextDmaDesc = &handle->dmaDesc[1];
203 }
204 else
205 {
206 reloadDmaXferCfg = false;
207 nextDmaDesc = NULL;
208 }
209
210 dmaDesc = &handle->dmaDesc[0];
211
212 dmaDesc->xfercfg = DMA_SetChannelXferConfig(reloadDmaXferCfg, /* Reload */
213 true, /* Clear Trigger. */
214 true, /* intA */
215 false, /* intB */
216 4U, /* Width */
217 (uint8_t)kDMA_AddressInterleave0xWidth, /* Source increase. */
218 (uint8_t)kDMA_AddressInterleave1xWidth, /* Destination increase. */
219 xferSizeWordAligned);
220
221 dmaDesc->srcEndAddr = (uint32_t *)(uintptr_t) & (handle->lcdic->RFIFO_RDATA);
222 dmaDesc->dstEndAddr = DMA_DESCRIPTOR_END_ADDRESS(handle->rxData, 1U, xferSizeWordAligned, 4U);
223
224 dmaDesc->linkToNextDesc = nextDmaDesc;
225
226 /* All data will be sent out after this DMA transfer. */
227 handle->xferSizeWordAligned = 0UL;
228 handle->xferSizeWordUnaligned = 0U;
229 }
230 else
231 {
232 if (xferSizeWordUnaligned > 0U)
233 {
234 /* Handle the unaligned part. */
235 dmaDesc = &handle->dmaDesc[1];
236
237 /* All data will be sent out after this DMA transfer. */
238 handle->xferSizeWordUnaligned = 0U;
239 }
240 else
241 {
242 /*
243 * All data received, fill the unaligned part to user array if necessary,
244 * then call the callback to notify user.
245 */
246 startDMA = false;
247
248 if (handle->rxSizeWordUnaligned > 0U)
249 {
250 LCDIC_ExtractByteFromWord(handle->tmpData, handle->rxData, handle->rxSizeWordUnaligned);
251 handle->rxSizeWordUnaligned = 0U;
252 }
253
254 LCDIC_TransferDoneDMA(handle, kStatus_Success);
255 }
256 }
257
258 if (startDMA)
259 {
260 DMA_SubmitChannelDescriptor(dmaHandle, dmaDesc);
261 LCDIC_EnableDMA(handle->lcdic, true);
262 DMA_StartTransfer(dmaHandle);
263 }
264 }
265
266 /*
267 * brief Submit TX transfer request to DMA.
268 *
269 * Submit the data transfer request saved in LCDIC DMA driver handle to DMA.
270 *
271 * param handle LCDIC DMA driver handle.
272 */
LCDIC_TransferSubmitTxDataDMA(lcdic_dma_handle_t * handle)273 static void LCDIC_TransferSubmitTxDataDMA(lcdic_dma_handle_t *handle)
274 {
275 dma_handle_t *dmaHandle = handle->txDmaHandle;
276 dma_descriptor_t *dmaDesc, *nextDmaDesc;
277 bool startDMA = true;
278 bool reloadDmaXferCfg;
279 uint8_t xferSizeWordUnaligned = handle->xferSizeWordUnaligned;
280 uint32_t xferSizeWordAligned = handle->xferSizeWordAligned;
281
282 LCDIC_EnableDMA(handle->lcdic, false);
283 /*
284 * If left word-size aligned data is more than LCDIC_MAX_DMA_XFER_COUNT,
285 * start DMA to send the first LCDIC_MAX_DMA_XFER_COUNT part.
286 */
287 if (xferSizeWordAligned > LCDIC_MAX_DMA_XFER_COUNT)
288 {
289 dmaDesc = &handle->dmaDesc[0];
290
291 dmaDesc->xfercfg = DMA_SetChannelXferConfig(false, /* Reload */
292 true, /* Clear Trigger. */
293 true, /* intA */
294 false, /* intB */
295 4U, /* Width */
296 (uint8_t)kDMA_AddressInterleave1xWidth, /* Source increase. */
297 (uint8_t)kDMA_AddressInterleave0xWidth, /* Destination increase. */
298 LCDIC_MAX_DMA_XFER_COUNT);
299 dmaDesc->srcEndAddr = DMA_DESCRIPTOR_END_ADDRESS(handle->txData, 1U, LCDIC_MAX_DMA_XFER_COUNT, 4U);
300 dmaDesc->dstEndAddr = (uint32_t *)(uintptr_t) & (handle->lcdic->TFIFO_WDATA);
301 dmaDesc->linkToNextDesc = NULL;
302
303 handle->xferSizeWordAligned = xferSizeWordAligned - LCDIC_MAX_DMA_XFER_COUNT;
304 handle->txData += LCDIC_MAX_DMA_XFER_COUNT;
305 }
306 /*
307 * If left word-size aligned data is equal or less than LCDIC_MAX_DMA_XFER_COUNT,
308 * besides the word-size aligned part, a descriptor is setup to send the
309 * word-size unaligned part.
310 */
311 else if (xferSizeWordAligned > 0U)
312 {
313 /* If there is unaligned part, using transfer link. */
314 if (xferSizeWordUnaligned > 0U)
315 {
316 reloadDmaXferCfg = true;
317 nextDmaDesc = &handle->dmaDesc[1];
318 }
319 else
320 {
321 reloadDmaXferCfg = false;
322 nextDmaDesc = NULL;
323 }
324
325 dmaDesc = &handle->dmaDesc[0];
326
327 dmaDesc->xfercfg = DMA_SetChannelXferConfig(reloadDmaXferCfg, /* Reload */
328 true, /* Clear Trigger. */
329 false, /* intA */
330 false, /* intB */
331 4U, /* Width */
332 (uint8_t)kDMA_AddressInterleave1xWidth, /* Source increase. */
333 (uint8_t)kDMA_AddressInterleave0xWidth, /* Destination increase. */
334 xferSizeWordAligned);
335
336 dmaDesc->srcEndAddr = DMA_DESCRIPTOR_END_ADDRESS(handle->txData, 1U, xferSizeWordAligned, 4U);
337 dmaDesc->dstEndAddr = (uint32_t *)(uintptr_t) & (handle->lcdic->TFIFO_WDATA);
338
339 dmaDesc->linkToNextDesc = nextDmaDesc;
340
341 /* All data will be sent out after this DMA transfer. */
342 handle->xferSizeWordAligned = 0UL;
343 handle->xferSizeWordUnaligned = 0U;
344 }
345 else
346 {
347 if (xferSizeWordUnaligned > 0U)
348 {
349 dmaDesc = &handle->dmaDesc[1];
350
351 /* All data will be sent out after this DMA transfer. */
352 handle->xferSizeWordUnaligned = 0U;
353 }
354 else
355 {
356 startDMA = false;
357 }
358 }
359
360 if (startDMA)
361 {
362 DMA_SubmitChannelDescriptor(dmaHandle, dmaDesc);
363 LCDIC_EnableDMA(handle->lcdic, true);
364 DMA_StartTransfer(dmaHandle);
365 }
366 }
367
368 /*
369 * brief Send data array using DMA way.
370 *
371 * param base LCDIC peripheral base address.
372 * param handle LCDIC DMA driver handle.
373 * param xfer Pointer to the transfer structure.
374 * retval kStatus_Success Successfully start a transfer.
375 * retval kStatus_InvalidArgument Input argument is invalid.
376 */
LCDIC_TransferSendDataArrayDMA(LCDIC_Type * base,lcdic_dma_handle_t * handle,const lcdic_tx_xfer_t * xfer)377 static status_t LCDIC_TransferSendDataArrayDMA(LCDIC_Type *base,
378 lcdic_dma_handle_t *handle,
379 const lcdic_tx_xfer_t *xfer)
380 {
381 status_t status;
382 uint32_t xferSizeWordAligned;
383 uint8_t xferSizeWordUnaligned;
384 uint32_t wordUnalignedData;
385 dma_descriptor_t *dmaDesc;
386
387 /* Data must be 4-byte aligned. */
388 if (0U != (0x03U & (uint32_t)xfer->txData))
389 {
390 return kStatus_InvalidArgument;
391 }
392
393 status = LCDIC_PrepareSendDataArray(base, xfer, &xferSizeWordAligned, &xferSizeWordUnaligned, &wordUnalignedData);
394
395 if (kStatus_Success == status)
396 {
397 handle->xferSizeWordUnaligned = xferSizeWordUnaligned;
398 handle->xferSizeWordAligned = xferSizeWordAligned;
399 handle->tmpData = wordUnalignedData;
400 handle->txData = xfer->txData;
401
402 /*
403 * There are two DMA descriptors in LCDIC DMA driver handle, the first is
404 * used for 4-byte size aligned part, the second is for 4-byte size unaligned
405 * part. For the second part, the descriptor is prepared during transfer started,
406 * then used directly in DMA callback function.
407 */
408 /* If the data size is not word aligned, link descriptor is used. */
409 if (xferSizeWordUnaligned > 0U)
410 {
411 dmaDesc = &handle->dmaDesc[1];
412
413 dmaDesc->xfercfg =
414 DMA_SetChannelXferConfig(false, /* Reload */
415 true, /* Clear Trigger. */
416 true, /* intA */
417 false, /* intB */
418 4U, /* Width */
419 (uint8_t)kDMA_AddressInterleave0xWidth, /* Source increase. */
420 (uint8_t)kDMA_AddressInterleave0xWidth, /* Destination increase. */
421 4U);
422 dmaDesc->srcEndAddr = &handle->tmpData;
423 dmaDesc->dstEndAddr = (uint32_t *)(uintptr_t) & (base->TFIFO_WDATA);
424 dmaDesc->linkToNextDesc = NULL;
425 }
426
427 LCDIC_TransferSubmitTxDataDMA(handle);
428
429 LCDIC_EnableInterrupts(base, (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
430 (uint32_t)kLCDIC_CmdTimeoutInterrupt);
431 }
432
433 return status;
434 }
435
436 /*
437 * brief Read data array using DMA way.
438 *
439 * param base LCDIC peripheral base address.
440 * param handle LCDIC DMA driver handle.
441 * param xfer Pointer to the transfer structure.
442 * retval kStatus_Success Successfully start a transfer.
443 * retval kStatus_InvalidArgument Input argument is invalid.
444 */
LCDIC_TransferReceiveDataArrayDMA(LCDIC_Type * base,lcdic_dma_handle_t * handle,const lcdic_rx_xfer_t * xfer)445 static status_t LCDIC_TransferReceiveDataArrayDMA(LCDIC_Type *base,
446 lcdic_dma_handle_t *handle,
447 const lcdic_rx_xfer_t *xfer)
448 {
449 status_t status;
450 uint32_t xferSizeWordAligned;
451 uint8_t xferSizeWordUnaligned;
452 dma_descriptor_t *dmaDesc;
453
454 /* Data must be 4-byte aligned. */
455 if (0U != (0x03U & (uint32_t)xfer->rxData))
456 {
457 return kStatus_InvalidArgument;
458 }
459
460 status = LCDIC_PrepareReadDataArray(base, xfer, &xferSizeWordAligned, &xferSizeWordUnaligned);
461
462 if (kStatus_Success == status)
463 {
464 handle->xferSizeWordUnaligned = xferSizeWordUnaligned;
465 handle->xferSizeWordAligned = xferSizeWordAligned;
466 handle->rxData = xfer->rxData;
467
468 /*
469 * There are two DMA descriptors in LCDIC DMA driver handle, the first is
470 * used for 4-byte size aligned part, the second is for 4-byte size unaligned
471 * part. For the second part, the descriptor is prepared during transfer started,
472 * then used directly in DMA callback function.
473 */
474
475 /* If the data size is not word aligned, link descriptor is used. */
476 if (xferSizeWordUnaligned > 0U)
477 {
478 dmaDesc = &handle->dmaDesc[1];
479
480 dmaDesc->xfercfg =
481 DMA_SetChannelXferConfig(false, /* Reload */
482 true, /* Clear Trigger. */
483 true, /* intA */
484 false, /* intB */
485 4U, /* Width */
486 (uint8_t)kDMA_AddressInterleave0xWidth, /* Source increase. */
487 (uint8_t)kDMA_AddressInterleave0xWidth, /* Destination increase. */
488 4U);
489 dmaDesc->srcEndAddr = (uint32_t *)(uintptr_t) & (base->RFIFO_RDATA);
490 dmaDesc->dstEndAddr = &handle->tmpData;
491 dmaDesc->linkToNextDesc = NULL;
492 }
493
494 LCDIC_TransferSubmitRxDataDMA(handle);
495
496 LCDIC_EnableInterrupts(base, (uint32_t)kLCDIC_TeTimeoutInterrupt | (uint32_t)kLCDIC_CmdTimeoutInterrupt);
497 }
498
499 return status;
500 }
501
502 /*
503 * brief Handle the LCDIC DMA transfer done.
504 *
505 * Disables the related interrupts, disable DMA, calling user callback.
506 *
507 * param base LCDIC peripheral base address.
508 * param handle LCDIC DMA driver handle.
509 * param status The status passing to user callback.
510 */
LCDIC_TransferDoneDMA(lcdic_dma_handle_t * handle,status_t status)511 static void LCDIC_TransferDoneDMA(lcdic_dma_handle_t *handle, status_t status)
512 {
513 LCDIC_Type *lcdic = handle->lcdic;
514
515 LCDIC_DisableInterrupts(lcdic, (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
516 (uint32_t)kLCDIC_CmdTimeoutInterrupt);
517
518 LCDIC_EnableDMA(lcdic, false);
519
520 handle->xferInProgress = false;
521
522 if (NULL != handle->callback)
523 {
524 handle->callback(lcdic, handle, status, handle->userData);
525 }
526 }
527
528 /*
529 * brief Initialize the LCDIC DMA handle.
530 *
531 * This function initializes the LCDIC DMA handle which can be used for other LCDIC transactional APIs.
532 * Usually, for a specified LCDIC instance, user need only call this API once to get the initialized handle.
533 *
534 * param base LCDIC peripheral base address.
535 * param handle LCDIC handle pointer.
536 * param callback User callback function called at the end of a transfer.
537 * param userData User data for callback.
538 * param txDmaHandle DMA handle pointer for LCDIC Tx, the handle shall be static allocated by users.
539 * param rxDmaHandle DMA handle pointer for LCDIC Rx, the handle shall be static allocated by users.
540 * param dmaDesc User allocated dma descriptor, it should be in non-cacheable region and 16-byte aligned.
541 */
LCDIC_TransferCreateHandleDMA(LCDIC_Type * base,lcdic_dma_handle_t * handle,lcdic_dma_callback_t callback,void * userData,dma_handle_t * txDmaHandle,dma_handle_t * rxDmaHandle,dma_descriptor_t dmaDesc[2])542 status_t LCDIC_TransferCreateHandleDMA(LCDIC_Type *base,
543 lcdic_dma_handle_t *handle,
544 lcdic_dma_callback_t callback,
545 void *userData,
546 dma_handle_t *txDmaHandle,
547 dma_handle_t *rxDmaHandle,
548 dma_descriptor_t dmaDesc[2])
549 {
550 assert(NULL != handle);
551 assert(!((NULL == txDmaHandle) && (NULL == rxDmaHandle)));
552
553 uint32_t instance;
554
555 dma_channel_trigger_t trigger = {
556 .type = kDMA_RisingEdgeTrigger, .burst = kDMA_EdgeBurstTransfer1, .wrap = kDMA_NoWrap};
557
558 if (((uint32_t)dmaDesc & ((uint32_t)FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE - 1UL)) != 0UL)
559 {
560 return kStatus_InvalidArgument;
561 }
562
563 (void)memset(handle, 0, sizeof(lcdic_dma_handle_t));
564
565 instance = LCDIC_GetInstance(base);
566
567 handle->lcdic = base;
568 handle->txDmaHandle = txDmaHandle;
569 handle->rxDmaHandle = rxDmaHandle;
570 handle->callback = callback;
571 handle->userData = userData;
572 handle->dmaDesc = dmaDesc;
573
574 /* Configure RX callback. */
575 if (rxDmaHandle != NULL)
576 {
577 DMA_SetChannelConfig(rxDmaHandle->base, rxDmaHandle->channel, &trigger, false);
578 DMA_SetCallback(rxDmaHandle, LCDIC_TransferReceiveDMACallback, handle);
579
580 LCDIC_SetRxThreshold(base, kLCDIC_RxThreshold0Word);
581 }
582
583 /* Configure TX callback. */
584 if (txDmaHandle != NULL)
585 {
586 DMA_SetChannelConfig(txDmaHandle->base, txDmaHandle->channel, &trigger, false);
587 DMA_SetCallback(txDmaHandle, LCDIC_TransferSendDMACallback, handle);
588
589 LCDIC_SetTxThreshold(base, kLCDIC_TxThreshold0Word);
590 }
591
592 LCDIC_TransferInstallIRQHandler(instance, handle, LCDIC_TransferHandleIRQDMA);
593
594 (void)EnableIRQ(LCDIC_GetIRQn(instance));
595
596 return kStatus_Success;
597 }
598
599 /*
600 * brief Perform a non-blocking LCDIC transfer using DMA.
601 *
602 * This function returned immediately after transfer initiates, monitor the transfer
603 * done by callback.
604 *
605 * param base LCDIC peripheral base address.
606 * param handle LCDIC DMA handle pointer.
607 * param xfer Pointer to dma transfer structure.
608 * retval kStatus_Success Successfully start a transfer.
609 * retval kStatus_InvalidArgument Input argument is invalid.
610 * retval kStatus_Busy LCDIC is not idle, is running another transfer.
611 */
LCDIC_TransferDMA(LCDIC_Type * base,lcdic_dma_handle_t * handle,const lcdic_xfer_t * xfer)612 status_t LCDIC_TransferDMA(LCDIC_Type *base, lcdic_dma_handle_t *handle, const lcdic_xfer_t *xfer)
613 {
614 status_t status = kStatus_InvalidArgument;
615
616 if (((kLCDIC_XferSendDataArray == xfer->mode) &&
617 (NULL == handle->txDmaHandle)) || /* send mode but no TX DMA handle. */
618 ((kLCDIC_XferReceiveDataArray == xfer->mode) &&
619 (NULL == handle->rxDmaHandle))) /* read mode but no RX DMA handle. */
620 {
621 return kStatus_InvalidArgument;
622 }
623
624 if (handle->xferInProgress)
625 {
626 return kStatus_Busy;
627 }
628
629 handle->xferInProgress = true;
630 handle->xferMode = xfer->mode;
631
632 switch (xfer->mode)
633 {
634 case kLCDIC_XferCmdOnly:
635 status = LCDIC_PrepareSendCommand(base, xfer->cmdToSendOnly);
636 LCDIC_EnableInterrupts(base, (uint32_t)kLCDIC_CmdDoneInterrupt);
637 break;
638
639 case kLCDIC_XferSendRepeatData:
640 status = LCDIC_PrepareSendRepeatData(base, &xfer->repeatTxXfer);
641 LCDIC_EnableInterrupts(base, (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
642 (uint32_t)kLCDIC_CmdTimeoutInterrupt);
643 break;
644
645 case kLCDIC_XferSendDataArray:
646 status = LCDIC_TransferSendDataArrayDMA(base, handle, &xfer->txXfer);
647 break;
648
649 case kLCDIC_XferReceiveDataArray:
650 status = LCDIC_TransferReceiveDataArrayDMA(base, handle, &xfer->rxXfer);
651 break;
652
653 default:
654 /* Should not reach here. */
655 status = kStatus_InvalidArgument;
656 break;
657 }
658
659 if (status != kStatus_Success)
660 {
661 handle->xferInProgress = false;
662 }
663
664 return status;
665 }
666
667 /*
668 * brief Send data array using DMA.
669 *
670 * param base LCDIC peripheral base address.
671 * param handle Pointer to the lcdic_handle_t structure to store the transfer state.
672 * param xfer LCDIC transfer structure.
673 * retval kStatus_Success Successfully start a transfer.
674 * retval kStatus_InvalidArgument Input argument is invalid.
675 * retval kStatus_Busy LCDIC driver is busy with another transfer.
676 */
LCDIC_SendDataArrayDMA(LCDIC_Type * base,lcdic_dma_handle_t * handle,const lcdic_tx_xfer_t * xfer)677 status_t LCDIC_SendDataArrayDMA(LCDIC_Type *base, lcdic_dma_handle_t *handle, const lcdic_tx_xfer_t *xfer)
678 {
679 status_t status = kStatus_InvalidArgument;
680
681 if (NULL == handle->txDmaHandle)
682 {
683 return kStatus_InvalidArgument;
684 }
685
686 if (handle->xferInProgress)
687 {
688 return kStatus_Busy;
689 }
690
691 handle->xferInProgress = true;
692 handle->xferMode = kLCDIC_XferSendDataArray;
693
694 status = LCDIC_TransferSendDataArrayDMA(base, handle, xfer);
695
696 if (status != kStatus_Success)
697 {
698 handle->xferInProgress = false;
699 }
700
701 return status;
702 }
703
704 /*
705 * brief Read data array using DMA.
706 *
707 * param base LCDIC peripheral base address.
708 * param handle Pointer to the lcdic_handle_t structure to store the transfer state.
709 * param xfer LCDIC transfer structure.
710 * retval kStatus_Success Successfully start a transfer.
711 * retval kStatus_InvalidArgument Input argument is invalid.
712 * retval kStatus_Busy LCDIC driver is busy with another transfer.
713 */
LCDIC_ReadDataArrayDMA(LCDIC_Type * base,lcdic_dma_handle_t * handle,const lcdic_rx_xfer_t * xfer)714 status_t LCDIC_ReadDataArrayDMA(LCDIC_Type *base, lcdic_dma_handle_t *handle, const lcdic_rx_xfer_t *xfer)
715 {
716 status_t status = kStatus_InvalidArgument;
717
718 if (NULL == handle->rxDmaHandle) /* read mode but no RX DMA handle. */
719 {
720 return kStatus_InvalidArgument;
721 }
722
723 if (handle->xferInProgress)
724 {
725 return kStatus_Busy;
726 }
727
728 handle->xferInProgress = true;
729 handle->xferMode = kLCDIC_XferReceiveDataArray;
730
731 status = LCDIC_TransferReceiveDataArrayDMA(base, handle, xfer);
732
733 if (status != kStatus_Success)
734 {
735 handle->xferInProgress = false;
736 }
737
738 return status;
739 }
740
741 /*
742 * brief LCDIC IRQ handler function work with DMA transactional APIs.
743 *
744 * IRQ handler to work with @ref LCDIC_TransferDMA.
745 *
746 * param base LCDIC peripheral base address.
747 * param handle Pointer to the lcdic_dma_handle_t structure to store the transfer state.
748 */
LCDIC_TransferHandleIRQDMA(LCDIC_Type * base,void * handle)749 void LCDIC_TransferHandleIRQDMA(LCDIC_Type *base, void *handle)
750 {
751 assert(NULL != handle);
752
753 uint32_t intStat;
754 status_t status;
755 bool xferDone = false;
756
757 lcdic_dma_handle_t *lcdicDmaHandle = (lcdic_dma_handle_t *)handle;
758
759 if (lcdicDmaHandle->xferInProgress)
760 {
761 intStat = LCDIC_GetInterruptStatus(base);
762 LCDIC_ClearInterruptStatus(base, intStat);
763
764 /* Timeout. */
765 if (0U != (intStat & ((uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt)))
766 {
767 if (kLCDIC_XferReceiveDataArray == lcdicDmaHandle->xferMode)
768 {
769 DMA_AbortTransfer(lcdicDmaHandle->rxDmaHandle);
770 }
771 else if (kLCDIC_XferSendDataArray == lcdicDmaHandle->xferMode)
772 {
773 DMA_AbortTransfer(lcdicDmaHandle->txDmaHandle);
774 }
775 else
776 {
777 /* Empty */
778 }
779
780 xferDone = true;
781 status = kStatus_Timeout;
782 }
783 else if (0U != (intStat & ((uint32_t)kLCDIC_CmdDoneInterrupt)))
784 {
785 if (lcdicDmaHandle->xferMode != kLCDIC_XferReceiveDataArray)
786 {
787 xferDone = true;
788 status = kStatus_Success;
789 }
790 }
791 else
792 {
793 /* Empty. */
794 }
795
796 if (xferDone)
797 {
798 LCDIC_TransferDoneDMA(lcdicDmaHandle, status);
799 }
800 }
801 }
802