You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/01/14 05:40:20 UTC

[nuttx] 02/02: sama5/sam_flexcom_spi: enable DMA support

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 246a677045c4e0c6809919f82a4b2b43db4aaab4
Author: Janne Rosberg <ja...@offcode.fi>
AuthorDate: Wed Jan 11 13:21:40 2023 +0200

    sama5/sam_flexcom_spi: enable DMA support
---
 arch/arm/src/sama5/Kconfig           |  41 +++++++++++++
 arch/arm/src/sama5/sam_flexcom_spi.c | 109 +++++++++++++++++------------------
 2 files changed, 94 insertions(+), 56 deletions(-)

diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig
index 1f3c0b7673..b0dfd1ba3b 100644
--- a/arch/arm/src/sama5/Kconfig
+++ b/arch/arm/src/sama5/Kconfig
@@ -3131,6 +3131,47 @@ config SAMA5_SPI_REGDEBUG
 endmenu # SPI device driver options
 endif # SAMA5_SPI0 || SAMA5_SPI1
 
+if SAMA5_FLEXCOM0_SPI || SAMA5_FLEXCOM1_SPI || SAMA5_FLEXCOM2_SPI || SAMA5_FLEXCOM3_SPI || SAMA5_FLEXCOM4_SPI
+
+menu "Flexcom SPI device driver options"
+
+config SAMA5_FLEXCOM_SPI_DMA
+	bool "Flexcom SPI DMA"
+	default n
+	depends on (SAMA5_XDMAC0 && SAMA5_FLEXCOM_SPI) || (SAMA5_XDMAC1 && SAMA5_FLEXCOM_SPI)
+	---help---
+		Use DMA to improve SPI transfer performance.
+
+config SAMA5_FLEXCOM_SPI_DMAC_NUMBER
+	int "Flexcom SPI DMA Controller number"
+	default 0
+	range 0 1
+	depends on SAMA5_FLEXCOM_SPI_DMA
+	---help---
+		Select witch xdma controller to use for Flexcom SPI DMA.
+
+config SAMA5_FLEXCOM_SPI_DMATHRESHOLD
+	int "FLEXCOM SPI DMA threshold"
+	default 4
+	depends on SAMA5_FLEXCOM_SPI_DMA
+	---help---
+		When SPI 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 SAMA5_SPI_DMATHRESHOLD.
+
+config SAMA5_FLEXCOM_SPI_DMADEBUG
+	bool "FLEXCOM SPI DMA transfer debug"
+	depends on SAMA5_SPI_DMA && DEBUG_FEATURES && DEBUG_DMA
+	default n
+	---help---
+		Enable special debug instrumentation analyze SPI 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.
+
+endmenu # Flexcom SPI device driver options
+endif # SAMA5_FLEXCOM0_SPI || SAMA5_FLEXCOM1_SPI || SAMA5_FLEXCOM2_SPI || SAMA5_FLEXCOM3_SPI || SAMA5_FLEXCOM4_SPI
+
 if SAMA5_TWI0 || SAMA5_TWI1 || SAMA5_TWI2 || SAMA5_TWI3
 
 menu "TWI device driver options"
diff --git a/arch/arm/src/sama5/sam_flexcom_spi.c b/arch/arm/src/sama5/sam_flexcom_spi.c
index 49f5f9786f..f13055ab65 100644
--- a/arch/arm/src/sama5/sam_flexcom_spi.c
+++ b/arch/arm/src/sama5/sam_flexcom_spi.c
@@ -47,7 +47,6 @@
 #include "arm_internal.h"
 
 #include "chip.h"
-#include "sam_pio.h"
 #include "sam_dmac.h"
 #include "sam_memories.h"
 #include "sam_periphclks.h"
@@ -56,7 +55,6 @@
 #include "hardware/sam_flexcom_spi.h"
 #include "hardware/sam_flexcom.h"
 #include "sam_config.h"
-#include "hardware/sam_pinmap.h"
 
 #if defined(SAMA5_HAVE_FLEXCOM_SPI)
 
