add DMA support to QSPI; tested. Updated Kconfig to more cleanly present the options and defaults.

This commit is contained in:
ziggurat29 2016-04-24 16:28:30 -05:00
parent 0f8dc3e7b4
commit 8d4dccb3b9
3 changed files with 623 additions and 61 deletions

View File

@ -79,7 +79,7 @@ config STM32L4_HAVE_LTDC
default n
# These "hidden" settings are the OR of individual peripheral selections
# indicating that the general capabilitiy is required.
# indicating that the general capability is required.
config STM32L4_ADC
bool
@ -133,7 +133,6 @@ config STM32L4_DMA2
select STM32L4_DMA
select ARCH_DMA
config STM32L4_CRC
bool "CRC"
default n
@ -209,7 +208,119 @@ config STM32L4_QSPI_CSHT
---help---
The STM32L4 QSPI peripheral requires that it be specified the minimum number
of AHB cycles that Chip Select be held inactive between transactions.
choice
prompt "Transfer technique"
default STM32L4_QSPI_DMA
---help---
You can choose between using polling, interrupts, or DMA to transfer data
over the QSPI interface.
config STM32L4_QSPI_POLLING
bool "Polling"
---help---
Use conventional register I/O with status polling to transfer data.
config STM32L4_QSPI_INTERRUPTS
bool "Interrupts"
---help---
User interrupt driven I/O transfers.
config STM32L4_QSPI_DMA
bool "DMA"
depends on STM32L4_DMA
---help---
Use DMA to improve QSPI transfer performance.
endchoice
choice
prompt "DMA Channel"
default STM32L4_QSPI_DMA_CHAN_1_5
depends on STM32L4_DMA
---help---
You can choose between two DMA channels for use with QSPI:
either DMA1 channel 5, or DMA2 channel 7.
If you only see one choice here, it is probably because
you have not also enabled the associated DMA controller.
config STM32L4_QSPI_DMA_CHAN_1_5
bool "DMA1 Channel 5"
depends on STM32L4_DMA1
---help---
Use DMA1 channel 5 for QSPI.
config STM32L4_QSPI_DMA_CHAN_2_7
bool "DMA2 Channel 7"
depends on STM32L4_DMA2
---help---
Use DMA2 channel 7 for QSPI.
endchoice
choice
prompt "DMA Priority"
default STM32L4_QSPI_DMAPRIORITY_MEDIUM
depends on STM32L4_DMA
---help---
The DMA controller supports priority levels. You are probably fine
with the default of 'medium' except for special cases. In the event
of contention between to channels at the same priority, the lower
numbered channel has hardware priority over the higher numbered one.
config STM32L4_QSPI_DMAPRIORITY_VERYHIGH
bool "Very High priority"
depends on STM32L4_DMA
---help---
'Highest' priority.
config STM32L4_QSPI_DMAPRIORITY_HIGH
bool "High priority"
depends on STM32L4_DMA
---help---
'High' priority.
config STM32L4_QSPI_DMAPRIORITY_MEDIUM
bool "Medium priority"
depends on STM32L4_DMA
---help---
'Medium' priority.
config STM32L4_QSPI_DMAPRIORITY_LOW
bool "Low priority"
depends on STM32L4_DMA
---help---
'Low' priority.
endchoice
config STM32L4_QSPI_DMATHRESHOLD
int "QSPI DMA threshold"
default 4
depends on STM32L4_QSPI_DMA
---help---
When QSPI DMA is enabled, small DMA transfers will still be performed
by polling logic. This value is the threshold below which transfers
will still be performed by conventional register status polling.
config STM32L4_QSPI_DMADEBUG
bool "QSPI DMA transfer debug"
depends on STM32L4_QSPI_DMA && DEBUG && DEBUG_DMA
default n
---help---
Enable special debug instrumentation to analyze QSPI DMA data transfers.
This logic is as non-invasive as possible: It samples DMA
registers at key points in the data transfer and then dumps all of
the registers at the end of the transfer.
config STM32L4_QSPI_REGDEBUG
bool "QSPI Register level debug"
depends on DEBUG
default n
---help---
Output detailed register-level QSPI device debug information.
Requires also DEBUG.
endif
comment "APB1 Peripherals"

