summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/arch/arm/src/sama5/sam_nand.c495
1 files changed, 272 insertions, 223 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_nand.c b/nuttx/arch/arm/src/sama5/sam_nand.c
index e41a7b8c6..8227ba4d2 100644
--- a/nuttx/arch/arm/src/sama5/sam_nand.c
+++ b/nuttx/arch/arm/src/sama5/sam_nand.c
@@ -219,24 +219,22 @@ static int nand_dma_write(struct sam_nandcs_s *priv,
/* Raw Data Transfer Helpers */
-static int nand_nfcsram_read(uintptr_t src, uint8_t *dest,
- size_t buflen);
+static int nand_nfcsram_read(struct sam_nandcs_s *priv,
+ uint8_t *buffer, uint16_t buflen);
+#ifdef CONFIG_SAMA5_HAVE_PMECC
static int nand_read(struct sam_nandcs_s *priv, uint8_t *buffer,
- uint16_t buflen, uint16_t offset);
+ uint16_t buflen);
+#endif
#ifdef CONFIG_SAMA5_HAVE_PMECC
static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
unsigned int page, void *data);
#endif
-static int nand_nfcsram_write(const uint8_t *src, uintptr_t dest,
- size_t buflen);
-static int nand_smc_write8(const uint8_t *src, uintptr_t dest,
- size_t buflen);
-static int nand_smc_write16(const uint8_t *src, uintptr_t dest,
- size_t buflen);
-static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
- uint8_t *buffer, size_t buflen, off_t offset);
+static int nand_nfcsram_write(struct sam_nandcs_s *priv,
+ uint8_t *buffer, uint16_t buflen, uint16_t offset);
+static int nand_write(struct sam_nandcs_s *priv, uint8_t *buffer,
+ uint16_t buflen, uint16_t offset);
/* NAND Access Helpers */
@@ -1453,66 +1451,98 @@ static int nand_dma_write(struct sam_nandcs_s *priv,
* Name: nand_nfcsram_read
*
* Description:
- * Read data from NAND using the NFC SRAM (without DMA)
+ * Read data from NAND using the NFC SRAM
*
* Input Parameters:
- * src - NAND data source address
- * dest - Buffer that will receive the data from the read
- * buflen - The number of bytes to transfer
+ * priv - Lower-half, private NAND FLASH device state
+ * buffer - Buffer that provides the data for the write
+ * buflen - The amount of data to read into the buffer
+ * offset - If reading from NFC SRAM, this is the offset into
+ * the SRAM.
*
* Returned Value
- * OK always
+ * OK on success; a negated errno value on failure.
*
****************************************************************************/
-static int nand_nfcsram_read(uintptr_t src, uint8_t *dest, size_t buflen)
+static int nand_nfcsram_read(struct sam_nandcs_s *priv, uint8_t *buffer,
+ uint16_t buflen)
{
- uint8_t *src8 = (uint8_t *)src;
+ int remaining;
+ int ret;
+
+ fvdbg("buffer=%p buflen=%d\n", buffer, buflen);
+
+#ifdef CONFIG_SAMA5_NAND_DMA
+ /* Then perform the transfer via memory-to-memory DMA or not, depending
+ * on if we have a DMA channel assigned and if the transfer is
+ * sufficiently large. Small DMAs (e.g., for spare data) are not performed
+ * because the DMA context switch can take more time that the DMA itself.
+ */
+
+ if (priv->dma && buflen > CONFIG_SAMA5_NAND_DMA_THRESHOLD)
+ {
+ /* Get the buswidth */
+
+ int buswidth = nandmodel_getbuswidth(&priv->raw.model);
+
+ /* Select NFC SRAM DMA */
+
+ uint32_t dmaflags =
+ (buswidth == 16 ? NFCSRAM_DMA_FLAGS16 : NFCSRAM_DMA_FLAGS8);
+
+ /* Transfer using DMA */
+
+ ret = nand_dma_read(priv, NFCSRAM_BASE, (uintptr_t)buffer, buflen,
+ dmaflags);
+ }
+ else
+#endif
+
+ /* Transfer without DMA */
- for (; buflen > 0; buflen--)
{
- *dest++ = *src8++;
+ uint8_t *src8 = (uint8_t *)NFCSRAM_BASE;
+ uint8_t *dest8 = buffer;
+
+ for (remaining = buflen; remaining > 0; remaining--)
+ {
+ *dest8++ = *src8++;
+ }
+
+ ret = OK;
}
- return OK;
+ nand_dump("NFS SRAM Read", buffer, buflen);
+ return ret;
}
/****************************************************************************
* Name: nand_read
*
* Description:
- * Read data from NAND using the NFC SRAM
+ * Read data directly from the NAND data address. Currently this only used
+ * by the PMECC logic which I could not get working if I read from NFC SRAM.
*
* Input Parameters:
* priv - Lower-half, private NAND FLASH device state
+ * nfcsram - True: Use NFC Host SRAM
* buffer - Buffer that provides the data for the write
- * buflen - The amount of data to read into the buffer
- * offset - If reading from NFC SRAM, this is the offset into
- * the SRAM.
*
* Returned Value
* OK on success; a negated errno value on failure.
*
****************************************************************************/
+#ifdef CONFIG_SAMA5_HAVE_PMECC
static int nand_read(struct sam_nandcs_s *priv, uint8_t *buffer,
- uint16_t buflen, uint16_t offset)
+ uint16_t buflen)
{
- uintptr_t src;
-#ifdef CONFIG_SAMA5_NAND_DMA
- uint32_t dmaflags;
-#endif
+ int remaining;
int buswidth;
int ret;
- fvdbg("buffer=%p buflen=%d offset=%d\n", buffer, buflen, offset);
-
- /* Get the data source: NFC SRAM (perhaps with an offset)
- * NOTE: We could use the address priv->raw.dataaddr if we want to
- * bypass NFC SRAM.
- */
-
- src = NFCSRAM_BASE + offset;
+ fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen);
/* Get the buswidth */
@@ -1521,19 +1551,21 @@ static int nand_read(struct sam_nandcs_s *priv, uint8_t *buffer,
#ifdef CONFIG_SAMA5_NAND_DMA
/* Then perform the transfer via memory-to-memory DMA or not, depending
* on if we have a DMA channel assigned and if the transfer is
- * sufficiently large. Small DMAs (e.g., for spare data) are not performed
+ * sufficiently large. Small DMAs (e.g., for spare data) are not peformed
* because the DMA context switch can take more time that the DMA itself.
*/
if (priv->dma && buflen > CONFIG_SAMA5_NAND_DMA_THRESHOLD)
{
- /* Select NFC SRAM DMA */
+ /* Select NFC DATA DMA */
- dmaflags = (buswidth == 16 ? NFCSRAM_DMA_FLAGS16 : NFCSRAM_DMA_FLAGS8);
+ uint32_t dmaflags =
+ (buswidth == 16 ? NAND_DMA_FLAGS16 : NAND_DMA_FLAGS8);
/* Transfer using DMA */
- ret = nand_dma_read(priv, src, (uintptr_t)buffer, buflen, dmaflags);
+ ret = nand_dma_read(priv, priv->raw.dataaddr, (uintptr_t)buffer,
+ buflen, dmaflags);
}
else
#endif
@@ -1541,12 +1573,39 @@ static int nand_read(struct sam_nandcs_s *priv, uint8_t *buffer,
/* Transfer without DMA */
{
- ret = nand_nfcsram_read(src, buffer, buflen);
+ /* Check the data bus width of the NAND FLASH */
+
+ remaining = buflen;
+ if (buswidth == 16)
+ {
+ volatile uint16_t *src16 = (volatile uint16_t *)priv->raw.dataaddr;
+ uint16_t *dest16 = (uint16_t *)buffer;
+
+ DEBUGASSERT(((uintptr_t)buffer & 1) == 0);
+
+ for (; remaining > 1; remaining -= sizeof(uint16_t))
+ {
+ *dest16++ = *src16;
+ }
+ }
+ else
+ {
+ volatile uint8_t *src8 = (volatile uint8_t *)priv->raw.dataaddr;
+ uint8_t *dest8 = (uint8_t *)buffer;
+
+ for (; remaining > 0; remaining--)
+ {
+ *dest8++ = *src8;
+ }
+ }
+
+ ret = OK;
}
nand_dump("NAND Read", buffer, buflen);
return ret;
}
+#endif
/****************************************************************************
* Name: nand_read_pmecc
@@ -1616,7 +1675,7 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
regval |= (HSMC_CFG_RSPARE | HSMC_CFG_RBEDGE | HSMC_CFG_DTOCYC(15) |
HSMC_CFG_DTOMUL_1048576 |
- HSMC_CFG_NFCSPARESIZE((sparesize-1) >> 2));
+ HSMC_CFG_NFCSPARESIZE((sparesize - 1) >> 2));
nand_putreg(SAM_HSMC_CFG, regval);
/* Calculate actual address of the page */
@@ -1639,9 +1698,12 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
/* Start the data phase and perform the transfer */
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_DATA);
+
+ nand_setup_rbedge(priv);
nand_nfc_cleale(priv,
- HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN | HSMC_CLE_VCMD2_EN | HSMC_CLE_DATA_EN,
+ HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN | HSMC_CLE_VCMD2_EN,
COMMAND_READ_1, COMMAND_READ_2, 0, rowaddr);
+ nand_wait_rbedge(priv);
/* Reset the PMECC module */
@@ -1651,20 +1713,21 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_DATA);
- /* Read the data area into the caller provided buffer (pagesize bytes) */
+ /* Read the data area into the caller provided buffer (pagesize bytes).
+ * NOTE: NFC SRAM is not used. In that case, the wait for PMECC not
+ * busy below would hang.
+ */
- ret = nand_read(priv, (uint8_t *)data, pagesize, 0);
+ ret = nand_read(priv, (uint8_t *)data, pagesize);
if (ret < 0)
{
fdbg("ERROR: nand_read for data region failed: %d\n", ret);
return ret;
}
- /* Read the spare area into priv->raw.spare. The data to be read lies at
- * offset pagesize in NFC SRAM.
- */
+ /* Now read the spare area into priv->raw.spare (sparesize bytes). */
- ret = nand_read(priv, priv->raw.spare, priv->raw.model.sparesize, pagesize);
+ ret = nand_read(priv, priv->raw.spare, sparesize);
if (ret < 0)
{
fdbg("ERROR: nand_read for spare region failed: %d\n", ret);
@@ -1682,98 +1745,80 @@ static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
* Name: nand_nfcsram_write
*
* Description:
- * Write data to NAND using the NFC SRAM (without DMA)
+ * Write data to NAND using NAND NFC SRAM
*
* Input Parameters:
- * src - Buffer that provides the data for the write
- * dest - NAND data destination address
- * buflen - The number of bytes to transfer
+ * priv - Lower-half, private NAND FLASH device state
+ * buffer - Buffer that provides the data for the write
+ * offset - Data offset in bytes
*
* Returned Value
- * OK always
+ * OK on success; a negated errno value on failure.
*
****************************************************************************/
-static int nand_nfcsram_write(const uint8_t *src, uintptr_t dest, size_t buflen)
+static int nand_nfcsram_write(struct sam_nandcs_s *priv, uint8_t *buffer,
+ uint16_t buflen, uint16_t offset)
{
- uint8_t *dest8 = (uint8_t *)dest;
+ uintptr_t dest;
+ int ret;
- for (; buflen > 0; buflen--)
- {
- *dest8++ = *src++;
- }
+ fvdbg("buffer=%p buflen=%d offset=%d\n", buffer, buflen, offset);
+ nand_dump("NFC SRAM Write", buffer, buflen);
- return OK;
-}
+ /* Apply the offset to the destination address */
-/****************************************************************************
- * Name: nand_smc_write8
- *
- * Description:
- * Write 8-bit wide data to NAND using the NAND data address (without DMA)
- *
- * Input Parameters:
- * src - Buffer that provides the data for the write
- * dest - NAND data destination address
- * buflen - The number of bytes to transfer
- *
- * Returned Value
- * OK always
- *
- ****************************************************************************/
+ dest = NFCSRAM_BASE + offset;
-static int nand_smc_write8(const uint8_t *src, uintptr_t dest, size_t buflen)
-{
- volatile uint8_t *dest8 = (volatile uint8_t *)dest;
+#ifdef CONFIG_SAMA5_NAND_DMA
+ /* Then perform the transfer via memory-to-memory DMA or not, depending
+ * on if we have a DMA channel assigned and if the transfer is
+ * sufficiently large. Small DMAs (e.g., for spare data) are not peformed
+ * because the DMA context switch can take more time that the DMA itself.
+ */
- for (; buflen > 0; buflen--)
+ if (priv->dma && buflen > CONFIG_SAMA5_NAND_DMA_THRESHOLD)
{
- *dest8 = *src++;
- }
+ /* Get the buswidth */
- return OK;
-}
+ int buswidth = nandmodel_getbuswidth(&priv->raw.model);
-/****************************************************************************
- * Name: nand_smc_write16
- *
- * Description:
- * Write 16-bit wide data to NAND using the NAND data address (without DMA)
- *
- * Input Parameters:
- * src - Buffer that provides the data for the write
- * dest - NAND data destination address
- * buflen - The number of bytes to transfer
- *
- * Returned Value
- * OK always
- *
- ****************************************************************************/
+ /* Select NFC SRAM DMA */
-static int nand_smc_write16(const uint8_t *src, uintptr_t dest, size_t buflen)
-{
- volatile uint16_t *dest16 = (volatile uint16_t *)dest;
- const uint16_t *src16 = (const uint16_t *)src;
+ uint32_t dmaflags =
+ (buswidth == 16 ? NFCSRAM_DMA_FLAGS16 : NFCSRAM_DMA_FLAGS8);
+
+ /* Transfer using DMA */
- DEBUGASSERT(((uintptr_t)src & 1) == 0);
+ ret = nand_dma_write(priv, (uintptr_t)buffer, dest, buflen, dmaflags);
+ }
+ else
+#endif
+
+ /* Transfer without DMA */
- for (; buflen > 1; buflen -= sizeof(uint16_t))
{
- *dest16 = *src16++;
+ uint8_t *dest8 = (uint8_t *)dest;
+
+ for (; buflen > 0; buflen--)
+ {
+ *dest8++ = *buffer++;
+ }
+
+ ret = OK;
}
- return OK;
+ return ret;
}
/****************************************************************************
* Name: nand_write
*
* Description:
- * Write data to NAND using the appropriate method
+ * Write data to NAND using the NAND data address.
*
* Input Parameters:
* priv - Lower-half, private NAND FLASH device state
- * nfcsram - True: Use NFC Host SRAM
* buffer - Buffer that provides the data for the write
* offset - Data offset in bytes
*
@@ -1782,54 +1827,23 @@ static int nand_smc_write16(const uint8_t *src, uintptr_t dest, size_t buflen)
*
****************************************************************************/
-static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
- uint8_t *buffer, size_t buflen, off_t offset)
+static int nand_write(struct sam_nandcs_s *priv, uint8_t *buffer,
+ uint16_t buflen, uint16_t offset)
{
uintptr_t dest;
-#ifdef CONFIG_SAMA5_NAND_DMA
- uint32_t dmaflags;
-#endif
int buswidth;
+ int ret;
- fvdbg("nfcsram=%d buffer=%p buflen=%d offset=%d\n",
- nfcsram, buffer, (int)buflen, (int)offset);
-
+ fvdbg("buffer=%p buflen=%d offset=%d\n", buffer, buflen, offset);
nand_dump("NAND Write", buffer, buflen);
- /* Get the buswidth */
-
- buswidth = nandmodel_getbuswidth(&priv->raw.model);
-
- /* Pick the data destination: The NFC SRAM or the NAND data address */
-
- if (nfcsram)
- {
- /* Destination is NFC SRAM */
-
- dest = NFCSRAM_BASE;
+ /* Apply the offset to the destination address */
-#ifdef CONFIG_SAMA5_NAND_DMA
- /* Select NFC SRAM DMA */
+ dest = priv->raw.dataaddr + offset;
- dmaflags = (buswidth == 16 ? NFCSRAM_DMA_FLAGS16 : NFCSRAM_DMA_FLAGS8);
-#endif
- }
- else
- {
- /* Destination is NFC NAND */
-
- dest = priv->raw.dataaddr;
-
-#ifdef CONFIG_SAMA5_NAND_DMA
- /* Select NAND DMA */
-
- dmaflags = (buswidth == 16 ? NAND_DMA_FLAGS16 : NAND_DMA_FLAGS8);
-#endif
- }
-
- /* Apply the offset to the source address */
+ /* Get the buswidth */
- dest += offset;
+ buswidth = nandmodel_getbuswidth(&priv->raw.model);
#ifdef CONFIG_SAMA5_NAND_DMA
/* Then perform the transfer via memory-to-memory DMA or not, depending
@@ -1840,32 +1854,49 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
if (priv->dma && buflen > CONFIG_SAMA5_NAND_DMA_THRESHOLD)
{
+ /* Select NFC DATA DMA */
+
+ uint32_t dmaflags =
+ (buswidth == 16 ? NAND_DMA_FLAGS16 : NAND_DMA_FLAGS8);
+
/* Transfer using DMA */
- return nand_dma_write(priv, (uintptr_t)buffer, dest, buflen, dmaflags);
+ ret = nand_dma_write(priv, (uintptr_t)buffer, dest, buflen, dmaflags);
}
else
#endif
/* Transfer without DMA */
- if (nfcsram)
- {
- return nand_nfcsram_write(buffer, dest, buflen);
- }
- else
{
/* Check the data bus width of the NAND FLASH */
if (buswidth == 16)
{
- return nand_smc_write16(buffer, dest, buflen);
+ volatile uint16_t *dest16 = (volatile uint16_t *)dest;
+ const uint16_t *src16 = (const uint16_t *)buffer;
+
+ DEBUGASSERT(((uintptr_t)buffer & 1) == 0);
+
+ for (; buflen > 1; buflen -= sizeof(uint16_t))
+ {
+ *dest16 = *src16++;
+ }
}
else
{
- return nand_smc_write8(buffer, dest, buflen);
+ volatile uint8_t *dest8 = (volatile uint8_t *)dest;
+
+ for (; buflen > 0; buflen--)
+ {
+ *dest8 = *buffer++;
+ }
}
+
+ ret = OK;
}
+
+ return ret;
}
/****************************************************************************
@@ -1938,7 +1969,7 @@ static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
/* Configure the SMC */
regval |= (HSMC_CFG_RBEDGE | HSMC_CFG_DTOCYC(15) | HSMC_CFG_DTOMUL_1048576 |
- HSMC_CFG_NFCSPARESIZE((sparesize-1) >> 2));
+ HSMC_CFG_NFCSPARESIZE((sparesize -1 ) >> 2));
nand_putreg(SAM_HSMC_CFG, regval);
/* Calculate actual address of the page */
@@ -1958,10 +1989,10 @@ static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
if (data)
{
- ret = nand_read(priv, (uint8_t *)data, pagesize, 0);
+ ret = nand_nfcsram_read(priv, (uint8_t *)data, pagesize);
if (ret < 0)
{
- fdbg("ERROR: nand_read for data region failed: %d\n", ret);
+ fdbg("ERROR: nand_nfcsram_read for data region failed: %d\n", ret);
return ret;
}
}
@@ -1973,10 +2004,10 @@ static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
if (spare)
{
- ret = nand_read(priv, (uint8_t *)spare, sparesize, 0);
+ ret = nand_nfcsram_read(priv, (uint8_t *)spare, sparesize);
if (ret < 0)
{
- fdbg("ERROR: nand_read for spare region failed: %d\n", ret);
+ fdbg("ERROR: nand_nfcsram_read for spare region failed: %d\n", ret);
return ret;
}
}
@@ -2033,7 +2064,8 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
ret = nand_read_pmecc(priv, block, page, data);
if (ret < 0)
{
- fdbg("ERROR: Failed to read page\n");
+ fdbg("ERROR: Block %d page %d Failed to read page\n",
+ block, page, ret);
goto errout;
}
@@ -2042,15 +2074,18 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
regval = nand_getreg(SAM_HSMC_PMECCISR);
if (regval)
{
- fdbg("ERROR: block=%d page=%d Corrupted sectors: %08x\n",
- block, page, regval);
+ /* Bad sectors. Check if this is because spare area has been erased */
+ /* First, re-read the spare area. REVISIT: Is this necessary? */
- /* Check if the spare area was erased
- * REVISIT: Necessary to re-read. Isn't the spare data alread
- * intack in priv->raw.spare from nand_read_pmecc()?
- */
+ ret = nand_readpage_noecc(priv, block, page, NULL, priv->raw.spare);
+ if (ret < 0)
+ {
+ fdbg("ERROR: Block %d page %d Failed to re-read spare area: %d\n",
+ block, page, ret);
+ goto errout;
+ }
- //nand_readpage_noecc(priv, block, page, NULL, priv->raw.spare);
+ /* Then check if all bytes are in the erased state */
sparesize = nandmodel_getsparesize(&priv->raw.model);
for (i = 0 ; i < sparesize; i++)
@@ -2061,14 +2096,21 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
}
}
- /* The spare area has been erased */
+ /* Has the spare area has been erased? */
if (i >= sparesize)
{
- /* Clear sector errors */
+ /* Yes.. clear sector errors */
+ fdbg("Block=%d page=%d has been erased: %08x\n",
+ block, page, regval);
regval = 0;
}
+ else
+ {
+ fdbg("ERROR: block=%d page=%d Corrupted sectors: %08x\n",
+ block, page, regval);
+ }
}
/* Bit correction will be done directly in destination buffer. */
@@ -2076,7 +2118,8 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
ret = pmecc_correction(regval, (uintptr_t)data);
if (ret < 0)
{
- fdbg("ERROR: block=%d page=%d Unrecoverable data\n", block, page);
+ fdbg("ERROR: block=%d page=%d Unrecoverable data error: %d\n",
+ block, page, ret);
}
/* Disable auto mode */
@@ -2159,7 +2202,7 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
/* Configure the SMC */
regval |= (HSMC_CFG_RBEDGE | HSMC_CFG_DTOCYC(15) | HSMC_CFG_DTOMUL_1048576 |
- HSMC_CFG_NFCSPARESIZE((sparesize-1) >> 2));
+ HSMC_CFG_NFCSPARESIZE((sparesize - 1) >> 2));
if (spare)
{
@@ -2178,19 +2221,19 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
if (data)
{
- ret = nand_write(priv, true, (uint8_t *)data, pagesize, 0);
+ ret = nand_nfcsram_write(priv, (uint8_t *)data, pagesize, 0);
if (ret < 0)
{
- fdbg("ERROR: nand_write for data region failed: %d\n", ret);
+ fdbg("ERROR: nand_nfcsram_write for data region failed: %d\n", ret);
return ret;
}
if (spare)
{
- ret = nand_write(priv, true, (uint8_t *)spare, sparesize, pagesize);
+ ret = nand_nfcsram_write(priv, (uint8_t *)spare, sparesize, pagesize);
if (ret < 0)
{
- fdbg("ERROR: nand_write for data region failed: %d\n", ret);
+ fdbg("ERROR: nand_nfcsram_write for data region failed: %d\n", ret);
return ret;
}
}
@@ -2230,7 +2273,7 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
HSMC_CLE_WRITE_EN | HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN,
COMMAND_WRITE_1,0, pagesize, rowaddr);
- ret = nand_write(priv, false, (uint8_t *)spare, sparesize, 0);
+ ret = nand_write(priv, (uint8_t *)spare, sparesize, 0);
if (ret < 0)
{
fdbg("ERROR: nand_write for spare region failed: %d\n", ret);
@@ -2268,16 +2311,17 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
unsigned int page, const void *data)
{
- uint32_t pagesize;
- uint32_t rowaddr;
- uint32_t startaddr;
- uint32_t eccpersector;
- uint32_t sectornumber;
- uint32_t sectorindex;
uint32_t regval;
- uint8_t *pmecc[8];
- uint8_t sectersperpage;
- int i;
+ volatile uint8_t *pmecc;
+ uint8_t *ecc;
+ unsigned int pagesize;
+ unsigned int rowaddr;
+ unsigned int eccsaddr;
+ unsigned int eccpersector;
+ unsigned int sectersperpage;
+ unsigned int eccsize;
+ unsigned int sector;
+ unsigned int i;
int ret = 0;
fvdbg("block=%d page=%d data=%p\n", (int)block, page, data);
@@ -2297,22 +2341,25 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
/* Calculate the start page address */
- regval = nand_getreg(SAM_HSMC_PMECCSADDR);
- pagesize = nandmodel_getpagesize(&priv->raw.model);
- startaddr = regval + pagesize;
+ regval = nand_getreg(SAM_HSMC_PMECCSADDR);
+ pagesize = nandmodel_getpagesize(&priv->raw.model);
+ eccsaddr = pagesize + regval;
/* Calculate physical address of the page */
- rowaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
+ rowaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
+
+ fvdbg("pagesize=%d eccsaddr=%d rowaddr=%d\n", pagesize, eccsaddr, rowaddr);
/* Write data area if needed */
if (data)
{
- ret = nand_write(priv, true, (uint8_t *)data, pagesize, 0);
+ ret = nand_nfcsram_write(priv, (uint8_t *)data, pagesize, 0);
if (ret < 0)
{
- fdbg("ERROR: nand_write for data region failed: %d\n", ret);
+ fdbg("ERROR: Block %d page %d nand_nfcsram_write for data region failed: %d\n",
+ block, page, ret);
goto errout;
}
}
@@ -2347,13 +2394,6 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_RST);
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_ENABLE);
- /* Read the PMECC redundancy base address for each of (up to) 8 sectors */
-
- for (i = 0; i < 8; i++)
- {
- pmecc[i] = (uint8_t*)(SAM_HSMC_PMECC_BASE(i));
- }
-
/* Start a data phase */
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_DATA);
@@ -2373,7 +2413,7 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
nand_nfc_cleale(priv,
HSMC_CLE_WRITE_EN | HSMC_ALE_COL_EN,
- COMMAND_RANDOM_IN, 0, startaddr, 0);
+ COMMAND_RANDOM_IN, 0, eccsaddr, 0);
/* Wait until the kernel of the PMECC is not busy */
@@ -2382,7 +2422,10 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
/* Write the ECC */
eccpersector = (pmecc_get_eccsize()) / sectersperpage;
- sectornumber = 1 << pmecc_get_pagesize();
+ eccsize = sectersperpage * eccpersector;
+
+ fvdbg("sectersperpage=%d eccpersector=%d eccsize=%d\n",
+ sectersperpage, eccpersector, eccsize);
#ifdef CONFIG_SAMA5_PMECC_TRIMPAGE
if (nand_trrimffs(priv) && page >= nand_get_trimpage(priv))
@@ -2391,33 +2434,32 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
* cleanly erased NAND partitions
*/
- for (sectorindex = 0; sectorindex < sectornumber; sectorindex++)
- {
- for (i = 0; i < eccpersector; i++)
- {
- g_nand.ecctab[sectorindex * eccpersector + i] = 0xff;
- }
- }
+ memset(g_nand.ecctab, 0xff, eccsize);
}
else
#endif
{
- /* Read all ECC registers */
+ /* Read ECC registers for each sector in the page */
- for (sectorindex = 0; sectorindex < sectornumber; sectorindex++)
+ ecc = g_nand.ecctab;
+ for (sector = 0; sector < sectersperpage; sector++)
{
- for(i = 0; i < eccpersector; i++)
+ pmecc = (volatile uint8_t *)SAM_HSMC_PMECC_BASE(sector);
+
+ /* Read all EEC registers for this page */
+
+ for (i = 0; i < eccpersector; i++)
{
- g_nand.ecctab[sectorindex * eccpersector + i] = pmecc[sectorindex][i];
+ *ecc++ = *pmecc++;
}
}
}
- ret = nand_write(priv, false, (uint8_t *)(uint8_t *)g_nand.ecctab,
- sectornumber * eccpersector, 0);
+ ret = nand_write(priv, (uint8_t *)g_nand.ecctab, eccsize, 0);
if (ret < 0)
{
- fdbg("ERROR: nand_write for spare region failed: %d\n", ret);
+ fdbg("ERROR: Block %d page %d nand_write for spare region failed: %d\n",
+ block, page, ret);
goto errout;
}
@@ -2429,7 +2471,8 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
ret = nand_operation_complete(priv);
if (ret < 0)
{
- fdbg("ERROR: Failed writing data area: %d\n", ret);
+ fdbg("ERROR: Block %d page %d Failed writing data area: %d\n",
+ block, page, ret);
}
/* Disable the PMECC */
@@ -2477,7 +2520,7 @@ static inline int nand_tryeraseblock(struct sam_nandcs_s *priv, off_t block)
ret = nand_operation_complete(priv);
if (ret < 0)
{
- fdbg("ERROR: Could not erase block %d: %d\n", block, ret);
+ fdbg("ERROR: Block %d Could not erase: %d\n", block, ret);
}
return ret;
@@ -2513,7 +2556,7 @@ static int nand_eraseblock(struct nand_raw_s *raw, off_t block)
retries--;
}
- fdbg("ERROR: Failed to erase %d after %d tries\n",
+ fdbg("ERROR: Block %d Failed to erase after %d tries\n",
(int)block, NAND_ERASE_NRETRIES);
nand_unlock();
@@ -2638,16 +2681,19 @@ static int nand_readpage(struct nand_raw_s *raw, off_t block,
case NANDECC_NONE:
case NANDECC_CHIPECC:
ret = nand_readpage_noecc(priv, block, page, data, spare);
+ break;
#ifdef CONFIG_SAMA5_HAVE_PMECC
case NANDECC_PMECC:
DEBUGASSERT(!spare);
ret = nand_readpage_pmecc(priv, block, page, data);
+ break;
#endif
case NANDECC_SWECC:
default:
ret = -EINVAL;
+ break;
}
nand_unlock();
@@ -2698,16 +2744,19 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block,
case NANDECC_NONE:
case NANDECC_CHIPECC:
ret = nand_writepage_noecc(priv, block, page, data, spare);
+ break;
#ifdef CONFIG_SAMA5_HAVE_PMECC
case NANDECC_PMECC:
DEBUGASSERT(!spare);
ret = nand_writepage_pmecc(priv, block, page, data);
+ break;
#endif
case NANDECC_SWECC:
default:
ret = -EINVAL;
+ break;
}
nand_unlock();
@@ -2771,7 +2820,7 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
fvdbg("CS%d\n", cs);
- /* Select the device structure */
+ /* Select the device structure (In SAMA5D3, NAND is only supported on CS3). */
#ifdef CONFIG_SAMA5_EBICS0_NAND
if (cs == HSMC_CS0)