@@ -68,18 +66,18 @@
 
 /* When SPI 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 CONFIG_SAMA5_SPI_DMATHRESHOLD.
+ * That value is provided by CONFIG_SAMA5_FLEXCOM_SPI_DMATHRESHOLD.
  */
 
-#  ifndef CONFIG_SAMA5_SPI_DMATHRESHOLD
-#    define CONFIG_SAMA5_SPI_DMATHRESHOLD 4
+#  ifndef CONFIG_SAMA5_FLEXCOM_SPI_DMATHRESHOLD
+#    define CONFIG_SAMA5_FLEXCOM_SPI_DMATHRESHOLD 4
 #  endif
 
 #  ifndef CONFIG_DEBUG_SPI_INFO
 #    undef CONFIG_SAMA5_SPI_REGDEBUG
 #  endif
 
-#  ifdef CONFIG_SAMA5_SPI_DMA
+#  ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 
 #  if defined(CONFIG_SAMA5_FLEXCOM0_SPI) && defined(CONFIG_SAMA5_XDMAC0)
 #    define SAMA5_FLEXCOM0_SPI_DMA true
@@ -113,8 +111,8 @@
 
 #endif
 
-#ifndef CONFIG_SAMA5_SPI_DMA
-#  undef CONFIG_SAMA5_SPI_DMADEBUG
+#ifndef CONFIG_SAMA5_FLEXCOM_SPI_DMA
+#  undef CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG
 #endif
 
 /* Clocking *****************************************************************/
@@ -138,7 +136,7 @@
 /* Check if SPI debug is enabled */
 
 #ifndef CONFIG_DEBUG_DMA
-#  undef CONFIG_SAMA5_SPI_DMADEBUG
+#  undef CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG
 #endif
 
 #define DMA_INITIAL      0
@@ -168,7 +166,7 @@ struct sam_flex_spics_s
 #endif
   uint8_t cs;                      /* Chip select number */
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
   bool candma;                     /* DMA is supported */
   sem_t dmawait;                   /* Used to wait for DMA completion */
   struct wdog_s dmadog;            /* Watchdog that handles DMA timeouts */
@@ -179,7 +177,7 @@ struct sam_flex_spics_s
 
   /* Debug stuff */
 
-#ifdef CONFIG_SAMA5_SPI_DMADEBUG
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG
   struct sam_dmaregs_s rxdmaregs[DMA_NSAMPLES];
   struct sam_dmaregs_s txdmaregs[DMA_NSAMPLES];
 #endif
@@ -199,7 +197,7 @@ struct sam_flex_spidev_s
   mutex_t spilock;             /* Assures mutually exclusive access to SPI */
   select_t select;             /* SPI select callout */
   bool initialized;            /* TRUE: Controller has been initialized */
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
   uint8_t pid;                 /* Peripheral ID */
 #endif
 
@@ -245,11 +243,11 @@ static inline uint32_t flex_spi_cs2pcs(struct sam_flex_spics_s *flex_spics);
 
 /* DMA support */
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 
-#  ifdef CONFIG_SAMA5_SPI_DMADEBUG
-#    define spi_rxdma_sample(s,i) sam_dmasample((s)->rxdma, &(s)->rxdmaregs[i])
-#    define spi_txdma_sample(s,i) sam_dmasample((s)->txdma, &(s)->txdmaregs[i])
+#  ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG
+#    define flex_spi_rxdma_sample(s,i) sam_dmasample((s)->rxdma, &(s)->rxdmaregs[i])
+#    define flex_spi_txdma_sample(s,i) sam_dmasample((s)->txdma, &(s)->txdmaregs[i])
 static void     flex_spi_dma_sampleinit(struct sam_flex_spics_s *flex_spics);
 static void     flex_spi_dma_sampledone(struct sam_flex_spics_s *flex_spics);
 
