SAMA5 NAND: Return value should not be ignored

This commit is contained in:
Gregory Nutt 2013-12-01 13:39:28 -06:00
parent cdaa0b9671
commit 06dca0d263
3 changed files with 200 additions and 15 deletions

View File

@ -3434,9 +3434,18 @@ endif # SAMA5_HAVE_PMECC
config SAMA5_NAND_REGDEBUG config SAMA5_NAND_REGDEBUG
bool "Register-Level NAND Debug" bool "Register-Level NAND Debug"
default n default n
depends on DEBUG depends on DEBUG && DEBUG_FS
---help--- ---help---
Enable very low-level register access debug. Depends on DEBUG. Enable very low-level register access debug. Depends on DEBUG and
DEBUG_FS.
config SAMA5_NAND_DUMP
bool "NAND data dump"
default n
depends on DEBUG && DEBUG_FS
---help---
Dump the contents of all data read and written to FLAH. Depends on
DEBUG and DEBUG_FS.
endif # SAMA5_HAVE_NAND endif # SAMA5_HAVE_NAND
endmenu # External Memory Configuration endmenu # External Memory Configuration

View File

@ -158,6 +158,12 @@ void nand_unlock(void);
# define nand_unlock() # define nand_unlock()
#endif #endif
#ifdef CONFIG_SAMA5_NAND_DUMP
# define nand_dump(m,b,s) lib_dumpbuffer(m,b,s)
#else
# define nand_dump(m,b,s)
#endif
static void nand_wait_ready(struct sam_nandcs_s *priv); static void nand_wait_ready(struct sam_nandcs_s *priv);
static void nand_nfc_cmdsend(struct sam_nandcs_s *priv, uint32_t cmd, static void nand_nfc_cmdsend(struct sam_nandcs_s *priv, uint32_t cmd,
uint32_t acycle, uint32_t cycle0); uint32_t acycle, uint32_t cycle0);
@ -176,7 +182,12 @@ static void nand_wait_cmddone(struct sam_nandcs_s *priv);
static void nand_setup_cmddone(struct sam_nandcs_s *priv); static void nand_setup_cmddone(struct sam_nandcs_s *priv);
static void nand_wait_xfrdone(struct sam_nandcs_s *priv); static void nand_wait_xfrdone(struct sam_nandcs_s *priv);
static void nand_setup_xfrdone(struct sam_nandcs_s *priv); static void nand_setup_xfrdone(struct sam_nandcs_s *priv);
#ifdef USE_RBEDGE
static void nand_wait_rbedge(struct sam_nandcs_s *priv);
static void nand_setup_rbedge(struct sam_nandcs_s *priv);
#else
static void nand_wait_nfcbusy(struct sam_nandcs_s *priv); static void nand_wait_nfcbusy(struct sam_nandcs_s *priv);
#endif
static uint32_t nand_nfc_poll(void); static uint32_t nand_nfc_poll(void);
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS #ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
static int hsmc_interrupt(int irq, void *context); static int hsmc_interrupt(int irq, void *context);
@ -455,7 +466,7 @@ static int nand_translate_address(struct sam_nandcs_s *priv,
bool rowonly) bool rowonly)
{ {
uint16_t maxsize; uint16_t maxsize;
uint32_t page; uint32_t maxpage;
uint32_t accum0; uint32_t accum0;
uint32_t accum1234; uint32_t accum1234;
uint8_t bytes[8]; uint8_t bytes[8];
@ -467,7 +478,7 @@ static int nand_translate_address(struct sam_nandcs_s *priv,
maxsize = nandmodel_getpagesize(&priv->raw.model) + maxsize = nandmodel_getpagesize(&priv->raw.model) +
nandmodel_getsparesize(&priv->raw.model) - 1; nandmodel_getsparesize(&priv->raw.model) - 1;
page = nandmodel_getdevpagesize(&priv->raw.model) - 1; maxpage = nandmodel_getdevpagesize(&priv->raw.model) - 1;
ncycles = 0; ncycles = 0;
accum0 = 0; accum0 = 0;
accum1234 = 0; accum1234 = 0;
@ -499,10 +510,10 @@ static int nand_translate_address(struct sam_nandcs_s *priv,
/* Convert row address */ /* Convert row address */
while (page > 0) while (maxpage > 0)
{ {
bytes[ncycles++] = rowaddr & 0xff; bytes[ncycles++] = rowaddr & 0xff;
page >>= 8; maxpage >>= 8;
rowaddr >>= 8; rowaddr >>= 8;
} }
@ -633,12 +644,13 @@ static void nand_nfc_cleale(struct sam_nandcs_s *priv, uint8_t mode,
if (((mode & HSMC_ALE_COL_EN) != 0) || ((mode & HSMC_ALE_ROW_EN) != 0)) if (((mode & HSMC_ALE_COL_EN) != 0) || ((mode & HSMC_ALE_ROW_EN) != 0))
{ {
bool rowonly = ((mode & HSMC_ALE_COL_EN) == 0); bool rowonly = ((mode & HSMC_ALE_COL_EN) == 0);
nand_translate_address(priv, coladdr, rowaddr, &acycle0, &acycle1234, rowonly); ncycles = nand_translate_address(priv, coladdr, rowaddr,
acycle = nand_get_acycle(ncycles); &acycle0, &acycle1234, rowonly);
acycle = nand_get_acycle(ncycles);
} }
else else
{ {
acycle = NFCADDR_CMD_ACYCLE_NONE; acycle = NFCADDR_CMD_ACYCLE_NONE;
} }
cmd = (rw | regval | NFCADDR_CMD_CSID(priv->cs) | acycle | cmd = (rw | regval | NFCADDR_CMD_CSID(priv->cs) | acycle |
@ -830,6 +842,101 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
#endif #endif
} }
/****************************************************************************
* Name: nand_wait_rbedge
*
* Description:
* Wait for read/busy edge detection
*
* Input parameters:
* priv - CS state structure instance
*
* Returned value.
* None
*
****************************************************************************/
#ifdef USE_RBEDGE
static void nand_wait_rbedge(struct sam_nandcs_s *priv)
{
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
int ret;
/* Wait for the RBEDGE0 interrupt to occur */
flags = irqsave();
do
{
ret = sem_wait(&g_nand.waitsem);
if (ret < 0)
{
DEBUGASSERT(errno == EINTR);
}
}
while (!g_nand.rbedge);
/* RBEDGE0 received */
g_nand.rbedge = false;
irqrestore(flags);
#else
/* Poll for the RBEDGE0 event (latching other events as necessary) */
do
{
(void)nand_nfc_poll();
}
while (!g_nand.rbedge);
#endif
}
#endif
/****************************************************************************
* Name: nand_setup_rbedge
*
* Description:
* Setup to wait for RBEDGE0 event
*
* Input parameters:
* priv - CS state structure instance
*
* Returned value.
* None
*
****************************************************************************/
#ifdef USE_RBEDGE
static void nand_setup_rbedge(struct sam_nandcs_s *priv)
{
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqstate_t flags;
/* Clear all pending interrupts. This must be done with interrupts
* enabled or we could lose interrupts.
*/
nand_getreg(SAM_HSMC_SR);
flags = irqsave();
/* Mark RBEDGE0 not received */
g_nand.rbedge = false;
/* Enable the RBEDGE0 interrupt */
nand_putreg(SAM_HSMC_IER, HSMC_NFCINT_RBEDGE0);
irqrestore(flags);
#else
/* Just sample and clear any pending NFC status, then clear RBEDGE0 status */
(void)nand_nfc_poll();
g_nand.rbedge = false;
#endif
}
#endif
/**************************************************************************** /****************************************************************************
* Name: nand_wait_nfcbusy * Name: nand_wait_nfcbusy
* *
@ -844,6 +951,7 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
* *
****************************************************************************/ ****************************************************************************/
#ifndef USE_RBEDGE
static void nand_wait_nfcbusy(struct sam_nandcs_s *priv) static void nand_wait_nfcbusy(struct sam_nandcs_s *priv)
{ {
uint32_t sr; uint32_t sr;
@ -856,6 +964,7 @@ static void nand_wait_nfcbusy(struct sam_nandcs_s *priv)
} }
while ((sr & HSMC_SR_NFCBUSY) != 0); while ((sr & HSMC_SR_NFCBUSY) != 0);
} }
#endif
/**************************************************************************** /****************************************************************************
* Name: nand_nfc_poll * Name: nand_nfc_poll
@ -916,6 +1025,21 @@ static uint32_t nand_nfc_poll(void)
g_nand.cmddone = true; g_nand.cmddone = true;
} }
#ifdef USE_RBEDGE
/* If set to one, the RBEDGE0 flag indicates that an edge has been detected
* on the Ready/Busy Line x. Depending on the EDGE CTRL field located in the
* SMC_CFG register, only rising or falling edge is detected. This flag is
* reset after the status read.
*/
if ((pending & HSMC_NFCINT_RBEDGE0) != 0)
{
/* Set the latching RBEDGE0 status */
g_nand.rbedge = true;
}
#endif
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS #ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
irqrestore(flags); irqrestore(flags);
#endif #endif
@ -977,6 +1101,25 @@ static int hsmc_interrupt(int irq, void *context)
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_CMDDONE); nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_CMDDONE);
} }
#ifdef USE_RBEDGE
/* If set to one, the RBEDGE0 flag indicates that an edge has been detected
* on the Ready/Busy Line x. Depending on the EDGE CTRL field located in the
* SMC_CFG register, only rising or falling edge is detected. This flag is
* reset after the status read.
*/
if (g_nand.rbedge && (imr & HSMC_NFCINT_RBEDGE0) != 0)
{
/* Post the RBEDGE0 event */
sem_post(&g_nand.waitsem);
/* Disable further RBEDGE0 interrupts */
nand_putreg(SAM_HSMC_IDR, HSMC_NFCINT_RBEDGE0);
}
#endif
return OK; return OK;
} }
#endif /* CONFIG_SAMA5_NAND_HSMCINTERRUPTS */ #endif /* CONFIG_SAMA5_NAND_HSMCINTERRUPTS */
@ -1306,6 +1449,7 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
uint32_t dmaflags; uint32_t dmaflags;
#endif #endif
int buswidth; int buswidth;
int ret;
fvdbg("nfcsram=%d buffer=%p buflen=%d\n", nfcsram, buffer, (int)buflen); fvdbg("nfcsram=%d buffer=%p buflen=%d\n", nfcsram, buffer, (int)buflen);
@ -1349,7 +1493,7 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
{ {
/* Transfer using DMA */ /* Transfer using DMA */
return nand_dma_read(priv, src, (uintptr_t)buffer, buflen, dmaflags); ret = nand_dma_read(priv, src, (uintptr_t)buffer, buflen, dmaflags);
} }
else else
#endif #endif
@ -1358,7 +1502,7 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
if (nfcsram) if (nfcsram)
{ {
return nand_nfcsram_read(src, buffer, buflen); ret = nand_nfcsram_read(src, buffer, buflen);
} }
else else
{ {
@ -1366,13 +1510,16 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
if (buswidth == 16) if (buswidth == 16)
{ {
return nand_smc_read16(src, buffer, buflen); ret = nand_smc_read16(src, buffer, buflen);
} }
else else
{ {
return nand_smc_read8(src, buffer, buflen); ret = nand_smc_read8(src, buffer, buflen);
} }
} }
nand_dump("NAND Read", buffer, buflen);
return ret;
} }
/**************************************************************************** /****************************************************************************
@ -1611,6 +1758,8 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
fvdbg("nfcsram=%d buffer=%p buflen=%d offset=%d\n", fvdbg("nfcsram=%d buffer=%p buflen=%d offset=%d\n",
nfcsram, buffer, (int)buflen, (int)offset); nfcsram, buffer, (int)buflen, (int)offset);
nand_dump("NAND Write", buffer, buflen);
/* Get the buswidth */ /* Get the buswidth */
buswidth = nandmodel_getbuswidth(&priv->raw.model); buswidth = nandmodel_getbuswidth(&priv->raw.model);
@ -2001,9 +2150,14 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
COMMAND_WRITE_1, 0, 0, rowaddr); COMMAND_WRITE_1, 0, 0, rowaddr);
nand_wait_xfrdone(priv); nand_wait_xfrdone(priv);
#ifdef USE_RBEDGE
nand_setup_rbedge(priv);
nand_nfc_cleale(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0);
nand_wait_rbedge(priv);
#else
nand_nfc_cleale(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0); nand_nfc_cleale(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0);
nand_wait_nfcbusy(priv); nand_wait_nfcbusy(priv);
#endif
ret = nand_operation_complete(priv); ret = nand_operation_complete(priv);
if (ret < 0) if (ret < 0)
{ {

View File

@ -226,12 +226,20 @@
# define NAND_HAVE_EBICS3 0 # define NAND_HAVE_EBICS3 0
#endif #endif
#ifdef CONFIG_SAMA5_HAVE_NAND
/* Count the number of banks configured for NAND */ /* Count the number of banks configured for NAND */
#define NAND_NBANKS \ #define NAND_NBANKS \
(NAND_HAVE_EBICS0 + NAND_HAVE_EBICS1 + NAND_HAVE_EBICS2 + NAND_HAVE_EBICS3) (NAND_HAVE_EBICS0 + NAND_HAVE_EBICS1 + NAND_HAVE_EBICS2 + NAND_HAVE_EBICS3)
#ifdef CONFIG_SAMA5_HAVE_NAND /* Debug */
#if !defined(CONFIG_DEBUG)
# undef CONFIG_DEBUG_FS
# undef CONFIG_SAMA5_NAND_REGDEBUG
# undef CONFIG_SAMA5_NAND_DUMP
#endif
/* An early version of this driver used SMC interrupts to determine when /* An early version of this driver used SMC interrupts to determine when
* NAND commands completed, transfers completed, and RB edges occurred. It * NAND commands completed, transfers completed, and RB edges occurred. It
@ -244,6 +252,13 @@
#undef CONFIG_SAMA5_NAND_HSMCINTERRUPTS #undef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
/* In the write sequence, there is a step where we should wait on an R/B
* edge transition. The step currently hangs but, presumably must be
* restored when NAND is working.
*/
#undef USE_RBEDGE
/**************************************************************************** /****************************************************************************
* Public Types * Public Types
****************************************************************************/ ****************************************************************************/
@ -288,10 +303,17 @@ struct sam_nand_s
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS #ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
volatile bool cmddone; /* True: NFC command has completed (latching) */ volatile bool cmddone; /* True: NFC command has completed (latching) */
volatile bool xfrdone; /* True: Transfer has completed (latching) */ volatile bool xfrdone; /* True: Transfer has completed (latching) */
#ifdef USE_RBEDGE
volatile bool rbedge; /* True: Ready/busy edge detected (latching) */
#endif
sem_t waitsem; /* Used to wait for one of the above states */ sem_t waitsem; /* Used to wait for one of the above states */
#else #else
bool cmddone; /* True: NFC command has completed (latching) */ bool cmddone; /* True: NFC command has completed (latching) */
bool xfrdone; /* True: Transfer has completed (latching) */ bool xfrdone; /* True: Transfer has completed (latching) */
#ifdef USE_RBEDGE
bool rbedge; /* True: Ready/busy edge detected (latching) */
#endif
#endif #endif
#ifdef CONFIG_SAMA5_HAVE_PMECC #ifdef CONFIG_SAMA5_HAVE_PMECC