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