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 }