summaryrefslogtreecommitdiffstats
path: root/bsps/arm/atsam/contrib/libraries/libchip/source/qspi_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/atsam/contrib/libraries/libchip/source/qspi_dma.c')
-rw-r--r--bsps/arm/atsam/contrib/libraries/libchip/source/qspi_dma.c619
1 files changed, 619 insertions, 0 deletions
diff --git a/bsps/arm/atsam/contrib/libraries/libchip/source/qspi_dma.c b/bsps/arm/atsam/contrib/libraries/libchip/source/qspi_dma.c
new file mode 100644
index 0000000000..12e217ebf0
--- /dev/null
+++ b/bsps/arm/atsam/contrib/libraries/libchip/source/qspi_dma.c
@@ -0,0 +1,619 @@
+/* ---------------------------------------------------------------------------- */
+/* Atmel Microcontroller Software Support */
+/* SAM Software Package License */
+/* ---------------------------------------------------------------------------- */
+/* Copyright (c) 2015, Atmel Corporation */
+/* */
+/* All rights reserved. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following condition is met: */
+/* */
+/* - Redistributions of source code must retain the above copyright notice, */
+/* this list of conditions and the disclaimer below. */
+/* */
+/* Atmel's name may not be used to endorse or promote products derived from */
+/* this software without specific prior written permission. */
+/* */
+/* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */
+/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */
+/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */
+/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
+/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */
+/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
+/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
+/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+/* ---------------------------------------------------------------------------- */
+
+/**
+ * \addtogroup qspi_dma_module QSPI xDMA driver
+ * \ingroup peripherals_module
+ *
+ *
+ */
+
+/**
+ * \file
+ *
+ * Implementation for the SPI Flash with xDMA driver.
+ *
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "chip.h"
+#ifdef __rtems__
+#include "../../../utils/utility.h"
+#endif /* __rtems__ */
+
+/*----------------------------------------------------------------------------
+ * Definitions
+ *----------------------------------------------------------------------------*/
+
+/** xDMA support */
+
+/** xDMA Link List size for SPI transmission*/
+#define DMA_QSPI_LLI 2
+
+/*-----------------------------------------------------------------------------
+ * QSPI DMA Local functions
+ *----------------------------------------------------------------------------*/
+
+/**
+ * \brief SPI xDMA Rx callback
+ * Invoked on SPi DMA reception done.
+ * \param channel DMA channel.
+ * \param pArg Pointer to callback argument - Pointer to Spid instance.
+ */
+static void QSPID_Spi_Cb(uint32_t channel, QspiDma_t *pArg)
+{
+ Qspi *pQspiHw = pArg->Qspid.pQspiHw;
+
+ if (channel != pArg->RxChNum)
+ return;
+
+ /* Release the semaphore */
+ ReleaseMutex(pArg->progress);
+ QSPI_EndTransfer(pQspiHw);
+ SCB_InvalidateDCache_by_Addr((uint32_t *)pArg->Qspid.qspiBuffer.pDataRx,
+ pArg->Qspid.qspiBuffer.RxDataSize);
+ memory_sync();
+}
+
+
+/**
+ * \brief QSPI xDMA Tx callback
+ * Invoked on QSPi DMA Write done.
+ * \param channel DMA channel.
+ * \param pArg Pointer to callback argument - Pointer to Spid instance.
+ */
+static void QSPID_qspiTx_Cb(uint32_t channel, QspiDma_t *pArg)
+{
+ Qspi *pQspiHw = pArg->Qspid.pQspiHw;
+
+ if (channel != pArg->TxChNum)
+ return;
+
+ /* Release the semaphore */
+ ReleaseMutex(pArg->progress);
+ QSPI_EndTransfer(pQspiHw);
+
+ while (!QSPI_GetStatus(pArg->Qspid.pQspiHw, IsEofInst));
+
+ memory_sync();
+}
+
+
+/**
+ * \brief QSPI xDMA Rx callback
+ * Invoked on SPi DMA reception done.
+ * \param channel DMA channel.
+ * \param pArg Pointer to callback argument - Pointer to Spid instance.
+ */
+static void QSPID_qspiRx_Cb(uint32_t channel, QspiDma_t *pArg)
+{
+ Qspi *pQspiHw = pArg->Qspid.pQspiHw;
+
+ if (channel != pArg->RxChNum)
+ return;
+
+ /* Release the semaphore */
+ ReleaseMutex(pArg->progress);
+ QSPI_EndTransfer(pQspiHw);
+
+ while (!QSPI_GetStatus(pArg->Qspid.pQspiHw, IsEofInst));
+
+ SCB_InvalidateDCache_by_Addr((uint32_t *)pArg->Qspid.qspiBuffer.pDataRx,
+ pArg->Qspid.qspiBuffer.RxDataSize);
+ memory_sync();
+}
+
+/**
+ * \brief Configures the DMA for QSPI
+ *
+ * \param pQspidma Pointer to QSPI DMA structure
+ * \param Addr Address to Read or write of QSPI flash memory
+ * \param pBuffer Pointer input/output buffer
+ * \param ReadWrite Read or write memory flag
+ * \returns 0 if the dma multibuffer configuration successfully; otherwise returns
+ * QSPID_ERROR_XXX.
+ */
+static uint8_t QSPID_configureQpsiDma(QspiDma_t *pQspidma, uint32_t Addr,
+ QspiBuffer_t *pBuffer, Access_t const ReadWrite)
+{
+ sXdmadCfg xdmadCfg, xdmadRxCfg, xdmadTxCfg;
+ uint8_t chanNum;
+ uint8_t qspi_id = pQspidma->Qspid.qspiId;
+ Qspi *pQspiHw = pQspidma->Qspid.pQspiHw;
+ uint32_t xdmaCndc, xdmaInt, BurstSize, ChannelWidth;
+
+
+ /* Setup DMA for QSPI */
+
+ if (pQspidma->Qspid.qspiMode == QSPI_MR_SMM_SPI) {
+ // SPI mode
+ /* SPI TX DMA config */
+ xdmadTxCfg.mbr_sa = (uint32_t)pBuffer->pDataTx;
+ xdmadTxCfg.mbr_da = (uint32_t)&pQspiHw->QSPI_TDR;
+ xdmadTxCfg.mbr_ubc = (pBuffer->TxDataSize);
+
+ xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
+ XDMAC_CC_MBSIZE_SINGLE |
+ XDMAC_CC_DSYNC_MEM2PER |
+ XDMAC_CC_CSIZE_CHK_1 |
+ XDMAC_CC_DWIDTH_BYTE |
+ XDMAC_CC_SIF_AHB_IF0 |
+ XDMAC_CC_DIF_AHB_IF1 |
+ XDMAC_CC_SAM_INCREMENTED_AM |
+ XDMAC_CC_DAM_FIXED_AM |
+ XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber
+ (qspi_id, XDMAD_TRANSFER_TX));
+
+ xdmadTxCfg.mbr_bc = 0;
+ xdmadTxCfg.mbr_sus = 0;
+ xdmadTxCfg.mbr_dus = 0;
+
+ /* SPI RX DMA config */
+
+ xdmadRxCfg.mbr_da = (uint32_t)pBuffer->pDataRx;
+ xdmadRxCfg.mbr_sa = (uint32_t)&pQspiHw->QSPI_RDR;
+ xdmadRxCfg.mbr_ubc = (pBuffer->RxDataSize);
+ xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
+ XDMAC_CC_MBSIZE_SINGLE |
+ XDMAC_CC_DSYNC_PER2MEM |
+ XDMAC_CC_CSIZE_CHK_1 |
+ XDMAC_CC_DWIDTH_BYTE |
+ XDMAC_CC_SIF_AHB_IF1 |
+ XDMAC_CC_DIF_AHB_IF0 |
+ XDMAC_CC_SAM_FIXED_AM |
+ XDMAC_CC_DAM_INCREMENTED_AM |
+ XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber
+ (qspi_id, XDMAD_TRANSFER_RX));
+
+ xdmadRxCfg.mbr_bc = 0;
+ xdmadRxCfg.mbr_sus = 0;
+ xdmadRxCfg.mbr_dus = 0;
+ xdmaCndc = 0;
+ /* Put all interrupts on for non LLI list setup of DMA */
+ xdmaInt = (XDMAC_CIE_BIE |
+ XDMAC_CIE_RBIE |
+ XDMAC_CIE_WBIE |
+ XDMAC_CIE_ROIE);
+
+ memory_barrier();
+
+ if (XDMAD_ConfigureTransfer
+ (pQspidma->pXdmad, pQspidma->RxChNum, &xdmadRxCfg, xdmaCndc, 0, xdmaInt))
+ return QSPID_ERROR;
+
+ if (XDMAD_ConfigureTransfer
+ (pQspidma->pXdmad, pQspidma->TxChNum, &xdmadTxCfg, xdmaCndc, 0, xdmaInt))
+ return QSPID_ERROR;
+
+ return 0;
+
+ } else {
+ if (ReadWrite == WriteAccess) {
+ xdmadCfg.mbr_sa = (uint32_t)pBuffer->pDataTx;
+ xdmadCfg.mbr_da = (uint32_t)(QSPIMEM_ADDR | Addr);
+ xdmadCfg.mbr_ubc = (pBuffer->TxDataSize);
+ chanNum = pQspidma->TxChNum;
+ ChannelWidth = XDMAC_CC_DWIDTH_BYTE;
+ BurstSize = XDMAC_CC_MBSIZE_SIXTEEN;
+ } else if (ReadWrite == ReadAccess) {
+ xdmadCfg.mbr_da = (uint32_t)pBuffer->pDataRx;
+ xdmadCfg.mbr_sa = (uint32_t)(QSPIMEM_ADDR | Addr);
+ xdmadCfg.mbr_ubc = ((pBuffer->RxDataSize >> 2));
+ chanNum = pQspidma->RxChNum;
+ ChannelWidth = XDMAC_CC_DWIDTH_WORD;
+ BurstSize = XDMAC_CC_MBSIZE_SIXTEEN;
+ } else {
+ TRACE_ERROR(" QSPI error \n\r");
+ return 1;
+ }
+
+ xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_MEM_TRAN |
+ XDMAC_CC_MEMSET_NORMAL_MODE |
+ BurstSize |
+ ChannelWidth |
+ XDMAC_CC_SIF_AHB_IF1 |
+ XDMAC_CC_DIF_AHB_IF1 |
+ XDMAC_CC_SAM_INCREMENTED_AM |
+ XDMAC_CC_DAM_INCREMENTED_AM;
+
+ xdmadCfg.mbr_bc = 0;
+ xdmadCfg.mbr_sus = 0;
+ xdmadCfg.mbr_dus = 0;
+
+ xdmaCndc = 0;
+
+
+ /* Put all interrupts on for non LLI list setup of DMA */
+ xdmaInt = (XDMAC_CIE_BIE |
+ XDMAC_CIE_RBIE |
+ XDMAC_CIE_WBIE |
+ XDMAC_CIE_ROIE);
+
+ memory_barrier();
+
+ if (XDMAD_ConfigureTransfer(pQspidma->pXdmad, chanNum, &xdmadCfg, xdmaCndc, 0,
+ xdmaInt))
+ return QSPID_ERROR;
+
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * Exported functions
+ *----------------------------------------------------------------------------*/
+/**
+ * \brief Initializes the pQspidma structure and the corresponding QSPI & DMA .
+ * hardware select value.
+ *
+ * \param pQspidma Pointer to a QspiDma_t instance.
+ * \param Mode Associated SPI peripheral.
+ * \param dwConf QSPI peripheral configuration.
+ * \param pXdmad Pointer to a Xdmad instance.
+ */
+uint32_t QSPID_Configure(QspiDma_t *pQspidma, QspiMode_t Mode,
+ uint32_t dwConf, sXdmad *pXdmad)
+{
+ /* Initialize the QSPI structure */
+
+ QSPI_ConfigureInterface(&pQspidma->Qspid, Mode, dwConf);
+
+ pQspidma->Qspid.qspiCommand.Instruction = 0;
+ pQspidma->Qspid.qspiCommand.Option = 0;
+
+ pQspidma->RxChNum = QSPID_CH_NOT_ENABLED;
+ pQspidma->TxChNum = QSPID_CH_NOT_ENABLED;
+
+ assert(pXdmad == &XDMAD_Instance);
+ pQspidma->pXdmad = pXdmad;
+
+ return QSPI_SUCCESS;
+}
+
+
+
+/**
+ * \brief Enables a QSPI Rx channel. This function will allocate a dma Rx
+ * channel for QSPI
+ *
+ * \param pQspidma Pointer to a Spid instance.
+
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is not
+ * valid.
+ */
+uint32_t QSPID_EnableQspiRxChannel(QspiDma_t *pQspidma)
+{
+ static uint16_t DmaChannel;
+
+ /* Try to get the semaphore */
+ if (pQspidma->RxChNum != QSPID_CH_NOT_ENABLED)
+ return QSPID_ERROR_LOCK;
+
+ /* Allocate a DMA channel */
+ DmaChannel = XDMAD_AllocateChannel(
+ pQspidma->pXdmad, XDMAD_TRANSFER_MEMORY, XDMAD_TRANSFER_MEMORY);
+
+ if (DmaChannel == XDMAD_ALLOC_FAILED)
+ return QSPID_ERROR;
+
+ pQspidma->RxChNum = DmaChannel;
+ /* Setup callbacks*/
+ XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum,
+ (XdmadTransferCallback)QSPID_qspiRx_Cb, pQspidma);
+
+ if (XDMAD_PrepareChannel(pQspidma->pXdmad, pQspidma->RxChNum))
+ return QSPID_ERROR;
+
+ return 0;
+}
+
+
+/**
+ * \brief Enables a QSPI Tx channel. This function will allocate a dma Tx
+ * channel for QSPI
+ *
+ * \param pQspidma Pointer to a Spid instance.
+
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is
+ * not valid.
+ */
+uint32_t QSPID_EnableQspiTxChannel(QspiDma_t *pQspidma)
+{
+ static uint16_t DmaChannel;
+
+ /* Try to get the semaphore */
+ if (pQspidma->TxChNum != QSPID_CH_NOT_ENABLED)
+ return QSPID_ERROR_LOCK;
+
+ /* Allocate a DMA channel */
+ DmaChannel = XDMAD_AllocateChannel(pQspidma->pXdmad,
+ XDMAD_TRANSFER_MEMORY, XDMAD_TRANSFER_MEMORY);
+
+ if (DmaChannel == XDMAD_ALLOC_FAILED)
+ return QSPID_ERROR;
+
+ pQspidma->TxChNum = DmaChannel;
+ /* Setup callbacks */
+ XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->TxChNum,
+ (XdmadTransferCallback)QSPID_qspiTx_Cb, pQspidma);
+
+ if (XDMAD_PrepareChannel(pQspidma->pXdmad, pQspidma->TxChNum))
+ return QSPID_ERROR;
+
+ return 0;
+}
+
+
+/**
+ * \brief Enables a QSPI SPI Rx channel. This function will allocate a dma
+ * Rx channel for QSPI SPI mode
+ *
+ * \param pQspidma Pointer to a Spid instance.
+
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is
+ * not valid.
+ */
+uint32_t QSPID_EnableSpiChannel(QspiDma_t *pQspidma)
+{
+ static uint16_t DmaChannel;
+
+ /* Try to get the semaphore */
+ if (pQspidma->RxChNum != QSPID_CH_NOT_ENABLED)
+ return QSPID_ERROR_LOCK;
+
+ /* Try to get the semaphore */
+ if (pQspidma->TxChNum != QSPID_CH_NOT_ENABLED)
+ return QSPID_ERROR_LOCK;
+
+ /* Allocate a DMA channel */
+ DmaChannel = XDMAD_AllocateChannel
+ (pQspidma->pXdmad, pQspidma->Qspid.qspiId, XDMAD_TRANSFER_MEMORY);
+
+ if (DmaChannel == XDMAD_ALLOC_FAILED)
+ return QSPID_ERROR;
+
+ pQspidma->RxChNum = DmaChannel;
+
+ /* Allocate a DMA channel */
+ DmaChannel = XDMAD_AllocateChannel(pQspidma->pXdmad,
+ XDMAD_TRANSFER_MEMORY, pQspidma->Qspid.qspiId);
+
+ if (DmaChannel == XDMAD_ALLOC_FAILED)
+ return QSPID_ERROR;
+
+ pQspidma->TxChNum = DmaChannel;
+
+ /* Setup callbacks*/
+ XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum,
+ (XdmadTransferCallback)QSPID_Spi_Cb, pQspidma);
+
+ if (XDMAD_PrepareChannel(pQspidma->pXdmad, pQspidma->RxChNum))
+ return QSPID_ERROR;
+
+ /* Setup callbacks for SPI0/1 TX (ignored) */
+ XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->TxChNum, NULL, NULL);
+
+ if (XDMAD_PrepareChannel(pQspidma->pXdmad, pQspidma->TxChNum))
+ return QSPID_ERROR;
+
+ return 0;
+}
+
+
+/**
+ * \brief Disables a QSPI Rx channel. This function will de-allocate previous
+ * allocated dma Rx channel for QSPI
+ *
+ * \param pQspidma Pointer to a Spid instance.
+
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is
+ * not valid.
+ */
+uint32_t QSPID_DisableQspiRxChannel(QspiDma_t *pQspidma)
+{
+
+ XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->RxChNum);
+ XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->RxChNum);
+
+ XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum, NULL, NULL);
+
+
+ /* Free allocated DMA channel for QSPI RX. */
+ XDMAD_FreeChannel(pQspidma->pXdmad, pQspidma->RxChNum);
+
+ pQspidma->RxChNum = QSPID_CH_NOT_ENABLED;
+
+ return 0;
+}
+
+
+
+/**
+ * \brief Disables a QSPI Tx channel. This function will de-allocate previous
+ * allocated dma Tx channel for QSPI
+ *
+ * \param pQspidma Pointer to a Spid instance.
+
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is
+ * not valid.
+ */
+uint32_t QSPID_DisableQspiTxChannel(QspiDma_t *pQspidma)
+{
+
+ XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->TxChNum);
+ XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->TxChNum);
+
+ XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->TxChNum, NULL, NULL);
+
+ /* Free allocated DMA channel for QSPI TX. */
+ XDMAD_FreeChannel(pQspidma->pXdmad, pQspidma->TxChNum);
+
+ pQspidma->TxChNum = QSPID_CH_NOT_ENABLED;
+
+ return 0;
+}
+
+
+/**
+ * \brief Disables a QSPI SPI Rx and Tx channels. This function will
+ * de-allocate privious allocated dma Rx, Txchannel for QSPI in SPI mode
+ *
+ * \param pQspidma Pointer to a Spid instance.
+
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is
+ * not valid.
+ */
+uint32_t QSPID_DisableSpiChannel(QspiDma_t *pQspidma)
+{
+
+ XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->RxChNum);
+ //XDMAC_SoftwareFlushReq(pQspidma->pXdmad->pXdmacs, pQspidma->TxChNum);
+ XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->RxChNum);
+ XDMAD_StopTransfer(pQspidma->pXdmad, pQspidma->TxChNum);
+
+ XDMAD_SetCallback(pQspidma->pXdmad, pQspidma->RxChNum, NULL, NULL);
+
+ /* Free allocated DMA channel for QSPI RX. */
+ XDMAD_FreeChannel(pQspidma->pXdmad, pQspidma->RxChNum);
+
+ XDMAD_FreeChannel(pQspidma->pXdmad, pQspidma->TxChNum);
+
+ pQspidma->RxChNum = QSPID_CH_NOT_ENABLED;
+ pQspidma->TxChNum = QSPID_CH_NOT_ENABLED;
+
+ return 0;
+}
+
+
+/**
+ * \brief Starts a QSPI read or write operation.
+ *
+ * \param pQspidma Pointer to a Qspid instance.
+ * \param ReadWrite Defines the memory access type
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * QSPID_ERROR_LOCK is the driver is in use, or QSPID_ERROR if the command is
+ * not valid.
+ */
+uint32_t QSPID_ReadWriteQSPI(QspiDma_t *pQspidma, Access_t const ReadWrite)
+{
+ QspiBuffer_t *pBuffer = &pQspidma->Qspid.qspiBuffer;
+ uint8_t chanNum;
+ uint32_t semTimer = 0x7FF;
+
+ //assert(pBuffer->pDataTx);
+
+ if (pQspidma->progress)
+ return QSPID_ERROR_LOCK;
+
+ LockMutex(pQspidma->progress, semTimer);
+
+ if (QSPID_configureQpsiDma
+ (pQspidma, pQspidma->Qspid.pQspiFrame->Addr, pBuffer, ReadWrite))
+ return QSPID_ERROR_LOCK;
+
+ if (ReadWrite == WriteAccess) {
+ chanNum = pQspidma->TxChNum;
+ SCB_CleanDCache_by_Addr((uint32_t *)pBuffer->pDataTx, pBuffer->TxDataSize);
+ } else {
+ if (ReadWrite != ReadAccess)
+ TRACE_ERROR("%s QSPI Access Error\n\r", __FUNCTION__);
+ chanNum = pQspidma->RxChNum;
+ }
+
+ /* Start DMA 0(RX) && 1(TX) */
+ if (XDMAD_StartTransfer(pQspidma->pXdmad, chanNum))
+ return QSPID_ERROR_LOCK;
+
+ return 0;
+}
+
+/**
+ * \brief Starts a SPI master transfer. This is a non blocking function. It will
+ * return as soon as the transfer is started.
+ *
+ * \param pSpid Pointer to a Spid instance.
+ * \param pCommand Pointer to the SPI command to execute.
+ * \returns 0 if the transfer has been started successfully; otherwise returns
+ * SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not
+ * valid.
+ */
+uint32_t QSPID_ReadWriteSPI(QspiDma_t *pQspidma, Access_t const ReadWrite)
+{
+ QspiBuffer_t *pBuffer = &pQspidma->Qspid.qspiBuffer;
+ uint32_t semTimer = 0x7FF;
+
+ assert(pBuffer->pDataRx);
+ assert(pBuffer->pDataTx);
+
+ /* Try to get the dataflash semaphore */
+ if (pQspidma->progress)
+
+ return QSPID_ERROR_LOCK;
+
+ LockMutex(pQspidma->progress, semTimer);
+
+ if (QSPID_configureQpsiDma
+ (pQspidma, pQspidma->Qspid.pQspiFrame->Addr, pBuffer, ReadWrite))
+ return QSPID_ERROR_LOCK;
+
+ SCB_CleanDCache_by_Addr((uint32_t *)pBuffer->pDataTx, pBuffer->TxDataSize);
+
+ /* Start DMA 0(RX) && 1(TX) */
+ if (XDMAD_StartTransfer(pQspidma->pXdmad, pQspidma->RxChNum))
+ return QSPID_ERROR_LOCK;
+
+ if (XDMAD_StartTransfer(pQspidma->pXdmad, pQspidma->TxChNum))
+ return QSPID_ERROR_LOCK;
+
+ return 0;
+}
+
+/**
+ * \brief Check if the QSPI driver is busy.
+ *
+ * \param pSpid Pointer to a Spid instance.
+ * \returns 1 if the SPI driver is currently busy executing a command; otherwise
+ */
+uint32_t QSPID_IsBusy(volatile uint8_t *QspiSemaphore)
+{
+ if (Is_LockFree(QspiSemaphore))
+ return 1;
+ else
+ return 0;
+}