View File

@ -23,13 +23,13 @@ LSE : works, but TODO autotrim of MSI, etc
RCC : All registers defined, peripherals enabled, basic clock working
SYSCTL : All registers defined
USART : Working in normal mode (no DMA, to be tested, code is written)
DMA : Ported from STM32, code written, to be tested
DMA : works; at least tested with QSPI
SRAM2 : Should work with enough MM regions
FIREWALL : Code written, to be tested, requires support from ldscript
SPI : Code written, to be tested, including DMA
I2C : Registers defined
RTC : works
QSPI : TODO (port from stm32f7)
QSPI : works in polling, interrupt, DMA, and also memory-mapped modes
CAN : TODO
OTGFS : TODO
Timers : TODO

View File

@ -120,18 +120,12 @@
#define DMA_END_TRANSFER 4
#define DMA_NSAMPLES 5
#ifdef CONFIG_STM32L4_QSPI_DMA
# error QSPI DMA support not yet implemented
/* Can't have both interrupt-driven QSPI and DMA QSPI */
#if defined(STM32L4_QSPI_INTERRUPTS) && defined(CONFIG_STM32L4_QSPI_DMA)
# error "Cannot enable both interrupt mode and DMA mode for QSPI"
#endif
/* QSPI dma is not yet implemented */
#undef CONFIG_STM32L4_QSPI_DMA
/* QSPI Interrupt mode is implemented */
#define QSPI_USE_INTERRUPTS
/* Sanity check that board.h defines requisite QSPI pinmap options for */
#if (!defined(GPIO_QSPI_CS) || !defined(GPIO_QSPI_IO0) || !defined(GPIO_QSPI_IO1) || \
@ -141,9 +135,27 @@
#endif
#ifdef CONFIG_STM32L4_QSPI_DMA
# if !defined(DMACHAN_QUADSPI)
# if defined(CONFIG_STM32L4_QSPI_DMA_CHAN_1_5)
# define DMACHAN_QUADSPI DMACHAN_QUADSPI_1
# elif defined(CONFIG_STM32L4_QSPI_DMA_CHAN_2_7)
# define DMACHAN_QUADSPI DMACHAN_QUADSPI_2
# else
# error QSPI DMA channel must be specified via DMACHAN_QUADSPI in your board.h
# endif
# if defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_LOW)
# define QSPI_DMA_PRIO DMA_CCR_PRILO
# elif defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_MEDIUM)
# define QSPI_DMA_PRIO DMA_CCR_PRIMED
# elif defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_HIGH)
# define QSPI_DMA_PRIO DMA_CCR_PRIHI
# elif defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_VERYHIGH)
# define QSPI_DMA_PRIO DMA_CCR_PRIVERYHI
# else
# define QSPI_DMA_PRIO DMA_CCR_PRIMED
# endif
#endif
#ifndef BOARD_AHB_FREQUENCY
@ -154,6 +166,13 @@
# error you must specify a positive flash size via CONFIG_STM32L4_QSPI_FLASH_SIZE
#endif
/* DMA timeout. The value is not critical; we just don't want the system to
* hang in the event that a DMA does not finish.
*/
#define DMA_TIMEOUT_MS (800)
#define DMA_TIMEOUT_TICKS MSEC2TICK(DMA_TIMEOUT_MS)
/* Clocking *****************************************************************/
/* The QSPI bit rate clock is generated by dividing the peripheral clock by
* a value between 1 and 255
@ -184,7 +203,7 @@ struct stm32l4_qspidev_s
sem_t exclsem; /* Assures mutually exclusive access to QSPI */
bool memmap; /* TRUE: Controller is in memory mapped mode */
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
xcpt_t handler; /* Interrupt handler */
uint8_t irq; /* Interrupt number */
sem_t op_sem; /* Block until complete */
@ -192,7 +211,11 @@ struct stm32l4_qspidev_s
#endif
#ifdef CONFIG_STM32L4_QSPI_DMA
/* XXX III needs implementation */
bool candma; /* DMA is supported */
sem_t dmawait; /* Used to wait for DMA completion */
int result; /* DMA result */
DMA_HANDLE dmach; /* QSPI DMA handle */
WDOG_ID dmadog; /* Watchdog that handles DMA timeouts */
#endif
/* Debug stuff */
@ -238,7 +261,7 @@ struct qspi_xctnspec_s
uint8_t isddr; /* true if 'double data rate' */
uint8_t issioo; /* true if 'send instruction only once' mode */
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
uint8_t function; /* functional mode; to distinguish a read or write */
int8_t disposition; /* how it all turned out */
uint32_t idxnow; /* index into databuffer of current byte in transfer */
@ -277,11 +300,37 @@ static void qspi_dumpgpioconfig(const char *msg);
/* Interrupts */
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
static int qspi0_interrupt(int irq, void *context);
#endif
/* DMA support */
#ifdef CONFIG_STM32L4_QSPI_DMA
# if defined(CONFIG_QSPI_DMAPRIO)
# define QSPI_DMA_PRIO CONFIG_QSPI_DMAPRIO
# else
# define QSPI_DMA_PRIO DMA_CCR_PRIMED
# endif
# ifdef CONFIG_STM32L4_QSPI_DMADEBUG
# define qspi_dma_sample(s,i) stm32l4_dmasample((s)->dmach, &(s)->dmaregs[i])
static void qspi_dma_sampleinit(struct stm32l4_qspidev_s *priv);
static void qspi_dma_sampledone(struct stm32l4_qspidev_s *priv);
# else
# define qspi_dma_sample(s,i)
# define qspi_dma_sampleinit(s)
# define qspi_dma_sampledone(s)
# endif
# ifndef CONFIG_STM32L4_QSPI_DMATHRESHOLD
# define CONFIG_STM32L4_QSPI_DMATHRESHOLD 4
# endif
#endif
/* QSPI methods */
static int qspi_lock(struct qspi_dev_s *dev, bool lock);
@ -326,13 +375,13 @@ static struct stm32l4_qspidev_s g_qspi0dev =
.ops = &g_qspi0ops,
},
.base = STM32L4_QSPI_BASE,
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
.handler = qspi0_interrupt,
.irq = STM32L4_IRQ_QUADSPI,
#endif
.intf = 0,
#ifdef CONFIG_STM32L4_QSPI_DMA
/* XXX III needs implementation */
.candma = true,
#endif
};
@ -572,6 +621,93 @@ static void qspi_dumpgpioconfig(const char *msg)
}
#endif
#ifdef CONFIG_STM32L4_QSPI_DMADEBUG
/****************************************************************************
* Name: qspi_dma_sampleinit
*
* Description:
* Initialize sampling of DMA registers
*
* Input Parameters:
* priv - QSPI driver instance
*
* Returned Value:
* None
*
****************************************************************************/
static void qspi_dma_sampleinit(struct stm32l4_qspidev_s *priv)
{
/* Put contents of register samples into a known state */
memset(priv->dmaregs, 0xff, DMA_NSAMPLES * sizeof(struct stm32l4_dmaregs_s));
/* Then get the initial samples */
stm32l4_dmasample(priv->dmach, &priv->dmaregs[DMA_INITIAL]);
}
/****************************************************************************
* Name: qspi_dma_sampledone
*
* Description:
* Dump sampled DMA registers
*
* Input Parameters:
* priv - QSPI driver instance
*
* Returned Value:
* None
*
****************************************************************************/
static void qspi_dma_sampledone(struct stm32l4_qspidev_s *priv)
{
/* Sample the final registers */
stm32l4_dmasample(priv->dmach, &priv->dmaregs[DMA_END_TRANSFER]);
/* Then dump the sampled DMA registers */
/* Initial register values */
stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_INITIAL],
"Initial Registers");
/* Register values after DMA setup */
stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_AFTER_SETUP],
"After DMA Setup");
/* Register values after DMA start */
stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_AFTER_START],
"After DMA Start");
/* Register values at the time of the TX and RX DMA callbacks
* -OR- DMA timeout.
*
* If the DMA timed out, then there will not be any RX DMA
* callback samples. There is probably no TX DMA callback
* samples either, but we don't know for sure.
*/
if (priv->result == -ETIMEDOUT)
{
stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_TIMEOUT],
"At DMA timeout");
}
else
{
stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_CALLBACK],
"At DMA callback");
}
stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_END_TRANSFER],
"At End-of-Transfer");
}
#endif
/****************************************************************************
* Name: qspi_setupxctnfromcmd
*
@ -687,7 +823,7 @@ static int qspi_setupxctnfromcmd(struct qspi_xctnspec_s *xctn,
xctn->isddr = 0;
}
#if defined(QSPI_USE_INTERRUPTS)
#if defined(STM32L4_QSPI_INTERRUPTS)
xctn->function = QSPICMD_ISWRITE(cmdinfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD;
xctn->disposition = - EIO;
xctn->idxnow = 0;
@ -816,7 +952,7 @@ static int qspi_setupxctnfrommem(struct qspi_xctnspec_s *xctn,
xctn->isddr = 0;
#if defined(QSPI_USE_INTERRUPTS)
#if defined(STM32L4_QSPI_INTERRUPTS)
xctn->function = QSPIMEM_ISWRITE(meminfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD;
xctn->disposition = - EIO;
xctn->idxnow = 0;
@ -938,7 +1074,7 @@ static void qspi_ccrconfig(struct stm32l4_qspidev_s *priv,
}
}
#if defined(QSPI_USE_INTERRUPTS)
#if defined(STM32L4_QSPI_INTERRUPTS)
/****************************************************************************
* Name: qspi0_interrupt
*
@ -1146,9 +1282,267 @@ static int qspi0_interrupt(int irq, void *context)
}
#elif defined(CONFIG_STM32L4_QSPI_DMA)
/* XXX III dma mode */
/****************************************************************************
* Name: qspi_dma_timeout
*
* Description:
* The watchdog timeout setup when a has expired without completion of a
* DMA.
*
* Input Parameters:
* argc - The number of arguments (should be 1)
* arg - The argument (state structure reference cast to uint32_t)
*
* Returned Value:
* None
*
* Assumptions:
* Always called from the interrupt level with interrupts disabled.
*
****************************************************************************/
#else
static void qspi_dma_timeout(int argc, uint32_t arg)
{
struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)arg;
DEBUGASSERT(priv != NULL);
/* Sample DMA registers at the time of the timeout */
qspi_dma_sample(priv, DMA_CALLBACK);
/* Report timeout result, perhaps overwriting any failure reports from
* the TX callback.
*/
priv->result = -ETIMEDOUT;
/* Then wake up the waiting thread */
sem_post(&priv->dmawait);
}
/****************************************************************************
* Name: qspi_dma_callback
*
* Description:
* This callback function is invoked at the completion of the QSPI DMA.
*
* Input Parameters:
* handle - The DMA handler
* isr - source of the DMA interrupt
* arg - A pointer to the chip select structure
*
* Returned Value:
* None
*
****************************************************************************/
static void qspi_dma_callback(DMA_HANDLE handle, uint8_t isr, void *arg)
{
struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)arg;
DEBUGASSERT(priv != NULL);
/* Cancel the watchdog timeout */
(void)wd_cancel(priv->dmadog);
/* Sample DMA registers at the time of the callback */
qspi_dma_sample(priv, DMA_CALLBACK);
/* Report the result of the transfer only if the callback has not already
* reported an error.
*/
if (priv->result == -EBUSY)
{
/* Save the result of the transfer if no error was previously reported */
if ( isr & DMA_CHAN_TCIF_BIT )
{
priv->result = OK;
}
else if ( isr & DMA_CHAN_TEIF_BIT )
{
priv->result = -EIO;
}
else
{
priv->result = OK;
}
}
/* Then wake up the waiting thread */
sem_post(&priv->dmawait);
}
/****************************************************************************
* Name: qspi_regaddr
*
* Description:
* Return the address of an QSPI register
*
****************************************************************************/
static inline uintptr_t qspi_regaddr(struct stm32l4_qspidev_s *priv,
unsigned int offset)
{
return priv->base + offset;
}
/****************************************************************************
* Name: qspi_memory_dma
*
* Description:
* Perform one QSPI memory transfer using DMA
*
* Input Parameters:
* priv - Device-specific state data
* meminfo - Describes the memory transfer to be performed.
* xctn - Describes the transaction context.
*
* Returned Value:
* Zero (OK) on SUCCESS, a negated errno on value of failure
*
****************************************************************************/
static int qspi_memory_dma(struct stm32l4_qspidev_s *priv,
struct qspi_meminfo_s *meminfo,
struct qspi_xctnspec_s *xctn)
{
uint32_t dmaflags;
uint32_t regval;
int ret;
/* Initialize register sampling */
qspi_dma_sampleinit(priv);
/* Determine DMA flags and setup the DMA */
if (QSPIMEM_ISWRITE(meminfo->flags))
{
/* Setup the DMA (memory-to-peripheral) */
dmaflags = (QSPI_DMA_PRIO | DMA_CCR_MSIZE_8BITS | DMA_CCR_PSIZE_8BITS | DMA_CCR_MINC | DMA_CCR_DIR);
}
else
{
/* Setup the DMA (peripheral-to-memory) */
dmaflags = (QSPI_DMA_PRIO | DMA_CCR_MSIZE_8BITS | DMA_CCR_PSIZE_8BITS | DMA_CCR_MINC );
}
stm32l4_dmasetup(priv->dmach, qspi_regaddr(priv, STM32L4_QUADSPI_DR_OFFSET),
(uint32_t)meminfo->buffer, meminfo->buflen, dmaflags);
qspi_dma_sample(priv, DMA_AFTER_SETUP);
/* Enable the memory transfer */
regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
regval |= QSPI_CR_DMAEN;
qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
/* Set up the Communications Configuration Register as per command info */
qspi_ccrconfig(priv, xctn,
QSPIMEM_ISWRITE(meminfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD);
/* Start the DMA */
priv->result = -EBUSY;
stm32l4_dmastart(priv->dmach, qspi_dma_callback, priv, false);
qspi_dma_sample(priv, DMA_AFTER_START);
/* Wait for DMA completion. This is done in a loop because there may be
* false alarm semaphore counts that cause sem_wait() not fail to wait
* or to wake-up prematurely (for example due to the receipt of a signal).
* We know that the DMA has completed when the result is anything other
* that -EBUSY.
*/
do
{
/* Start (or re-start) the watchdog timeout */
ret = wd_start(priv->dmadog, DMA_TIMEOUT_TICKS,
(wdentry_t)qspi_dma_timeout, 1, (uint32_t)priv);
if (ret != OK)
{
qspidbg("ERROR: wd_start failed: %d\n", ret);
}
/* Wait for the DMA complete */
ret = sem_wait(&priv->dmawait);
/* Cancel the watchdog timeout */
(void)wd_cancel(priv->dmadog);
/* Check if we were awakened by an error of some kind */
if (ret < 0)
{
/* EINTR is not a failure. That simply means that the wait
* was awakened by a signal.
*/
int errorcode = errno;
if (errorcode != EINTR)
{
DEBUGPANIC();
regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
regval &= ~QSPI_CR_DMAEN;
qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
return -errorcode;
}
}
/* Note that we might be awakened before the wait is over due to
* residual counts on the semaphore. So, to handle, that case,
* we loop until something changes the DMA result to any value other
* than -EBUSY.
*/
}
while (priv->result == -EBUSY);
/* Wait for Transfer complete, and not busy */
qspi_waitstatusflags(priv, QSPI_SR_TCF,1);
qspi_waitstatusflags(priv, QSPI_SR_BUSY,0);
MEMORY_SYNC();
/* Dump the sampled DMA registers */
qspi_dma_sampledone(priv);
/* Make sure that the DMA is stopped (it will be stopped automatically
* on normal transfers, but not necessarily when the transfer terminates
* on an error condition).
*/
stm32l4_dmastop(priv->dmach);
regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
regval &= ~QSPI_CR_DMAEN;
qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
/* Complain if the DMA fails */
if (priv->result)
{
qspidbg("ERROR: DMA failed with result: %d\n", priv->result);
}
return priv->result;
}
#endif
#if !defined(STM32L4_QSPI_INTERRUPTS)
/****************************************************************************
* Name: qspi_receive_blocking
*
@ -1581,7 +1975,7 @@ static int qspi_command(struct qspi_dev_s *dev,
QSPI_FCR_CTEF | QSPI_FCR_CTCF | QSPI_FCR_CSMF | QSPI_FCR_CTOF,
STM32L4_QUADSPI_FCR);
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
/* interrupt mode will need access to the transaction context */
priv->xctn = &xctn;
@ -1665,9 +2059,9 @@ static int qspi_command(struct qspi_dev_s *dev,
ret = xctn.disposition;
#elif defined(CONFIG_STM32L4_QSPI_DMA)
/* XXX III dma mode (and 'autopolling'?) */
/* because command transfers are so small, we're not going to use
* DMA for them, only interrupts or polling
*/
#else
/* Polling mode */
@ -1762,7 +2156,7 @@ static int qspi_memory(struct qspi_dev_s *dev,
QSPI_FCR_CTEF | QSPI_FCR_CTCF | QSPI_FCR_CSMF | QSPI_FCR_CTOF,
STM32L4_QUADSPI_FCR);
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
/* interrupt mode will need access to the transaction context */
priv->xctn = &xctn;
@ -1824,8 +2218,46 @@ static int qspi_memory(struct qspi_dev_s *dev,
ret = xctn.disposition;
#elif defined(CONFIG_STM32L4_QSPI_DMA)
/* XXX III dma mode (and 'autopolling'?) */
/* Can we perform DMA? Should we perform DMA? */
if (priv->candma &&
meminfo->buflen > CONFIG_STM32L4_QSPI_DMATHRESHOLD &&
IS_ALIGNED((uintptr_t)meminfo->buffer) &&
IS_ALIGNED(meminfo->buflen))
{
ret = qspi_memory_dma(priv, meminfo, &xctn);
}
else
{
/* polling mode */
/* Set up the Communications Configuration Register as per command info */
qspi_ccrconfig(priv, &xctn,
QSPIMEM_ISWRITE(meminfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD);
/* Transfer data */
DEBUGASSERT(meminfo->buffer != NULL && meminfo->buflen > 0);
DEBUGASSERT(IS_ALIGNED(meminfo->buffer));
if (QSPIMEM_ISWRITE(meminfo->flags))
{
ret = qspi_transmit_blocking(priv, &xctn);
}
else
{
ret = qspi_receive_blocking(priv, &xctn);
}
/* Wait for Transfer complete, and not busy */
qspi_waitstatusflags(priv, QSPI_SR_TCF,1);
qspi_waitstatusflags(priv, QSPI_SR_BUSY,0);
MEMORY_SYNC();
}
#else
/* polling mode */
@ -1848,31 +2280,13 @@ static int qspi_memory(struct qspi_dev_s *dev,
ret = qspi_receive_blocking(priv, &xctn);
}
MEMORY_SYNC();
#if 0
#ifdef CONFIG_STM32L4_QSPI_DMA
/* Can we perform DMA? Should we perform DMA? */
if (priv->candma &&
meminfo->buflen > CONFIG_STM32L4_QSPI_DMATHRESHOLD &&
IS_ALIGNED((uintptr_t)meminfo->buffer) &&
IS_ALIGNED(meminfo->buflen))
{
return qspi_memory_dma(priv, meminfo);
}
else
#endif
{
return qspi_memory_nodma(priv, meminfo);
}
#endif
/* Wait for Transfer complete, and not busy */
qspi_waitstatusflags(priv, QSPI_SR_TCF,1);
qspi_waitstatusflags(priv, QSPI_SR_BUSY,0);
MEMORY_SYNC();
#endif
return ret;
@ -1949,7 +2363,7 @@ static int qspi_hw_initialize(struct stm32l4_qspidev_s *priv)
qspi_abort(priv);
regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
regval = 0;
regval &= ~(QSPI_CR_EN);
qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
@ -2099,10 +2513,35 @@ struct qspi_dev_s *stm32l4_qspi_initialize(int intf)
sem_init(&priv->exclsem, 0, 1);
#ifdef CONFIG_STM32L4_QSPI_DMA
/* XXX III needs implementation */
/* Pre-allocate DMA channels. */
if (priv->candma)
{
priv->dmach = stm32l4_dmachannel(DMACHAN_QUADSPI);
if (!priv->dmach)
{
qspidbg("ERROR: Failed to allocate the DMA channel\n");
priv->candma = false;
}
}
/* Initialize the QSPI semaphore that is used to wake up the waiting
* thread when the DMA transfer completes.
*/
sem_init(&priv->dmawait, 0, 0);
/* Create a watchdog time to catch DMA timeouts */
priv->dmadog = wd_create();
if (priv->dmadog == NULL)
{
qspidbg("ERROR: Failed to create wdog\n");
goto errout_with_dmahandles;
}
#endif
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
/* Attach the interrupt handler */
ret = irq_attach(priv->irq, priv->handler);
@ -2133,7 +2572,7 @@ struct qspi_dev_s *stm32l4_qspi_initialize(int intf)
priv->initialized = true;
priv->memmap = false;
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
up_enable_irq(priv->irq);
#endif
}
@ -2141,13 +2580,22 @@ struct qspi_dev_s *stm32l4_qspi_initialize(int intf)
return &priv->qspi;
errout_with_irq:
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
irq_detach(priv->irq);
errout_with_dmadog:
#endif
#ifdef CONFIG_STM32L4_QSPI_DMA
/* XXX III needs implementation */
wd_delete(priv->dmadog);
errout_with_dmahandles:
sem_destroy(&priv->dmawait);
if (priv->dmach)
{
stm32l4_dmafree(priv->dmach);
priv->dmach = NULL;
}
#endif
sem_destroy(&priv->exclsem);
@ -2209,7 +2657,7 @@ void stm32l4_qspi_enter_memorymapped(struct qspi_dev_s* dev,
qspi_putreg(&g_qspi0dev, QSPI_FCR_CTOF, STM32L4_QUADSPI_FCR);
#ifdef QSPI_USE_INTERRUPTS
#ifdef STM32L4_QSPI_INTERRUPTS
/* Enable Timeout interrupt */
regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
@ -2227,7 +2675,10 @@ void stm32l4_qspi_enter_memorymapped(struct qspi_dev_s* dev,
/* create a transaction object */
qspi_setupxctnfrommem(&xctn, meminfo);
#ifdef STM32L4_QSPI_INTERRUPTS
priv->xctn = NULL;
#endif
/* set it into the ccr */