1 /**
2 * \file QSPI_dma.c
3 *
4 * \brief EDMA based QSPI driver for IP verion 1.
5 *
6 * This file contains the EDMA driver APIs for QSPI.
7 */
9 /*
10 * Copyright (c) 2020, Texas Instruments Incorporated
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * * Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * * Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 *
24 * * Neither the name of Texas Instruments Incorporated nor the names of
25 * its contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
32 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
35 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
38 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
41 #include <string.h>
42 #include <ti/drv/spi/soc/SPI_soc.h>
43 #include <ti/drv/edma/edma.h>
45 #define QSPI_EVENTQUE (0U)
46 #define QSPI_DMA_XFER_SIZE_ALIGN (4U)
48 /* DMA functions */
49 static void QSPI_dmaIsrHandler (uintptr_t appData, uint8_t tcc);
51 int32_t QSPI_dmaConfig(SPI_Handle handle);
52 int32_t QSPI_dmaTransfer(SPI_Handle handle, const SPI_Transaction *transaction);
53 int32_t QSPI_dmaFreeChannel(SPI_Handle handle);
55 static void QSPI_edmaParamInit(EDMA_paramSetConfig_t *param, uint8_t tcc, uint8_t xferType);
56 static int32_t QSPI_edmaChannelConfig(EDMA_Handle hEdma,
57 uint8_t chId,
58 uint8_t queueId,
59 uint8_t xferType);
60 static int32_t QSPI_dmaMemcpy(SPI_Handle handle,
61 uintptr_t destBuf,
62 uintptr_t srcBuf,
63 uint32_t length);
66 int32_t QSPI_dmaConfig(SPI_Handle handle)
67 {
68 QSPI_HwAttrs *hwAttrs;
69 int32_t status = SPI_STATUS_SUCCESS;
70 int32_t edmaStatus = EDMA_NO_ERROR;
71 QSPI_v1_Object *object;
73 /* Get the pointer to the object and hwAttrs */
74 object = (QSPI_v1_Object *)handle->object;
75 hwAttrs = (QSPI_HwAttrs*)handle->hwAttrs;
77 /* Check EDMA handle is not NULL */
78 if (hwAttrs->edmaHandle == NULL)
79 {
80 status = SPI_STATUS_ERROR;
81 }
83 if ( status == SPI_STATUS_SUCCESS)
84 {
85 edmaStatus = QSPI_edmaChannelConfig((EDMA_Handle)hwAttrs->edmaHandle,
86 hwAttrs->edmaChId,
87 QSPI_EVENTQUE,
88 EDMA3_SYNC_AB);
89 if (EDMA_NO_ERROR != edmaStatus)
90 {
91 status = SPI_STATUS_ERROR;
92 }
93 }
94 object->intermediateDmaXferInitiated = false;
95 return status;
96 }
98 #define QSPI_DMA_MAX_XFER_SIZE (31U * 1024U)
100 int32_t QSPI_dmaTransfer(SPI_Handle handle,
101 const SPI_Transaction *transaction)
102 {
103 QSPI_v1_Object *object;
104 QSPI_HwAttrs const *hwAttrs;
105 uintptr_t dataPtr;
106 int32_t status = SPI_STATUS_SUCCESS;
108 /* Get the pointer to the hwAttrs */
109 object = (QSPI_v1_Object *)handle->object;
110 hwAttrs = (QSPI_HwAttrs *)handle->hwAttrs;
112 dataPtr = ((uintptr_t)hwAttrs->memMappedBaseAddr + (uintptr_t)transaction->txBuf);
114 object->intermediateDmaXferInitiated = false;
115 if(SPI_TRANSACTION_TYPE_READ == object->transactionType)
116 {
117 uint32_t i;
119 for (i = 0; i < transaction->count; i += QSPI_DMA_MAX_XFER_SIZE)
120 {
121 /* QSPI EDMA read transfer should be 4 byte aligned else will result in corrupted tranfer */
122 uint32_t xferLen = CSL_NEXT_MULTIPLE_OF(CSL_MIN((transaction->count - i), QSPI_DMA_MAX_XFER_SIZE), QSPI_DMA_XFER_SIZE_ALIGN);
124 if (transaction->count > (i + xferLen))
125 {
126 object->intermediateDmaXferInitiated = true;
127 }
128 /* RX Mode */
129 status = QSPI_dmaMemcpy(handle,
130 ((uintptr_t)transaction->rxBuf + i),
131 ((uintptr_t)dataPtr + i),
132 xferLen);
133 //TODO: This reprogramming of intermidiate xfers shoud be done in
134 //intermediate xfer complete ISR and not in loop here.
135 while (object->intermediateDmaXferInitiated == true);
136 }
137 }
138 else
139 {
140 /* TX Mode */
141 status = QSPI_dmaMemcpy(handle,
142 (uintptr_t)dataPtr,
143 (uintptr_t)transaction->rxBuf,
144 transaction->count);
145 }
147 return (status);
148 }
150 int32_t QSPI_dmaFreeChannel(SPI_Handle handle)
151 {
152 QSPI_HwAttrs const *hwAttrs;
153 int32_t status = SPI_STATUS_SUCCESS;
154 int32_t edmaStatus;
156 /* Get the pointer to the object and hwAttrs */
157 hwAttrs = (QSPI_HwAttrs*)handle->hwAttrs;
159 edmaStatus = EDMA_disableChannel(hwAttrs->edmaHandle,
160 hwAttrs->edmaChId,
161 EDMA3_CHANNEL_TYPE_DMA);
163 if (EDMA_NO_ERROR != edmaStatus)
164 {
165 status = SPI_STATUS_ERROR;
166 }
168 return (status);
169 }
171 static void QSPI_dmaIsrHandler (uintptr_t appData, uint8_t tcc)
172 {
173 SPI_Handle handle;
174 QSPI_v1_Object *object;
175 QSPI_HwAttrs const *hwAttrs;
177 /* Get the pointer to the object and hwAttrs */
178 handle = (SPI_Handle)appData;
179 object = (QSPI_v1_Object*)handle->object;
180 hwAttrs = (QSPI_HwAttrs*)handle->hwAttrs;
182 if (object->intermediateDmaXferInitiated == false)
183 {
184 object->transaction->status = SPI_TRANSFER_COMPLETED;
185 }
186 /* EDMA is done - disable the DMA channel */
187 EDMA_disableChannel(hwAttrs->edmaHandle,
188 tcc,
189 EDMA3_CHANNEL_TYPE_DMA);
191 if (object->intermediateDmaXferInitiated == false)
192 {
193 /* Call the transfer completion callback function */
194 object->qspiParams.transferCallbackFxn(handle, object->transaction);
195 }
196 else
197 {
198 object->intermediateDmaXferInitiated = false;
199 }
200 }
202 static void QSPI_edmaParamInit(EDMA_paramSetConfig_t *param, uint8_t tcc, uint8_t xferType)
203 {
204 memset(param, 0, sizeof(*param));
206 param->transferType = xferType;
208 param->destinationAddressingMode = EDMA3_ADDRESSING_MODE_LINEAR;
209 param->sourceAddressingMode = EDMA3_ADDRESSING_MODE_LINEAR;
210 param->fifoWidth = 0;
212 param->transferCompletionCode = tcc;
214 param->isEarlyCompletion = false;
215 param->isFinalTransferInterruptEnabled = false;
216 param->isIntermediateChainingEnabled = false;
217 param->isStaticSet = false;
218 param->linkAddress = EDMA_NULL_LINK_ADDRESS;
220 param->sourceAddress = 0;
221 param->destinationAddress = 0;
223 param->aCount = 0;
225 param->bCount = 0;
226 param->sourceBindex = 0;
227 param->destinationBindex = 0;
228 param->bCountReload = 0;
230 param->cCount = 0;
231 param->sourceCindex = 0;
232 param->destinationCindex = 0;
233 }
236 static int32_t QSPI_edmaChannelConfig(EDMA_Handle hEdma,
237 uint8_t chId,
238 uint8_t queueId,
239 uint8_t xferType)
240 {
241 int32_t status;
242 EDMA_channelConfig_t chConfig;
244 chConfig.channelType = EDMA3_CHANNEL_TYPE_DMA;
245 chConfig.channelId = chId;
246 chConfig.eventQueueId = queueId;
247 chConfig.paramId = chId;
249 QSPI_edmaParamInit(&chConfig.paramSetConfig, chId, xferType);
251 chConfig.paramSetConfig.isFinalTransferInterruptEnabled = false;
253 chConfig.transferCompletionCallbackFxn = NULL;
254 chConfig.transferCompletionCallbackFxnArg = NULL;
256 status = EDMA_configChannel(hEdma, &chConfig,false);
258 return status;
259 }
261 static int32_t QSPI_dmaMemcpy(SPI_Handle handle,
262 uintptr_t destBuf,
263 uintptr_t srcBuf,
264 uint32_t length)
266 {
267 QSPI_HwAttrs const *hwAttrs;
268 EDMA_paramConfig_t paramSet;
269 int32_t cIdx;
270 int32_t status = SPI_STATUS_SUCCESS;
271 int32_t edmaStatus;
273 /* Get the pointer to the hwAttrs */
274 hwAttrs = (QSPI_HwAttrs *)handle->hwAttrs;
276 /* Initialize param set configuration */
277 QSPI_edmaParamInit(¶mSet.paramSetConfig, hwAttrs->edmaChId, EDMA3_SYNC_AB);
279 /* Set source address */
280 paramSet.paramSetConfig.sourceAddress = (uint32_t)srcBuf;
282 /* set destination address */
283 paramSet.paramSetConfig.destinationAddress = (uint32_t)destBuf;
285 /* aCount holds the number of bytes in an array. */
286 paramSet.paramSetConfig.aCount = (uint16_t)1;
288 /*
289 * bCnt holds the number of such arrays to be transferred.
290 * cCnt holds the number of frames of aCnt*bBcnt bytes to be transferred
291 */
292 DebugP_assert (length < 0x8000U);
293 paramSet.paramSetConfig.bCount = (uint16_t)length;
294 paramSet.paramSetConfig.cCount = (uint16_t)1;
295 cIdx = (int32_t)paramSet.paramSetConfig.bCount;
297 /**
298 * Be Careful !!!
299 * Valid values for SRCBIDX/DSTBIDX are between -32768 and 32767
300 * Valid values for SRCCIDX/DSTCIDX are between -32768 and 32767
301 */
302 paramSet.paramSetConfig.sourceBindex = (int32_t)paramSet.paramSetConfig.aCount;
303 paramSet.paramSetConfig.destinationBindex = (int32_t)paramSet.paramSetConfig.aCount;
304 paramSet.paramSetConfig.sourceCindex = cIdx;
305 paramSet.paramSetConfig.destinationCindex = cIdx;
307 /* Linking transfers in EDMA3 are not used. */
308 paramSet.paramSetConfig.linkAddress = EDMA_NULL_LINK_ADDRESS;
310 paramSet.paramSetConfig.bCountReload = paramSet.paramSetConfig.bCount;
312 /* EDMA3_DRV_OPT_FIELD_TCINTEN */
313 paramSet.paramSetConfig.isFinalTransferInterruptEnabled = true;
315 paramSet.transferCompletionCallbackFxn = QSPI_dmaIsrHandler;
316 paramSet.transferCompletionCallbackFxnArg = (uintptr_t)handle;
318 /* Write param set */
319 edmaStatus = EDMA_configParamSet(hwAttrs->edmaHandle,
320 hwAttrs->edmaChId,
321 ¶mSet);
323 if (EDMA_NO_ERROR == edmaStatus)
324 {
325 /* Enable the EDMA channel */
326 edmaStatus = EDMA_enableChannel(hwAttrs->edmaHandle,
327 hwAttrs->edmaChId,
328 EDMA3_CHANNEL_TYPE_DMA);
329 }
331 if (EDMA_NO_ERROR == edmaStatus)
332 {
333 /* Start the transfer */
334 edmaStatus = EDMA_startTransfer(hwAttrs->edmaHandle,
335 hwAttrs->edmaChId,
336 EDMA3_CHANNEL_TYPE_DMA);
337 }
339 if (EDMA_NO_ERROR != edmaStatus)
340 {
341 status = SPI_STATUS_ERROR;
342 }
344 return (status);
345 }