1 /*
2 * Copyright 2016-2020 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_ecspi_sdma.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.ecspi_sdma"
16 #endif
17
18 /*!
19 * @brief Structure definition for ecspi_master_sdma_private_handle_t. The structure is private.
20 */
21 typedef struct _ecspi_master_sdma_private_handle
22 {
23 ECSPI_Type *base; /*!< ECSPI peripheral base address. */
24 ecspi_sdma_handle_t *handle; /*!< ecspi_sdma_handle_t handle */
25 } ecspi_master_sdma_private_handle_t;
26
27 /*!
28 * @brief Structure definition for ecspi_slave_sdma_private_handle_t. The structure is private.
29 */
30 typedef struct _ecspi_slave_sdma_private_handle
31 {
32 ECSPI_Type *base; /*!< ECSPI peripheral base address. */
33 ecspi_sdma_handle_t *handle; /*!< ecspi_sdma_handle_t handle */
34 } ecspi_slave_sdma_private_handle_t;
35
36 /*! @brief ECSPI transfer state, which is used for ECSPI transactiaonl APIs' internal state. */
37 enum _ecspi_sdma_states_t
38 {
39 kECSPI_Idle = 0x0, /*!< ECSPI is idle state */
40 kECSPI_Busy /*!< ECSPI is busy tranferring data. */
41 };
42 /*! @brief Base pointer array */
43 static ECSPI_Type *const s_ecspiBases[] = ECSPI_BASE_PTRS;
44 /*<! Private handle only used for internally. */
45 static ecspi_master_sdma_private_handle_t s_ecspiMasterSdmaPrivateHandle[ARRAY_SIZE(s_ecspiBases)];
46 static ecspi_slave_sdma_private_handle_t s_ecspiSlaveSdmaPrivateHandle[ARRAY_SIZE(s_ecspiBases)];
47 /*******************************************************************************
48 * Prototypes
49 ******************************************************************************/
50 /*!
51 * @brief SDMA_EcspiMasterCallback after the ECSPI master transfer completed by using SDMA.
52 * This is not a public API.
53 */
54 static void SDMA_EcspiMasterCallback(sdma_handle_t *sdmaHandle,
55 void *g_ecspiSdmaPrivateHandle,
56 bool transferDone,
57 uint32_t tcds);
58
59 /*!
60 * @brief SDMA_EcspiSlaveCallback after the ECSPI slave transfer completed by using SDMA.
61 * This is not a public API.
62 */
63 static void SDMA_EcspiSlaveCallback(sdma_handle_t *sdmaHandle,
64 void *g_ecspiSdmaPrivateHandle,
65 bool transferDone,
66 uint32_t tcds);
67 /*******************************************************************************
68 * Variables
69 ******************************************************************************/
70
71 /*******************************************************************************
72 * Code
73 ******************************************************************************/
SDMA_EcspiMasterCallback(sdma_handle_t * sdmaHandle,void * g_ecspiSdmaPrivateHandle,bool transferDone,uint32_t tcds)74 static void SDMA_EcspiMasterCallback(sdma_handle_t *sdmaHandle,
75 void *g_ecspiSdmaPrivateHandle,
76 bool transferDone,
77 uint32_t tcds)
78 {
79 assert(sdmaHandle != NULL);
80 assert(g_ecspiSdmaPrivateHandle != NULL);
81
82 ecspi_master_sdma_private_handle_t *ecspiSdmaPrivateHandle;
83
84 ecspiSdmaPrivateHandle = (ecspi_master_sdma_private_handle_t *)g_ecspiSdmaPrivateHandle;
85 /* if channel is Tx channel, disable Tx channel SDMA enable*/
86 if (sdmaHandle->channel == ecspiSdmaPrivateHandle->handle->ChannelTx)
87 {
88 ECSPI_EnableDMA((ecspiSdmaPrivateHandle->base), kECSPI_TxDmaEnable, false);
89 ecspiSdmaPrivateHandle->handle->txInProgress = false;
90 SDMA_SetChannelPriority(sdmaHandle->base, sdmaHandle->channel, 0);
91 SDMA_AbortTransfer(sdmaHandle);
92 }
93 /* if channel is Rx channel, disable Rx channel SDMA enable*/
94 else
95 {
96 ECSPI_EnableDMA((ecspiSdmaPrivateHandle->base), kECSPI_RxDmaEnable, false);
97 ecspiSdmaPrivateHandle->handle->rxInProgress = false;
98 SDMA_SetChannelPriority(sdmaHandle->base, sdmaHandle->channel, 0);
99 SDMA_AbortTransfer(sdmaHandle);
100 }
101 /* if both channel is finished, then abort SDMA transfer*/
102 if ((ecspiSdmaPrivateHandle->handle->txInProgress == false) &&
103 (ecspiSdmaPrivateHandle->handle->rxInProgress == false))
104 {
105 ECSPI_MasterTransferAbortSDMA(ecspiSdmaPrivateHandle->base, ecspiSdmaPrivateHandle->handle);
106 if (ecspiSdmaPrivateHandle->handle->callback != NULL)
107 {
108 ecspiSdmaPrivateHandle->handle->callback(ecspiSdmaPrivateHandle->base, ecspiSdmaPrivateHandle->handle,
109 kStatus_Success, ecspiSdmaPrivateHandle->handle->userData);
110 }
111 ecspiSdmaPrivateHandle->handle->state = (uint32_t)kECSPI_Idle;
112 }
113 }
114
115 /*!
116 * brief Abort a ECSPI master transfer using SDMA.
117 *
118 * param base ECSPI peripheral base address.
119 * param handle ECSPI SDMA handle pointer.
120 */
ECSPI_MasterTransferAbortSDMA(ECSPI_Type * base,ecspi_sdma_handle_t * handle)121 void ECSPI_MasterTransferAbortSDMA(ECSPI_Type *base, ecspi_sdma_handle_t *handle)
122 {
123 assert(handle != NULL);
124
125 ECSPI_Enable(base, false);
126
127 ECSPI_EnableDMA(base, kECSPI_DmaAllEnable, false);
128
129 SDMA_AbortTransfer(handle->rxSdmaHandle);
130 SDMA_AbortTransfer(handle->txSdmaHandle);
131
132 handle->state = (uint32_t)kECSPI_Idle;
133 }
134
SDMA_EcspiSlaveCallback(sdma_handle_t * sdmaHandle,void * g_ecspiSdmaPrivateHandle,bool transferDone,uint32_t tcds)135 static void SDMA_EcspiSlaveCallback(sdma_handle_t *sdmaHandle,
136 void *g_ecspiSdmaPrivateHandle,
137 bool transferDone,
138 uint32_t tcds)
139 {
140 assert(sdmaHandle != NULL);
141 assert(g_ecspiSdmaPrivateHandle != NULL);
142
143 ecspi_slave_sdma_private_handle_t *ecspiSdmaPrivateHandle;
144
145 ecspiSdmaPrivateHandle = (ecspi_slave_sdma_private_handle_t *)g_ecspiSdmaPrivateHandle;
146 /* if channel is Tx channel, disable Tx channel SDMA enable*/
147 if (sdmaHandle->channel == ecspiSdmaPrivateHandle->handle->ChannelTx)
148 {
149 ECSPI_EnableDMA((ecspiSdmaPrivateHandle->base), kECSPI_TxDmaEnable, false);
150 ecspiSdmaPrivateHandle->handle->txInProgress = false;
151 SDMA_SetChannelPriority(sdmaHandle->base, sdmaHandle->channel, 0);
152 SDMA_AbortTransfer(sdmaHandle);
153 }
154 /* if channel is Rx channel, disable Rx channel SDMA enable*/
155 else
156 {
157 ECSPI_EnableDMA((ecspiSdmaPrivateHandle->base), kECSPI_RxDmaEnable, false);
158 ecspiSdmaPrivateHandle->handle->rxInProgress = false;
159 SDMA_SetChannelPriority(sdmaHandle->base, sdmaHandle->channel, 0);
160 SDMA_AbortTransfer(sdmaHandle);
161 }
162 /* if both channel is finished, then abort SDMA transfer*/
163 if ((ecspiSdmaPrivateHandle->handle->txInProgress == false) &&
164 (ecspiSdmaPrivateHandle->handle->rxInProgress == false))
165 {
166 ECSPI_MasterTransferAbortSDMA(ecspiSdmaPrivateHandle->base, ecspiSdmaPrivateHandle->handle);
167 if (ecspiSdmaPrivateHandle->handle->callback != NULL)
168 {
169 ecspiSdmaPrivateHandle->handle->callback(ecspiSdmaPrivateHandle->base, ecspiSdmaPrivateHandle->handle,
170 kStatus_Success, ecspiSdmaPrivateHandle->handle->userData);
171 }
172 ecspiSdmaPrivateHandle->handle->state = (uint32_t)kECSPI_Idle;
173 }
174 }
175
176 /*!
177 * brief Abort a ECSPI slave transfer using SDMA.
178 *
179 * param base ECSPI peripheral base address.
180 * param handle ECSPI SDMA handle pointer.
181 */
ECSPI_SlaveTransferAbortSDMA(ECSPI_Type * base,ecspi_sdma_handle_t * handle)182 void ECSPI_SlaveTransferAbortSDMA(ECSPI_Type *base, ecspi_sdma_handle_t *handle)
183 {
184 assert(handle != NULL);
185
186 ECSPI_Enable(base, false);
187
188 ECSPI_EnableDMA(base, kECSPI_RxDmaEnable, false);
189 ECSPI_EnableDMA(base, kECSPI_TxDmaEnable, false);
190
191 SDMA_AbortTransfer(handle->rxSdmaHandle);
192 SDMA_AbortTransfer(handle->txSdmaHandle);
193
194 handle->state = (uint32_t)kECSPI_Idle;
195 }
196
197 /*!
198 * brief Initialize the ECSPI master SDMA handle.
199 *
200 * This function initializes the ECSPI master SDMA handle which can be used for other SPI master transactional APIs.
201 * Usually, for a specified ECSPI instance, user need only call this API once to get the initialized handle.
202 *
203 * param base ECSPI peripheral base address.
204 * param handle ECSPI handle pointer.
205 * param callback User callback function called at the end of a transfer.
206 * param userData User data for callback.
207 * param txHandle SDMA handle pointer for ECSPI Tx, the handle shall be static allocated by users.
208 * param rxHandle SDMA handle pointer for ECSPI Rx, the handle shall be static allocated by users.
209 * param eventSourceTx event source for ECSPI send, which can be found in SDMA mapping.
210 * param eventSourceRx event source for ECSPI receive, which can be found in SDMA mapping.
211 * param TxChannel SDMA channel for ECSPI send.
212 * param RxChannel SDMA channel for ECSPI receive.
213 */
ECSPI_MasterTransferCreateHandleSDMA(ECSPI_Type * base,ecspi_sdma_handle_t * handle,ecspi_sdma_callback_t callback,void * userData,sdma_handle_t * txHandle,sdma_handle_t * rxHandle,uint32_t eventSourceTx,uint32_t eventSourceRx,uint32_t TxChannel,uint32_t RxChannel)214 void ECSPI_MasterTransferCreateHandleSDMA(ECSPI_Type *base,
215 ecspi_sdma_handle_t *handle,
216 ecspi_sdma_callback_t callback,
217 void *userData,
218 sdma_handle_t *txHandle,
219 sdma_handle_t *rxHandle,
220 uint32_t eventSourceTx,
221 uint32_t eventSourceRx,
222 uint32_t TxChannel,
223 uint32_t RxChannel)
224 {
225 assert(handle != NULL);
226 assert(txHandle != NULL);
227 assert(rxHandle != NULL);
228 uint32_t instance = ECSPI_GetInstance(base);
229
230 /* Zero the handle */
231 (void)memset(handle, 0, sizeof(*handle));
232
233 /* Set ECSPI base to handle */
234 rxHandle->eventSource = eventSourceRx;
235 txHandle->eventSource = eventSourceTx;
236 handle->txSdmaHandle = txHandle;
237 handle->rxSdmaHandle = rxHandle;
238 handle->ChannelTx = TxChannel;
239 handle->ChannelRx = RxChannel;
240 handle->callback = callback;
241 handle->userData = userData;
242
243 /* Set ECSPI state to idle */
244 handle->state = (uint32_t)kECSPI_Idle;
245
246 /* Set handle to global state */
247 s_ecspiMasterSdmaPrivateHandle[instance].base = base;
248 s_ecspiMasterSdmaPrivateHandle[instance].handle = handle;
249
250 /* Install callback for Tx and Rx sdma channel */
251 SDMA_SetCallback(handle->rxSdmaHandle, SDMA_EcspiMasterCallback, &s_ecspiMasterSdmaPrivateHandle[instance]);
252 SDMA_SetCallback(handle->txSdmaHandle, SDMA_EcspiMasterCallback, &s_ecspiMasterSdmaPrivateHandle[instance]);
253 }
254
255 /*!
256 * brief Initialize the ECSPI Slave SDMA handle.
257 *
258 * This function initializes the ECSPI Slave SDMA handle which can be used for other SPI Slave transactional APIs.
259 * Usually, for a specified ECSPI instance, user need only call this API once to get the initialized handle.
260 *
261 * param base ECSPI peripheral base address.
262 * param handle ECSPI handle pointer.
263 * param callback User callback function called at the end of a transfer.
264 * param userData User data for callback.
265 * param txHandle SDMA handle pointer for ECSPI Tx, the handle shall be static allocated by users.
266 * param rxHandle SDMA handle pointer for ECSPI Rx, the handle shall be static allocated by users.
267 * param eventSourceTx event source for ECSPI send, which can be found in SDMA mapping.
268 * param eventSourceRx event source for ECSPI receive, which can be found in SDMA mapping.
269 * param TxChannel SDMA channel for ECSPI send.
270 * param RxChannel SDMA channel for ECSPI receive.
271 */
ECSPI_SlaveTransferCreateHandleSDMA(ECSPI_Type * base,ecspi_sdma_handle_t * handle,ecspi_sdma_callback_t callback,void * userData,sdma_handle_t * txHandle,sdma_handle_t * rxHandle,uint32_t eventSourceTx,uint32_t eventSourceRx,uint32_t TxChannel,uint32_t RxChannel)272 void ECSPI_SlaveTransferCreateHandleSDMA(ECSPI_Type *base,
273 ecspi_sdma_handle_t *handle,
274 ecspi_sdma_callback_t callback,
275 void *userData,
276 sdma_handle_t *txHandle,
277 sdma_handle_t *rxHandle,
278 uint32_t eventSourceTx,
279 uint32_t eventSourceRx,
280 uint32_t TxChannel,
281 uint32_t RxChannel)
282 {
283 assert(handle != NULL);
284 assert(txHandle != NULL);
285 assert(rxHandle != NULL);
286 uint32_t instance = ECSPI_GetInstance(base);
287
288 /* Zero the handle */
289 (void)memset(handle, 0, sizeof(*handle));
290
291 /* Set ECSPI base to handle */
292 rxHandle->eventSource = eventSourceRx;
293 txHandle->eventSource = eventSourceTx;
294 handle->txSdmaHandle = txHandle;
295 handle->rxSdmaHandle = rxHandle;
296 handle->ChannelTx = TxChannel;
297 handle->ChannelRx = RxChannel;
298 handle->callback = callback;
299 handle->userData = userData;
300
301 /* Set ECSPI state to idle */
302 handle->state = (uint32_t)kECSPI_Idle;
303
304 /* Set handle to global state */
305 s_ecspiSlaveSdmaPrivateHandle[instance].base = base;
306 s_ecspiSlaveSdmaPrivateHandle[instance].handle = handle;
307
308 /* Install callback for Tx and Rx sdma channel */
309 SDMA_SetCallback(handle->txSdmaHandle, SDMA_EcspiSlaveCallback, &s_ecspiSlaveSdmaPrivateHandle[instance]);
310 SDMA_SetCallback(handle->rxSdmaHandle, SDMA_EcspiSlaveCallback, &s_ecspiSlaveSdmaPrivateHandle[instance]);
311 }
312
313 /*!
314 * brief Perform a non-blocking ECSPI master transfer using SDMA.
315 *
316 * note This interface returned immediately after transfer initiates.
317 *
318 * param base ECSPI peripheral base address.
319 * param handle ECSPI SDMA handle pointer.
320 * param xfer Pointer to sdma transfer structure.
321 * retval kStatus_Success Successfully start a transfer.
322 * retval kStatus_InvalidArgument Input argument is invalid.
323 * retval kStatus_ECSPI_Busy EECSPI is not idle, is running another transfer.
324 */
ECSPI_MasterTransferSDMA(ECSPI_Type * base,ecspi_sdma_handle_t * handle,ecspi_transfer_t * xfer)325 status_t ECSPI_MasterTransferSDMA(ECSPI_Type *base, ecspi_sdma_handle_t *handle, ecspi_transfer_t *xfer)
326 {
327 assert((base != NULL) && (handle != NULL) && (xfer != NULL));
328
329 sdma_transfer_config_t xferConfig = {0U};
330 sdma_peripheral_t perType = kSDMA_PeripheralNormal;
331
332 /* Check if ECSPI is busy */
333 if (handle->state == (uint32_t)kECSPI_Busy)
334 {
335 return kStatus_ECSPI_Busy;
336 }
337
338 /* Check if the input arguments valid */
339 if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
340 {
341 return kStatus_InvalidArgument;
342 }
343 ECSPI_Enable(base, true);
344 handle->state = (uint32_t)kECSPI_Busy;
345
346 ECSPI_SetChannelSelect(base, xfer->channel);
347
348 #if defined(FSL_FEATURE_SOC_SPBA_COUNT) && (FSL_FEATURE_SOC_SPBA_COUNT > 0)
349 bool isSpba = SDMA_IsPeripheralInSPBA((uint32_t)base);
350 /* Judge if the instance is located in SPBA */
351 if (isSpba)
352 {
353 perType = kSDMA_PeripheralNormal_SP;
354 }
355 #endif /* FSL_FEATURE_SOC_SPBA_COUNT */
356
357 /* Prepare transfer. */
358 SDMA_PrepareTransfer(&xferConfig, (uint32_t)xfer->txData, (uint32_t) & (base->TXDATA), sizeof(uint8_t),
359 sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, handle->txSdmaHandle->eventSource, perType,
360 kSDMA_MemoryToPeripheral);
361
362 /* Submit transfer. */
363 SDMA_SubmitTransfer(handle->txSdmaHandle, &xferConfig);
364
365 /* Prepare transfer. */
366 SDMA_PrepareTransfer(&xferConfig, (uint32_t) & (base->RXDATA), (uint32_t)xfer->rxData, sizeof(uint8_t),
367 sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, handle->rxSdmaHandle->eventSource, perType,
368 kSDMA_PeripheralToMemory);
369 /* Submit transfer. */
370 SDMA_SubmitTransfer(handle->rxSdmaHandle, &xferConfig);
371 /* Start Rx transfer */
372 handle->rxInProgress = true;
373 SDMA_StartTransfer(handle->rxSdmaHandle);
374 ECSPI_EnableDMA(base, kECSPI_RxDmaEnable, true);
375
376 /* Start Tx transfer */
377 handle->txInProgress = true;
378 SDMA_StartTransfer(handle->txSdmaHandle);
379 ECSPI_EnableDMA(base, kECSPI_TxDmaEnable, true);
380
381 return kStatus_Success;
382 }
383
384 /*!
385 * brief Perform a non-blocking ECSPI slave transfer using SDMA.
386 *
387 * note This interface returned immediately after transfer initiates.
388 *
389 * param base ECSPI peripheral base address.
390 * param handle ECSPI SDMA handle pointer.
391 * param xfer Pointer to sdma transfer structure.
392 * retval kStatus_Success Successfully start a transfer.
393 * retval kStatus_InvalidArgument Input argument is invalid.
394 * retval kStatus_ECSPI_Busy EECSPI is not idle, is running another transfer.
395 */
ECSPI_SlaveTransferSDMA(ECSPI_Type * base,ecspi_sdma_handle_t * handle,ecspi_transfer_t * xfer)396 status_t ECSPI_SlaveTransferSDMA(ECSPI_Type *base, ecspi_sdma_handle_t *handle, ecspi_transfer_t *xfer)
397 {
398 assert((base != NULL) && (handle != NULL) && (xfer != NULL));
399
400 sdma_transfer_config_t xferConfig;
401 sdma_peripheral_t perType = kSDMA_PeripheralNormal;
402
403 /* Check if ECSPI is busy */
404 if (handle->state == (uint32_t)kECSPI_Busy)
405 {
406 return kStatus_ECSPI_Busy;
407 }
408
409 /* Check if the input arguments valid */
410 if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
411 {
412 return kStatus_InvalidArgument;
413 }
414 ECSPI_Enable(base, true);
415 handle->state = (uint32_t)kECSPI_Busy;
416
417 ECSPI_SetChannelSelect(base, xfer->channel);
418
419 #if defined(FSL_FEATURE_SOC_SPBA_COUNT) && (FSL_FEATURE_SOC_SPBA_COUNT > 0)
420 bool isSpba = SDMA_IsPeripheralInSPBA((uint32_t)base);
421 /* Judge if the instance is located in SPBA */
422 if (isSpba)
423 {
424 perType = kSDMA_PeripheralNormal_SP;
425 }
426 #endif /* FSL_FEATURE_SOC_SPBA_COUNT */
427
428 /* Prepare transfer. */
429 SDMA_PrepareTransfer(&xferConfig, (uint32_t) & (base->RXDATA), (uint32_t)xfer->rxData, sizeof(uint8_t),
430 sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, handle->rxSdmaHandle->eventSource, perType,
431 kSDMA_PeripheralToMemory);
432 /* Submit transfer. */
433 SDMA_SubmitTransfer(handle->rxSdmaHandle, &xferConfig);
434
435 /* Prepare transfer. */
436 SDMA_PrepareTransfer(&xferConfig, (uint32_t)xfer->txData, (uint32_t) & (base->TXDATA), sizeof(uint8_t),
437 sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, handle->txSdmaHandle->eventSource, perType,
438 kSDMA_MemoryToPeripheral);
439
440 /* Submit transfer. */
441 SDMA_SubmitTransfer(handle->txSdmaHandle, &xferConfig);
442 /* start Tx transfer */
443 handle->txInProgress = true;
444 ECSPI_EnableDMA(base, kECSPI_TxDmaEnable, true);
445 SDMA_StartTransfer(handle->txSdmaHandle);
446
447 /* start Rx transfer */
448 handle->rxInProgress = true;
449 ECSPI_EnableDMA(base, kECSPI_RxDmaEnable, true);
450 SDMA_StartTransfer(handle->rxSdmaHandle);
451
452 return kStatus_Success;
453 }
454