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