summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-12-02 17:15:57 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-12-02 17:15:57 -0600
commit37e27b758f6883a2acc7e9dc5e591b92ef6e7d06 (patch)
treead9bc56091756acbfb44c9405085647b2ce15a79
parentf0d3858518cf76dc6fda4b26467e1534c92817c7 (diff)
downloadnuttx-37e27b758f6883a2acc7e9dc5e591b92ef6e7d06.tar.gz
nuttx-37e27b758f6883a2acc7e9dc5e591b92ef6e7d06.tar.bz2
nuttx-37e27b758f6883a2acc7e9dc5e591b92ef6e7d06.zip
SAMA5 NAND: Can't DMA using DMAC1. Add lots of NAND DMA debug instrumentation
-rw-r--r--nuttx/arch/arm/src/sama5/Kconfig15
-rw-r--r--nuttx/arch/arm/src/sama5/sam_dmac.c3
-rw-r--r--nuttx/arch/arm/src/sama5/sam_nand.c123
-rw-r--r--nuttx/arch/arm/src/sama5/sam_nand.h41
-rw-r--r--nuttx/arch/arm/src/sama5/sam_ssc.c2
5 files changed, 169 insertions, 15 deletions
diff --git a/nuttx/arch/arm/src/sama5/Kconfig b/nuttx/arch/arm/src/sama5/Kconfig
index b5b3d8a65..0f5660631 100644
--- a/nuttx/arch/arm/src/sama5/Kconfig
+++ b/nuttx/arch/arm/src/sama5/Kconfig
@@ -3340,9 +3340,10 @@ if SAMA5_HAVE_NAND
config SAMA5_NAND_DMA
bool "NAND DMA Transfers"
default y
- depends on SAMA5_DMAC0 || SAMA5_DMAC1
+ depends on SAMA5_DMAC0
---help---
- Use DMA to perform NAND data transfers (highly recommended)
+ Use DMA to perform NAND data transfers. NOTE that DMAC0 must be
+ selected (DMAC1 cannot access NFC SRAM). (highly recommended)
config SAMA5_NAND_READYBUSY
bool "NAND Ready/Busy"
@@ -3431,6 +3432,16 @@ config SAMA5_PMECC_GALOIS_CUSTOM
endif # SAMA5_HAVE_PMECC
+config SAMA5_NAND_DMADEBUG
+ bool "NAND DMA transfer debug"
+ depends on SAMA5_NAND_DMA && DEBUG && DEBUG_DMA
+ default n
+ ---help---
+ Enable special debug instrumentation analyze NAND 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 SAMA5_NAND_REGDEBUG
bool "Register-Level NAND Debug"
default n
diff --git a/nuttx/arch/arm/src/sama5/sam_dmac.c b/nuttx/arch/arm/src/sama5/sam_dmac.c
index ff8a13735..33541943c 100644
--- a/nuttx/arch/arm/src/sama5/sam_dmac.c
+++ b/nuttx/arch/arm/src/sama5/sam_dmac.c
@@ -1807,7 +1807,8 @@ static int sam_dmac_interrupt(struct sam_dmac_s *dmac)
{
/* Yes... Terminate the transfer with an error? */
- sam_dmaterminate(dmach, -EIO);
+ dmalldbg("ERROR: DMA failed: %08x\n", regval);
+ sam_dmaterminate(dmach, -EIO);
}
/* Is the transfer complete? */
diff --git a/nuttx/arch/arm/src/sama5/sam_nand.c b/nuttx/arch/arm/src/sama5/sam_nand.c
index 7d23e0b02..6fecea58f 100644
--- a/nuttx/arch/arm/src/sama5/sam_nand.c
+++ b/nuttx/arch/arm/src/sama5/sam_nand.c
@@ -195,6 +195,18 @@ static int hsmc_interrupt(int irq, void *context);
/* DMA Helpers */
#ifdef CONFIG_SAMA5_NAND_DMA
+#ifdef CONFIG_SAMA5_NAND_DMADEBUG
+static void nand_dma_sampleinit(struct sam_nandcs_s *priv);
+# define nand_dma_sample(p,i) sam_dmasample((p)->dma, &(p)->dmaregs[i])
+static void nand_dma_sampledone(struct sam_nandcs_s *priv, int result);
+
+#else
+# define nand_dma_sampleinit(p)
+# define nand_dma_sample(p,i)
+# define nand_dma_sampledone(p,r)
+
+#endif
+
static int nand_wait_dma(struct sam_nandcs_s *priv);
static void nand_dmacallback(DMA_HANDLE handle, void *arg, int result);
static int nand_dma_read(struct sam_nandcs_s *priv,
@@ -202,7 +214,7 @@ static int nand_dma_read(struct sam_nandcs_s *priv,
uint32_t dmaflags);
static int nand_dma_write(struct sam_nandcs_s *priv,
uintptr_t vsrc, uintptr_t vdest, size_t nbytes,
- uint32_t dmaflags)
+ uint32_t dmaflags);
#endif
/* Raw Data Transfer Helpers */
@@ -1122,6 +1134,92 @@ static int hsmc_interrupt(int irq, void *context)
#endif /* CONFIG_SAMA5_NAND_HSMCINTERRUPTS */
/****************************************************************************
+ * Name: nand_dma_sampleinit
+ *
+ * Description:
+ * Initialize sampling of DMA registers (if CONFIG_SAMA5_NAND_DMADEBUG)
+ *
+ * Input Parameters:
+ * priv - Lower-half, private NAND FLASH device state
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_NAND_DMADEBUG
+static void nand_dma_sampleinit(struct sam_nandcs_s *priv)
+{
+ /* Put contents of register samples into a known state */
+
+ memset(priv->dmaregs, 0xff, DMA_NSAMPLES * sizeof(struct sam_dmaregs_s));
+
+ /* Then get the initial samples */
+
+ sam_dmasample(priv->dma, &priv->dmaregs[DMA_INITIAL]);
+}
+#endif
+
+/****************************************************************************
+ * Name: nand_dma_sampledone
+ *
+ * Description:
+ * Dump sampled RX DMA registers
+ *
+ * Input Parameters:
+ * priv - Lower-half, private NAND FLASH device state
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_NAND_DMADEBUG
+static void nand_dma_sampledone(struct sam_nandcs_s *priv, int result)
+{
+ lldbg("result: %d\n", result);
+
+ /* Sample the final registers */
+
+ sam_dmasample(priv->dma, &priv->dmaregs[DMA_END_TRANSFER]);
+
+ /* Then dump the sampled DMA registers */
+ /* Initial register values */
+
+ sam_dmadump(priv->dma, &priv->dmaregs[DMA_INITIAL], "Initial Registers");
+
+ /* Register values after DMA setup */
+
+ sam_dmadump(priv->dma, &priv->dmaregs[DMA_AFTER_SETUP], "After DMA Setup");
+
+ /* Register values after DMA start */
+
+ sam_dmadump(priv->dma, &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 timedout, 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 0 /* No timeout */
+ if (result == -ETIMEDOUT || result == -EINTR)
+ {
+ sam_dmadump(priv->dma, &priv->dmaregs[DMA_TIMEOUT], "At DMA timeout");
+ }
+ else
+#endif
+ {
+ sam_dmadump(priv->dma, &priv->dmaregs[DMA_CALLBACK], "At DMA callback");
+ }
+
+ sam_dmadump(priv->dma, &priv->dmaregs[DMA_END_TRANSFER], "At End-of-Transfer");
+}
+#endif
+
+/****************************************************************************
* Name: nand_wait_dma
*
* Description:
@@ -1170,6 +1268,7 @@ static void nand_dmacallback(DMA_HANDLE handle, void *arg, int result)
struct sam_nandcs_s *priv = (struct sam_nandcs_s *)arg;
DEBUGASSERT(priv);
+ nand_dma_sample(priv, DMA_CALLBACK);
/* Wake up the thread that is waiting for the DMA result */
@@ -1211,6 +1310,10 @@ static int nand_dma_read(struct sam_nandcs_s *priv,
fvdbg("vsrc=%08x vdest=%08x nbytes=%d\n",
(int)vsrc, (int)vdest, (int)nbytes);
+ /* Initialize sampling */
+
+ nand_dma_sampleinit(priv);
+
/* Invalidate the destination memory buffer before performing the DMA (so
* that nothing gets flushed later, corrupting the DMA transfer, and so
* that memory will be re-cached after the DMA completes).
@@ -1240,12 +1343,15 @@ static int nand_dma_read(struct sam_nandcs_s *priv,
return ret;
}
+ nand_dma_sample(priv, DMA_AFTER_SETUP);
+
/* Start the DMA */
priv->dmadone = false;
priv->result = -EBUSY;
sam_dmastart(priv->dma, nand_dmacallback, priv);
+ nand_dma_sample(priv, DMA_AFTER_START);
/* Wait for the DMA to complete */
@@ -1255,6 +1361,8 @@ static int nand_dma_read(struct sam_nandcs_s *priv,
fdbg("ERROR: DMA failed: %d\n", ret);
}
+ nand_dma_sample(priv, DMA_END_TRANSFER);
+ nand_dma_sampledone(priv, ret);
return ret;
}
#endif
@@ -1288,6 +1396,10 @@ static int nand_dma_write(struct sam_nandcs_s *priv,
DEBUGASSERT(priv->dma);
+ /* Initialize sampling */
+
+ nand_dma_sampleinit(priv);
+
/* Clean the D-Cache associated with the source data buffer so that all of
* the data to be transferred lies in physical memory
*/
@@ -1316,12 +1428,15 @@ static int nand_dma_write(struct sam_nandcs_s *priv,
return ret;
}
+ nand_dma_sample(priv, DMA_AFTER_SETUP);
+
/* Start the DMA */
priv->dmadone = false;
priv->result = -EBUSY;
sam_dmastart(priv->dma, nand_dmacallback, priv);
+ nand_dma_sample(priv, DMA_AFTER_START);
/* Wait for the DMA to complete */
@@ -1331,6 +1446,8 @@ static int nand_dma_write(struct sam_nandcs_s *priv,
fdbg("ERROR: DMA failed: %d\n", ret);
}
+ nand_dma_sample(priv, DMA_END_TRANSFER);
+ nand_dma_sampledone(priv, ret);
return ret;
}
#endif
@@ -2871,8 +2988,8 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
/* Initialize the NAND hardware for this CS */
/* Perform board-specific SMC intialization for this CS. This should include:
*
- * 1. Enable clocking to the HSMC
- * 2. Configuration timing for the HSMC CS
+ * 1. Enabling of clocking to the HSMC
+ * 2. Configuration of timing for the HSMC NAND CS
* 3. Configuration of PIO pins
*
* Other than enabling the HSMC, these are all things that the board-cognizant
diff --git a/nuttx/arch/arm/src/sama5/sam_nand.h b/nuttx/arch/arm/src/sama5/sam_nand.h
index 505f33050..01a141107 100644
--- a/nuttx/arch/arm/src/sama5/sam_nand.h
+++ b/nuttx/arch/arm/src/sama5/sam_nand.h
@@ -60,15 +60,16 @@
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
-/* DMA */
+/* DMA. DMA support requires that DMAC0 be enabled. According to
+ * "Table 15-2. SAMA5 Master to Slave Access", DMAC1 does not have access
+ * to NFC SRAM.
+ */
#ifdef CONFIG_SAMA5_NAND_DMA
-# if defined(CONFIG_SAMA5_DMAC1)
-# define NAND_DMAC 1
-# elif defined(CONFIG_SAMA5_DMAC0)
+# ifdef CONFIG_SAMA5_DMAC0
# define NAND_DMAC 0
# else
-# error "A DMA controller must be enabled to perform DMA transfers"
+# error "DMA controller 0 (DMAC0) must be enabled to perform DMA transfers"
# undef CONFIG_SAMA5_NAND_DMA
# endif
#endif
@@ -235,12 +236,17 @@
/* Debug */
-#if !defined(CONFIG_DEBUG)
+#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_FS)
# undef CONFIG_DEBUG_FS
+# undef CONFIG_SAMA5_NAND_DMADEBUG
# undef CONFIG_SAMA5_NAND_REGDEBUG
# undef CONFIG_SAMA5_NAND_DUMP
#endif
+#if !defined(CONFIG_SAMA5_NAND_DMA) || !defined(CONFIG_DEBUG_DMA)
+# undef CONFIG_SAMA5_NAND_DMADEBUG
+#endif
+
/* An early version of this driver used SMC interrupts to determine when
* NAND commands completed, transfers completed, and RB edges occurred. It
* turns out that those interrupts occurred so quickly that some really
@@ -252,6 +258,16 @@
#undef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
+/* DMA Debug */
+
+#define DMA_INITIAL 0
+#define DMA_AFTER_SETUP 1
+#define DMA_AFTER_START 2
+#define DMA_CALLBACK 3
+#define DMA_TIMEOUT 3 /* No timeout */
+#define DMA_END_TRANSFER 4
+#define DMA_NSAMPLES 5
+
/****************************************************************************
* Public Types
****************************************************************************/
@@ -284,6 +300,10 @@ struct sam_nandcs_s
sem_t waitsem; /* Used to wait for DMA done */
DMA_HANDLE dma; /* DMA channel assigned to this CS */
int result; /* The result of the DMA */
+
+#ifdef CONFIG_SAMA5_NAND_DMADEBUG
+ struct sam_dmaregs_s dmaregs[DMA_NSAMPLES];
+#endif
#endif
};
@@ -374,7 +394,12 @@ struct mtd_dev_s *sam_nand_initialize(int cs);
* If CONFIG_SAMA5_BOOT_CS3FLASH is defined, then NAND FLASH support is
* enabled. This function provides the board-specific implementation of
* the logic to reprogram the SMC to support NAND FLASH on the specified
- * CS.
+ * CS. As a minimum, this board-specific initialization should do the
+ * following:
+ *
+ * 1. Enable clocking to the HSMC
+ * 2. Configure timing for the HSMC CS
+ * 3. Configure NAND PIO pins
*
* Input Parameters:
* cs - Chip select number (in the event that multiple NAND devices
@@ -411,7 +436,7 @@ bool board_nand_busy(int cs);
#endif
/****************************************************************************
- * Name: board_nandflash_config
+ * Name: board_nand_ce
*
* Description:
* Must be provided if the board logic supports and interface to control
diff --git a/nuttx/arch/arm/src/sama5/sam_ssc.c b/nuttx/arch/arm/src/sama5/sam_ssc.c
index 9420af350..f578a8dee 100644
--- a/nuttx/arch/arm/src/sama5/sam_ssc.c
+++ b/nuttx/arch/arm/src/sama5/sam_ssc.c
@@ -901,7 +901,7 @@ static void ssc_buf_initialize(struct sam_ssc_s *priv)
* Name: ssc_dma_sampleinit
*
* Description:
- * Initialize sampling of RX DMA registers (if CONFIG_SAMA5_SSC_DMADEBUG)
+ * Initialize sampling of DMA registers (if CONFIG_SAMA5_SSC_DMADEBUG)
*
* Input Parameters:
* priv - SSC state instance