SAMA5 NAND: Return value should not be ignored
This commit is contained in:
parent
cdaa0b9671
commit
06dca0d263
@ -3434,9 +3434,18 @@ endif # SAMA5_HAVE_PMECC
|
||||
config SAMA5_NAND_REGDEBUG
|
||||
bool "Register-Level NAND Debug"
|
||||
default n
|
||||
depends on DEBUG
|
||||
depends on DEBUG && DEBUG_FS
|
||||
---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
|
||||
endmenu # External Memory Configuration
|
||||
|
@ -158,6 +158,12 @@ void nand_unlock(void);
|
||||
# define nand_unlock()
|
||||
#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_nfc_cmdsend(struct sam_nandcs_s *priv, uint32_t cmd,
|
||||
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_wait_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);
|
||||
#endif
|
||||
static uint32_t nand_nfc_poll(void);
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
static int hsmc_interrupt(int irq, void *context);
|
||||
@ -455,7 +466,7 @@ static int nand_translate_address(struct sam_nandcs_s *priv,
|
||||
bool rowonly)
|
||||
{
|
||||
uint16_t maxsize;
|
||||
uint32_t page;
|
||||
uint32_t maxpage;
|
||||
uint32_t accum0;
|
||||
uint32_t accum1234;
|
||||
uint8_t bytes[8];
|
||||
@ -467,7 +478,7 @@ static int nand_translate_address(struct sam_nandcs_s *priv,
|
||||
|
||||
maxsize = nandmodel_getpagesize(&priv->raw.model) +
|
||||
nandmodel_getsparesize(&priv->raw.model) - 1;
|
||||
page = nandmodel_getdevpagesize(&priv->raw.model) - 1;
|
||||
maxpage = nandmodel_getdevpagesize(&priv->raw.model) - 1;
|
||||
ncycles = 0;
|
||||
accum0 = 0;
|
||||
accum1234 = 0;
|
||||
@ -499,10 +510,10 @@ static int nand_translate_address(struct sam_nandcs_s *priv,
|
||||
|
||||
/* Convert row address */
|
||||
|
||||
while (page > 0)
|
||||
while (maxpage > 0)
|
||||
{
|
||||
bytes[ncycles++] = rowaddr & 0xff;
|
||||
page >>= 8;
|
||||
maxpage >>= 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))
|
||||
{
|
||||
bool rowonly = ((mode & HSMC_ALE_COL_EN) == 0);
|
||||
nand_translate_address(priv, coladdr, rowaddr, &acycle0, &acycle1234, rowonly);
|
||||
acycle = nand_get_acycle(ncycles);
|
||||
ncycles = nand_translate_address(priv, coladdr, rowaddr,
|
||||
&acycle0, &acycle1234, rowonly);
|
||||
acycle = nand_get_acycle(ncycles);
|
||||
}
|
||||
else
|
||||
{
|
||||
acycle = NFCADDR_CMD_ACYCLE_NONE;
|
||||
acycle = NFCADDR_CMD_ACYCLE_NONE;
|
||||
}
|
||||
|
||||
cmd = (rw | regval | NFCADDR_CMD_CSID(priv->cs) | acycle |
|
||||
@ -830,6 +842,101 @@ static void nand_setup_xfrdone(struct sam_nandcs_s *priv)
|
||||
#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
|
||||
*
|
||||
@ -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)
|
||||
{
|
||||
uint32_t sr;
|
||||
@ -856,6 +964,7 @@ static void nand_wait_nfcbusy(struct sam_nandcs_s *priv)
|
||||
}
|
||||
while ((sr & HSMC_SR_NFCBUSY) != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_nfc_poll
|
||||
@ -916,6 +1025,21 @@ static uint32_t nand_nfc_poll(void)
|
||||
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
|
||||
irqrestore(flags);
|
||||
#endif
|
||||
@ -977,6 +1101,25 @@ static int hsmc_interrupt(int irq, void *context)
|
||||
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;
|
||||
}
|
||||
#endif /* CONFIG_SAMA5_NAND_HSMCINTERRUPTS */
|
||||
@ -1306,6 +1449,7 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
uint32_t dmaflags;
|
||||
#endif
|
||||
int buswidth;
|
||||
int ret;
|
||||
|
||||
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 */
|
||||
|
||||
return nand_dma_read(priv, src, (uintptr_t)buffer, buflen, dmaflags);
|
||||
ret = nand_dma_read(priv, src, (uintptr_t)buffer, buflen, dmaflags);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1358,7 +1502,7 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
|
||||
if (nfcsram)
|
||||
{
|
||||
return nand_nfcsram_read(src, buffer, buflen);
|
||||
ret = nand_nfcsram_read(src, buffer, buflen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1366,13 +1510,16 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
|
||||
if (buswidth == 16)
|
||||
{
|
||||
return nand_smc_read16(src, buffer, buflen);
|
||||
ret = nand_smc_read16(src, buffer, buflen);
|
||||
}
|
||||
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",
|
||||
nfcsram, buffer, (int)buflen, (int)offset);
|
||||
|
||||
nand_dump("NAND Write", buffer, buflen);
|
||||
|
||||
/* Get the buswidth */
|
||||
|
||||
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);
|
||||
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_wait_nfcbusy(priv);
|
||||
|
||||
#endif
|
||||
ret = nand_operation_complete(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
|
@ -226,12 +226,20 @@
|
||||
# define NAND_HAVE_EBICS3 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMA5_HAVE_NAND
|
||||
|
||||
/* Count the number of banks configured for NAND */
|
||||
|
||||
#define NAND_NBANKS \
|
||||
(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
|
||||
* NAND commands completed, transfers completed, and RB edges occurred. It
|
||||
@ -244,6 +252,13 @@
|
||||
|
||||
#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
|
||||
****************************************************************************/
|
||||
@ -288,10 +303,17 @@ struct sam_nand_s
|
||||
#ifdef CONFIG_SAMA5_NAND_HSMCINTERRUPTS
|
||||
volatile bool cmddone; /* True: NFC command 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 */
|
||||
|
||||
#else
|
||||
bool cmddone; /* True: NFC command has completed (latching) */
|
||||
bool xfrdone; /* True: Transfer has completed (latching) */
|
||||
#ifdef USE_RBEDGE
|
||||
bool rbedge; /* True: Ready/busy edge detected (latching) */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMA5_HAVE_PMECC
|
||||
|
Loading…
Reference in New Issue
Block a user