
Hi Sylvain,
On 05.08.2015 21:31, slemieux.tyco@gmail.com wrote:
From: Sylvain Lemieux slemieux@tycoint.com
Incorporate NAND SLC hardware ECC support from legacy LPCLinux NXP BSP. The code taken from the legacy patch is:
- lpc32xx SLC NAND driver (hardware ECC support)
- lpc3250 header file missing SLC NAND registers definition
The legacy driver code was updated to integrate with the existing NAND SLC driver.
Signed-off-by: Sylvain Lemieux slemieux@tycoint.com
Changes from v4 to v5:
- Addressed Marek's comments on LPC32xx DMA driver:
- Move macro use by the DMA client to write the next DMA linked list item address to NAND SLC driver.
- Updated multiline comments style.
- Use "uxx" instead of "uintxx_t" (new code), note: keep uintxx_t for API; to match initial patch.
Changes from v3 to v4:
- No changes.
Changes from v2 to v3:
- As per feedback on mailing list from Vladimir,
- add warning when DMA and SPL build option are selected.
- add another DMA specific read and write buffer functions.
- Addressed Marek's comments on LPC32xx NAND driver removed typecast and update variable type, when possible.
- As per discussion on mailing list with Vladimir & Marek, updated conditional compile option (DMA only) to build the original NAND SLC code using software ECC.
- Re-organized the conditional compile code inside "board_nand_init()" - DMA vs. non-DMA initialization.
- Added original source code credit (copyright & author).
Changes from v1 to v2:
- Moved the NAND SLC patch as the second patch of the series.
- As per discussion on mailing list with Vladimir, incorporate NAND SLC hardware ECC support into the following NAND SLC patch: https://patchwork.ozlabs.org/patch/497308/
- As per discussion on mailing list with Vladimir & Albert, add conditional compile option to build the original NAND SLC code using software ECC for SPL build.
- Removed ECC layout for small page NAND from this patch.
Update to the legacy code to integrate with the NAND SLC patch:
- Fixed checkpatch script output in legacy code.
- Use u-boot API for register access to remove the volatile in register definition taken from "lpc3250.h" header file.
- Use register definition from the NAND SLC patch.
The legacy BSP patch (u-boot-2009.03_lpc32x0-v1.07.patch.tar.bz2) was downloaded from the LPCLinux Web site.
drivers/mtd/nand/lpc32xx_nand_slc.c | 369 +++++++++++++++++++++++++++++++++++- 1 file changed, 364 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/nand/lpc32xx_nand_slc.c b/drivers/mtd/nand/lpc32xx_nand_slc.c index 719a74d..715152d 100644 --- a/drivers/mtd/nand/lpc32xx_nand_slc.c +++ b/drivers/mtd/nand/lpc32xx_nand_slc.c @@ -3,15 +3,38 @@
- (C) Copyright 2015 Vladimir Zapolskiy vz@mleia.com
- Hardware ECC support original source code
- Copyright (C) 2008 by NXP Semiconductors
- Author: Kevin Wells
*/
- SPDX-License-Identifier: GPL-2.0+
#include <common.h> #include <nand.h> +#include <linux/mtd/nand_ecc.h> #include <asm/errno.h> #include <asm/io.h> #include <asm/arch/clk.h> #include <asm/arch/sys_proto.h> +#include <asm/arch/dma.h> +#include <asm/arch/cpu.h>
+#if defined(CONFIG_DMA_LPC32XX) && defined(CONFIG_SPL_BUILD) +#warning "DMA support in SPL image is not tested" +#endif
+/* Provide default for ECC size / bytes / OOB size for large page)
- if target did not. */
+#if !defined(CONFIG_SYS_NAND_ECCSIZE) +#define CONFIG_SYS_NAND_ECCSIZE 2048 +#endif
The definition above looks wrong...
s/CONFIG_SYS_NAND_ECCSIZE/CONFIG_SYS_NAND_PAGE_SIZE/g
CONFIG_SYS_NAND_ECCSIZE is hardcoded to 0x100 for LPC32xx NAND SLC.
+#if !defined(CONFIG_SYS_NAND_ECCBYTES) +#define CONFIG_SYS_NAND_ECCBYTES 24 +#endif +#if !defined(CONFIG_SYS_NAND_OOBSIZE) +#define CONFIG_SYS_NAND_OOBSIZE 64 +#endif
struct lpc32xx_nand_slc_regs { u32 data; @@ -33,11 +56,18 @@ struct lpc32xx_nand_slc_regs {
/* CFG register */ #define CFG_CE_LOW (1 << 5) +#define SLCCFG_DMA_ECC (1 << 4) /* Enable DMA ECC bit */ +#define SLCCFG_ECC_EN (1 << 3) /* ECC enable bit */ +#define SLCCFG_DMA_BURST (1 << 2) /* DMA burst bit */ +#define SLCCFG_DMA_DIR (1 << 1) /* DMA write(0)/read(1) bit */
/* CTRL register */ #define CTRL_SW_RESET (1 << 2) +#define SLCCTRL_ECC_CLEAR (1 << 1) /* Reset ECC bit */ +#define SLCCTRL_DMA_START (1 << 0) /* Start DMA channel bit */
/* STAT register */ +#define SLCSTAT_DMA_FIFO (1 << 2) /* DMA FIFO has data bit */ #define STAT_NAND_READY (1 << 0)
Do you see any chance of confusion, if "SLC" prefix is dropped from new bit field definition? IMO it is more confusing, if there are two styles of them at once.
/* INT_STAT register */ @@ -54,6 +84,59 @@ struct lpc32xx_nand_slc_regs { #define TAC_R_HOLD(n) (max_t(uint32_t, (n), 0xF) << 4) #define TAC_R_SETUP(n) (max_t(uint32_t, (n), 0xF) << 0)
+/* control register definitions */ +#define DMAC_CHAN_INT_TC_EN (1 << 31) /* channel terminal count interrupt */ +#define DMAC_CHAN_DEST_AUTOINC (1 << 27) /* automatic destination increment */ +#define DMAC_CHAN_SRC_AUTOINC (1 << 26) /* automatic source increment */ +#define DMAC_CHAN_DEST_AHB1 (1 << 25) /* AHB1 master for dest. transfer */ +#define DMAC_CHAN_DEST_WIDTH_32 (1 << 22) /* Destination data width selection */ +#define DMAC_CHAN_SRC_WIDTH_32 (1 << 19) /* Source data width selection */ +#define DMAC_CHAN_DEST_BURST_1 0 +#define DMAC_CHAN_DEST_BURST_4 (1 << 15) /* Destination data burst size */ +#define DMAC_CHAN_SRC_BURST_1 0 +#define DMAC_CHAN_SRC_BURST_4 (1 << 12) /* Source data burst size */
+/*
- config_ch register definitions
- DMAC_CHAN_FLOW_D_xxx: flow control with DMA as the controller
- DMAC_DEST_PERIP: Macro for loading destination peripheral
- DMAC_SRC_PERIP: Macro for loading source peripheral
- */
+#define DMAC_CHAN_FLOW_D_M2P (0x1 << 11) +#define DMAC_CHAN_FLOW_D_P2M (0x2 << 11) +#define DMAC_DEST_PERIP(n) (((n) & 0x1F) << 6) +#define DMAC_SRC_PERIP(n) (((n) & 0x1F) << 1)
+/*
- config_ch register definitions
- (source and destination peripheral ID numbers).
- These can be used with the DMAC_DEST_PERIP and DMAC_SRC_PERIP macros.
- */
+#define DMA_PERID_NAND1 1
+/* Channel enable bit */ +#define DMAC_CHAN_ENABLE (1 << 0)
All these DMA specific macro definitions above should go to arch/dma.h added in 1/5, this is not the right place for any of them.
+#define NAND_LARGE_BLOCK_PAGE_SIZE 2048
NB! See NB below.
This macro is used only in
(CONFIG_SYS_NAND_ECCSIZE == NAND_LARGE_BLOCK_PAGE_SIZE ? 8 : 2)
cases, and actually the resulting value is always (CONFIG_SYS_NAND_ECCSIZE / 0x100)
Here I would propose
* to add a sanity check in board_nand_init() for (CONFIG_SYS_NAND_ECCSIZE == NAND_LARGE_BLOCK_PAGE_SIZE || CONFIG_SYS_NAND_ECCSIZE == NAND_SMALL_BLOCK_PAGE_SIZE),
* to replace the tristate operator case above with (CONFIG_SYS_NAND_ECCSIZE / 0x100).
NB! Here CONFIG_SYS_NAND_ECCSIZE is misused, it must be replaced by CONFIG_SYS_NAND_PAGE_SIZE, and 0x100 must be replaced by CONFIG_SYS_NAND_ECCSIZE. In comments I keep the old notation to reduce confusion, but please change the names.
+#define NAND_SMALL_BLOCK_PAGE_SIZE 512
This macro is not used at the moment, but see the comment above.
+#if defined(CONFIG_DMA_LPC32XX) +/*
- DMA Descriptors
- For Large Block: 17 descriptors = ((16 Data and ECC Read) + 1 Spare Area)
- For Small Block: 5 descriptors = ((4 Data and ECC Read) + 1 Spare Area)
- */
+static struct lpc32xx_dmac_ll dmalist[(CONFIG_SYS_NAND_ECCSIZE/256) * 2 + 1];
Aha, I see CONFIG_SYS_NAND_ECCSIZE / 0x100 again, it deserves its own macro.
+static u32 ecc_buffer[8]; /* MAX ECC size */
And this 8 again stands for CONFIG_SYS_NAND_ECCSIZE / 0x100.
Well, you remember it must be (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE) in the corrected version, e.g. for small page devices it is 2.
+static int dmachan = -1;
+/*
- Helper macro for the DMA client (i.e. NAND SLC) to write the next
- DMA linked list item address (see arch/include/asm/arch-lpc32xx/dma.h).
- */
+#define lpc32xx_dmac_next_lli(x) ((u32)x) +#endif
static struct lpc32xx_nand_slc_regs __iomem *lpc32xx_nand_slc_regs = (struct lpc32xx_nand_slc_regs __iomem *)SLC_NAND_BASE;
@@ -108,15 +191,266 @@ static int lpc32xx_nand_dev_ready(struct mtd_info *mtd) return readl(&lpc32xx_nand_slc_regs->stat) & STAT_NAND_READY; }
-static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +#if defined(CONFIG_DMA_LPC32XX) +/*
- Prepares DMA descriptors for NAND RD/WR operations
- If the size is < 256 Bytes then it is assumed to be
- an OOB transfer
- */
+static void lpc32xx_nand_dma_configure(struct nand_chip *chip,
const u8 *buffer, int size,
int read)
{
- while (len-- > 0)
*buf++ = readl(&lpc32xx_nand_slc_regs->data);
- u32 i, dmasrc, ctrl, ecc_ctrl, oob_ctrl, dmadst;
- u32 base = (u32)chip->IO_ADDR_R;
This is SLC_NAND_BASE, but the variable is not needed, see below.
- struct lpc32xx_dmac_ll *dmalist_cur;
- struct lpc32xx_dmac_ll *dmalist_cur_ecc;
- /*
* CTRL descriptor entry for reading ECC
* Copy Multiple times to sync DMA with Flash Controller
*/
- ecc_ctrl = 0x5 |
DMAC_CHAN_SRC_BURST_1 |
DMAC_CHAN_DEST_BURST_1 |
DMAC_CHAN_SRC_WIDTH_32 |
DMAC_CHAN_DEST_WIDTH_32 |
DMAC_CHAN_DEST_AHB1;
- /* CTRL descriptor entry for reading/writing Data */
- ctrl = 64 | /* 256/4 */
DMAC_CHAN_SRC_BURST_4 |
DMAC_CHAN_DEST_BURST_4 |
DMAC_CHAN_SRC_WIDTH_32 |
DMAC_CHAN_DEST_WIDTH_32 |
DMAC_CHAN_DEST_AHB1;
- /* CTRL descriptor entry for reading/writing Spare Area */
- oob_ctrl = (CONFIG_SYS_NAND_OOBSIZE / 4) |
DMAC_CHAN_SRC_BURST_4 |
DMAC_CHAN_DEST_BURST_4 |
DMAC_CHAN_SRC_WIDTH_32 |
DMAC_CHAN_DEST_WIDTH_32 |
DMAC_CHAN_DEST_AHB1;
- if (read) {
dmasrc = base + offsetof(struct lpc32xx_nand_slc_regs,
dma_data);
This is &lpc32xx_nand_slc_regs->dma_data.
dmadst = (u32)buffer;
ctrl |= DMAC_CHAN_DEST_AUTOINC;
- } else {
dmadst = base + offsetof(struct lpc32xx_nand_slc_regs,
dma_data);
This is &lpc32xx_nand_slc_regs->dma_data.
dmasrc = (u32)buffer;
ctrl |= DMAC_CHAN_SRC_AUTOINC;
- }
- /*
* Write Operation Sequence for Small Block NAND
* ----------------------------------------------------------
* 1. X'fer 256 bytes of data from Memory to Flash.
* 2. Copy generated ECC data from Register to Spare Area
* 3. X'fer next 256 bytes of data from Memory to Flash.
* 4. Copy generated ECC data from Register to Spare Area.
* 5. X'fer 16 byets of Spare area from Memory to Flash.
* Read Operation Sequence for Small Block NAND
* ----------------------------------------------------------
* 1. X'fer 256 bytes of data from Flash to Memory.
* 2. Copy generated ECC data from Register to ECC calc Buffer.
* 3. X'fer next 256 bytes of data from Flash to Memory.
* 4. Copy generated ECC data from Register to ECC calc Buffer.
* 5. X'fer 16 bytes of Spare area from Flash to Memory.
* Write Operation Sequence for Large Block NAND
* ----------------------------------------------------------
* 1. Steps(1-4) of Write Operations repeate for four times
* which generates 16 DMA descriptors to X'fer 2048 bytes of
* data & 32 bytes of ECC data.
* 2. X'fer 64 bytes of Spare area from Memory to Flash.
* Read Operation Sequence for Large Block NAND
* ----------------------------------------------------------
* 1. Steps(1-4) of Read Operations repeate for four times
* which generates 16 DMA descriptors to X'fer 2048 bytes of
* data & 32 bytes of ECC data.
* 2. X'fer 64 bytes of Spare area from Flash to Memory.
*/
- for (i = 0; i < size/256; i++) {
dmalist_cur = &dmalist[i * 2];
dmalist_cur_ecc = &dmalist[(i * 2) + 1];
dmalist_cur->dma_src = (read ? (dmasrc) : (dmasrc + (i*256)));
dmalist_cur->dma_dest = (read ? (dmadst + (i*256)) : dmadst);
dmalist_cur->next_lli = lpc32xx_dmac_next_lli(dmalist_cur_ecc);
dmalist_cur->next_ctrl = ctrl;
dmalist_cur_ecc->dma_src =
base + offsetof(struct lpc32xx_nand_slc_regs, ecc);
dmalist_cur_ecc->dma_dest = (u32)&ecc_buffer[i];
dmalist_cur_ecc->next_lli =
lpc32xx_dmac_next_lli(&dmalist[(i * 2) + 2]);
dmalist_cur_ecc->next_ctrl = ecc_ctrl;
- }
- if (i) { /* Data only transfer */
dmalist_cur_ecc = &dmalist[(i * 2) - 1];
dmalist_cur_ecc->next_lli = 0;
dmalist_cur_ecc->next_ctrl |= DMAC_CHAN_INT_TC_EN;
return;
- }
- /* OOB only transfer */
- if (read) {
dmasrc = base + offsetof(struct lpc32xx_nand_slc_regs,
dma_data);
This is &lpc32xx_nand_slc_regs->dma_data.
dmadst = (u32)buffer;
oob_ctrl |= DMAC_CHAN_DEST_AUTOINC;
- } else {
dmadst = base + offsetof(struct lpc32xx_nand_slc_regs,
dma_data);
This is &lpc32xx_nand_slc_regs->dma_data. No "base" variable please.
dmasrc = (u32)buffer;
oob_ctrl |= DMAC_CHAN_SRC_AUTOINC;
- }
- /* Read/ Write Spare Area Data To/From Flash */
- dmalist_cur = &dmalist[i * 2];
- dmalist_cur->dma_src = dmasrc;
- dmalist_cur->dma_dest = dmadst;
- dmalist_cur->next_lli = 0;
- dmalist_cur->next_ctrl = (oob_ctrl | DMAC_CHAN_INT_TC_EN);
}
-static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) +static void lpc32xx_nand_xfer(struct mtd_info *mtd, const u8 *buf,
int len, int read)
{
- return readl(&lpc32xx_nand_slc_regs->data);
- struct nand_chip *chip = mtd->priv;
- u32 config;
- /* DMA Channel Configuration */
- config = (read ? DMAC_CHAN_FLOW_D_P2M : DMAC_CHAN_FLOW_D_M2P) |
(read ? DMAC_DEST_PERIP(0) : DMAC_DEST_PERIP(DMA_PERID_NAND1)) |
(read ? DMAC_SRC_PERIP(DMA_PERID_NAND1) : DMAC_SRC_PERIP(0)) |
DMAC_CHAN_ENABLE;
- /* Prepare DMA descriptors */
- lpc32xx_nand_dma_configure(chip, buf, len, read);
- /* Setup SLC controller and start transfer */
- if (read)
setbits_le32(&lpc32xx_nand_slc_regs->cfg, SLCCFG_DMA_DIR);
- else /* NAND_ECC_WRITE */
clrbits_le32(&lpc32xx_nand_slc_regs->cfg, SLCCFG_DMA_DIR);
- setbits_le32(&lpc32xx_nand_slc_regs->cfg, SLCCFG_DMA_BURST);
- /* Write length for new transfers */
- if (!((readl(&lpc32xx_nand_slc_regs->stat) & SLCSTAT_DMA_FIFO) |
readl(&lpc32xx_nand_slc_regs->tc))) {
int tmp = (len != mtd->oobsize) ? mtd->oobsize : 0;
writel(len + tmp, &lpc32xx_nand_slc_regs->tc);
- }
- setbits_le32(&lpc32xx_nand_slc_regs->ctrl, SLCCTRL_DMA_START);
- /* Start DMA transfers */
- lpc32xx_dma_start_xfer(dmachan, dmalist, config);
- /* Wait for NAND to be ready */
- while (!lpc32xx_nand_dev_ready(mtd))
;
- /* Wait till DMA transfer is DONE */
- if (lpc32xx_dma_wait_status(dmachan))
pr_err("NAND DMA transfer error!\r\n");
- /* Stop DMA & HW ECC */
- clrbits_le32(&lpc32xx_nand_slc_regs->ctrl, SLCCTRL_DMA_START);
- clrbits_le32(&lpc32xx_nand_slc_regs->cfg,
SLCCFG_DMA_DIR | SLCCFG_DMA_BURST |
SLCCFG_ECC_EN | SLCCFG_DMA_ECC);
+}
+static u32 slc_ecc_copy_to_buffer(u8 *spare, const u32 *ecc, int count) +{
- int i;
- for (i = 0; i < (count * 3); i += 3) {
u32 ce = ecc[i/3];
ce = ~(ce << 2) & 0xFFFFFF;
spare[i+2] = (u8)(ce & 0xFF); ce >>= 8;
spare[i+1] = (u8)(ce & 0xFF); ce >>= 8;
spare[i] = (u8)(ce & 0xFF);
- }
- return 0;
+}
+static int lpc32xx_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
uint8_t *ecc_code)
+{
- return slc_ecc_copy_to_buffer(ecc_code, ecc_buffer,
CONFIG_SYS_NAND_ECCSIZE
== NAND_LARGE_BLOCK_PAGE_SIZE ? 8 : 2);
+}
+/*
- Enables and prepares SLC NAND controller
- for doing data transfers with H/W ECC enabled.
- */
+static void lpc32xx_hwecc_enable(struct mtd_info *mtd, int mode) +{
- /* Clear ECC */
- writel(SLCCTRL_ECC_CLEAR, &lpc32xx_nand_slc_regs->ctrl);
- /* Setup SLC controller for H/W ECC operations */
- setbits_le32(&lpc32xx_nand_slc_regs->cfg,
SLCCFG_ECC_EN | SLCCFG_DMA_ECC);
+}
+/*
- lpc32xx_correct_data - [NAND Interface] Detect and correct bit error(s)
- mtd: MTD block structure
- dat: raw data read from the chip
- read_ecc: ECC from the chip
- calc_ecc: the ECC calculated from raw data
- Detect and correct a 1 bit error for 256 byte block
- */
+int lpc32xx_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
+{
- u8 i, nb_ecc256;
- int ret1, ret2 = 0;
- u_char *r = read_ecc;
- u_char *c = calc_ecc;
- u16 data_offset = 0;
- nb_ecc256 = (CONFIG_SYS_NAND_ECCSIZE == NAND_LARGE_BLOCK_PAGE_SIZE
? 8 : 2);
- for (i = 0 ; i < nb_ecc256 ; i++ , r += 3, c += 3, data_offset += 256) {
ret1 = nand_correct_data(mtd, dat + data_offset, r, c);
if (ret1 < 0)
return -EBADMSG;
else
ret2 += ret1;
- }
- return ret2;
+}
+static void lpc32xx_dma_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{
- lpc32xx_nand_xfer(mtd, buf, len, 1);
+}
+static void lpc32xx_dma_write_buf(struct mtd_info *mtd, const uint8_t *buf,
int len)
+{
- lpc32xx_nand_xfer(mtd, buf, len, 0);
+} +#else +static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{
- while (len-- > 0)
*buf++ = readl(&lpc32xx_nand_slc_regs->data);
}
Please preserve the original order:
lpc32xx_read_buf() lpc32xx_read_byte() lpc32xx_write_buf() lpc32xx_write_byte()
I'd like to see $OP_byte() follows $OP_buf() as a motivator to measure performance degradation one day, if $OP_byte() body is replaced by $OP_buf(..., 1).
static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) @@ -124,6 +458,12 @@ static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) while (len-- > 0) writel(*buf++, &lpc32xx_nand_slc_regs->data); } +#endif
+static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) +{
- return readl(&lpc32xx_nand_slc_regs->data);
+}
static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte) { @@ -137,9 +477,45 @@ static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte) */ int board_nand_init(struct nand_chip *lpc32xx_chip) { +#if defined(CONFIG_DMA_LPC32XX)
- /* Acquire a channel for our use */
- dmachan = lpc32xx_dma_get_channel();
- if (unlikely(dmachan < 0)) {
pr_info("Unable to get free DMA channel for NAND transfers\n");
return -1;
- }
+#endif
- lpc32xx_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; lpc32xx_chip->dev_ready = lpc32xx_nand_dev_ready;
+#if defined(CONFIG_DMA_LPC32XX)
- /*
* Hardware ECC calculation is supported when
* DMA driver is selected.
*/
- lpc32xx_chip->ecc.mode = NAND_ECC_HW;
- /*
* The implementation of these functions is quite common, but
* they MUST be defined, because access to data register
* is strictly 32-bit aligned.
*/
- lpc32xx_chip->read_byte = lpc32xx_read_byte;
- lpc32xx_chip->write_byte = lpc32xx_write_byte;
.read_byte() / .write_byte() are shared, these two lines should be outside of #if defined(CONFIG_DMA_LPC32XX)
- lpc32xx_chip->read_buf = lpc32xx_dma_read_buf;
- lpc32xx_chip->write_buf = lpc32xx_dma_write_buf;
- lpc32xx_chip->ecc.calculate = lpc32xx_ecc_calculate;
- lpc32xx_chip->ecc.correct = lpc32xx_correct_data;
- lpc32xx_chip->ecc.hwctl = lpc32xx_hwecc_enable;
- lpc32xx_chip->chip_delay = 2000;
- lpc32xx_chip->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
- lpc32xx_chip->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
- lpc32xx_chip->ecc.strength = 1;
Please double check, because this is wrong, it should be the same as below for PIO:
lpc32xx_chip->ecc.size = CONFIG_SYS_NAND_ECCSIZE; lpc32xx_chip->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES / (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE); lpc32xx_chip->ecc.strength = 1;
and therefore this chunk should be placed outside of #if defined(CONFIG_DMA_LPC32XX)/ #else / #endif block.
+#else /* * Hardware ECC calculation is not supported by the driver, * because it requires DMA support, see LPC32x0 User Manual, @@ -164,6 +540,7 @@ int board_nand_init(struct nand_chip *lpc32xx_chip) lpc32xx_chip->ecc.size = 256; lpc32xx_chip->ecc.bytes = 3; lpc32xx_chip->ecc.strength = 1;
^^^ It is the same as for DMA branch.
+#endif
#if defined(CONFIG_SYS_NAND_USE_FLASH_BBT) lpc32xx_chip->bbt_options |= NAND_BBT_USE_FLASH;
-- With best wishes, Vladimir