@@ -278,7 +276,7 @@ static void flex_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode);
 static void flex_spi_setbits(struct spi_dev_s *dev, int nbits);
 static uint32_t flex_spi_send(struct spi_dev_s *dev, uint32_t wd);
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 static void flex_spi_exchange_nodma(struct spi_dev_s *dev,
                                     const void *txbuffer, void *rxbuffer,
                                     size_t nwords);
@@ -639,8 +637,8 @@ static void flex_spi_dumpregs(struct sam_flex_spidev_s *flex_spi,
   spiinfo("  CSR0:%08x CSR1:%08x \n",
           getreg32(flex_spi->base + SAM_FLEXCOM_SPI_CSR0_OFFSET),
           getreg32(flex_spi->base + SAM_FLEXCOM_SPI_CSR1_OFFSET));
-  spiinfo("  WPCR:%08x WPSR:%08x\n",
-          getreg32(flex_spi->base + SAM_FLEXCOM_SPI_WPCR_OFFSET),
+  spiinfo("  WPMR:%08x WPSR:%08x\n",
+          getreg32(flex_spi->base + SAM_FLEXCOM_SPI_WPMR_OFFSET),
           getreg32(flex_spi->base + SAM_FLEXCOM_SPI_WPSR_OFFSET));
 }
 #endif
@@ -759,7 +757,8 @@ static inline uint32_t flex_spi_cs2pcs(struct sam_flex_spics_s *flex_spics)
  * Name: flex_spi_dma_sampleinit
  *
  * Description:
- *   Initialize sampling of DMA registers (if CONFIG_SAMA5_SPI_DMADEBUG)
+ *   Initialize sampling of DMA registers
+ *     (if CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG)
  *
  * Input Parameters:
  *   flex_spics - Chip select doing the DMA
@@ -769,7 +768,7 @@ static inline uint32_t flex_spi_cs2pcs(struct sam_flex_spics_s *flex_spics)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SAMA5_SPI_DMADEBUG
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG
 static void flex_spi_dma_sampleinit(struct sam_flex_spics_s *flex_spics)
 {
   /* Put contents of register samples into a known state */
@@ -800,7 +799,7 @@ static void flex_spi_dma_sampleinit(struct sam_flex_spics_s *flex_spics)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SAMA5_SPI_DMADEBUG
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG
 static void flex_spi_dma_sampledone(struct sam_flex_spics_s *flex_spics)
 {
   /* Sample the final registers */
@@ -860,7 +859,7 @@ static void flex_spi_dma_sampledone(struct sam_flex_spics_s *flex_spics)
   sam_dmadump(flex_spics->txdma, &flex_spics->txdmaregs[DMA_END_TRANSFER],
               "TX: At End-of-Transfer");
 }
-#endif /* CONFIG_SAMA5_SPI_DMADEBUG */
+#endif /* CONFIG_SAMA5_FLEXCOM_SPI_DMADEBUG */
 
 /****************************************************************************
  * Name: flex_spi_dmatimeout
@@ -880,7 +879,7 @@ static void flex_spi_dma_sampledone(struct sam_flex_spics_s *flex_spics)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 static void flex_spi_dmatimeout(wdparm_t arg)
 {
   struct sam_flex_spics_s *flex_spics = (struct sam_flex_spics_s *)arg;
@@ -918,7 +917,7 @@ static void flex_spi_dmatimeout(wdparm_t arg)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 static void flex_spi_rxcallback(DMA_HANDLE handle, void *arg, int result)
 {
   struct sam_flex_spics_s *flex_spics = (struct sam_flex_spics_s *)arg;
@@ -967,10 +966,10 @@ static void flex_spi_rxcallback(DMA_HANDLE handle, void *arg, int result)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 static void flex_spi_txcallback(DMA_HANDLE handle, void *arg, int result)
 {
-  struct sam_flex_spics_s *flex_spics = (struct sam_spics_s *)arg;
+  struct sam_flex_spics_s *flex_spics = (struct sam_flex_spics_s *)arg;
   DEBUGASSERT(flex_spics != NULL);
 
   flex_spi_txdma_sample(flex_spics, DMA_CALLBACK);
@@ -997,7 +996,7 @@ static void flex_spi_txcallback(DMA_HANDLE handle, void *arg, int result)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 static inline uintptr_t flex_spi_physregaddr(struct sam_flex_spics_s
                                             *flex_spics, unsigned int offset)
 {
@@ -1380,12 +1379,14 @@ static uint32_t flex_spi_send(struct spi_dev_s *dev, uint32_t wd)
  *
  * Description:
  *   Exchange a block of data from SPI.  There are two versions of this
- *   function:  (1) One that is enabled only when CONFIG_SAMA5_SPI_DMA=y
+ *   function:
+ *   (1) One that is enabled only when CONFIG_SAMA5_FLEXCOM_SPI_DMA=y
  *   that performs DMA SPI transfers, but only when a larger block of
  *   data is being transferred.  And (2) another version that does polled
- *   SPI transfers.  When CONFIG_SAMA5_SPI_DMA=n the latter is the only
- *   version available; when CONFIG_SAMA5_SPI_DMA=y, this version is only
- *   used for short SPI transfers and gets renamed as spi_exchange_nodma).
+ *   SPI transfers. When CONFIG_SAMA5_FLEXCOM_SPI_DMA=n the latter is the
+ *   only version available; when CONFIG_SAMA5_FLEXCOM_SPI_DMA=y, this
+ *   version is only used for short SPI transfers and gets renamed as
+ *   spi_exchange_nodma.
  *
  * Input Parameters:
  *   dev      - Device-specific state data
@@ -1402,12 +1403,13 @@ static uint32_t flex_spi_send(struct spi_dev_s *dev, uint32_t wd)
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SAMA5_SPI_DMA
-static void spi_exchange_nodma(struct spi_dev_s *dev, const void *txbuffer,
-              void *rxbuffer, size_t nwords)
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
+static void flex_spi_exchange_nodma(struct spi_dev_s *dev,
+                                    const void *txbuffer,
+                                    void *rxbuffer, size_t nwords)
 #else
 static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
-              void *rxbuffer, size_t nwords)
+                              void *rxbuffer, size_t nwords)
 #endif
 {
   struct sam_flex_spics_s *flex_spics = (struct sam_flex_spics_s *)dev;
@@ -1515,7 +1517,7 @@ static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
     }
 }
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
 static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
                               void *rxbuffer, size_t nwords)
 {
@@ -1533,7 +1535,7 @@ static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
    * spi_exchange_nodma() do the work.
    */
 
-  if (!flex_spics->candma || nwords <= CONFIG_SAMA5_SPI_DMATHRESHOLD)
+  if (!flex_spics->candma || nwords <= CONFIG_SAMA5_FLEXCOM_SPI_DMATHRESHOLD)
     {
       flex_spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords);
       return;
@@ -1541,8 +1543,6 @@ static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
 
   spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords);
 
-  flex_spics = (struct flex_sam_spics_s *)dev;
-  flex_spi = flex_spi_dev(flex_spics);
   DEBUGASSERT(flex_spics && flex_spi);
 
   /* Make sure that any previous transfer is flushed from the hardware */
@@ -1571,7 +1571,7 @@ static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
             DMACH_FLAG_PERIPHPID(flex_spi->pid) |
             DMACH_FLAG_PERIPHH2SEL |
             DMACH_FLAG_PERIPHISPERIPH |
-            DMACH_FLAG_PERIPHAHB_AHB_IF2 |
+            DMACH_FLAG_PERIPHAHB_AHB_IF1 |
             DMACH_FLAG_PERIPHWIDTH_8BITS |
             DMACH_FLAG_PERIPHCHUNKSIZE_1 |
             DMACH_FLAG_MEMPID_MAX |
@@ -1599,7 +1599,7 @@ static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
             DMACH_FLAG_PERIPHPID(flex_spi->pid) |
             DMACH_FLAG_PERIPHH2SEL |
             DMACH_FLAG_PERIPHISPERIPH |
-            DMACH_FLAG_PERIPHAHB_AHB_IF2 |
+            DMACH_FLAG_PERIPHAHB_AHB_IF1 |
             DMACH_FLAG_PERIPHWIDTH_8BITS |
             DMACH_FLAG_PERIPHCHUNKSIZE_1 |
             DMACH_FLAG_MEMPID_MAX |
@@ -1677,7 +1677,7 @@ static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
       return;
     }
 
