1 /*
2  * Copyright 2022-2023 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "fsl_i3c_edma.h"
8 
9 /*******************************************************************************
10  * Definitions
11  ******************************************************************************/
12 
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.i3c_edma"
16 #endif
17 
18 /*! @brief States for the state machine used by transactional APIs. */
19 enum _i3c_edma_transfer_states
20 {
21     kIdleState = 0,
22     kIBIWonState,
23     kSlaveStartState,
24     kSendCommandState,
25     kWaitRepeatedStartCompleteState,
26     kTransmitDataState,
27     kReceiveDataState,
28     kStopState,
29     kWaitForCompletionState,
30     kAddressMatchState,
31 };
32 
33 /*! @brief Common sets of flags used by the driver. */
34 enum _i3c_edma_flag_constants
35 {
36     /*! All flags which are cleared by the driver upon starting a transfer. */
37     kMasterClearFlags = kI3C_MasterSlaveStartFlag | kI3C_MasterControlDoneFlag | kI3C_MasterCompleteFlag |
38                         kI3C_MasterArbitrationWonFlag | kI3C_MasterSlave2MasterFlag | kI3C_MasterErrorFlag,
39 
40     /*! IRQ sources enabled by the non-blocking transactional API. */
41     kMasterDMAIrqFlags = kI3C_MasterSlaveStartFlag | kI3C_MasterControlDoneFlag | kI3C_MasterCompleteFlag |
42                          kI3C_MasterArbitrationWonFlag | kI3C_MasterErrorFlag | kI3C_MasterSlave2MasterFlag,
43 
44     /*! Errors to check for. */
45     kMasterErrorFlags = kI3C_MasterErrorNackFlag | kI3C_MasterErrorWriteAbortFlag |
46 #if !defined(FSL_FEATURE_I3C_HAS_NO_MERRWARN_TERM) || (!FSL_FEATURE_I3C_HAS_NO_MERRWARN_TERM)
47                         kI3C_MasterErrorTermFlag |
48 #endif
49                         kI3C_MasterErrorParityFlag | kI3C_MasterErrorCrcFlag | kI3C_MasterErrorReadFlag |
50                         kI3C_MasterErrorWriteFlag | kI3C_MasterErrorMsgFlag | kI3C_MasterErrorInvalidReqFlag |
51                         kI3C_MasterErrorTimeoutFlag,
52     /*! All flags which are cleared by the driver upon starting a transfer. */
53     kSlaveClearFlags = kI3C_SlaveBusStartFlag | kI3C_SlaveMatchedFlag | kI3C_SlaveBusStopFlag,
54 
55     /*! IRQ sources enabled by the non-blocking transactional API. */
56     kSlaveDMAIrqFlags = kI3C_SlaveBusStartFlag | kI3C_SlaveMatchedFlag |
57                         kI3C_SlaveBusStopFlag | /*kI3C_SlaveRxReadyFlag |*/
58                         kI3C_SlaveDynamicAddrChangedFlag | kI3C_SlaveReceivedCCCFlag | kI3C_SlaveErrorFlag |
59                         kI3C_SlaveHDRCommandMatchFlag | kI3C_SlaveCCCHandledFlag | kI3C_SlaveEventSentFlag,
60 
61     /*! Errors to check for. */
62     kSlaveErrorFlags = kI3C_SlaveErrorOverrunFlag | kI3C_SlaveErrorUnderrunFlag | kI3C_SlaveErrorUnderrunNakFlag |
63                        kI3C_SlaveErrorTermFlag | kI3C_SlaveErrorInvalidStartFlag | kI3C_SlaveErrorSdrParityFlag |
64                        kI3C_SlaveErrorHdrParityFlag | kI3C_SlaveErrorHdrCRCFlag | kI3C_SlaveErrorS0S1Flag |
65                        kI3C_SlaveErrorOverreadFlag | kI3C_SlaveErrorOverwriteFlag,
66 };
67 /*******************************************************************************
68  * Variables
69  ******************************************************************************/
70 /*! @brief Array to map I3C instance number to base pointer. */
71 static I3C_Type *const kI3cBases[] = I3C_BASE_PTRS;
72 
73 /*! @brief Array to store the END byte of I3C teransfer. */
74 static uint8_t i3cEndByte[ARRAY_SIZE(kI3cBases)] = {0};
75 
76 /*******************************************************************************
77  * Prototypes
78  ******************************************************************************/
79 static void I3C_MasterRunEDMATransfer(
80     I3C_Type *base, i3c_master_edma_handle_t *handle, void *data, size_t dataSize, i3c_direction_t direction);
81 
82 /*******************************************************************************
83  * Code
84  ******************************************************************************/
I3C_MasterTransferEDMACallbackRx(edma_handle_t * dmaHandle,void * param,bool transferDone,uint32_t tcds)85 static void I3C_MasterTransferEDMACallbackRx(edma_handle_t *dmaHandle, void *param, bool transferDone, uint32_t tcds)
86 {
87     i3c_master_edma_handle_t *i3cHandle = (i3c_master_edma_handle_t *)param;
88 
89     if (transferDone)
90     {
91         /* Terminate following data if present. */
92         i3cHandle->base->MCTRL |= I3C_MCTRL_RDTERM(1U);
93 
94 #if defined(FSL_FEATURE_I3C_HAS_ERRATA_052086) && (FSL_FEATURE_I3C_HAS_ERRATA_052086)
95         if (i3cHandle->transfer.dataSize > 1U)
96         {
97             size_t rxCount;
98             /* Read out the last byte data. */
99             do
100             {
101                 I3C_MasterGetFifoCounts(i3cHandle->base, &rxCount, NULL);
102             } while (rxCount == 0U);
103             *(uint8_t *)((uint32_t)(uint32_t *)i3cHandle->transfer.data + i3cHandle->transfer.dataSize - 1U) =
104                 (uint8_t)i3cHandle->base->MRDATAB;
105         }
106 #endif
107 
108         /* Disable I3C Rx DMA. */
109         i3cHandle->base->MDATACTRL &= ~I3C_MDMACTRL_DMAFB_MASK;
110     }
111 }
112 
I3C_MasterTransferEDMACallbackTx(edma_handle_t * dmaHandle,void * param,bool transferDone,uint32_t tcds)113 static void I3C_MasterTransferEDMACallbackTx(edma_handle_t *dmaHandle, void *param, bool transferDone, uint32_t tcds)
114 {
115     i3c_master_edma_handle_t *i3cHandle = (i3c_master_edma_handle_t *)param;
116     uint32_t instance;
117 
118     if (transferDone)
119     {
120         /* Disable I3C Tx DMA. */
121         i3cHandle->base->MDATACTRL &= ~I3C_MDMACTRL_DMATB_MASK;
122 
123         if (i3cHandle->transferCount != 1U)
124         {
125             instance = I3C_GetInstance(i3cHandle->base);
126             /* Ensure there's space in the Tx FIFO. */
127             while ((i3cHandle->base->MDATACTRL & I3C_MDATACTRL_TXFULL_MASK) != 0U)
128             {
129             }
130             i3cHandle->base->MWDATABE = i3cEndByte[instance];
131         }
132     }
133 }
134 /*!
135  * brief Prepares the transfer state machine and fills in the command buffer.
136  * param handle Master nonblocking driver handle.
137  */
I3C_MasterInitTransferStateMachineEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle)138 static status_t I3C_MasterInitTransferStateMachineEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle)
139 {
140     i3c_master_transfer_t *xfer = &handle->transfer;
141     status_t result             = kStatus_Success;
142     i3c_direction_t direction   = xfer->direction;
143 
144     /* Calculate command count and put into command buffer. */
145     handle->subaddressCount = 0U;
146     if (xfer->subaddressSize != 0U)
147     {
148         for (uint32_t i = xfer->subaddressSize; i > 0U; i--)
149         {
150             handle->subaddressBuffer[handle->subaddressCount++] = (uint8_t)((xfer->subaddress) >> (8U * (i - 1U)));
151         }
152     }
153 
154     /* Start condition shall be ommited, switch directly to next phase */
155     if (xfer->dataSize == 0U)
156     {
157         handle->state = (uint8_t)kStopState;
158     }
159 
160     if (0UL != (xfer->flags & (uint32_t)kI3C_TransferStartWithBroadcastAddr))
161     {
162         if (0UL != (xfer->flags & (uint32_t)kI3C_TransferNoStartFlag))
163         {
164             return kStatus_InvalidArgument;
165         }
166 
167         if (0UL != (xfer->flags & (uint32_t)kI3C_TransferRepeatedStartFlag))
168         {
169             return kStatus_InvalidArgument;
170         }
171 
172         /* Issue 0x7E as start. */
173         result = I3C_MasterStart(base, xfer->busType, 0x7E, kI3C_Write);
174         if (result != kStatus_Success)
175         {
176             return result;
177         }
178 
179         result = I3C_MasterWaitForCtrlDone(base, false);
180         if (result != kStatus_Success)
181         {
182             return result;
183         }
184     }
185 
186     /* Handle no start option. */
187     if (0U != (xfer->flags & (uint32_t)kI3C_TransferNoStartFlag))
188     {
189         /* No need to send start flag, directly go to send command or data */
190         if (xfer->subaddressSize > 0UL)
191         {
192             handle->state = (uint8_t)kSendCommandState;
193         }
194         else
195         {
196             if (direction == kI3C_Write)
197             {
198                 /* Next state, send data. */
199                 handle->state = (uint8_t)kTransmitDataState;
200             }
201             else
202             {
203                 /* Only support write with no stop signal. */
204                 return kStatus_InvalidArgument;
205             }
206         }
207     }
208     else
209     {
210         if (xfer->subaddressSize != 0U)
211         {
212             handle->state = (uint8_t)kSendCommandState;
213         }
214         else
215         {
216             if (handle->transfer.direction == kI3C_Write)
217             {
218                 handle->state = (uint8_t)kTransmitDataState;
219             }
220             else if (handle->transfer.direction == kI3C_Read)
221             {
222                 handle->state = (uint8_t)kReceiveDataState;
223             }
224             else
225             {
226                 return kStatus_InvalidArgument;
227             }
228         }
229 
230         if (handle->transfer.direction == kI3C_Read)
231         {
232             I3C_MasterRunEDMATransfer(base, handle, xfer->data, xfer->dataSize, kI3C_Read);
233         }
234 
235         if (handle->state != (uint8_t)kStopState)
236         {
237             /* If repeated start is requested, send repeated start. */
238             if (0U != (xfer->flags & (uint32_t)kI3C_TransferRepeatedStartFlag))
239             {
240                 result = I3C_MasterRepeatedStart(base, xfer->busType, xfer->slaveAddress, direction);
241             }
242             else /* For normal transfer, send start. */
243             {
244                 result = I3C_MasterStart(base, xfer->busType, xfer->slaveAddress, direction);
245             }
246         }
247     }
248 
249     I3C_MasterTransferEDMAHandleIRQ(base, handle);
250     return result;
251 }
252 
I3C_MasterRunEDMATransfer(I3C_Type * base,i3c_master_edma_handle_t * handle,void * data,size_t dataSize,i3c_direction_t direction)253 static void I3C_MasterRunEDMATransfer(
254     I3C_Type *base, i3c_master_edma_handle_t *handle, void *data, size_t dataSize, i3c_direction_t direction)
255 {
256     bool isEnableTxDMA = false;
257     bool isEnableRxDMA = false;
258     edma_transfer_config_t xferConfig;
259     uint32_t instance;
260     uint32_t address;
261     uint32_t width;
262 
263     handle->transferCount = dataSize;
264 
265     switch (direction)
266     {
267         case kI3C_Write:
268             if (dataSize != 1U)
269             {
270                 address = (uint32_t)&base->MWDATAB1;
271                 /* Cause controller sends command and data with same interface, need special buffer to store the END byte. */
272                 instance = I3C_GetInstance(base);
273                 i3cEndByte[instance] = *(uint8_t *)((uint32_t)(uint32_t *)data + dataSize - 1U);
274                 dataSize--;
275             }
276             else
277             {
278                 address = (uint32_t)&base->MWDATABE;
279             }
280             EDMA_PrepareTransfer(&xferConfig, data, sizeof(uint8_t), (uint32_t *)address, sizeof(uint8_t), 1, dataSize,
281                                  kEDMA_MemoryToPeripheral);
282             (void)EDMA_SubmitTransfer(handle->txDmaHandle, &xferConfig);
283             EDMA_StartTransfer(handle->txDmaHandle);
284             isEnableTxDMA = true;
285             width         = 1U;
286             break;
287 
288         case kI3C_Read:
289 #if defined(FSL_FEATURE_I3C_HAS_ERRATA_052086) && (FSL_FEATURE_I3C_HAS_ERRATA_052086)
290             /* ERRATA052086: Soc integration issue results in target misses the last DMA request to copy the
291             last one byte from controler when transmission data size is > 1 byte. Resolution: Triggering DMA
292             interrupt one byte in advance, then receive the last one byte data after DMA transmission finishes. */
293             if (dataSize > 1U)
294             {
295                 dataSize--;
296             }
297 #endif
298             address = (uint32_t)&base->MRDATAB;
299             EDMA_PrepareTransfer(&xferConfig, (uint32_t *)address, sizeof(uint8_t), data, sizeof(uint8_t), 1, dataSize,
300                                  kEDMA_PeripheralToMemory);
301             (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
302             EDMA_StartTransfer(handle->rxDmaHandle);
303             isEnableRxDMA = true;
304             width         = 1U;
305             break;
306 
307         default:
308             /* This should never happen */
309             assert(false);
310             break;
311     }
312 
313     I3C_MasterEnableDMA(base, isEnableTxDMA, isEnableRxDMA, width);
314 }
315 
I3C_MasterRunTransferStateMachineEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle,bool * isDone)316 static status_t I3C_MasterRunTransferStateMachineEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle, bool *isDone)
317 {
318     uint32_t status;
319     uint32_t errStatus;
320     status_t result = kStatus_Success;
321     i3c_master_transfer_t *xfer;
322     size_t rxCount      = 0;
323     bool state_complete = false;
324 
325     /* Set default isDone return value. */
326     *isDone = false;
327 
328     /* Check for errors. */
329     status = (uint32_t)I3C_MasterGetPendingInterrupts(base);
330     I3C_MasterClearStatusFlags(base, status);
331 
332     i3c_master_state_t masterState = I3C_MasterGetState(base);
333     errStatus                      = I3C_MasterGetErrorStatusFlags(base);
334     result                         = I3C_MasterCheckAndClearError(base, errStatus);
335     if (kStatus_Success != result)
336     {
337         return result;
338     }
339 
340     if (0UL != (status & (uint32_t)kI3C_MasterSlave2MasterFlag))
341     {
342         if (handle->callback.slave2Master != NULL)
343         {
344             handle->callback.slave2Master(base, handle->userData);
345         }
346     }
347 
348     if ((0UL != (status & (uint32_t)kI3C_MasterSlaveStartFlag)) && (handle->transfer.busType != kI3C_TypeI2C))
349     {
350         handle->state = (uint8_t)kSlaveStartState;
351     }
352 
353     if ((masterState == kI3C_MasterStateIbiRcv) || (masterState == kI3C_MasterStateIbiAck))
354     {
355         handle->state = (uint8_t)kIBIWonState;
356     }
357 
358     if (handle->state == (uint8_t)kIdleState)
359     {
360         return result;
361     }
362 
363     if (handle->state == (uint8_t)kIBIWonState)
364     {
365         /* Get fifo counts and compute room in tx fifo. */
366         rxCount = (base->MDATACTRL & I3C_MDATACTRL_RXCOUNT_MASK) >> I3C_MDATACTRL_RXCOUNT_SHIFT;
367     }
368 
369     /* Get pointer to private data. */
370     xfer = &handle->transfer;
371 
372     while (!state_complete)
373     {
374         /* Execute the state. */
375         switch (handle->state)
376         {
377             case (uint8_t)kSlaveStartState:
378                 /* Emit start + 0x7E */
379                 I3C_MasterEmitRequest(base, kI3C_RequestAutoIbi);
380                 handle->state  = (uint8_t)kIBIWonState;
381                 state_complete = true;
382                 break;
383 
384             case (uint8_t)kIBIWonState:
385                 if (masterState == kI3C_MasterStateIbiAck)
386                 {
387                     handle->ibiType = I3C_GetIBIType(base);
388                     if (handle->callback.ibiCallback != NULL)
389                     {
390                         handle->callback.ibiCallback(base, handle, handle->ibiType, kI3C_IbiAckNackPending);
391                     }
392                     else
393                     {
394                         I3C_MasterEmitIBIResponse(base, kI3C_IbiRespNack);
395                     }
396                 }
397 
398                 /* Make sure there is data in the rx fifo. */
399                 if (0UL != rxCount)
400                 {
401                     if ((handle->ibiBuff == NULL) && (handle->callback.ibiCallback != NULL))
402                     {
403                         handle->callback.ibiCallback(base, handle, kI3C_IbiNormal, kI3C_IbiDataBuffNeed);
404                     }
405                     uint8_t tempData = (uint8_t)base->MRDATAB;
406                     if (handle->ibiBuff != NULL)
407                     {
408                         handle->ibiBuff[handle->ibiPayloadSize++] = tempData;
409                     }
410                     rxCount--;
411                     break;
412                 }
413                 else if (0UL != (status & (uint32_t)kI3C_MasterCompleteFlag))
414                 {
415                     handle->ibiType    = I3C_GetIBIType(base);
416                     handle->ibiAddress = I3C_GetIBIAddress(base);
417                     state_complete     = true;
418                     result             = kStatus_I3C_IBIWon;
419                 }
420                 else
421                 {
422                     state_complete = true;
423                 }
424                 break;
425 
426             case (uint8_t)kSendCommandState:
427                 I3C_MasterRunEDMATransfer(base, handle, handle->subaddressBuffer, handle->subaddressCount, kI3C_Write);
428 
429                 if ((xfer->direction == kI3C_Read) || (0UL == xfer->dataSize))
430                 {
431                     if (0UL == xfer->dataSize)
432                     {
433                         handle->state = (uint8_t)kWaitForCompletionState;
434                     }
435                     else
436                     {
437                         /* xfer->dataSize != 0U, xfer->direction = kI3C_Read */
438                         handle->state = (uint8_t)kWaitRepeatedStartCompleteState;
439                     }
440                 }
441                 else
442                 {
443                     /* Next state, transfer data. */
444                     handle->state = (uint8_t)kTransmitDataState;
445                 }
446 
447                 state_complete = true;
448                 break;
449 
450             case (uint8_t)kWaitRepeatedStartCompleteState:
451                 /* We stay in this state until the maste complete. */
452                 if (0UL != (status & (uint32_t)kI3C_MasterCompleteFlag))
453                 {
454                     handle->state = (uint8_t)kReceiveDataState;
455                     /* Send repeated start and slave address. */
456                     result = I3C_MasterRepeatedStart(base, xfer->busType, xfer->slaveAddress, kI3C_Read);
457                 }
458 
459                 state_complete = true;
460                 break;
461 
462             case (uint8_t)kTransmitDataState:
463                 I3C_MasterRunEDMATransfer(base, handle, xfer->data, xfer->dataSize, kI3C_Write);
464                 handle->state = (uint8_t)kWaitForCompletionState;
465 
466                 state_complete = true;
467                 break;
468 
469             case (uint8_t)kReceiveDataState:
470                 /* Do DMA read. */
471                 handle->state = (uint8_t)kWaitForCompletionState;
472 
473                 state_complete = true;
474                 break;
475 
476             case (uint8_t)kWaitForCompletionState:
477                 /* We stay in this state until the maste complete. */
478                 if (0UL != (status & (uint32_t)kI3C_MasterCompleteFlag))
479                 {
480                     handle->state = (uint8_t)kStopState;
481                 }
482                 else
483                 {
484                     state_complete = true;
485                 }
486                 break;
487 
488             case (uint8_t)kStopState:
489                 /* Only issue a stop transition if the caller requested it. */
490                 if (0UL == (xfer->flags & (uint32_t)kI3C_TransferNoStopFlag))
491                 {
492                     if (xfer->busType == kI3C_TypeI3CDdr)
493                     {
494                         I3C_MasterEmitRequest(base, kI3C_RequestForceExit);
495                     }
496                     else
497                     {
498                         I3C_MasterEmitRequest(base, kI3C_RequestEmitStop);
499                         result = I3C_MasterWaitForCtrlDone(base, false);
500                     }
501                 }
502                 *isDone        = true;
503                 state_complete = true;
504                 break;
505 
506             default:
507                 assert(false);
508                 break;
509         }
510     }
511     return result;
512 }
513 
I3C_MasterTransferCreateHandleEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle,const i3c_master_edma_callback_t * callback,void * userData,edma_handle_t * rxDmaHandle,edma_handle_t * txDmaHandle)514 void I3C_MasterTransferCreateHandleEDMA(I3C_Type *base,
515                                         i3c_master_edma_handle_t *handle,
516                                         const i3c_master_edma_callback_t *callback,
517                                         void *userData,
518                                         edma_handle_t *rxDmaHandle,
519                                         edma_handle_t *txDmaHandle)
520 {
521     uint32_t instance;
522 
523     assert(NULL != handle);
524 
525     /* Clear out the handle. */
526     (void)memset(handle, 0, sizeof(*handle));
527 
528     /* Look up instance number */
529     instance = I3C_GetInstance(base);
530 
531     handle->base        = base;
532     handle->txDmaHandle = txDmaHandle;
533     handle->rxDmaHandle = rxDmaHandle;
534     handle->callback    = *callback;
535     handle->userData    = userData;
536 
537     /* Save this handle for IRQ use. */
538     s_i3cMasterHandle[instance] = handle;
539 
540     /* Set irq handler. */
541     s_i3cMasterIsr = I3C_MasterTransferEDMAHandleIRQ;
542 
543     EDMA_SetCallback(handle->rxDmaHandle, I3C_MasterTransferEDMACallbackRx, handle);
544     EDMA_SetCallback(handle->txDmaHandle, I3C_MasterTransferEDMACallbackTx, handle);
545 
546     /* Clear all flags. */
547     I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
548     I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
549     /* Reset fifos. These flags clear automatically. */
550     base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
551 
552     /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
553      In some cases the I3C IRQ is configured through INTMUX, user needs to enable
554      INTMUX IRQ in application code. */
555     (void)EnableIRQ(kI3cIrqs[instance]);
556 
557     /* Clear internal IRQ enables and enable NVIC IRQ. */
558     I3C_MasterEnableInterrupts(base, (uint32_t)kMasterDMAIrqFlags);
559 }
560 
561 /*!
562  * brief Performs a non-blocking DMA transaction on the I2C/I3C bus.
563  *
564  * param base The I3C peripheral base address.
565  * param handle Pointer to the I3C master driver handle.
566  * param transfer The pointer to the transfer descriptor.
567  * retval #kStatus_Success The transaction was started successfully.
568  * retval #kStatus_I3C_Busy Either another master is currently utilizing the bus, or a non-blocking
569  *      transaction is already in progress.
570  */
I3C_MasterTransferEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle,i3c_master_transfer_t * transfer)571 status_t I3C_MasterTransferEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle, i3c_master_transfer_t *transfer)
572 {
573     assert(NULL != handle);
574     assert(NULL != transfer);
575     assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
576     i3c_master_state_t masterState = I3C_MasterGetState(base);
577     bool checkDdrState             = false;
578 
579     /* Return busy if another transaction is in progress. */
580     if (handle->state != (uint8_t)kIdleState)
581     {
582         return kStatus_I3C_Busy;
583     }
584 
585     /* Return an error if the bus is already in use not by us. */
586     checkDdrState = (transfer->busType == kI3C_TypeI3CDdr) ? (masterState != kI3C_MasterStateDdr) : true;
587     if ((masterState != kI3C_MasterStateIdle) && (masterState != kI3C_MasterStateNormAct) && checkDdrState)
588     {
589         return kStatus_I3C_Busy;
590     }
591 
592     /* Disable I3C IRQ sources while we configure stuff. */
593     I3C_MasterDisableInterrupts(
594         base, ((uint32_t)kMasterDMAIrqFlags | (uint32_t)kI3C_MasterRxReadyFlag | (uint32_t)kI3C_MasterTxReadyFlag));
595 
596     /* Save transfer into handle. */
597     handle->transfer = *transfer;
598 
599     /* Configure IBI response type. */
600     base->MCTRL &= ~I3C_MCTRL_IBIRESP_MASK;
601     base->MCTRL |= I3C_MCTRL_IBIRESP(transfer->ibiResponse);
602 
603     /* Clear all flags. */
604     I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
605     I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
606     /* Reset fifos. These flags clear automatically. */
607     base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
608 
609     /* Generate commands to send. */
610     (void)I3C_MasterInitTransferStateMachineEDMA(base, handle);
611 
612     /* Enable I3C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
613     I3C_MasterEnableInterrupts(base, (uint32_t)(kMasterDMAIrqFlags));
614 
615     if (transfer->busType == kI3C_TypeI2C)
616     {
617         I3C_MasterDisableInterrupts(base, (uint32_t)kI3C_MasterSlaveStartFlag);
618     }
619 
620     return kStatus_Success;
621 }
622 
I3C_MasterTransferEDMAHandleIRQ(I3C_Type * base,void * i3cHandle)623 void I3C_MasterTransferEDMAHandleIRQ(I3C_Type *base, void *i3cHandle)
624 {
625     i3c_master_edma_handle_t *handle = (i3c_master_edma_handle_t *)i3cHandle;
626 
627     bool isDone;
628     status_t result;
629 
630     /* Don't do anything if we don't have a valid handle. */
631     if (NULL == handle)
632     {
633         return;
634     }
635 
636     result = I3C_MasterRunTransferStateMachineEDMA(base, handle, &isDone);
637 
638     if (handle->state == (uint8_t)kIdleState)
639     {
640         return;
641     }
642 
643     if (isDone || (result != kStatus_Success))
644     {
645         /* XXX need to handle data that may be in rx fifo below watermark level? */
646 
647         /* XXX handle error, terminate xfer */
648         if ((result == kStatus_I3C_Nak) || (result == kStatus_I3C_IBIWon))
649         {
650             I3C_MasterEmitRequest(base, kI3C_RequestEmitStop);
651             (void)I3C_MasterWaitForCtrlDone(base, false);
652         }
653 
654         /* Set handle to idle state. */
655         handle->state = (uint8_t)kIdleState;
656 
657         /* Invoke IBI user callback. */
658         if ((result == kStatus_I3C_IBIWon) && (handle->callback.ibiCallback != NULL))
659         {
660             handle->callback.ibiCallback(base, handle, handle->ibiType, kI3C_IbiReady);
661             handle->ibiPayloadSize = 0;
662         }
663 
664         /* Invoke callback. */
665         if (NULL != handle->callback.transferComplete)
666         {
667             handle->callback.transferComplete(base, handle, result, handle->userData);
668         }
669     }
670 }
671 
672 /*!
673  * brief Get master transfer status during a dma non-blocking transfer
674  *
675  * param base I3C peripheral base address
676  * param handle pointer to i2c_master_edma_handle_t structure
677  * param count Number of bytes transferred so far by the non-blocking transaction.
678  */
I3C_MasterTransferGetCountEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle,size_t * count)679 status_t I3C_MasterTransferGetCountEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle, size_t *count)
680 {
681     assert(handle != NULL);
682 
683     if (NULL == count)
684     {
685         return kStatus_InvalidArgument;
686     }
687 
688     /* Catch when there is not an active transfer. */
689     if (handle->state == (uint8_t)kIdleState)
690     {
691         *count = 0;
692         return kStatus_NoTransferInProgress;
693     }
694 
695     /* There is no necessity to disable interrupts as we read a single integer value */
696     i3c_direction_t dir = handle->transfer.direction;
697 
698     if (dir == kI3C_Read)
699     {
700         *count = handle->transferCount -
701                  1U * EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
702     }
703     else
704     {
705         *count = handle->transferCount -
706                  1U * EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel);
707     }
708 
709     return kStatus_Success;
710 }
711 
712 /*!
713  * brief Abort a master edma non-blocking transfer in a early time
714  *
715  * param base I3C peripheral base address
716  * param handle pointer to i2c_master_edma_handle_t structure
717  */
I3C_MasterTransferAbortEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle)718 void I3C_MasterTransferAbortEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle)
719 {
720     if (handle->state != (uint8_t)kIdleState)
721     {
722         EDMA_AbortTransfer(handle->txDmaHandle);
723         EDMA_AbortTransfer(handle->rxDmaHandle);
724 
725         I3C_MasterEnableDMA(base, false, false, 0);
726 
727         /* Reset fifos. These flags clear automatically. */
728         base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
729 
730         /* Send a stop command to finalize the transfer. */
731         (void)I3C_MasterStop(base);
732 
733         /* Reset handle. */
734         handle->state = (uint8_t)kIdleState;
735     }
736 }
737 
I3C_SlaveTransferEDMACallback(edma_handle_t * dmaHandle,void * param,bool transferDone,uint32_t tcds)738 static void I3C_SlaveTransferEDMACallback(edma_handle_t *dmaHandle, void *param, bool transferDone, uint32_t tcds)
739 {
740     i3c_slave_edma_handle_t *i3cHandle = (i3c_slave_edma_handle_t *)param;
741 
742     if (transferDone)
743     {
744         /* Simply disable dma enablement */
745         if (i3cHandle->txDmaHandle == dmaHandle)
746         {
747             i3cHandle->base->SDMACTRL &= ~I3C_SDMACTRL_DMATB_MASK;
748 
749             if (i3cHandle->transfer.txDataSize > 1U)
750             {
751                 /* Ensure there's space in the Tx FIFO. */
752                 while ((i3cHandle->base->SDATACTRL & I3C_SDATACTRL_TXFULL_MASK) != 0U)
753                 {
754                 }
755                 /* Send the last byte. */
756                 i3cHandle->base->SWDATABE = *(uint8_t *)((uintptr_t)i3cHandle->transfer.txData + i3cHandle->transfer.txDataSize - 1U);
757             }
758         }
759         else
760         {
761 #if defined(FSL_FEATURE_I3C_HAS_ERRATA_052086) && (FSL_FEATURE_I3C_HAS_ERRATA_052086)
762             if (i3cHandle->transfer.rxDataSize > 1U)
763             {
764                 size_t rxCount;
765                 /* Read out the last byte data. */
766                 do
767                 {
768                     I3C_SlaveGetFifoCounts(i3cHandle->base, &rxCount, NULL);
769                 } while (rxCount == 0U);
770                 *(uint8_t *)((uintptr_t)i3cHandle->transfer.rxData + i3cHandle->transfer.rxDataSize - 1U) =
771                     (uint8_t)i3cHandle->base->SRDATAB;
772             }
773 #endif
774             i3cHandle->base->SDMACTRL &= ~I3C_SDMACTRL_DMAFB_MASK;
775         }
776     }
777 }
778 
779 /*!
780  * brief Create a new handle for the I3C slave DMA APIs.
781  *
782  * The creation of a handle is for use with the DMA APIs. Once a handle
783  * is created, there is not a corresponding destroy handle. If the user wants to
784  * terminate a transfer, the I3C_SlaveTransferAbortDMA() API shall be called.
785  *
786  * For devices where the I3C send and receive DMA requests are OR'd together, the @a txDmaHandle
787  * parameter is ignored and may be set to NULL.
788  *
789  * param base The I3C peripheral base address.
790  * param handle Pointer to the I3C slave driver handle.
791  * param callback User provided pointer to the asynchronous callback function.
792  * param userData User provided pointer to the application callback data.
793  * param rxDmaHandle Handle for the DMA receive channel. Created by the user prior to calling this function.
794  * param txDmaHandle Handle for the DMA transmit channel. Created by the user prior to calling this function.
795  */
I3C_SlaveTransferCreateHandleEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle,i3c_slave_edma_callback_t callback,void * userData,edma_handle_t * rxDmaHandle,edma_handle_t * txDmaHandle)796 void I3C_SlaveTransferCreateHandleEDMA(I3C_Type *base,
797                                        i3c_slave_edma_handle_t *handle,
798                                        i3c_slave_edma_callback_t callback,
799                                        void *userData,
800                                        edma_handle_t *rxDmaHandle,
801                                        edma_handle_t *txDmaHandle)
802 {
803     uint32_t instance;
804 
805     assert(NULL != handle);
806 
807     /* Clear out the handle. */
808     (void)memset(handle, 0, sizeof(*handle));
809 
810     /* Look up instance number */
811     instance = I3C_GetInstance(base);
812 
813     handle->base        = base;
814     handle->txDmaHandle = txDmaHandle;
815     handle->rxDmaHandle = rxDmaHandle;
816     handle->callback    = callback;
817     handle->userData    = userData;
818 
819     /* Save this handle for IRQ use. */
820     s_i3cSlaveHandle[instance] = handle;
821 
822     /* Set irq handler. */
823     s_i3cSlaveIsr = I3C_SlaveTransferEDMAHandleIRQ;
824 
825     EDMA_SetCallback(handle->rxDmaHandle, I3C_SlaveTransferEDMACallback, handle);
826     EDMA_SetCallback(handle->txDmaHandle, I3C_SlaveTransferEDMACallback, handle);
827 
828     /* Clear internal IRQ enables and enable NVIC IRQ. */
829     I3C_SlaveDisableInterrupts(base, (uint32_t)kSlaveDMAIrqFlags);
830 
831     /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
832      In some cases the I3C IRQ is configured through INTMUX, user needs to enable
833      INTMUX IRQ in application code. */
834     (void)EnableIRQ(kI3cIrqs[instance]);
835 
836     /* Enable IRQ. */
837     I3C_SlaveEnableInterrupts(base, (uint32_t)kSlaveDMAIrqFlags);
838 }
839 
I3C_SlavePrepareTxEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle)840 static void I3C_SlavePrepareTxEDMA(I3C_Type *base, i3c_slave_edma_handle_t *handle)
841 {
842     edma_transfer_config_t txConfig;
843     uint32_t *txFifoBase;
844     i3c_slave_edma_transfer_t *xfer = &handle->transfer;
845 
846     if (xfer->txDataSize == 1U)
847     {
848         txFifoBase = (uint32_t *)(uintptr_t)&base->SWDATABE;
849         EDMA_PrepareTransfer(&txConfig, xfer->txData, 1, (void *)txFifoBase, 1, 1, xfer->txDataSize,
850                              kEDMA_MemoryToPeripheral);
851     }
852     else
853     {
854         txFifoBase = (uint32_t *)(uintptr_t)&base->SWDATAB1;
855         EDMA_PrepareTransfer(&txConfig, xfer->txData, 1, (void *)txFifoBase, 1, 1, xfer->txDataSize - 1U,
856                              kEDMA_MemoryToPeripheral);
857     }
858 
859     (void)EDMA_SubmitTransfer(handle->txDmaHandle, &txConfig);
860     EDMA_StartTransfer(handle->txDmaHandle);
861 }
862 
I3C_SlavePrepareRxEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle)863 static void I3C_SlavePrepareRxEDMA(I3C_Type *base, i3c_slave_edma_handle_t *handle)
864 {
865     uint32_t *rxFifoBase            = (uint32_t *)(uintptr_t)&base->SRDATAB;
866     i3c_slave_edma_transfer_t *xfer = &handle->transfer;
867     size_t dataSize                 = xfer->rxDataSize;
868     edma_transfer_config_t rxConfig;
869 
870 #if defined(FSL_FEATURE_I3C_HAS_ERRATA_052086) && (FSL_FEATURE_I3C_HAS_ERRATA_052086)
871     /* ERRATA052086: Soc integration issue results in target misses the last DMA request to copy the
872     last one byte from controler when transmission data size is > 1 byte. Resolution: Triggering DMA
873     interrupt one byte in advance, then receive the last one byte data after DMA transmission finishes. */
874     if (dataSize > 1U)
875     {
876         dataSize--;
877     }
878 #endif
879 
880     EDMA_PrepareTransfer(&rxConfig, (void *)rxFifoBase, 1, xfer->rxData, 1, 1, dataSize,
881                          kEDMA_PeripheralToMemory);
882     (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &rxConfig);
883     EDMA_StartTransfer(handle->rxDmaHandle);
884 }
885 
886 /*!
887  * brief Prepares for a non-blocking DMA-based transaction on the I3C bus.
888  *
889  * The API will do DMA configuration according to the input transfer descriptor, and the data will be transferred when
890  * there's bus master requesting transfer from/to this slave. So the timing of call to this API need be aligned
891  * with master application to ensure the transfer is executed as expected.
892  * Callback specified when the @a handle was created is invoked when the transaction has completed.
893  *
894  * param base The I3C peripheral base address.
895  * param handle Pointer to the I3C slave driver handle.
896  * param transfer The pointer to the transfer descriptor.
897  * param eventMask Bit mask formed by OR'ing together #i3c_slave_transfer_event_t enumerators to specify
898  *      which events to send to the callback. The transmit and receive events is not allowed to be enabled.
899  * retval kStatus_Success The transaction was started successfully.
900  * retval #kStatus_I3C_Busy Either another master is currently utilizing the bus, or another DMA
901  *      transaction is already in progress.
902  * retval #kStatus_Fail The transaction can't be set.
903  */
I3C_SlaveTransferEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle,i3c_slave_edma_transfer_t * transfer,uint32_t eventMask)904 status_t I3C_SlaveTransferEDMA(I3C_Type *base,
905                                i3c_slave_edma_handle_t *handle,
906                                i3c_slave_edma_transfer_t *transfer,
907                                uint32_t eventMask)
908 {
909     assert(NULL != handle);
910     assert(NULL != transfer);
911 
912     bool txDmaEn = false, rxDmaEn = false;
913     uint32_t width;
914 
915     if (handle->isBusy)
916     {
917         return kStatus_I3C_Busy;
918     }
919     /* Clear all flags. */
920     I3C_SlaveClearErrorStatusFlags(base, (uint32_t)kSlaveErrorFlags);
921     I3C_SlaveClearStatusFlags(base, (uint32_t)kSlaveClearFlags);
922     /* Reset fifos. These flags clear automatically. */
923     base->SDATACTRL |= I3C_SDATACTRL_FLUSHTB_MASK | I3C_SDATACTRL_FLUSHFB_MASK;
924 
925     handle->transfer = *transfer;
926 
927     /* Set up event mask. */
928     handle->eventMask = eventMask;
929 
930     if ((transfer->txData != NULL) && (transfer->txDataSize != 0U))
931     {
932         I3C_SlavePrepareTxEDMA(base, handle);
933         txDmaEn = true;
934         width   = 1U;
935     }
936 
937     if ((transfer->rxData != NULL) && (transfer->rxDataSize != 0U))
938     {
939         I3C_SlavePrepareRxEDMA(base, handle);
940         rxDmaEn = true;
941         width   = 1U;
942     }
943 
944     if (txDmaEn || rxDmaEn)
945     {
946         I3C_SlaveEnableDMA(base, txDmaEn, rxDmaEn, width);
947         return kStatus_Success;
948     }
949     else
950     {
951         return kStatus_Fail;
952     }
953 }
954 
I3C_SlaveTransferEDMAHandleIRQ(I3C_Type * base,void * i3cHandle)955 void I3C_SlaveTransferEDMAHandleIRQ(I3C_Type *base, void *i3cHandle)
956 {
957     uint32_t flags;
958     uint32_t errFlags;
959     i3c_slave_edma_transfer_t *xfer;
960 
961     i3c_slave_edma_handle_t *handle = (i3c_slave_edma_handle_t *)i3cHandle;
962     /* Check for a valid handle in case of a spurious interrupt. */
963     if (NULL == handle)
964     {
965         return;
966     }
967 
968     xfer = &handle->transfer;
969 
970     /* Get status flags. */
971     flags    = I3C_SlaveGetStatusFlags(base);
972     errFlags = I3C_SlaveGetErrorStatusFlags(base);
973 
974     /* Clear status flags. */
975     I3C_SlaveClearStatusFlags(base, flags);
976 
977     if (0UL != (errFlags & (uint32_t)kSlaveErrorFlags))
978     {
979         xfer->event            = (uint32_t)kI3C_SlaveCompletionEvent;
980         xfer->completionStatus = I3C_SlaveCheckAndClearError(base, errFlags);
981 
982         if ((0UL != (handle->eventMask & (uint32_t)kI3C_SlaveCompletionEvent)) && (NULL != handle->callback))
983         {
984             handle->callback(base, xfer, handle->userData);
985         }
986         return;
987     }
988 
989     if (0UL != (flags & (uint32_t)kI3C_SlaveEventSentFlag))
990     {
991         xfer->event = (uint32_t)kI3C_SlaveRequestSentEvent;
992         if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
993         {
994             handle->callback(base, xfer, handle->userData);
995         }
996     }
997 
998     if (0UL != (flags & (uint32_t)kI3C_SlaveReceivedCCCFlag))
999     {
1000         handle->isBusy = true;
1001         xfer->event    = (uint32_t)kI3C_SlaveReceivedCCCEvent;
1002         if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
1003         {
1004             handle->callback(base, xfer, handle->userData);
1005         }
1006     }
1007 
1008     if (0UL != (flags & (uint32_t)kI3C_SlaveBusStopFlag))
1009     {
1010         if (handle->isBusy == true)
1011         {
1012             xfer->event            = (uint32_t)kI3C_SlaveCompletionEvent;
1013             xfer->completionStatus = kStatus_Success;
1014             handle->isBusy         = false;
1015 
1016             if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
1017             {
1018                 handle->callback(base, xfer, handle->userData);
1019             }
1020             I3C_SlaveTransferAbortEDMA(base, handle);
1021         }
1022         else
1023         {
1024             return;
1025         }
1026     }
1027 
1028     if (0UL != (flags & (uint32_t)kI3C_SlaveMatchedFlag))
1029     {
1030         xfer->event    = (uint32_t)kI3C_SlaveAddressMatchEvent;
1031         handle->isBusy = true;
1032         if ((0UL != (handle->eventMask & (uint32_t)kI3C_SlaveAddressMatchEvent)) && (NULL != handle->callback))
1033         {
1034             handle->callback(base, xfer, handle->userData);
1035         }
1036     }
1037 }
1038 
1039 /*!
1040  * brief Abort a slave dma non-blocking transfer in a early time
1041  *
1042  * param base I3C peripheral base address
1043  * param handle pointer to i3c_slave_edma_handle_t structure
1044  */
I3C_SlaveTransferAbortEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle)1045 void I3C_SlaveTransferAbortEDMA(I3C_Type *base, i3c_slave_edma_handle_t *handle)
1046 {
1047     if (handle->isBusy != false)
1048     {
1049         EDMA_AbortTransfer(handle->txDmaHandle);
1050         EDMA_AbortTransfer(handle->rxDmaHandle);
1051 
1052         I3C_SlaveEnableDMA(base, false, false, 0);
1053 
1054         /* Reset fifos. These flags clear automatically. */
1055         base->SDATACTRL |= I3C_SDATACTRL_FLUSHTB_MASK | I3C_SDATACTRL_FLUSHFB_MASK;
1056     }
1057 }