SAMA5 NAND: Can't DMA using DMAC1. Add lots of NAND DMA debug instrumentation
This commit is contained in:
parent
c62a9c269a
commit
1de529cc42
@ -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
|
||||
|
@ -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? */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user