-  flex_spi_txdma_sample(spics, DMA_AFTER_START);
+  flex_spi_txdma_sample(flex_spics, DMA_AFTER_START);
 
   /* Wait for DMA completion.  This is done in a loop because there my be
    * false alarm semaphore counts that cause sam_wait() not fail to wait
@@ -1737,10 +1737,10 @@ static void flex_spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
 
   if (flex_spics->result)
     {
-      spierr("ERROR: DMA failed with result: %d\n", spics->result);
+      spierr("ERROR: DMA failed with result: %d\n", flex_spics->result);
     }
 }
-#endif /* CONFIG_SAMA5_SPI_DMA */
+#endif /* CONFIG_SAMA5_FLEXCOM_SPI_DMA */
 
 /****************************************************************************
  * Name: flex_spi_sndblock
@@ -1869,7 +1869,7 @@ struct spi_dev_s *sam_flex_spibus_initialize(int port)
    * were zeroed by kmm_zalloc().
    */
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
   switch (flex_spino)
     {
 #ifdef CONFIG_SAMA5_FLEXCOM0_SPI
@@ -1902,16 +1902,12 @@ struct spi_dev_s *sam_flex_spibus_initialize(int port)
         break;
     }
 
-  flex_spics->candma = flex_spino ? SAMA5_SPI1_DMA : SAMA5_SPI0_DMA;
-
-  /* Pre-allocate DMA channels.  These allocations exploit that fact that
-   * SPI0 is managed by DMAC0 and SPI1 is managed by DMAC1.  Hence,
-   * the SPI number (spino) is the same as the DMAC number.
-   */
+  /* Pre-allocate DMA channels. */
 
   if (flex_spics->candma)
     {
-      flex_spics->rxdma = sam_dmachannel(flex_spino, 0);
+      flex_spics->rxdma = sam_dmachannel(
+                           CONFIG_SAMA5_FLEXCOM_SPI_DMAC_NUMBER, 0);
       if (!flex_spics->rxdma)
         {
           spierr("ERROR: Failed to allocate the RX DMA channel\n");
@@ -1921,7 +1917,8 @@ struct spi_dev_s *sam_flex_spibus_initialize(int port)
 
   if (flex_spics->candma)
     {
-      flex_spics->txdma = sam_dmachannel(flex_spino, 0);
+      flex_spics->txdma = sam_dmachannel(
+                           CONFIG_SAMA5_FLEXCOM_SPI_DMAC_NUMBER, 0);
       if (!flex_spics->txdma)
         {
           spierr("ERROR: Failed to allocate the TX DMA channel\n");
@@ -1930,7 +1927,7 @@ struct spi_dev_s *sam_flex_spibus_initialize(int port)
           flex_spics->candma = false;
         }
     }
-#endif /* CONFIG_SAMA5_SPI_DMA */
+#endif /* CONFIG_SAMA5_FLEXCOM_SPI_DMA */
 
   /* Select the SPI operations */
 
@@ -2094,7 +2091,7 @@ struct spi_dev_s *sam_flex_spibus_initialize(int port)
 
       flex_spi->initialized = true;
 
-#ifdef CONFIG_SAMA5_SPI_DMA
+#ifdef CONFIG_SAMA5_FLEXCOM_SPI_DMA
       /* Initialize the SPI semaphore that is used to wake up the waiting
        * thread when the DMA transfer completes.  This semaphore is used for
        * signaling and, hence, should not have priority inheritance enabled.