summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/raw/mxs_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/raw/mxs_nand.c')
-rw-r--r--drivers/mtd/nand/raw/mxs_nand.c330
1 files changed, 252 insertions, 78 deletions
diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index fe8097c146..e3516cd141 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -10,6 +10,7 @@
*
* Copyright (C) 2010 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ * Copyright 2017-2019 NXP
*/
#include <common.h>
@@ -30,7 +31,8 @@
#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
-#if (defined(CONFIG_MX6) || defined(CONFIG_MX7))
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7) || defined(CONFIG_IMX8) || \
+ defined(CONFIG_IMX8M)
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 2
#else
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 0
@@ -54,21 +56,21 @@ struct nand_ecclayout fake_ecc_layout;
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
static void mxs_nand_flush_data_buf(struct mxs_nand_info *info)
{
- uint32_t addr = (uint32_t)info->data_buf;
+ uint32_t addr = (uintptr_t)info->data_buf;
flush_dcache_range(addr, addr + info->data_buf_size);
}
static void mxs_nand_inval_data_buf(struct mxs_nand_info *info)
{
- uint32_t addr = (uint32_t)info->data_buf;
+ uint32_t addr = (uintptr_t)info->data_buf;
invalidate_dcache_range(addr, addr + info->data_buf_size);
}
static void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info)
{
- uint32_t addr = (uint32_t)info->cmd_buf;
+ uint32_t addr = (uintptr_t)info->cmd_buf;
flush_dcache_range(addr, addr + MXS_NAND_COMMAND_BUFFER_SIZE);
}
@@ -112,53 +114,32 @@ static uint32_t mxs_nand_aux_status_offset(void)
return (MXS_NAND_METADATA_SIZE + 0x3) & ~0x3;
}
-static inline int mxs_nand_calc_mark_offset(struct bch_geometry *geo,
- uint32_t page_data_size)
+static inline bool mxs_nand_bbm_in_data_chunk(struct bch_geometry *geo, struct mtd_info *mtd,
+ unsigned int *chunk_num)
{
- uint32_t chunk_data_size_in_bits = geo->ecc_chunk_size * 8;
- uint32_t chunk_ecc_size_in_bits = geo->ecc_strength * geo->gf_len;
- uint32_t chunk_total_size_in_bits;
- uint32_t block_mark_chunk_number;
- uint32_t block_mark_chunk_bit_offset;
- uint32_t block_mark_bit_offset;
+ unsigned int i, j;
- chunk_total_size_in_bits =
- chunk_data_size_in_bits + chunk_ecc_size_in_bits;
-
- /* Compute the bit offset of the block mark within the physical page. */
- block_mark_bit_offset = page_data_size * 8;
-
- /* Subtract the metadata bits. */
- block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
-
- /*
- * Compute the chunk number (starting at zero) in which the block mark
- * appears.
- */
- block_mark_chunk_number =
- block_mark_bit_offset / chunk_total_size_in_bits;
-
- /*
- * Compute the bit offset of the block mark within its chunk, and
- * validate it.
- */
- block_mark_chunk_bit_offset = block_mark_bit_offset -
- (block_mark_chunk_number * chunk_total_size_in_bits);
+ if (geo->ecc_chunk0_size != geo->ecc_chunkn_size) {
+ dev_err(this->dev, "The size of chunk0 must equal to chunkn\n");
+ return false;
+ }
- if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
- return -EINVAL;
+ i = (mtd->writesize * 8 - MXS_NAND_METADATA_SIZE * 8) /
+ (geo->gf_len * geo->ecc_strength +
+ geo->ecc_chunkn_size * 8);
- /*
- * Now that we know the chunk number in which the block mark appears,
- * we can subtract all the ECC bits that appear before it.
- */
- block_mark_bit_offset -=
- block_mark_chunk_number * chunk_ecc_size_in_bits;
+ j = (mtd->writesize * 8 - MXS_NAND_METADATA_SIZE * 8) -
+ (geo->gf_len * geo->ecc_strength +
+ geo->ecc_chunkn_size * 8) * i;
- geo->block_mark_byte_offset = block_mark_bit_offset >> 3;
- geo->block_mark_bit_offset = block_mark_bit_offset & 0x7;
+ if (j < geo->ecc_chunkn_size * 8) {
+ *chunk_num = i + 1;
+ dev_dbg(this->dev, "Set ecc to %d and bbm in chunk %d\n",
+ geo->ecc_strength, *chunk_num);
+ return true;
+ }
- return 0;
+ return false;
}
static inline int mxs_nand_calc_ecc_layout_by_info(struct bch_geometry *geo,
@@ -168,6 +149,7 @@ static inline int mxs_nand_calc_ecc_layout_by_info(struct bch_geometry *geo,
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+ unsigned int block_mark_bit_offset;
switch (ecc_step) {
case SZ_512:
@@ -180,45 +162,51 @@ static inline int mxs_nand_calc_ecc_layout_by_info(struct bch_geometry *geo,
return -EINVAL;
}
- geo->ecc_chunk_size = ecc_step;
+ geo->ecc_chunk0_size = ecc_step;
+ geo->ecc_chunkn_size = ecc_step;
geo->ecc_strength = round_up(ecc_strength, 2);
/* Keep the C >= O */
- if (geo->ecc_chunk_size < mtd->oobsize)
+ if (geo->ecc_chunkn_size < mtd->oobsize)
return -EINVAL;
if (geo->ecc_strength > nand_info->max_ecc_strength_supported)
return -EINVAL;
- geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+ geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunkn_size;
+
+ /* For bit swap. */
+ block_mark_bit_offset = mtd->writesize * 8 -
+ (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+ + MXS_NAND_METADATA_SIZE * 8);
+
+ geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+ geo->block_mark_bit_offset = block_mark_bit_offset % 8;
return 0;
}
-static inline int mxs_nand_calc_ecc_layout(struct bch_geometry *geo,
+static inline int mxs_nand_legacy_calc_ecc_layout(struct bch_geometry *geo,
struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+ unsigned int block_mark_bit_offset;
/* The default for the length of Galois Field. */
geo->gf_len = 13;
/* The default for chunk size. */
- geo->ecc_chunk_size = 512;
+ geo->ecc_chunk0_size = 512;
+ geo->ecc_chunkn_size = 512;
- if (geo->ecc_chunk_size < mtd->oobsize) {
+ if (geo->ecc_chunkn_size < mtd->oobsize) {
geo->gf_len = 14;
- geo->ecc_chunk_size *= 2;
+ geo->ecc_chunk0_size *= 2;
+ geo->ecc_chunkn_size *= 2;
}
- if (mtd->oobsize > geo->ecc_chunk_size) {
- printf("Not support the NAND chips whose oob size is larger then %d bytes!\n",
- geo->ecc_chunk_size);
- return -EINVAL;
- }
-
- geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+ geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunkn_size;
/*
* Determine the ECC layout with the formula:
@@ -234,6 +222,84 @@ static inline int mxs_nand_calc_ecc_layout(struct bch_geometry *geo,
geo->ecc_strength = min(round_down(geo->ecc_strength, 2),
nand_info->max_ecc_strength_supported);
+ block_mark_bit_offset = mtd->writesize * 8 -
+ (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+ + MXS_NAND_METADATA_SIZE * 8);
+
+ geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+ geo->block_mark_bit_offset = block_mark_bit_offset % 8;
+
+ return 0;
+}
+
+static inline int mxs_nand_calc_ecc_for_large_oob(struct bch_geometry *geo,
+ struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+ unsigned int block_mark_bit_offset;
+ unsigned int max_ecc;
+ unsigned int bbm_chunk;
+ unsigned int i;
+
+ /* sanity check for the minimum ecc nand required */
+ if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
+ return -EINVAL;
+ geo->ecc_strength = chip->ecc_strength_ds;
+
+ /* calculate the maximum ecc platform can support*/
+ geo->gf_len = 14;
+ geo->ecc_chunk0_size = 1024;
+ geo->ecc_chunkn_size = 1024;
+ geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunkn_size;
+ max_ecc = ((mtd->oobsize - MXS_NAND_METADATA_SIZE) * 8)
+ / (geo->gf_len * geo->ecc_chunk_count);
+ max_ecc = min(round_down(max_ecc, 2),
+ nand_info->max_ecc_strength_supported);
+
+
+ /* search a supported ecc strength that makes bbm */
+ /* located in data chunk */
+ geo->ecc_strength = chip->ecc_strength_ds;
+ while (!(geo->ecc_strength > max_ecc)) {
+ if (mxs_nand_bbm_in_data_chunk(geo, mtd, &bbm_chunk))
+ break;
+ geo->ecc_strength += 2;
+ }
+
+ /* if none of them works, keep using the minimum ecc */
+ /* nand required but changing ecc page layout */
+ if (geo->ecc_strength > max_ecc) {
+ geo->ecc_strength = chip->ecc_strength_ds;
+ /* add extra ecc for meta data */
+ geo->ecc_chunk0_size = 0;
+ geo->ecc_chunk_count = (mtd->writesize / geo->ecc_chunkn_size) + 1;
+ geo->ecc_for_meta = 1;
+ /* check if oob can afford this extra ecc chunk */
+ if (mtd->oobsize * 8 < MXS_NAND_METADATA_SIZE * 8 +
+ geo->gf_len * geo->ecc_strength
+ * geo->ecc_chunk_count) {
+ printf("unsupported NAND chip with new layout\n");
+ return -EINVAL;
+ }
+
+ /* calculate in which chunk bbm located */
+ bbm_chunk = (mtd->writesize * 8 - MXS_NAND_METADATA_SIZE * 8 -
+ geo->gf_len * geo->ecc_strength) /
+ (geo->gf_len * geo->ecc_strength +
+ geo->ecc_chunkn_size * 8) + 1;
+ }
+
+ /* calculate the number of ecc chunk behind the bbm */
+ i = (mtd->writesize / geo->ecc_chunkn_size) - bbm_chunk + 1;
+
+ block_mark_bit_offset = mtd->writesize * 8 -
+ (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - i)
+ + MXS_NAND_METADATA_SIZE * 8);
+
+ geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+ geo->block_mark_bit_offset = block_mark_bit_offset % 8;
+
return 0;
}
@@ -548,6 +614,45 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)
return buf;
}
+static bool mxs_nand_erased_page(struct mtd_info *mtd, struct nand_chip *nand,
+ u8 *buf, int chunk, int page)
+{
+ struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
+ struct bch_geometry *geo = &nand_info->bch_geometry;
+ unsigned int flip_bits = 0, flip_bits_noecc = 0;
+ unsigned int threshold;
+ unsigned int base = geo->ecc_chunkn_size * chunk;
+ u32 *dma_buf = (u32 *)buf;
+ int i;
+
+ threshold = geo->gf_len / 2;
+ if (threshold > geo->ecc_strength)
+ threshold = geo->ecc_strength;
+
+ for (i = 0; i < geo->ecc_chunkn_size; i++) {
+ flip_bits += hweight8(~buf[base + i]);
+ if (flip_bits > threshold)
+ return false;
+ }
+
+ nand->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ nand->read_buf(mtd, buf, mtd->writesize);
+
+ for (i = 0; i < mtd->writesize / 4; i++) {
+ flip_bits_noecc += hweight32(~dma_buf[i]);
+ if (flip_bits_noecc > threshold)
+ return false;
+ }
+
+ mtd->ecc_stats.corrected += flip_bits;
+
+ memset(buf, 0xff, mtd->writesize);
+
+ printf("The page(%d) is an erased page(%d,%d,%d,%d).\n", page, chunk, threshold, flip_bits, flip_bits_noecc);
+
+ return true;
+}
+
/*
* Read a page from NAND.
*/
@@ -557,11 +662,13 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
{
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
struct bch_geometry *geo = &nand_info->bch_geometry;
+ struct mxs_bch_regs *bch_regs = nand_info->bch_regs;
struct mxs_dma_desc *d;
uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip;
uint32_t corrected = 0, failed = 0;
uint8_t *status;
int i, ret;
+ int flag = 0;
/* Compile the DMA descriptor - wait for ready. */
d = mxs_nand_get_dma_desc(nand_info);
@@ -603,6 +710,12 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf;
d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf;
+ if (nand_info->en_randomizer) {
+ d->cmd.pio_words[2] |= GPMI_ECCCTRL_RANDOMIZER_ENABLE |
+ GPMI_ECCCTRL_RANDOMIZER_TYPE2;
+ d->cmd.pio_words[3] |= (page % 256) << 16;
+ }
+
mxs_dma_desc_append(channel, d);
/* Compile the DMA descriptor - disable the BCH block. */
@@ -651,6 +764,8 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
goto rtn;
}
+ mxs_nand_return_dma_descs(nand_info);
+
/* Invalidate caches */
mxs_nand_inval_data_buf(nand_info);
@@ -663,10 +778,19 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
if (status[i] == 0x00)
continue;
- if (status[i] == 0xff)
+ if (status[i] == 0xff) {
+ if (!nand_info->en_randomizer &&
+ (is_mx6dqp() || is_mx7() || is_mx6ul() ||
+ is_imx8() || is_imx8m()))
+ if (readl(&bch_regs->hw_bch_debug1))
+ flag = 1;
continue;
+ }
if (status[i] == 0xfe) {
+ if (mxs_nand_erased_page(mtd, nand,
+ nand_info->data_buf, i, page))
+ break;
failed++;
continue;
}
@@ -693,6 +817,8 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
memcpy(buf, nand_info->data_buf, mtd->writesize);
+ if (flag)
+ memset(buf, 0xff, mtd->writesize);
rtn:
mxs_nand_return_dma_descs(nand_info);
@@ -741,7 +867,7 @@ static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf;
d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf;
- if (is_mx7() && nand_info->en_randomizer) {
+ if (nand_info->en_randomizer) {
d->cmd.pio_words[2] |= GPMI_ECCCTRL_RANDOMIZER_ENABLE |
GPMI_ECCCTRL_RANDOMIZER_TYPE2;
/*
@@ -751,7 +877,7 @@ static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
* The value is between 0-255. For additional details
* check 9.6.6.4 of i.MX7D Applications Processor reference
*/
- d->cmd.pio_words[3] |= (page % 255) << 16;
+ d->cmd.pio_words[3] |= (page % 256) << 16;
}
mxs_dma_desc_append(channel, d);
@@ -983,18 +1109,23 @@ static int mxs_nand_set_geometry(struct mtd_info *mtd, struct bch_geometry *geo)
struct nand_chip *nand = mtd_to_nand(mtd);
struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
- if (chip->ecc.strength > 0 && chip->ecc.size > 0)
- return mxs_nand_calc_ecc_layout_by_info(geo, mtd,
- chip->ecc.strength, chip->ecc.size);
+ if (chip->ecc_strength_ds > nand_info->max_ecc_strength_supported) {
+ printf("unsupported NAND chip, minimum ecc required %d\n"
+ , chip->ecc_strength_ds);
+ return -EINVAL;
+ }
- if (nand_info->use_minimum_ecc ||
- mxs_nand_calc_ecc_layout(geo, mtd)) {
- if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
- return -EINVAL;
+ if ((!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0) &&
+ mtd->oobsize < 1024) || nand_info->legacy_bch_geometry) {
+ dev_warn(this->dev, "use legacy bch geometry\n");
+ return mxs_nand_legacy_calc_ecc_layout(geo, mtd);
+ }
+
+ if (mtd->oobsize > 1024 || chip->ecc_step_ds < mtd->oobsize)
+ return mxs_nand_calc_ecc_for_large_oob(geo, mtd);
- return mxs_nand_calc_ecc_layout_by_info(geo, mtd,
+ return mxs_nand_calc_ecc_layout_by_info(geo, mtd,
chip->ecc_strength_ds, chip->ecc_step_ds);
- }
return 0;
}
@@ -1025,8 +1156,6 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd)
if (ret)
return ret;
- mxs_nand_calc_mark_offset(geo, mtd->writesize);
-
/* Configure BCH and set NFC geometry */
mxs_reset_block(&bch_regs->hw_bch_ctrl_reg);
@@ -1034,7 +1163,7 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd)
tmp = (geo->ecc_chunk_count - 1) << BCH_FLASHLAYOUT0_NBLOCKS_OFFSET;
tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
tmp |= (geo->ecc_strength >> 1) << BCH_FLASHLAYOUT0_ECC0_OFFSET;
- tmp |= geo->ecc_chunk_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
+ tmp |= geo->ecc_chunk0_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
tmp |= (geo->gf_len == 14 ? 1 : 0) <<
BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET;
writel(tmp, &bch_regs->hw_bch_flash0layout0);
@@ -1043,12 +1172,18 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd)
tmp = (mtd->writesize + mtd->oobsize)
<< BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
tmp |= (geo->ecc_strength >> 1) << BCH_FLASHLAYOUT1_ECCN_OFFSET;
- tmp |= geo->ecc_chunk_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
+ tmp |= geo->ecc_chunkn_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT;
tmp |= (geo->gf_len == 14 ? 1 : 0) <<
BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
writel(tmp, &bch_regs->hw_bch_flash0layout1);
nand_info->bch_flash0layout1 = tmp;
+ /* Set erase threshold to ecc strength for mx6ul, mx6qp and mx7 */
+ if (is_mx6dqp() || is_mx7() ||
+ is_mx6ul() || is_imx8() || is_imx8m())
+ writel(BCH_MODE_ERASE_THRESHOLD(geo->ecc_strength),
+ &bch_regs->hw_bch_mode);
+
/* Set *all* chip selects to use layout 0 */
writel(0, &bch_regs->hw_bch_layoutselect);
@@ -1184,7 +1319,7 @@ int mxs_nand_init_spl(struct nand_chip *nand)
nand_info->gpmi_regs = (struct mxs_gpmi_regs *)MXS_GPMI_BASE;
nand_info->bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
- if (is_mx6sx() || is_mx7())
+ if (is_mx6sx() || is_mx7() || is_imx8() || is_imx8m())
nand_info->max_ecc_strength_supported = 62;
else
nand_info->max_ecc_strength_supported = 40;
@@ -1268,7 +1403,7 @@ int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info)
nand->ecc.layout = &fake_ecc_layout;
nand->ecc.mode = NAND_ECC_HW;
- nand->ecc.size = nand_info->bch_geometry.ecc_chunk_size;
+ nand->ecc.size = nand_info->bch_geometry.ecc_chunkn_size;
nand->ecc.strength = nand_info->bch_geometry.ecc_strength;
/* second phase scan */
@@ -1347,12 +1482,14 @@ void mxs_nand_get_layout(struct mtd_info *mtd, struct mxs_nand_layout *l)
BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET);
l->eccn = (tmp & BCH_FLASHLAYOUT1_ECCN_MASK) >>
BCH_FLASHLAYOUT1_ECCN_OFFSET;
+ l->gf_len = (tmp & BCH_FLASHLAYOUT1_GF13_0_GF14_1_MASK) >>
+ BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
}
/*
* Set BCH to specific layout used by ROM bootloader to read FCB.
*/
-void mxs_nand_mode_fcb(struct mtd_info *mtd)
+void mxs_nand_mode_fcb_62bit(struct mtd_info *mtd)
{
u32 tmp;
struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
@@ -1386,6 +1523,43 @@ void mxs_nand_mode_fcb(struct mtd_info *mtd)
}
/*
+ * Set BCH to specific layout used by ROM bootloader to read FCB.
+ */
+void mxs_nand_mode_fcb_40bit(struct mtd_info *mtd)
+{
+ u32 tmp;
+ struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE;
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mxs_nand_info *nand_info = nand_get_controller_data(nand);
+
+ /* no randomizer in this setting*/
+ nand_info->en_randomizer = 0;
+
+ mtd->writesize = 1024;
+ mtd->oobsize = 1576 - 1024;
+
+ /* 8 ecc_chunks_*/
+ tmp = 7 << BCH_FLASHLAYOUT0_NBLOCKS_OFFSET;
+ /* 32 bytes for metadata */
+ tmp |= 32 << BCH_FLASHLAYOUT0_META_SIZE_OFFSET;
+ /* using ECC40 level to be performed */
+ tmp |= 0x14 << BCH_FLASHLAYOUT0_ECC0_OFFSET;
+ /* 0x20 * 4 bytes of the data0 block */
+ tmp |= 0x20 << BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET;
+ tmp |= 0 << BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET;
+ writel(tmp, &bch_regs->hw_bch_flash0layout0);
+
+ /* 1024 for data + 552 for OOB */
+ tmp = 1576 << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET;
+ /* using ECC40 level to be performed */
+ tmp |= 0x14 << BCH_FLASHLAYOUT1_ECCN_OFFSET;
+ /* 0x20 * 4 bytes of the data0 block */
+ tmp |= 0x20 << BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET;
+ tmp |= 0 << BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET;
+ writel(tmp, &bch_regs->hw_bch_flash0layout1);
+}
+
+/*
* Restore BCH to normal settings.
*/
void mxs_nand_mode_normal(struct mtd_info *mtd)