]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/pdk.git/blob - packages/ti/drv/spi/soc/dma/v3/QSPI_dma.c
uniflash/tpr12: Add support for ROM flow
[processor-sdk/pdk.git] / packages / ti / drv / spi / soc / dma / v3 / QSPI_dma.c
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)
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);
150 int32_t QSPI_dmaFreeChannel(SPI_Handle handle)
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);
171 static void QSPI_dmaIsrHandler (uintptr_t appData, uint8_t tcc)
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     }
202 static void QSPI_edmaParamInit(EDMA_paramSetConfig_t *param, uint8_t tcc, uint8_t xferType)
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;
236 static int32_t QSPI_edmaChannelConfig(EDMA_Handle hEdma,
237                                       uint8_t chId,
238                                       uint8_t queueId,
239                                       uint8_t xferType)
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;
261 static int32_t QSPI_dmaMemcpy(SPI_Handle     handle,
262                               uintptr_t      destBuf,
263                               uintptr_t      srcBuf,
264                               uint32_t       length)
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(&paramSet.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                                      &paramSet);
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);