1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_lpspi_edma.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.lpspi_edma"
18 #endif
19
20 /*!
21 * @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private.
22 */
23 typedef struct _lpspi_master_edma_private_handle
24 {
25 LPSPI_Type *base; /*!< LPSPI peripheral base address. */
26 lpspi_master_edma_handle_t *handle; /*!< lpspi_master_edma_handle_t handle */
27 } lpspi_master_edma_private_handle_t;
28
29 /*!
30 * @brief Structure definition for dspi_slave_edma_private_handle_t. The structure is private.
31 */
32 typedef struct _lpspi_slave_edma_private_handle
33 {
34 LPSPI_Type *base; /*!< LPSPI peripheral base address. */
35 lpspi_slave_edma_handle_t *handle; /*!< lpspi_slave_edma_handle_t handle */
36 } lpspi_slave_edma_private_handle_t;
37
38 /***********************************************************************************************************************
39 * Prototypes
40 ***********************************************************************************************************************/
41
42 /*!
43 * @brief EDMA_LpspiMasterCallback after the LPSPI master transfer completed by using EDMA.
44 * This is not a public API.
45 */
46 static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
47 void *g_lpspiEdmaPrivateHandle,
48 bool transferDone,
49 uint32_t tcds);
50
51 /*!
52 * @brief EDMA_LpspiSlaveCallback after the LPSPI slave transfer completed by using EDMA.
53 * This is not a public API.
54 */
55 static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
56 void *g_lpspiEdmaPrivateHandle,
57 bool transferDone,
58 uint32_t tcds);
59
60 static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap);
61
62 /***********************************************************************************************************************
63 * Variables
64 ***********************************************************************************************************************/
65 /*! @brief Pointers to lpspi bases for each instance. */
66 static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
67
68 /*! @brief Pointers to lpspi edma handles for each instance. */
69 static lpspi_master_edma_private_handle_t s_lpspiMasterEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
70 static lpspi_slave_edma_private_handle_t s_lpspiSlaveEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
71
72 /***********************************************************************************************************************
73 * Code
74 ***********************************************************************************************************************/
LPSPI_SeparateEdmaReadData(uint8_t * rxData,uint32_t readData,uint32_t bytesEachRead,bool isByteSwap)75 static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap)
76 {
77 assert(rxData != NULL);
78
79 switch (bytesEachRead)
80 {
81 case 1:
82 if (!isByteSwap)
83 {
84 *rxData = (uint8_t)readData;
85 ++rxData;
86 }
87 else
88 {
89 *rxData = (uint8_t)(readData >> 24);
90 ++rxData;
91 }
92 break;
93
94 case 2:
95 if (!isByteSwap)
96 {
97 *rxData = (uint8_t)readData;
98 ++rxData;
99 *rxData = (uint8_t)(readData >> 8);
100 ++rxData;
101 }
102 else
103 {
104 *rxData = (uint8_t)(readData >> 16);
105 ++rxData;
106 *rxData = (uint8_t)(readData >> 24);
107 ++rxData;
108 }
109 break;
110
111 case 4:
112
113 *rxData = (uint8_t)readData;
114 ++rxData;
115 *rxData = (uint8_t)(readData >> 8);
116 ++rxData;
117 *rxData = (uint8_t)(readData >> 16);
118 ++rxData;
119 *rxData = (uint8_t)(readData >> 24);
120 ++rxData;
121
122 break;
123
124 default:
125 assert(false);
126 break;
127 }
128 }
129
130 /*!
131 * brief Initializes the LPSPI master eDMA handle.
132 *
133 * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
134 * specified LPSPI instance, call this API once to get the initialized handle.
135 *
136 * Note that the LPSPI eDMA has a separated (Rx and Rx as two sources) or shared (Rx and Tx are the same source) DMA
137 * request source.
138 * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
139 * Tx DMAMUX source for edmaIntermediaryToTxRegHandle.
140 * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle.
141 *
142 * param base LPSPI peripheral base address.
143 * param handle LPSPI handle pointer to lpspi_master_edma_handle_t.
144 * param callback LPSPI callback.
145 * param userData callback function parameter.
146 * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
147 * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
148 */
LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle,lpspi_master_edma_transfer_callback_t callback,void * userData,edma_handle_t * edmaRxRegToRxDataHandle,edma_handle_t * edmaTxDataToTxRegHandle)149 void LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type *base,
150 lpspi_master_edma_handle_t *handle,
151 lpspi_master_edma_transfer_callback_t callback,
152 void *userData,
153 edma_handle_t *edmaRxRegToRxDataHandle,
154 edma_handle_t *edmaTxDataToTxRegHandle)
155 {
156 assert(handle != NULL);
157 assert(edmaRxRegToRxDataHandle != NULL);
158 assert(edmaTxDataToTxRegHandle != NULL);
159
160 /* Zero the handle. */
161 (void)memset(handle, 0, sizeof(*handle));
162
163 uint32_t instance = LPSPI_GetInstance(base);
164
165 s_lpspiMasterEdmaPrivateHandle[instance].base = base;
166 s_lpspiMasterEdmaPrivateHandle[instance].handle = handle;
167
168 handle->callback = callback;
169 handle->userData = userData;
170
171 handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
172 handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
173 }
174
LPSPI_PrepareTransferEDMA(LPSPI_Type * base)175 static void LPSPI_PrepareTransferEDMA(LPSPI_Type *base)
176 {
177 /* Flush FIFO, clear status, disable all the inerrupts and DMA requests. */
178 LPSPI_FlushFifo(base, true, true);
179 LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
180 LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
181 LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
182 }
183
184 /*!
185 * brief LPSPI master transfer data using eDMA.
186 *
187 * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
188 * is transferred, the callback function is called.
189 *
190 * Note:
191 * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
192 * For bytesPerFrame greater than 4:
193 * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
194 * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
195 *
196 * param base LPSPI peripheral base address.
197 * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
198 * param transfer pointer to lpspi_transfer_t structure.
199 * return status of status_t.
200 */
LPSPI_MasterTransferEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle,lpspi_transfer_t * transfer)201 status_t LPSPI_MasterTransferEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, lpspi_transfer_t *transfer)
202 {
203 assert(handle != NULL);
204 assert(transfer != NULL);
205
206 /* Check that we're not busy.*/
207 if (handle->state == (uint8_t)kLPSPI_Busy)
208 {
209 return kStatus_LPSPI_Busy;
210 }
211
212 /* Disable module before configuration */
213 LPSPI_Enable(base, false);
214 /* Check arguements */
215 if (!LPSPI_CheckTransferArgument(base, transfer, true))
216 {
217 return kStatus_InvalidArgument;
218 }
219
220 LPSPI_PrepareTransferEDMA(base);
221
222 /* Variables */
223 bool isThereExtraTxBytes = false;
224 bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
225 bool isPcsContinuous = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U);
226 uint32_t instance = LPSPI_GetInstance(base);
227 uint8_t dummyData = g_lpspiDummyData[instance];
228 uint8_t bytesLastWrite = 0;
229 /*Used for byte swap*/
230 uint32_t addrOffset = 0;
231 uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base);
232 uint32_t txAddr = LPSPI_GetTxRegisterAddress(base);
233 uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
234 uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
235 edma_transfer_config_t transferConfigRx;
236 edma_transfer_config_t transferConfigTx;
237 edma_tcd_t *softwareTCD_pcsContinuous = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[2]) & (~0x1FU));
238 edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
239
240 handle->state = (uint8_t)kLPSPI_Busy;
241 handle->txData = transfer->txData;
242 handle->rxData = transfer->rxData;
243 handle->txRemainingByteCount = transfer->dataSize;
244 handle->rxRemainingByteCount = transfer->dataSize;
245 handle->totalByteCount = transfer->dataSize;
246 handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
247 handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
248 handle->txBuffIfNull =
249 ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
250 /*The TX and RX FIFO sizes are always the same*/
251 handle->fifoSize = LPSPI_GetRxFifoSize(base);
252 handle->isPcsContinuous = isPcsContinuous;
253 handle->isByteSwap = isByteSwap;
254 handle->isThereExtraRxBytes = false;
255
256 /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/
257 LPSPI_SetFifoWatermarks(base, 0U, 0U);
258
259 /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
260 base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
261
262 /* Enable module for following configuration of TCR to take effect. */
263 LPSPI_Enable(base, true);
264
265 /* For DMA transfer , we'd better not masked the transmit data and receive data in TCR since the transfer flow is
266 * hard to controlled by software. */
267 base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_PCS_MASK)) |
268 LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
269
270 /*Calculate the bytes for write/read the TX/RX register each time*/
271 if (bytesPerFrame <= 4U)
272 {
273 handle->bytesEachWrite = (uint8_t)bytesPerFrame;
274 handle->bytesEachRead = (uint8_t)bytesPerFrame;
275
276 handle->bytesLastRead = (uint8_t)bytesPerFrame;
277 }
278 else
279 {
280 handle->bytesEachWrite = 4U;
281 handle->bytesEachRead = 4U;
282
283 handle->bytesLastRead = 4U;
284
285 if ((transfer->dataSize % 4U) != 0U)
286 {
287 bytesLastWrite = (uint8_t)(transfer->dataSize % 4U);
288 handle->bytesLastRead = bytesLastWrite;
289
290 isThereExtraTxBytes = true;
291
292 --handle->writeRegRemainingTimes;
293
294 --handle->readRegRemainingTimes;
295 handle->isThereExtraRxBytes = true;
296 }
297 }
298
299 EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiMasterCallback,
300 &s_lpspiMasterEdmaPrivateHandle[instance]);
301
302 /* Configure rx EDMA transfer */
303 EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
304
305 if (handle->rxData != NULL)
306 {
307 transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]);
308 transferConfigRx.destOffset = 1;
309 }
310 else
311 {
312 transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull);
313 transferConfigRx.destOffset = 0;
314 }
315 transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
316
317 addrOffset = 0;
318 switch (handle->bytesEachRead)
319 {
320 case (1U):
321 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
322 transferConfigRx.minorLoopBytes = 1;
323 if (handle->isByteSwap)
324 {
325 addrOffset = 3;
326 }
327 break;
328
329 case (2U):
330 transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
331 transferConfigRx.minorLoopBytes = 2;
332 if (handle->isByteSwap)
333 {
334 addrOffset = 2;
335 }
336 break;
337
338 case (4U):
339 transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
340 transferConfigRx.minorLoopBytes = 4;
341 break;
342
343 default:
344 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
345 transferConfigRx.minorLoopBytes = 1;
346 assert(false);
347 break;
348 }
349
350 transferConfigRx.srcAddr = (uint32_t)rxAddr + addrOffset;
351 transferConfigRx.srcOffset = 0;
352
353 transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
354
355 /* Store the initially configured eDMA minor byte transfer count into the LPSPI handle */
356 handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
357
358 EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
359 &transferConfigRx, NULL);
360 EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
361 (uint32_t)kEDMA_MajorInterruptEnable);
362
363 /* Configure tx EDMA transfer */
364 EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
365
366 if (isThereExtraTxBytes)
367 {
368 if (handle->txData != NULL)
369 {
370 transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
371 transferConfigTx.srcOffset = 1;
372 }
373 else
374 {
375 transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
376 transferConfigTx.srcOffset = 0;
377 }
378
379 transferConfigTx.destOffset = 0;
380
381 transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
382
383 addrOffset = 0;
384 switch (bytesLastWrite)
385 {
386 case (1U):
387 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
388 transferConfigTx.minorLoopBytes = 1;
389 if (handle->isByteSwap)
390 {
391 addrOffset = 3;
392 }
393 break;
394
395 case (2U):
396 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
397 transferConfigTx.minorLoopBytes = 2;
398 if (handle->isByteSwap)
399 {
400 addrOffset = 2;
401 }
402 break;
403
404 default:
405 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
406 transferConfigTx.minorLoopBytes = 1;
407 assert(false);
408 break;
409 }
410
411 transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
412 transferConfigTx.majorLoopCounts = 1;
413
414 EDMA_TcdReset(softwareTCD_extraBytes);
415
416 if (handle->isPcsContinuous)
417 {
418 EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, softwareTCD_pcsContinuous);
419 }
420 else
421 {
422 EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
423 }
424 }
425
426 if (handle->isPcsContinuous)
427 {
428 handle->transmitCommand = base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK);
429
430 transferConfigTx.srcAddr = (uint32_t) & (handle->transmitCommand);
431 transferConfigTx.srcOffset = 0;
432
433 transferConfigTx.destAddr = (uint32_t) & (base->TCR);
434 transferConfigTx.destOffset = 0;
435
436 transferConfigTx.srcTransferSize = kEDMA_TransferSize4Bytes;
437 transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
438 transferConfigTx.minorLoopBytes = 4;
439 transferConfigTx.majorLoopCounts = 1;
440
441 EDMA_TcdReset(softwareTCD_pcsContinuous);
442 EDMA_TcdSetTransferConfig(softwareTCD_pcsContinuous, &transferConfigTx, NULL);
443 }
444
445 if (handle->txData != NULL)
446 {
447 transferConfigTx.srcAddr = (uint32_t)(handle->txData);
448 transferConfigTx.srcOffset = 1;
449 }
450 else
451 {
452 transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
453 transferConfigTx.srcOffset = 0;
454 }
455
456 transferConfigTx.destOffset = 0;
457
458 transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
459
460 addrOffset = 0U;
461 switch (handle->bytesEachRead)
462 {
463 case (1U):
464 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
465 transferConfigTx.minorLoopBytes = 1;
466 if (handle->isByteSwap)
467 {
468 addrOffset = 3;
469 }
470 break;
471
472 case (2U):
473 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
474 transferConfigTx.minorLoopBytes = 2;
475
476 if (handle->isByteSwap)
477 {
478 addrOffset = 2;
479 }
480 break;
481
482 case (4U):
483 transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
484 transferConfigTx.minorLoopBytes = 4;
485 break;
486
487 default:
488 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
489 transferConfigTx.minorLoopBytes = 1;
490 assert(false);
491 break;
492 }
493
494 transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
495
496 transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
497
498 if (isThereExtraTxBytes)
499 {
500 EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
501 &transferConfigTx, softwareTCD_extraBytes);
502 }
503 else if (handle->isPcsContinuous)
504 {
505 EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
506 &transferConfigTx, softwareTCD_pcsContinuous);
507 }
508 else
509 {
510 EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
511 &transferConfigTx, NULL);
512 }
513
514 EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
515 EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
516 LPSPI_EnableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
517
518 return kStatus_Success;
519 }
520
EDMA_LpspiMasterCallback(edma_handle_t * edmaHandle,void * g_lpspiEdmaPrivateHandle,bool transferDone,uint32_t tcds)521 static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
522 void *g_lpspiEdmaPrivateHandle,
523 bool transferDone,
524 uint32_t tcds)
525 {
526 assert(edmaHandle != NULL);
527 assert(g_lpspiEdmaPrivateHandle != NULL);
528
529 uint32_t readData;
530
531 lpspi_master_edma_private_handle_t *lpspiEdmaPrivateHandle;
532
533 lpspiEdmaPrivateHandle = (lpspi_master_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
534
535 size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
536 uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead;
537 bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap;
538
539 LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
540
541 if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
542 {
543 while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
544 {
545 }
546 readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
547
548 if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
549 {
550 LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
551 readData, bytesLastRead, isByteSwap);
552 }
553 }
554
555 lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
556
557 if (lpspiEdmaPrivateHandle->handle->callback != NULL)
558 {
559 lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
560 kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
561 }
562 }
563
564 /*!
565 * brief LPSPI master aborts a transfer which is using eDMA.
566 *
567 * This function aborts a transfer which is using eDMA.
568 *
569 * param base LPSPI peripheral base address.
570 * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
571 */
LPSPI_MasterTransferAbortEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle)572 void LPSPI_MasterTransferAbortEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle)
573 {
574 assert(handle != NULL);
575
576 LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
577
578 EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
579 EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
580
581 handle->state = (uint8_t)kLPSPI_Idle;
582 }
583
584 /*!
585 * brief Gets the master eDMA transfer remaining bytes.
586 *
587 * This function gets the master eDMA transfer remaining bytes.
588 *
589 * param base LPSPI peripheral base address.
590 * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
591 * param count Number of bytes transferred so far by the EDMA transaction.
592 * return status of status_t.
593 */
LPSPI_MasterTransferGetCountEDMA(LPSPI_Type * base,lpspi_master_edma_handle_t * handle,size_t * count)594 status_t LPSPI_MasterTransferGetCountEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, size_t *count)
595 {
596 assert(handle != NULL);
597
598 if (NULL == count)
599 {
600 return kStatus_InvalidArgument;
601 }
602
603 /* Catch when there is not an active transfer. */
604 if (handle->state != (uint8_t)kLPSPI_Busy)
605 {
606 *count = 0;
607 return kStatus_NoTransferInProgress;
608 }
609
610 size_t remainingByte;
611
612 remainingByte =
613 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
614 handle->edmaRxRegToRxDataHandle->channel);
615
616 *count = handle->totalByteCount - remainingByte;
617
618 return kStatus_Success;
619 }
620
621 /*!
622 * brief Initializes the LPSPI slave eDMA handle.
623 *
624 * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
625 * specified LPSPI instance, call this API once to get the initialized handle.
626 *
627 * Note that LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx and Tx as the same source) DMA request
628 * source.
629 *
630 * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
631 * Tx DMAMUX source for edmaTxDataToTxRegHandle.
632 * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle .
633 *
634 * param base LPSPI peripheral base address.
635 * param handle LPSPI handle pointer to lpspi_slave_edma_handle_t.
636 * param callback LPSPI callback.
637 * param userData callback function parameter.
638 * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
639 * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
640 */
LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle,lpspi_slave_edma_transfer_callback_t callback,void * userData,edma_handle_t * edmaRxRegToRxDataHandle,edma_handle_t * edmaTxDataToTxRegHandle)641 void LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type *base,
642 lpspi_slave_edma_handle_t *handle,
643 lpspi_slave_edma_transfer_callback_t callback,
644 void *userData,
645 edma_handle_t *edmaRxRegToRxDataHandle,
646 edma_handle_t *edmaTxDataToTxRegHandle)
647 {
648 assert(handle != NULL);
649 assert(edmaRxRegToRxDataHandle != NULL);
650 assert(edmaTxDataToTxRegHandle != NULL);
651
652 /* Zero the handle. */
653 (void)memset(handle, 0, sizeof(*handle));
654
655 uint32_t instance = LPSPI_GetInstance(base);
656
657 s_lpspiSlaveEdmaPrivateHandle[instance].base = base;
658 s_lpspiSlaveEdmaPrivateHandle[instance].handle = handle;
659
660 handle->callback = callback;
661 handle->userData = userData;
662
663 handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
664 handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
665 }
666
667 /*!
668 * brief LPSPI slave transfers data using eDMA.
669 *
670 * This function transfers data using eDMA. This is a non-blocking function, which return right away. When all data
671 * is transferred, the callback function is called.
672 *
673 * Note:
674 * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
675 * For bytesPerFrame greater than 4:
676 * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
677 * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
678 *
679 * param base LPSPI peripheral base address.
680 * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
681 * param transfer pointer to lpspi_transfer_t structure.
682 * return status of status_t.
683 */
LPSPI_SlaveTransferEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle,lpspi_transfer_t * transfer)684 status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer)
685 {
686 assert(handle != NULL);
687 assert(transfer != NULL);
688
689 /* Check that we're not busy.*/
690 if (handle->state == (uint8_t)kLPSPI_Busy)
691 {
692 return kStatus_LPSPI_Busy;
693 }
694 /* Disable module before configuration. */
695 LPSPI_Enable(base, false);
696 /* Check arguements, also dma transfer can not support 3 bytes */
697 if (!LPSPI_CheckTransferArgument(base, transfer, true))
698 {
699 return kStatus_InvalidArgument;
700 }
701
702 LPSPI_PrepareTransferEDMA(base);
703
704 /* Variables */
705 bool isThereExtraTxBytes = false;
706 bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
707 uint8_t bytesLastWrite = 0;
708 uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
709 uint32_t mask = (uint32_t)kLPSPI_RxDmaEnable;
710
711 /* Used for byte swap */
712 uint32_t addrOffset = 0;
713 uint32_t instance = LPSPI_GetInstance(base);
714 uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base);
715 uint32_t txAddr = LPSPI_GetTxRegisterAddress(base);
716 uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
717 uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
718 edma_transfer_config_t transferConfigRx;
719 edma_transfer_config_t transferConfigTx;
720 edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
721
722 /* Assign the original value for members of transfer handle. */
723 handle->state = (uint8_t)kLPSPI_Busy;
724 handle->txData = transfer->txData;
725 handle->rxData = transfer->rxData;
726 handle->txRemainingByteCount = transfer->dataSize;
727 handle->rxRemainingByteCount = transfer->dataSize;
728 handle->totalByteCount = transfer->dataSize;
729 handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
730 handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
731 handle->txBuffIfNull =
732 ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
733 /*The TX and RX FIFO sizes are always the same*/
734 handle->fifoSize = LPSPI_GetRxFifoSize(base);
735 handle->isByteSwap = isByteSwap;
736 handle->isThereExtraRxBytes = false;
737
738 /* Because DMA is fast enough, set the RX and TX watermarks to 0. */
739 LPSPI_SetFifoWatermarks(base, 0U, 0U);
740
741 /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
742 base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
743
744 /* Enable module for following configuration of TCR to take effect. */
745 LPSPI_Enable(base, true);
746
747 /* For DMA transfer, mask the transmit data if the tx data is null, for rx the receive data should not be masked at
748 any time since we use rx dma transfer finish cllback to indicate transfer finish. */
749 base->TCR =
750 (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_TXMSK_MASK)) |
751 LPSPI_TCR_TXMSK(transfer->txData == NULL) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
752
753 /*Calculate the bytes for write/read the TX/RX register each time*/
754 if (bytesPerFrame <= 4U)
755 {
756 handle->bytesEachWrite = (uint8_t)bytesPerFrame;
757 handle->bytesEachRead = (uint8_t)bytesPerFrame;
758
759 handle->bytesLastRead = (uint8_t)bytesPerFrame;
760 }
761 else
762 {
763 handle->bytesEachWrite = 4U;
764 handle->bytesEachRead = 4U;
765
766 handle->bytesLastRead = 4U;
767
768 if ((transfer->dataSize % 4U) != 0U)
769 {
770 bytesLastWrite = (uint8_t)(transfer->dataSize % 4U);
771 handle->bytesLastRead = bytesLastWrite;
772
773 isThereExtraTxBytes = true;
774 --handle->writeRegRemainingTimes;
775
776 handle->isThereExtraRxBytes = true;
777 --handle->readRegRemainingTimes;
778 }
779 }
780
781 EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiSlaveCallback,
782 &s_lpspiSlaveEdmaPrivateHandle[instance]);
783
784 /*Rx*/
785 if (handle->readRegRemainingTimes > 0U)
786 {
787 EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
788
789 if (handle->rxData != NULL)
790 {
791 transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]);
792 transferConfigRx.destOffset = 1;
793 }
794 else
795 {
796 transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull);
797 transferConfigRx.destOffset = 0;
798 }
799 transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
800
801 addrOffset = 0;
802 switch (handle->bytesEachRead)
803 {
804 case (1U):
805 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
806 transferConfigRx.minorLoopBytes = 1;
807 if (handle->isByteSwap)
808 {
809 addrOffset = 3;
810 }
811 break;
812
813 case (2U):
814 transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
815 transferConfigRx.minorLoopBytes = 2;
816 if (handle->isByteSwap)
817 {
818 addrOffset = 2;
819 }
820 break;
821
822 case (4U):
823 transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
824 transferConfigRx.minorLoopBytes = 4;
825 break;
826
827 default:
828 transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
829 transferConfigRx.minorLoopBytes = 1;
830 assert(false);
831 break;
832 }
833
834 transferConfigRx.srcAddr = (uint32_t)rxAddr + addrOffset;
835 transferConfigRx.srcOffset = 0;
836
837 transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
838
839 /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
840 handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
841
842 EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
843 &transferConfigRx, NULL);
844 EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
845 (uint32_t)kEDMA_MajorInterruptEnable);
846 EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
847 }
848
849 /*Tx*/
850 if (handle->txData != NULL)
851 {
852 EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
853 if (isThereExtraTxBytes)
854 {
855 transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
856 transferConfigTx.srcOffset = 1;
857 transferConfigTx.destOffset = 0;
858 transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
859 addrOffset = 0;
860 switch (bytesLastWrite)
861 {
862 case (1U):
863 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
864 transferConfigTx.minorLoopBytes = 1;
865 if (handle->isByteSwap)
866 {
867 addrOffset = 3;
868 }
869 break;
870
871 case (2U):
872 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
873 transferConfigTx.minorLoopBytes = 2;
874 if (handle->isByteSwap)
875 {
876 addrOffset = 2;
877 }
878 break;
879
880 default:
881 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
882 transferConfigTx.minorLoopBytes = 1;
883 assert(false);
884 break;
885 }
886
887 transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
888 transferConfigTx.majorLoopCounts = 1;
889
890 EDMA_TcdReset(softwareTCD_extraBytes);
891 EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
892 }
893
894 transferConfigTx.srcAddr = (uint32_t)(handle->txData);
895 transferConfigTx.srcOffset = 1;
896 transferConfigTx.destOffset = 0;
897 transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
898 addrOffset = 0;
899 switch (handle->bytesEachRead)
900 {
901 case (1U):
902 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
903 transferConfigTx.minorLoopBytes = 1;
904 if (handle->isByteSwap)
905 {
906 addrOffset = 3;
907 }
908 break;
909
910 case (2U):
911 transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
912 transferConfigTx.minorLoopBytes = 2;
913
914 if (handle->isByteSwap)
915 {
916 addrOffset = 2;
917 }
918 break;
919
920 case (4U):
921 transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
922 transferConfigTx.minorLoopBytes = 4;
923 break;
924
925 default:
926 transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
927 transferConfigTx.minorLoopBytes = 1;
928 assert(false);
929 break;
930 }
931
932 transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
933 transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
934
935 if (isThereExtraTxBytes)
936 {
937 EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
938 &transferConfigTx, softwareTCD_extraBytes);
939 }
940 else
941 {
942 EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
943 &transferConfigTx, NULL);
944 }
945 EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
946 mask |= (uint32_t)kLPSPI_TxDmaEnable;
947 }
948
949 LPSPI_EnableDMA(base, mask);
950
951 return kStatus_Success;
952 }
953
EDMA_LpspiSlaveCallback(edma_handle_t * edmaHandle,void * g_lpspiEdmaPrivateHandle,bool transferDone,uint32_t tcds)954 static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
955 void *g_lpspiEdmaPrivateHandle,
956 bool transferDone,
957 uint32_t tcds)
958 {
959 assert(edmaHandle != NULL);
960 assert(g_lpspiEdmaPrivateHandle != NULL);
961
962 uint32_t readData;
963
964 lpspi_slave_edma_private_handle_t *lpspiEdmaPrivateHandle;
965
966 lpspiEdmaPrivateHandle = (lpspi_slave_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
967
968 size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
969 uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead;
970 bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap;
971
972 LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
973
974 if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
975 {
976 while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
977 {
978 }
979 readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
980
981 if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
982 {
983 LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
984 readData, bytesLastRead, isByteSwap);
985 }
986 }
987
988 lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
989
990 if (lpspiEdmaPrivateHandle->handle->callback != NULL)
991 {
992 lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
993 kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
994 }
995 }
996
997 /*!
998 * brief LPSPI slave aborts a transfer which is using eDMA.
999 *
1000 * This function aborts a transfer which is using eDMA.
1001 *
1002 * param base LPSPI peripheral base address.
1003 * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
1004 */
LPSPI_SlaveTransferAbortEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle)1005 void LPSPI_SlaveTransferAbortEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle)
1006 {
1007 assert(handle != NULL);
1008
1009 LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
1010
1011 EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
1012 EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
1013
1014 handle->state = (uint8_t)kLPSPI_Idle;
1015 }
1016
1017 /*!
1018 * brief Gets the slave eDMA transfer remaining bytes.
1019 *
1020 * This function gets the slave eDMA transfer remaining bytes.
1021 *
1022 * param base LPSPI peripheral base address.
1023 * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
1024 * param count Number of bytes transferred so far by the eDMA transaction.
1025 * return status of status_t.
1026 */
LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type * base,lpspi_slave_edma_handle_t * handle,size_t * count)1027 status_t LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, size_t *count)
1028 {
1029 assert(handle != NULL);
1030
1031 if (NULL == count)
1032 {
1033 return kStatus_InvalidArgument;
1034 }
1035
1036 /* Catch when there is not an active transfer. */
1037 if (handle->state != (uint8_t)kLPSPI_Busy)
1038 {
1039 *count = 0;
1040 return kStatus_NoTransferInProgress;
1041 }
1042
1043 size_t remainingByte;
1044
1045 remainingByte =
1046 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
1047 handle->edmaRxRegToRxDataHandle->channel);
1048
1049 *count = handle->totalByteCount - remainingByte;
1050
1051 return kStatus_Success;
1052 }
1053