summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/raw/mxs_nand.c35
-rw-r--r--drivers/mtd/nand/raw/mxs_nand_spl.c90
2 files changed, 68 insertions, 57 deletions
diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index ee5d7fde9ce..7893e9d7e34 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -1246,22 +1246,6 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd)
/* Enable BCH complete interrupt */
writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set);
- /* Hook some operations at the MTD level. */
- if (mtd->_read_oob != mxs_nand_hook_read_oob) {
- nand_info->hooked_read_oob = mtd->_read_oob;
- mtd->_read_oob = mxs_nand_hook_read_oob;
- }
-
- if (mtd->_write_oob != mxs_nand_hook_write_oob) {
- nand_info->hooked_write_oob = mtd->_write_oob;
- mtd->_write_oob = mxs_nand_hook_write_oob;
- }
-
- if (mtd->_block_markbad != mxs_nand_hook_block_markbad) {
- nand_info->hooked_block_markbad = mtd->_block_markbad;
- mtd->_block_markbad = mxs_nand_hook_block_markbad;
- }
-
return 0;
}
@@ -1380,6 +1364,9 @@ int mxs_nand_init_spl(struct nand_chip *nand)
else
nand_info->max_ecc_strength_supported = 40;
+ if (IS_ENABLED(CONFIG_NAND_MXS_USE_MINIMUM_ECC))
+ nand_info->use_minimum_ecc = true;
+
err = mxs_nand_alloc_buffers(nand_info);
if (err)
return err;
@@ -1467,6 +1454,22 @@ int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info)
if (err)
goto err_free_buffers;
+ /* Hook some operations at the MTD level. */
+ if (mtd->_read_oob != mxs_nand_hook_read_oob) {
+ nand_info->hooked_read_oob = mtd->_read_oob;
+ mtd->_read_oob = mxs_nand_hook_read_oob;
+ }
+
+ if (mtd->_write_oob != mxs_nand_hook_write_oob) {
+ nand_info->hooked_write_oob = mtd->_write_oob;
+ mtd->_write_oob = mxs_nand_hook_write_oob;
+ }
+
+ if (mtd->_block_markbad != mxs_nand_hook_block_markbad) {
+ nand_info->hooked_block_markbad = mtd->_block_markbad;
+ mtd->_block_markbad = mxs_nand_hook_block_markbad;
+ }
+
err = nand_register(0, mtd);
if (err)
goto err_free_buffers;
diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
index 59a67ee4145..2bfb181007b 100644
--- a/drivers/mtd/nand/raw/mxs_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
@@ -218,14 +218,14 @@ void nand_init(void)
mxs_nand_setup_ecc(mtd);
}
-int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
{
- struct nand_chip *chip;
- unsigned int page;
+ unsigned int sz;
+ unsigned int block, lastblock;
+ unsigned int page, page_offset;
unsigned int nand_page_per_block;
- unsigned int sz = 0;
+ struct nand_chip *chip;
u8 *page_buf = NULL;
- u32 page_off;
chip = mtd_to_nand(mtd);
if (!chip->numchips)
@@ -235,47 +235,42 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf)
if (!page_buf)
return -ENOMEM;
- page = offs >> chip->page_shift;
- page_off = offs & (mtd->writesize - 1);
+ /* offs has to be aligned to a page address! */
+ block = offs / mtd->erasesize;
+ lastblock = (offs + size - 1) / mtd->erasesize;
+ page = (offs % mtd->erasesize) / mtd->writesize;
+ page_offset = offs % mtd->writesize;
nand_page_per_block = mtd->erasesize / mtd->writesize;
- debug("%s offset:0x%08x len:%d page:%x\n", __func__, offs, size, page);
-
- while (size) {
- if (mxs_read_page_ecc(mtd, page_buf, page) < 0)
- return -1;
-
- if (size > (mtd->writesize - page_off))
- sz = (mtd->writesize - page_off);
- else
- sz = size;
-
- memcpy(buf, page_buf + page_off, sz);
-
- offs += mtd->writesize;
- page++;
- buf += (mtd->writesize - page_off);
- page_off = 0;
- size -= sz;
-
- /*
- * Check if we have crossed a block boundary, and if so
- * check for bad block.
- */
- if (!(page % nand_page_per_block)) {
- /*
- * Yes, new block. See if this block is good. If not,
- * loop until we find a good block.
- */
- while (is_badblock(mtd, offs, 1)) {
- page = page + nand_page_per_block;
- /* Check i we've reached the end of flash. */
- if (page >= mtd->size >> chip->page_shift) {
+ while (block <= lastblock && size > 0) {
+ if (!is_badblock(mtd, mtd->erasesize * block, 1)) {
+ /* Skip bad blocks */
+ while (page < nand_page_per_block) {
+ int curr_page = nand_page_per_block * block + page;
+
+ if (mxs_read_page_ecc(mtd, page_buf, curr_page) < 0) {
free(page_buf);
- return -ENOMEM;
+ return -EIO;
}
+
+ if (size > (mtd->writesize - page_offset))
+ sz = (mtd->writesize - page_offset);
+ else
+ sz = size;
+
+ memcpy(dst, page_buf + page_offset, sz);
+ dst += sz;
+ size -= sz;
+ page_offset = 0;
+ page++;
}
+
+ page = 0;
+ } else {
+ lastblock++;
}
+
+ block++;
}
free(page_buf);
@@ -294,6 +289,19 @@ void nand_deselect(void)
u32 nand_spl_adjust_offset(u32 sector, u32 offs)
{
- /* Handle the offset adjust in nand_spl_load_image,*/
+ unsigned int block, lastblock;
+
+ block = sector / mtd->erasesize;
+ lastblock = (sector + offs) / mtd->erasesize;
+
+ while (block <= lastblock) {
+ if (is_badblock(mtd, block * mtd->erasesize, 1)) {
+ offs += mtd->erasesize;
+ lastblock++;
+ }
+
+ block++;
+ }
+
return offs;
}