From b887d39d2e17043a4248e919d0fedcaf16a9e9b2 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 29 Aug 2015 10:02:59 -0600 Subject: [PATCH] SAMV7 QSPI: Add DMA transfer support --- arch/arm/src/samv7/Kconfig | 43 +++- arch/arm/src/samv7/sam_qspi.c | 403 +++++++++++++++++++-------------- arch/arm/src/samv7/sam_xdmac.h | 4 +- 3 files changed, 272 insertions(+), 178 deletions(-) diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index 086a8a31a7..c255d90af8 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -512,7 +512,6 @@ config SAMV7_GPIOE_IRQ default n endif # SAMV7_GPIO_IRQ -endif # ARCH_CHIP_SAMV7 menu "SDRAM Configuration" depends on SAMV7_SDRAMC @@ -628,7 +627,46 @@ config SAMV7_SPI_REGDEBUG Output detailed register-level SPI device debug information. Requires also DEBUG. -endmenu # SAMV7 SPI device driver options +endmenu # SPI device driver options + +menu "QSPI Device Driver Configuration" + depends on SAMV7_QSPI && !SAMV7_QSPI_IS_SPI + +config SAMV7_QSPI_DMA + bool "QSPI DMA" + default n + depends on SAMV7_XDMAC + ---help--- + Use DMA to improve SPI transfer performance. + +config SAMV7_QSPI_DMATHRESHOLD + int "QSPI DMA threshold" + default 4 + depends on SAMV7_QSPI_DMA + ---help--- + When ASPI DMA is enabled, small DMA transfers will still be performed + by polling logic. But we need a threshold value to determine what + is small. That value is provided by SAMV7_QSPI_DMATHRESHOLD. + +config SAMV7_QSPI_DMADEBUG + bool "QSPI DMA transfer debug" + depends on SAMV7_QSPI_DMA && DEBUG && DEBUG_DMA + default n + ---help--- + Enable special debug instrumentation 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 SAMV7_QSPI_REGDEBUG + bool "QSPI Register level debug" + depends on DEBUG + default n + ---help--- + Output detailed register-level QSPI device debug information. + Requires also DEBUG. + +endmenu # QSPI device driver options menu "TWIHS device driver options" depends on SAMV7_TWIHS0 || SAMV7_TWIHS1 || SAMV7_TWIHS2 @@ -2046,3 +2084,4 @@ config SAMV7_MCAN_REGDEBUG endmenu # CAN device driver options endif # SAMV7_MCAN +endif # ARCH_CHIP_SAMV7 diff --git a/arch/arm/src/samv7/sam_qspi.c b/arch/arm/src/samv7/sam_qspi.c index 8a1d19fbe8..e8c324a115 100644 --- a/arch/arm/src/samv7/sam_qspi.c +++ b/arch/arm/src/samv7/sam_qspi.c @@ -84,19 +84,21 @@ # define CONFIG_SAMV7_QSPI_DMATHRESHOLD 4 #endif +#ifndef CONFIG_SAMV7_XDMAC +# undef CONFIG_SAMV7_QSPI_DMA +#endif + #ifdef CONFIG_SAMV7_QSPI_DMA -# if defined(CONFIG_SAMV7_QSPI) && defined(CONFIG_SAMV7_DMAC0) -# define SAMV7_QSPI0_DMA true -# else -# define SAMV7_QSPI0_DMA false -# endif +# define SAMV7_QSPI0_DMA true #endif #ifndef CONFIG_SAMV7_QSPI_DMA # undef CONFIG_SAMV7_QSPI_DMADEBUG #endif -#define MEMORY_SYNC() do { ARM_DSB();ARM_ISB(); } while (0) +/* QSPI interrupts are not used */ + +#undef QSPI_USE_INTERRUPTS /* Clocking *****************************************************************/ /* The QSPI Baud rate clock is generated by dividing the peripheral clock by @@ -112,6 +114,10 @@ #define DMA_TIMEOUT_MS (800) #define DMA_TIMEOUT_TICKS MSEC2TICK(DMA_TIMEOUT_MS) +/* QSPI memory synchronization */ + +#define MEMORY_SYNC() do { ARM_DSB();ARM_ISB(); } while (0) + /* Debug *******************************************************************/ /* Check if QSPI debug is enabled (non-standard.. no support in * include/debug.h @@ -129,15 +135,15 @@ #endif #ifdef CONFIG_DEBUG_SPI -# define spidbg lldbg +# define qspidbg lldbg # ifdef CONFIG_DEBUG_VERBOSE -# define spivdbg lldbg +# define qspivdbg lldbg # else -# define spivdbg(x...) +# define qspivdbg(x...) # endif #else -# define spidbg(x...) -# define spivdbg(x...) +# define qspidbg(x...) +# define qspivdbg(x...) #endif #define DMA_INITIAL 0 @@ -161,14 +167,18 @@ struct sam_qspidev_s { struct qspi_dev_s qspi; /* Externally visible part of the QSPI interface */ +#ifdef QSPI_USE_INTERRUPTS xcpt_t handler; /* Interrupt handler */ +#endif uint32_t base; /* QSPI controller register base address */ uint32_t frequency; /* Requested clock frequency */ uint32_t actual; /* Actual clock frequency */ uint8_t mode; /* Mode 0,1,2,3 */ uint8_t nbits; /* Width of word in bits (8 to 16) */ uint8_t intf; /* QSPI controller number (0) */ +#ifdef QSPI_USE_INTERRUPTS uint8_t irq; /* Interrupt number */ +#endif bool initialized; /* TRUE: Controller has been initialized */ sem_t exclsem; /* Assures mutually exclusive access to QSPI */ @@ -179,15 +189,13 @@ struct sam_qspidev_s sem_t dmawait; /* Used to wait for DMA completion */ WDOG_ID dmadog; /* Watchdog that handles DMA timeouts */ int result; /* DMA result */ - DMA_HANDLE rxdma; /* QSPI RX DMA handle */ - DMA_HANDLE txdma; /* QSPI TX DMA handle */ + DMA_HANDLE dmach; /* QSPI DMA handle */ #endif /* Debug stuff */ #ifdef CONFIG_SAMV7_QSPI_DMADEBUG - struct sam_dmaregs_s rxdmaregs[DMA_NSAMPLES]; - struct sam_dmaregs_s txdmaregs[DMA_NSAMPLES]; + struct sam_dmaregs_s dmaregs[DMA_NSAMPLES]; #endif #ifdef CONFIG_SAMV7_QSPI_REGDEBUG @@ -222,27 +230,22 @@ static void qspi_dumpregs(struct sam_qspidev_s *priv, const char *msg); # define qspi_dumpregs(priv,msg) #endif -static inline void qspi_flush(struct sam_qspidev_s *priv); - /* DMA support */ #ifdef CONFIG_SAMV7_QSPI_DMA #ifdef CONFIG_SAMV7_QSPI_DMADEBUG -# define qspi_rxdma_sample(s,i) sam_dmasample((s)->rxdma, &(s)->rxdmaregs[i]) -# define qspi_txdma_sample(s,i) sam_dmasample((s)->txdma, &(s)->txdmaregs[i]) +# define qspi_dma_sample(s,i) sam_dmasample((s)->dmach, &(s)->dmaregs[i]) static void qspi_dma_sampleinit(struct sam_qspidev_s *priv); static void qspi_dma_sampledone(struct sam_qspidev_s *priv); #else -# define qspi_rxdma_sample(s,i) -# define qspi_txdma_sample(s,i) +# define qspi_dma_sample(s,i) # define qspi_dma_sampleinit(s) # define qspi_dma_sampledone(s) #endif -static void qspi_rxcallback(DMA_HANDLE handle, void *arg, int result); -static void qspi_txcallback(DMA_HANDLE handle, void *arg, int result); +static void qspi_dma_callback(DMA_HANDLE handle, void *arg, int result); static inline uintptr_t qspi_regaddr(struct sam_qspidev_s *priv, unsigned int offset); #endif @@ -259,10 +262,12 @@ static int qspi_memory_nodma(struct sam_qspidev_s *priv, /* Interrupts */ +#ifdef QSPI_USE_INTERRUPTS static int qspi_interrupt(struct sam_qspidev_s *priv); #ifdef CONFIG_SAMV7_QSPI static int qspi0_interrupt(int irq, void *context); #endif +#endif /* QSPI methods */ @@ -305,9 +310,13 @@ static struct sam_qspidev_s g_qspi0dev = .ops = &g_qspi0ops, }, .base = SAM_QSPI_BASE, +#ifdef QSPI_USE_INTERRUPTS .handler = qspi0_interrupt, +#endif .intf = 0, +#ifdef QSPI_USE_INTERRUPTS .irq = SAM_IRQ_QSPI, +#endif #ifdef CONFIG_SAMV7_QSPI_DMA .candma = SAMV7_QSPI0_DMA, .rxintf = XDMACH_QSPI_RX, @@ -443,52 +452,22 @@ static inline void qspi_putreg(struct sam_qspidev_s *priv, uint32_t value, #if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_VERBOSE) static void qspi_dumpregs(struct sam_qspidev_s *priv, const char *msg) { - spivdbg("%s:\n", msg); - spivdbg(" MR:%08x SR:%08x IMR:%08x\n", + qspivdbg("%s:\n", msg); + qspivdbg(" MR:%08x SR:%08x IMR:%08x\n", getreg32(priv->base + SAM_QSPI_MR_OFFSET), getreg32(priv->base + SAM_QSPI_SR_OFFSET), getreg32(priv->base + SAM_QSPI_IMR_OFFSET)); - spivdbg(" SCR0:%08x SCR1:%08x SCR2:%08x SCR3:%08x\n", + qspivdbg(" SCR0:%08x SCR1:%08x SCR2:%08x SCR3:%08x\n", getreg32(priv->base + SAM_QSPI_SCR0_OFFSET), getreg32(priv->base + SAM_QSPI_SCR1_OFFSET), getreg32(priv->base + SAM_QSPI_SCR2_OFFSET), getreg32(priv->base + SAM_QSPI_SCR3_OFFSET)); - spivdbg(" WPCR:%08x WPSR:%08x\n", + qspivdbg(" WPCR:%08x WPSR:%08x\n", getreg32(priv->base + SAM_QSPI_WPCR_OFFSET), getreg32(priv->base + SAM_QSPI_WPSR_OFFSET)); } #endif -/**************************************************************************** - * Name: qspi_flush - * - * Description: - * Make sure that there are now dangling QSPI transfer in progress - * - * Input Parameters: - * priv - QSPI controller state - * - * Returned Value: - * None - * - ****************************************************************************/ - -static inline void qspi_flush(struct sam_qspidev_s *priv) -{ - /* Make sure the no TX activity is in progress... waiting if necessary */ - - while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_TXEMPTY) == 0); - - /* Then make sure that there is no pending RX data .. reading as - * discarding as necessary. - */ - - while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_RDRF) != 0) - { - (void)qspi_getreg(priv, SAM_QSPI_RDR_OFFSET); - } -} - /**************************************************************************** * Name: qspi_dma_sampleinit * @@ -508,13 +487,11 @@ static void qspi_dma_sampleinit(struct sam_qspidev_s *priv) { /* Put contents of register samples into a known state */ - memset(priv->rxdmaregs, 0xff, DMA_NSAMPLES * sizeof(struct sam_dmaregs_s)); - memset(priv->txdmaregs, 0xff, DMA_NSAMPLES * sizeof(struct sam_dmaregs_s)); + memset(priv->dmaregs, 0xff, DMA_NSAMPLES * sizeof(struct sam_dmaregs_s)); /* Then get the initial samples */ - sam_dmasample(priv->rxdma, &priv->rxdmaregs[DMA_INITIAL]); - sam_dmasample(priv->txdma, &priv->txdmaregs[DMA_INITIAL]); + sam_dmasample(priv->dmach, &priv->dmaregs[DMA_INITIAL]); } #endif @@ -537,29 +514,22 @@ static void qspi_dma_sampledone(struct sam_qspidev_s *priv) { /* Sample the final registers */ - sam_dmasample(priv->rxdma, &priv->rxdmaregs[DMA_END_TRANSFER]); - sam_dmasample(priv->txdma, &priv->txdmaregs[DMA_END_TRANSFER]); + sam_dmasample(priv->dmach, &priv->dmaregs[DMA_END_TRANSFER]); /* Then dump the sampled DMA registers */ /* Initial register values */ - sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_INITIAL], - "TX: Initial Registers"); - sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_INITIAL], + sam_dmadump(priv->dmach, &priv->dmaregs[DMA_INITIAL], "RX: Initial Registers"); /* Register values after DMA setup */ - sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_AFTER_SETUP], - "TX: After DMA Setup"); - sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_AFTER_SETUP], + sam_dmadump(priv->dmach, &priv->dmaregs[DMA_AFTER_SETUP], "RX: After DMA Setup"); /* Register values after DMA start */ - sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_AFTER_START], - "TX: After DMA Start"); - sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_AFTER_START], + sam_dmadump(priv->dmach, &priv->dmaregs[DMA_AFTER_START], "RX: After DMA Start"); /* Register values at the time of the TX and RX DMA callbacks @@ -570,31 +540,24 @@ static void qspi_dma_sampledone(struct sam_qspidev_s *priv) * samples either, but we don't know for sure. */ - sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_CALLBACK], - "TX: At DMA callback"); - - /* Register values at the end of the DMA */ - if (priv->result == -ETIMEDOUT) { - sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_TIMEOUT], + sam_dmadump(priv->dmach, &priv->dmaregs[DMA_TIMEOUT], "RX: At DMA timeout"); } else { - sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_CALLBACK], + sam_dmadump(priv->dmach, &priv->dmaregs[DMA_CALLBACK], "RX: At DMA callback"); } - sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_END_TRANSFER], - "TX: At End-of-Transfer"); - sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_END_TRANSFER], + sam_dmadump(priv->dmach, &priv->dmaregs[DMA_END_TRANSFER], "RX: At End-of-Transfer"); } #endif /**************************************************************************** - * Name: qspi_dmatimeout + * Name: qspi_dma_timeout * * Description: * The watchdog timeout setup when a has expired without completion of a @@ -613,14 +576,14 @@ static void qspi_dma_sampledone(struct sam_qspidev_s *priv) ****************************************************************************/ #ifdef CONFIG_SAMV7_QSPI_DMA -static void qspi_dmatimeout(int argc, uint32_t arg) +static void qspi_dma_timeout(int argc, uint32_t arg) { struct sam_qspidev_s *priv = (struct sam_qspidev_s *)arg; DEBUGASSERT(priv != NULL); /* Sample DMA registers at the time of the timeout */ - qspi_rxdma_sample(priv, DMA_CALLBACK); + qspi_dma_sample(priv, DMA_CALLBACK); /* Report timeout result, perhaps overwriting any failure reports from * the TX callback. @@ -635,7 +598,7 @@ static void qspi_dmatimeout(int argc, uint32_t arg) #endif /**************************************************************************** - * Name: qspi_rxcallback + * Name: qspi_dma_callback * * Description: * This callback function is invoked at the completion of the QSPI RX DMA. @@ -651,7 +614,7 @@ static void qspi_dmatimeout(int argc, uint32_t arg) ****************************************************************************/ #ifdef CONFIG_SAMV7_QSPI_DMA -static void qspi_rxcallback(DMA_HANDLE handle, void *arg, int result) +static void qspi_dma_callback(DMA_HANDLE handle, void *arg, int result) { struct sam_qspidev_s *priv = (struct sam_qspidev_s *)arg; DEBUGASSERT(priv != NULL); @@ -662,7 +625,7 @@ static void qspi_rxcallback(DMA_HANDLE handle, void *arg, int result) /* Sample DMA registers at the time of the callback */ - qspi_rxdma_sample(priv, DMA_CALLBACK); + qspi_dma_sample(priv, DMA_CALLBACK); /* Report the result of the transfer only if the TX callback has not already * reported an error. @@ -681,44 +644,6 @@ static void qspi_rxcallback(DMA_HANDLE handle, void *arg, int result) } #endif -/**************************************************************************** - * Name: qspi_txcallback - * - * Description: - * This callback function is invoked at the completion of the QSPI TX DMA. - * - * Input Parameters: - * handle - The DMA handler - * arg - A pointer to the chip select structure - * result - The result of the DMA transfer - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_SAMV7_QSPI_DMA -static void qspi_txcallback(DMA_HANDLE handle, void *arg, int result) -{ - struct sam_qspidev_s *priv = (struct sam_qspidev_s *)arg; - DEBUGASSERT(priv != NULL); - - qspi_txdma_sample(priv, DMA_CALLBACK); - - /* Do nothing on the TX callback unless an error is reported. This - * callback is not really important because the QSPI exchange is not - * complete until the RX callback is received. - */ - - if (result != OK && priv->result == -EBUSY) - { - /* Save the result of the transfer if an error is reported */ - - priv->result = result; - } -} -#endif - /**************************************************************************** * Name: qspi_regaddr * @@ -870,7 +795,142 @@ static int qspi_memory_enable(struct sam_qspidev_s *priv, static int qspi_memory_dma(struct sam_qspidev_s *priv, struct qspi_meminfo_s *meminfo) { -#warning Missing Logic + uintptr_t paddr = SAM_QSPIMEM_BASE + meminfo->addr; + uint32_t dmaflags; + int ret; + + /* Initialize register sampling */ + + qspi_dma_sampleinit(priv); + + /* Determine DMA flags and setup the DMA */ + + dmaflags = DMACH_FLAG_FIFOCFG_LARGEST | DMACH_FLAG_PERIPHAHB_AHB_IF1 | + DMACH_FLAG_PERIPHISMEMORY | DMACH_FLAG_PERIPHINCREMENT | + DMACH_FLAG_PERIPHCHUNKSIZE_1 | DMACH_FLAG_MEMPID_MAX | + DMACH_FLAG_MEMAHB_AHB_IF1 | DMACH_FLAG_MEMINCREMENT | + DMACH_FLAG_MEMCHUNKSIZE_1 | DMACH_FLAG_MEMBURST_16; + + if (QSPIMEM_ISWRITE(meminfo->flags)) + { + /* Configure TX DMA */ + + dmaflags |= ((uint32_t)priv->txintf << DMACH_FLAG_PERIPHPID_SHIFT) | + DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_MEMWIDTH_8BITS; + sam_dmaconfig(priv->dmach, dmaflags); + + /* Setup the TX DMA (peripheral-to-memory) */ + + ret = sam_dmatxsetup(priv->dmach, paddr, (uint32_t)meminfo->buffer, + meminfo->buflen); + } + else + { + /* Configure RX DMA */ + + dmaflags |= ((uint32_t)priv->rxintf << DMACH_FLAG_PERIPHPID_SHIFT) | + DMACH_FLAG_PERIPHWIDTH_16BITS | DMACH_FLAG_MEMWIDTH_16BITS; + sam_dmaconfig(priv->dmach, dmaflags); + + /* Setup the RX DMA (memory-to-peripheral) */ + + ret = sam_dmarxsetup(priv->dmach, paddr, (uint32_t)meminfo->buffer, + meminfo->buflen); + } + + if (ret < 0) + { + qspidbg("ERROR: DMA setup failed: %d\n", ret); + return ret; + } + + qspi_dma_sample(priv, DMA_AFTER_SETUP); + + /* Enable the memory transfer */ + + qspi_memory_enable(priv, meminfo); + + /* Start the DMA */ + + priv->result = -EBUSY; + ret = sam_dmastart(priv->dmach, qspi_dma_callback, (void *)priv); + if (ret < 0) + { + qspidbg("ERROR: sam_dmastart failed: %d\n", ret); + return ret; + } + + 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 sam_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(); + return -errorcode; + } + } + + /* Not 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); + + /* 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). + */ + + sam_dmastop(priv->dmach); + + /* Complain if the DMA fails */ + + if (priv->result) + { + qspidbg("ERROR: DMA failed with result: %d\n", priv->result); + } + + return priv->result; } #endif @@ -892,7 +952,7 @@ static int qspi_memory_dma(struct sam_qspidev_s *priv, static int qspi_memory_nodma(struct sam_qspidev_s *priv, struct qspi_meminfo_s *meminfo) { - uintptr_t memaddr = SAM_QSPIMEM_BASE + meminfo->addr; + uintptr_t paddr = SAM_QSPIMEM_BASE + meminfo->addr; /* Enable the memory transfer */ @@ -900,13 +960,13 @@ static int qspi_memory_nodma(struct sam_qspidev_s *priv, /* Transfer data to/from QSPI memory */ - if (QSPICMD_ISWRITE(meminfo->flags)) + if (QSPIMEM_ISWRITE(meminfo->flags)) { - memcpy((void *)memaddr, meminfo->buffer, meminfo->buflen); + memcpy((void *)paddr, meminfo->buffer, meminfo->buflen); } else { - memcpy(meminfo->buffer, (void *)memaddr, meminfo->buflen); + memcpy(meminfo->buffer, (void *)paddr, meminfo->buflen); } MEMORY_SYNC(); @@ -918,7 +978,12 @@ static int qspi_memory_nodma(struct sam_qspidev_s *priv, while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_TXEMPTY) == 0); qspi_putreg(priv, QSPI_CR_LASTXFER, SAM_QSPI_CR_OFFSET); - /* Wait for the end of the transfer */ + /* Wait for the end of the transfer + * + * REVISIT: If DMA is not used then large transfers could come through + * this path. In that case, there would be a benefit to waiting for an + * interrupt to signal the end of the transfer. + */ while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_SR_INSTRE) == 0); return OK; @@ -949,7 +1014,7 @@ static int qspi_lock(struct qspi_dev_s *dev, bool lock) { struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; - spivdbg("lock=%d\n", lock); + qspivdbg("lock=%d\n", lock); if (lock) { /* Take the semaphore (perhaps waiting) */ @@ -995,7 +1060,7 @@ static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency) uint32_t dlybct; uint32_t regval; - spivdbg("frequency=%d\n", frequency); + qspivdbg("frequency=%d\n", frequency); DEBUGASSERT(priv); /* Check if the requested frequency is the same as the frequency selection */ @@ -1069,14 +1134,14 @@ static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency) /* Calculate the new actual frequency */ actual = SAM_QSPI_CLOCK / scbr; - spivdbg("SCR=%08x actual=%d\n", regval, actual); + qspivdbg("SCR=%08x actual=%d\n", regval, actual); /* Save the frequency setting */ priv->frequency = frequency; priv->actual = actual; - spidbg("Frequency %d->%d\n", frequency, actual); + qspidbg("Frequency %d->%d\n", frequency, actual); return actual; } @@ -1100,7 +1165,7 @@ static void qspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode) struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; uint32_t regval; - spivdbg("mode=%d\n", mode); + qspivdbg("mode=%d\n", mode); /* Has the mode changed? */ @@ -1142,7 +1207,7 @@ static void qspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode) } qspi_putreg(priv, regval, SAM_QSPI_SCR_OFFSET); - spivdbg("SCR=%08x\n", regval); + qspivdbg("SCR=%08x\n", regval); /* Save the mode so that subsequent re-configurations will be faster */ @@ -1170,7 +1235,7 @@ static void qspi_setbits(struct qspi_dev_s *dev, int nbits) struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; uint32_t regval; - spivdbg("nbits=%d\n", nbits); + qspivdbg("nbits=%d\n", nbits); DEBUGASSERT(priv != NULL); DEBUGASSERT(nbits >= SAM_QSPI_MINBITS && nbits <= SAM_QSPI_MAXBITS); @@ -1185,7 +1250,7 @@ static void qspi_setbits(struct qspi_dev_s *dev, int nbits) regval |= QSPI_MR_NBBITS(nbits); qspi_putreg(priv, regval, SAM_QSPI_MR_OFFSET); - spivdbg("SCR%02x]=%08x\n", regval); + qspivdbg("SCR%02x]=%08x\n", regval); /* Save the selection so the subsequence re-configurations will be faster */ @@ -1218,19 +1283,19 @@ static int qspi_command(struct qspi_dev_s *dev, DEBUGASSERT(priv != NULL && cmdinfo != NULL); #ifdef CONFIG_DEBUG_SPI - spivdbg("Transfer:\n"); - spivdbg(" flags: %02x\n", cmdinfo->flags); - spivdbg(" cmd: %04x\n", cmdinfo->cmd); + qspivdbg("Transfer:\n"); + qspivdbg(" flags: %02x\n", cmdinfo->flags); + qspivdbg(" cmd: %04x\n", cmdinfo->cmd); if (QSPICMD_ISADDRESS(cmdinfo->flags)) { - spivdbg(" address/length: %08lx %d\n", + qspivdbg(" address/length: %08lx %d\n", (unsigned long)cmdinfo->addr, cmdinfo->addrlen); } if (QSPICMD_ISDATA(cmdinfo->flags)) { - spivdbg(" %s Data:\n", QSPICMD_ISWRITE(cmdinfo->flags) ? "Write" : "Read"); - spivdbg(" buffer/length: %p %d\n", cmdinfo->buffer, cmdinfo->buflen); + qspivdbg(" %s Data:\n", QSPICMD_ISWRITE(cmdinfo->flags) ? "Write" : "Read"); + qspivdbg(" buffer/length: %p %d\n", cmdinfo->buffer, cmdinfo->buflen); } #endif @@ -1500,7 +1565,7 @@ struct qspi_dev_s *sam_qspi_initialize(int intf) /* The support SAM parts have only a single QSPI port */ - spivdbg("intf: %d\n", intf); + qspivdbg("intf: %d\n", intf); DEBUGASSERT(intf >= 0 && intf < SAMV7_NQSPI); /* Select the QSPI interface */ @@ -1532,7 +1597,7 @@ struct qspi_dev_s *sam_qspi_initialize(int intf) else #endif { - spidbg("ERROR: QSPI%d not supported\n", intf); + qspidbg("ERROR: QSPI%d not supported\n", intf); return NULL; } @@ -1552,22 +1617,10 @@ struct qspi_dev_s *sam_qspi_initialize(int intf) if (priv->candma) { - priv->rxdma = sam_dmachannel(0); - if (!priv->rxdma) + priv->dmach = sam_dmachannel(0,0); + if (!priv->dmach) { - spidbg("ERROR: Failed to allocate the RX DMA channel\n"); - priv->candma = false; - } - } - - if (priv->candma) - { - priv->txdma = sam_dmachannel(0); - if (!priv->txdma) - { - spidbg("ERROR: Failed to allocate the TX DMA channel\n"); - sam_dmafree(priv->rxdma); - priv->rxdma = NULL; + qspidbg("ERROR: Failed to allocate the DMA channel\n"); priv->candma = false; } } @@ -1583,19 +1636,21 @@ struct qspi_dev_s *sam_qspi_initialize(int intf) priv->dmadog = wd_create(); if (priv->dmadog == NULL) { - spidbg("ERROR: Failed to create wdog\n"); + qspidbg("ERROR: Failed to create wdog\n"); goto errout_with_dmahandles; } #endif +#ifdef QSPI_USE_INTERRUPTS /* Attach the interrupt handler */ ret = irq_attach(priv->irq, priv->handler); if (ret < 0) { - spidbg("ERROR: Failed to attach irq %d\n", priv->irq); + qspidbg("ERROR: Failed to attach irq %d\n", priv->irq); goto errout_with_dmadog; } +#endif /* Perform hardware initialization. Puts the QSPI into an active * state. @@ -1604,20 +1659,24 @@ struct qspi_dev_s *sam_qspi_initialize(int intf) ret = qspi_hw_initialize(priv); if (ret < 0) { - spidbg("ERROR: Failed to initialize QSPI hardware\n"); + qspidbg("ERROR: Failed to initialize QSPI hardware\n"); goto errout_with_irq; } /* Enable interrupts at the NVIC */ priv->initialized = true; +#ifdef QSPI_USE_INTERRUPTS up_enable_irq(priv->irq); +#endif } return &priv->qspi; errout_with_irq: +#ifdef QSPI_USE_INTERRUPTS irq_detach(priv->irq); +#endif errout_with_dmadog: #ifdef CONFIG_SAMV7_QSPI_DMA @@ -1626,16 +1685,10 @@ errout_with_dmadog: errout_with_dmahandles: sem_destroy(&priv->dmawait); - if (priv->rxdma) + if (priv->dmach) { - sam_dmafree(priv->rxdma); - priv->rxdma = NULL; - } - - if (priv->txdma) - { - sam_dmafree(priv->txdma); - priv->txdma = NULL; + sam_dmafree(priv->dmach); + priv->dmach = NULL; } #endif diff --git a/arch/arm/src/samv7/sam_xdmac.h b/arch/arm/src/samv7/sam_xdmac.h index 68c99bdbe1..d11913f3cf 100644 --- a/arch/arm/src/samv7/sam_xdmac.h +++ b/arch/arm/src/samv7/sam_xdmac.h @@ -101,7 +101,9 @@ # define DMACH_FLAG_PERIPHPID(n) ((uint32_t)(n) << DMACH_FLAG_PERIPHPID_SHIFT) # define DMACH_FLAG_PERIPHPID_MAX DMACH_FLAG_PERIPHPID_MASK #define DMACH_FLAG_PERIPHH2SEL (0) /* No HW handshaking */ -#define DMACH_FLAG_PERIPHISPERIPH (1 << 7) /* Bit 7: 0=memory; 1=peripheral */ +#define DMACH_FLAG_PERIPHIS_MASK (1 << 7) /* Bit 7: Peripheral type */ +# define DMACH_FLAG_PERIPHISPERIPH (1 << 7) /* Bit 7: 1 = Peripheral */ +# define DMACH_FLAG_PERIPHISMEMORY (0 << 7) /* Bit 7: 0 = Memory */ #define DMACH_FLAG_PERIPHAHB_MASK (1 << 8) /* Bit 8: Peripheral ABH layer 1 */ # define DMACH_FLAG_PERIPHAHB_AHB_IF0 (0) # define DMACH_FLAG_PERIPHAHB_AHB_IF1 DMACH_FLAG_PERIPHAHB_MASK