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