diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index e9e65a0b93..b5b3d8a651 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -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 diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index f0c7fd4521..04103ccdd5 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -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) { diff --git a/arch/arm/src/sama5/sam_nand.h b/arch/arm/src/sama5/sam_nand.h index d1c92acb99..674e0d8c38 100644 --- a/arch/arm/src/sama5/sam_nand.h +++ b/arch/arm/src/sama5/sam_nand.h @@ -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