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