SAMA5 NAND: Can't DMA using DMAC1. Add lots of NAND DMA debug instrumentation

This commit is contained in:
Gregory Nutt 2013-12-02 17:15:57 -06:00
parent c62a9c269a
commit 1de529cc42
5 changed files with 169 additions and 15 deletions

View File

@ -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

View File

@ -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? */

View File

@ -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 */
@ -1121,6 +1133,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
*
@ -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

View File

@ -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

View File

@ -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