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                     }
500                 }
501                 *isDone        = true;
502                 state_complete = true;
503                 break;
504 
505             default:
506                 assert(false);
507                 break;
508         }
509     }
510     return result;
511 }
512 
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)513 void I3C_MasterTransferCreateHandleEDMA(I3C_Type *base,
514                                         i3c_master_edma_handle_t *handle,
515                                         const i3c_master_edma_callback_t *callback,
516                                         void *userData,
517                                         edma_handle_t *rxDmaHandle,
518                                         edma_handle_t *txDmaHandle)
519 {
520     uint32_t instance;
521 
522     assert(NULL != handle);
523 
524     /* Clear out the handle. */
525     (void)memset(handle, 0, sizeof(*handle));
526 
527     /* Look up instance number */
528     instance = I3C_GetInstance(base);
529 
530     handle->base        = base;
531     handle->txDmaHandle = txDmaHandle;
532     handle->rxDmaHandle = rxDmaHandle;
533     handle->callback    = *callback;
534     handle->userData    = userData;
535 
536     /* Save this handle for IRQ use. */
537     s_i3cMasterHandle[instance] = handle;
538 
539     /* Set irq handler. */
540     s_i3cMasterIsr = I3C_MasterTransferEDMAHandleIRQ;
541 
542     EDMA_SetCallback(handle->rxDmaHandle, I3C_MasterTransferEDMACallbackRx, handle);
543     EDMA_SetCallback(handle->txDmaHandle, I3C_MasterTransferEDMACallbackTx, handle);
544 
545     /* Clear all flags. */
546     I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
547     I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
548     /* Reset fifos. These flags clear automatically. */
549     base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
550 
551     /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
552      In some cases the I3C IRQ is configured through INTMUX, user needs to enable
553      INTMUX IRQ in application code. */
554     (void)EnableIRQ(kI3cIrqs[instance]);
555 
556     /* Clear internal IRQ enables and enable NVIC IRQ. */
557     I3C_MasterEnableInterrupts(base, (uint32_t)kMasterDMAIrqFlags);
558 }
559 
560 /*!
561  * brief Performs a non-blocking DMA transaction on the I2C/I3C bus.
562  *
563  * param base The I3C peripheral base address.
564  * param handle Pointer to the I3C master driver handle.
565  * param transfer The pointer to the transfer descriptor.
566  * retval #kStatus_Success The transaction was started successfully.
567  * retval #kStatus_I3C_Busy Either another master is currently utilizing the bus, or a non-blocking
568  *      transaction is already in progress.
569  */
I3C_MasterTransferEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle,i3c_master_transfer_t * transfer)570 status_t I3C_MasterTransferEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle, i3c_master_transfer_t *transfer)
571 {
572     assert(NULL != handle);
573     assert(NULL != transfer);
574     assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
575     i3c_master_state_t masterState = I3C_MasterGetState(base);
576     bool checkDdrState             = false;
577 
578     /* Return busy if another transaction is in progress. */
579     if (handle->state != (uint8_t)kIdleState)
580     {
581         return kStatus_I3C_Busy;
582     }
583 
584     /* Return an error if the bus is already in use not by us. */
585     checkDdrState = (transfer->busType == kI3C_TypeI3CDdr) ? (masterState != kI3C_MasterStateDdr) : true;
586     if ((masterState != kI3C_MasterStateIdle) && (masterState != kI3C_MasterStateNormAct) && checkDdrState)
587     {
588         return kStatus_I3C_Busy;
589     }
590 
591     /* Disable I3C IRQ sources while we configure stuff. */
592     I3C_MasterDisableInterrupts(
593         base, ((uint32_t)kMasterDMAIrqFlags | (uint32_t)kI3C_MasterRxReadyFlag | (uint32_t)kI3C_MasterTxReadyFlag));
594 
595     /* Save transfer into handle. */
596     handle->transfer = *transfer;
597 
598     /* Configure IBI response type. */
599     base->MCTRL &= ~I3C_MCTRL_IBIRESP_MASK;
600     base->MCTRL |= I3C_MCTRL_IBIRESP(transfer->ibiResponse);
601 
602     /* Clear all flags. */
603     I3C_MasterClearErrorStatusFlags(base, (uint32_t)kMasterErrorFlags);
604     I3C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
605     /* Reset fifos. These flags clear automatically. */
606     base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
607 
608     /* Generate commands to send. */
609     (void)I3C_MasterInitTransferStateMachineEDMA(base, handle);
610 
611     /* Enable I3C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
612     I3C_MasterEnableInterrupts(base, (uint32_t)(kMasterDMAIrqFlags));
613 
614     if (transfer->busType == kI3C_TypeI2C)
615     {
616         I3C_MasterDisableInterrupts(base, (uint32_t)kI3C_MasterSlaveStartFlag);
617     }
618 
619     return kStatus_Success;
620 }
621 
I3C_MasterTransferEDMAHandleIRQ(I3C_Type * base,void * i3cHandle)622 void I3C_MasterTransferEDMAHandleIRQ(I3C_Type *base, void *i3cHandle)
623 {
624     i3c_master_edma_handle_t *handle = (i3c_master_edma_handle_t *)i3cHandle;
625 
626     bool isDone;
627     status_t result;
628 
629     /* Don't do anything if we don't have a valid handle. */
630     if (NULL == handle)
631     {
632         return;
633     }
634 
635     result = I3C_MasterRunTransferStateMachineEDMA(base, handle, &isDone);
636 
637     if (handle->state == (uint8_t)kIdleState)
638     {
639         return;
640     }
641 
642     if (isDone || (result != kStatus_Success))
643     {
644         /* XXX need to handle data that may be in rx fifo below watermark level? */
645 
646         /* XXX handle error, terminate xfer */
647         if ((result == kStatus_I3C_Nak) || (result == kStatus_I3C_IBIWon))
648         {
649             I3C_MasterEmitRequest(base, kI3C_RequestEmitStop);
650         }
651 
652         /* Set handle to idle state. */
653         handle->state = (uint8_t)kIdleState;
654 
655         /* Invoke IBI user callback. */
656         if ((result == kStatus_I3C_IBIWon) && (handle->callback.ibiCallback != NULL))
657         {
658             handle->callback.ibiCallback(base, handle, handle->ibiType, kI3C_IbiReady);
659             handle->ibiPayloadSize = 0;
660         }
661 
662         /* Invoke callback. */
663         if (NULL != handle->callback.transferComplete)
664         {
665             handle->callback.transferComplete(base, handle, result, handle->userData);
666         }
667     }
668 }
669 
670 /*!
671  * brief Get master transfer status during a dma non-blocking transfer
672  *
673  * param base I3C peripheral base address
674  * param handle pointer to i2c_master_edma_handle_t structure
675  * param count Number of bytes transferred so far by the non-blocking transaction.
676  */
I3C_MasterTransferGetCountEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle,size_t * count)677 status_t I3C_MasterTransferGetCountEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle, size_t *count)
678 {
679     assert(handle != NULL);
680 
681     if (NULL == count)
682     {
683         return kStatus_InvalidArgument;
684     }
685 
686     /* Catch when there is not an active transfer. */
687     if (handle->state == (uint8_t)kIdleState)
688     {
689         *count = 0;
690         return kStatus_NoTransferInProgress;
691     }
692 
693     /* There is no necessity to disable interrupts as we read a single integer value */
694     i3c_direction_t dir = handle->transfer.direction;
695 
696     if (dir == kI3C_Read)
697     {
698         *count = handle->transferCount -
699                  1U * EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
700     }
701     else
702     {
703         *count = handle->transferCount -
704                  1U * EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel);
705     }
706 
707     return kStatus_Success;
708 }
709 
710 /*!
711  * brief Abort a master edma non-blocking transfer in a early time
712  *
713  * param base I3C peripheral base address
714  * param handle pointer to i2c_master_edma_handle_t structure
715  */
I3C_MasterTransferAbortEDMA(I3C_Type * base,i3c_master_edma_handle_t * handle)716 void I3C_MasterTransferAbortEDMA(I3C_Type *base, i3c_master_edma_handle_t *handle)
717 {
718     if (handle->state != (uint8_t)kIdleState)
719     {
720         EDMA_AbortTransfer(handle->txDmaHandle);
721         EDMA_AbortTransfer(handle->rxDmaHandle);
722 
723         I3C_MasterEnableDMA(base, false, false, 0);
724 
725         /* Reset fifos. These flags clear automatically. */
726         base->MDATACTRL |= I3C_MDATACTRL_FLUSHTB_MASK | I3C_MDATACTRL_FLUSHFB_MASK;
727 
728         /* Send a stop command to finalize the transfer. */
729         (void)I3C_MasterStop(base);
730 
731         /* Reset handle. */
732         handle->state = (uint8_t)kIdleState;
733     }
734 }
735 
I3C_SlaveTransferEDMACallback(edma_handle_t * dmaHandle,void * param,bool transferDone,uint32_t tcds)736 static void I3C_SlaveTransferEDMACallback(edma_handle_t *dmaHandle, void *param, bool transferDone, uint32_t tcds)
737 {
738     i3c_slave_edma_handle_t *i3cHandle = (i3c_slave_edma_handle_t *)param;
739 
740     if (transferDone)
741     {
742         /* Simply disable dma enablement */
743         if (i3cHandle->txDmaHandle == dmaHandle)
744         {
745             i3cHandle->base->SDMACTRL &= ~I3C_SDMACTRL_DMATB_MASK;
746 
747             if (i3cHandle->transfer.txDataSize > 1U)
748             {
749                 /* Ensure there's space in the Tx FIFO. */
750                 while ((i3cHandle->base->SDATACTRL & I3C_SDATACTRL_TXFULL_MASK) != 0U)
751                 {
752                 }
753                 /* Send the last byte. */
754                 i3cHandle->base->SWDATABE = *(uint8_t *)((uintptr_t)i3cHandle->transfer.txData + i3cHandle->transfer.txDataSize - 1U);
755             }
756         }
757         else
758         {
759 #if defined(FSL_FEATURE_I3C_HAS_ERRATA_052086) && (FSL_FEATURE_I3C_HAS_ERRATA_052086)
760             if (i3cHandle->transfer.rxDataSize > 1U)
761             {
762                 size_t rxCount;
763                 /* Read out the last byte data. */
764                 do
765                 {
766                     I3C_SlaveGetFifoCounts(i3cHandle->base, &rxCount, NULL);
767                 } while (rxCount == 0U);
768                 *(uint8_t *)((uint32_t)(uint32_t *)i3cHandle->transfer.rxData + i3cHandle->transfer.rxDataSize - 1U) =
769                     (uint8_t)i3cHandle->base->SRDATAB;
770             }
771 #endif
772             i3cHandle->base->SDMACTRL &= ~I3C_SDMACTRL_DMAFB_MASK;
773         }
774     }
775 }
776 
777 /*!
778  * brief Create a new handle for the I3C slave DMA APIs.
779  *
780  * The creation of a handle is for use with the DMA APIs. Once a handle
781  * is created, there is not a corresponding destroy handle. If the user wants to
782  * terminate a transfer, the I3C_SlaveTransferAbortDMA() API shall be called.
783  *
784  * For devices where the I3C send and receive DMA requests are OR'd together, the @a txDmaHandle
785  * parameter is ignored and may be set to NULL.
786  *
787  * param base The I3C peripheral base address.
788  * param handle Pointer to the I3C slave driver handle.
789  * param callback User provided pointer to the asynchronous callback function.
790  * param userData User provided pointer to the application callback data.
791  * param rxDmaHandle Handle for the DMA receive channel. Created by the user prior to calling this function.
792  * param txDmaHandle Handle for the DMA transmit channel. Created by the user prior to calling this function.
793  */
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)794 void I3C_SlaveTransferCreateHandleEDMA(I3C_Type *base,
795                                        i3c_slave_edma_handle_t *handle,
796                                        i3c_slave_edma_callback_t callback,
797                                        void *userData,
798                                        edma_handle_t *rxDmaHandle,
799                                        edma_handle_t *txDmaHandle)
800 {
801     uint32_t instance;
802 
803     assert(NULL != handle);
804 
805     /* Clear out the handle. */
806     (void)memset(handle, 0, sizeof(*handle));
807 
808     /* Look up instance number */
809     instance = I3C_GetInstance(base);
810 
811     handle->base        = base;
812     handle->txDmaHandle = txDmaHandle;
813     handle->rxDmaHandle = rxDmaHandle;
814     handle->callback    = callback;
815     handle->userData    = userData;
816 
817     /* Save this handle for IRQ use. */
818     s_i3cSlaveHandle[instance] = handle;
819 
820     /* Set irq handler. */
821     s_i3cSlaveIsr = I3C_SlaveTransferEDMAHandleIRQ;
822 
823     EDMA_SetCallback(handle->rxDmaHandle, I3C_SlaveTransferEDMACallback, handle);
824     EDMA_SetCallback(handle->txDmaHandle, I3C_SlaveTransferEDMACallback, handle);
825 
826     /* Clear internal IRQ enables and enable NVIC IRQ. */
827     I3C_SlaveDisableInterrupts(base, (uint32_t)kSlaveDMAIrqFlags);
828 
829     /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
830      In some cases the I3C IRQ is configured through INTMUX, user needs to enable
831      INTMUX IRQ in application code. */
832     (void)EnableIRQ(kI3cIrqs[instance]);
833 
834     /* Enable IRQ. */
835     I3C_SlaveEnableInterrupts(base, (uint32_t)kSlaveDMAIrqFlags);
836 }
837 
I3C_SlavePrepareTxEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle)838 static void I3C_SlavePrepareTxEDMA(I3C_Type *base, i3c_slave_edma_handle_t *handle)
839 {
840     edma_transfer_config_t txConfig;
841     uint32_t *txFifoBase;
842     i3c_slave_edma_transfer_t *xfer = &handle->transfer;
843 
844     if (xfer->txDataSize == 1U)
845     {
846         txFifoBase = (uint32_t *)(uintptr_t)&base->SWDATABE;
847         EDMA_PrepareTransfer(&txConfig, xfer->txData, 1, (void *)txFifoBase, 1, 1, xfer->txDataSize,
848                              kEDMA_MemoryToPeripheral);
849     }
850     else
851     {
852         txFifoBase = (uint32_t *)(uintptr_t)&base->SWDATAB1;
853         EDMA_PrepareTransfer(&txConfig, xfer->txData, 1, (void *)txFifoBase, 1, 1, xfer->txDataSize - 1U,
854                              kEDMA_MemoryToPeripheral);
855     }
856 
857     (void)EDMA_SubmitTransfer(handle->txDmaHandle, &txConfig);
858     EDMA_StartTransfer(handle->txDmaHandle);
859 }
860 
I3C_SlavePrepareRxEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle)861 static void I3C_SlavePrepareRxEDMA(I3C_Type *base, i3c_slave_edma_handle_t *handle)
862 {
863     uint32_t *rxFifoBase            = (uint32_t *)(uintptr_t)&base->SRDATAB;
864     i3c_slave_edma_transfer_t *xfer = &handle->transfer;
865     size_t dataSize                 = xfer->rxDataSize;
866     edma_transfer_config_t rxConfig;
867 
868 #if defined(FSL_FEATURE_I3C_HAS_ERRATA_052086) && (FSL_FEATURE_I3C_HAS_ERRATA_052086)
869     /* ERRATA052086: Soc integration issue results in target misses the last DMA request to copy the
870     last one byte from controler when transmission data size is > 1 byte. Resolution: Triggering DMA
871     interrupt one byte in advance, then receive the last one byte data after DMA transmission finishes. */
872     if (dataSize > 1U)
873     {
874         dataSize--;
875     }
876 #endif
877 
878     EDMA_PrepareTransfer(&rxConfig, (void *)rxFifoBase, 1, xfer->rxData, 1, 1, dataSize,
879                          kEDMA_PeripheralToMemory);
880     (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &rxConfig);
881     EDMA_StartTransfer(handle->rxDmaHandle);
882 }
883 
884 /*!
885  * brief Prepares for a non-blocking DMA-based transaction on the I3C bus.
886  *
887  * The API will do DMA configuration according to the input transfer descriptor, and the data will be transferred when
888  * there's bus master requesting transfer from/to this slave. So the timing of call to this API need be aligned
889  * with master application to ensure the transfer is executed as expected.
890  * Callback specified when the @a handle was created is invoked when the transaction has completed.
891  *
892  * param base The I3C peripheral base address.
893  * param handle Pointer to the I3C slave driver handle.
894  * param transfer The pointer to the transfer descriptor.
895  * param eventMask Bit mask formed by OR'ing together #i3c_slave_transfer_event_t enumerators to specify
896  *      which events to send to the callback. The transmit and receive events is not allowed to be enabled.
897  * retval kStatus_Success The transaction was started successfully.
898  * retval #kStatus_I3C_Busy Either another master is currently utilizing the bus, or another DMA
899  *      transaction is already in progress.
900  * retval #kStatus_Fail The transaction can't be set.
901  */
I3C_SlaveTransferEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle,i3c_slave_edma_transfer_t * transfer,uint32_t eventMask)902 status_t I3C_SlaveTransferEDMA(I3C_Type *base,
903                                i3c_slave_edma_handle_t *handle,
904                                i3c_slave_edma_transfer_t *transfer,
905                                uint32_t eventMask)
906 {
907     assert(NULL != handle);
908     assert(NULL != transfer);
909 
910     bool txDmaEn = false, rxDmaEn = false;
911     uint32_t width;
912 
913     if (handle->isBusy)
914     {
915         return kStatus_I3C_Busy;
916     }
917     /* Clear all flags. */
918     I3C_SlaveClearErrorStatusFlags(base, (uint32_t)kSlaveErrorFlags);
919     I3C_SlaveClearStatusFlags(base, (uint32_t)kSlaveClearFlags);
920     /* Reset fifos. These flags clear automatically. */
921     base->SDATACTRL |= I3C_SDATACTRL_FLUSHTB_MASK | I3C_SDATACTRL_FLUSHFB_MASK;
922 
923     handle->transfer = *transfer;
924 
925     /* Set up event mask. */
926     handle->eventMask = eventMask;
927 
928     if ((transfer->txData != NULL) && (transfer->txDataSize != 0U))
929     {
930         I3C_SlavePrepareTxEDMA(base, handle);
931         txDmaEn = true;
932         width   = 1U;
933     }
934 
935     if ((transfer->rxData != NULL) && (transfer->rxDataSize != 0U))
936     {
937         I3C_SlavePrepareRxEDMA(base, handle);
938         rxDmaEn = true;
939         width   = 1U;
940     }
941 
942     if (txDmaEn || rxDmaEn)
943     {
944         I3C_SlaveEnableDMA(base, txDmaEn, rxDmaEn, width);
945         return kStatus_Success;
946     }
947     else
948     {
949         return kStatus_Fail;
950     }
951 }
952 
I3C_SlaveTransferEDMAHandleIRQ(I3C_Type * base,void * i3cHandle)953 void I3C_SlaveTransferEDMAHandleIRQ(I3C_Type *base, void *i3cHandle)
954 {
955     uint32_t flags;
956     uint32_t errFlags;
957     i3c_slave_edma_transfer_t *xfer;
958 
959     i3c_slave_edma_handle_t *handle = (i3c_slave_edma_handle_t *)i3cHandle;
960     /* Check for a valid handle in case of a spurious interrupt. */
961     if (NULL == handle)
962     {
963         return;
964     }
965 
966     xfer = &handle->transfer;
967 
968     /* Get status flags. */
969     flags    = I3C_SlaveGetStatusFlags(base);
970     errFlags = I3C_SlaveGetErrorStatusFlags(base);
971 
972     /* Clear status flags. */
973     I3C_SlaveClearStatusFlags(base, flags);
974 
975     if (0UL != (errFlags & (uint32_t)kSlaveErrorFlags))
976     {
977         xfer->event            = (uint32_t)kI3C_SlaveCompletionEvent;
978         xfer->completionStatus = I3C_SlaveCheckAndClearError(base, errFlags);
979 
980         if ((0UL != (handle->eventMask & (uint32_t)kI3C_SlaveCompletionEvent)) && (NULL != handle->callback))
981         {
982             handle->callback(base, xfer, handle->userData);
983         }
984         return;
985     }
986 
987     if (0UL != (flags & (uint32_t)kI3C_SlaveEventSentFlag))
988     {
989         xfer->event = (uint32_t)kI3C_SlaveRequestSentEvent;
990         if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
991         {
992             handle->callback(base, xfer, handle->userData);
993         }
994     }
995 
996     if (0UL != (flags & (uint32_t)kI3C_SlaveReceivedCCCFlag))
997     {
998         handle->isBusy = true;
999         xfer->event    = (uint32_t)kI3C_SlaveReceivedCCCEvent;
1000         if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
1001         {
1002             handle->callback(base, xfer, handle->userData);
1003         }
1004     }
1005 
1006     if (0UL != (flags & (uint32_t)kI3C_SlaveBusStopFlag))
1007     {
1008         if (handle->isBusy == true)
1009         {
1010             xfer->event            = (uint32_t)kI3C_SlaveCompletionEvent;
1011             xfer->completionStatus = kStatus_Success;
1012             handle->isBusy         = false;
1013 
1014             if ((0UL != (handle->eventMask & xfer->event)) && (NULL != handle->callback))
1015             {
1016                 handle->callback(base, xfer, handle->userData);
1017             }
1018             I3C_SlaveTransferAbortEDMA(base, handle);
1019         }
1020         else
1021         {
1022             return;
1023         }
1024     }
1025 
1026     if (0UL != (flags & (uint32_t)kI3C_SlaveMatchedFlag))
1027     {
1028         xfer->event    = (uint32_t)kI3C_SlaveAddressMatchEvent;
1029         handle->isBusy = true;
1030         if ((0UL != (handle->eventMask & (uint32_t)kI3C_SlaveAddressMatchEvent)) && (NULL != handle->callback))
1031         {
1032             handle->callback(base, xfer, handle->userData);
1033         }
1034     }
1035 }
1036 
1037 /*!
1038  * brief Abort a slave dma non-blocking transfer in a early time
1039  *
1040  * param base I3C peripheral base address
1041  * param handle pointer to i3c_slave_edma_handle_t structure
1042  */
I3C_SlaveTransferAbortEDMA(I3C_Type * base,i3c_slave_edma_handle_t * handle)1043 void I3C_SlaveTransferAbortEDMA(I3C_Type *base, i3c_slave_edma_handle_t *handle)
1044 {
1045     if (handle->isBusy != false)
1046     {
1047         EDMA_AbortTransfer(handle->txDmaHandle);
1048         EDMA_AbortTransfer(handle->rxDmaHandle);
1049 
1050         I3C_SlaveEnableDMA(base, false, false, 0);
1051 
1052         /* Reset fifos. These flags clear automatically. */
1053         base->SDATACTRL |= I3C_SDATACTRL_FLUSHTB_MASK | I3C_SDATACTRL_FLUSHFB_MASK;
1054     }
1055 }