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
|
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
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user