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