]> git.karo-electronics.de Git - karo-tx-redboot.git/blobdiff - packages/devs/flash/arm/mxc/v2_0/src/mxc_nfc.c
Starterkit 5 Release 1.6
[karo-tx-redboot.git] / packages / devs / flash / arm / mxc / v2_0 / src / mxc_nfc.c
index 6f8991a23aa157f530363d4ec59195080abf4ed1..4bcf00603d792217f80dd424c790ca50366f86d6 100644 (file)
@@ -87,9 +87,6 @@
 #include <cyg/io/nand_bbt.h>
 #include <redboot.h>
 #include <stdlib.h>
-#if 0
-static int nfc_debug = 1;
-#endif
 
 #include CYGHWR_MEMORY_LAYOUT_H
 
@@ -143,7 +140,7 @@ static int g_spare_only_read_ok = true;
 static int g_nfc_debug_level = NFC_DEBUG_NONE;
 static bool g_nfc_debug_measure = false;
 static bool g_is_2k_page = false;
-static unsigned long g_block_offset;
+static unsigned int g_block_offset;
 static bool g_is_4k_page = false;
 static unsigned int g_nfc_version = MXC_NFC_V1; // default to version 1.0
 static int     num_of_nand_chips = 1;
@@ -302,8 +299,8 @@ static const flash_dev_info_t supported_devices[] = {
 #define BLOCK_TO_OFFSET(blk)                   ((blk) * NF_PG_PER_BLK * NF_PG_SZ)
 #define BLOCK_TO_PAGE(blk)                             ((blk) * NF_PG_PER_BLK)
 #define BLOCK_PAGE_TO_OFFSET(blk, pge) (((blk) * NF_PG_PER_BLK + (pge)) * NF_PG_SZ)
-#define OFFSET_TO_BLOCK(offset)                        (((offset) / NF_PG_SZ) / NF_PG_PER_BLK)
-#define OFFSET_TO_PAGE(offset)                 (((offset) / NF_PG_SZ) % NF_PG_PER_BLK)
+#define OFFSET_TO_BLOCK(offset)                        ((u32)((offset) / (NF_PG_SZ * NF_PG_PER_BLK)))
+#define OFFSET_TO_PAGE(offset)                 ((u32)((offset) / NF_PG_SZ) % NF_PG_PER_BLK)
 
 static u8 *g_bbt, *g_page_buf;
 static u32 g_bbt_sz;
@@ -317,6 +314,85 @@ nfc_setup_func_t *nfc_setup = NULL;
 // this callback allows the platform specific iomux setup
 nfc_iomuxsetup_func_t *nfc_iomux_setup = NULL;
 
+static flash_addr_t flash_region_start;
+static flash_addr_t flash_region_end;
+static int flash_enable;
+
+/* This assumes reading the flash with monotonically increasing flash addresses */
+static flash_addr_t nfc_l_to_p(flash_addr_t addr)
+{
+       if (g_block_offset == 0) {
+               return addr & MXC_NAND_ADDR_MASK;
+       } else {
+               flash_addr_t ra;
+               u32 block = (addr & MXC_NAND_ADDR_MASK) / NF_BLK_SZ;
+               u32 offset = addr % NF_BLK_SZ;
+
+               ra = (block + g_block_offset) * NF_BLK_SZ + offset;
+               if (offset == 0) {
+                       nfc_printf(NFC_DEBUG_MIN,
+                                          "Remapping block %u at addr 0x%08llx to block %u at addr 0x%08llx\n",
+                                          block, (u64)addr, block + g_block_offset, (u64)ra);
+               }
+               return ra;
+       }
+}
+
+static int flash_addr_valid(flash_addr_t addr)
+{
+       if (!flash_enable) {
+               nfc_printf(NFC_DEBUG_MIN, "No flash area enabled\n");
+               return 1;
+       }
+       if (addr < flash_region_start || addr >= flash_region_end) {
+               diag_printf("Flash address 0x%08llx is outside valid region 0x%08llx..0x%08llx\n",
+                                       (u64)addr, (u64)flash_region_start, (u64)flash_region_end);
+               return 0;
+       }
+       return 1;
+}
+
+/* FIXME: we should pass flash_addr_t as arguments */
+void mxc_flash_enable(void *start, void *end)
+{
+       flash_addr_t s = (unsigned long)start & MXC_NAND_ADDR_MASK;
+       flash_addr_t e = (unsigned long)end & MXC_NAND_ADDR_MASK;
+
+       if (flash_enable++ == 0) {
+               flash_region_start = s;
+               flash_region_end = e;
+               diag_printf1("Enabling flash region 0x%08llx..0x%08llx\n",
+                                        (u64)s, (u64)e);
+               g_block_offset = 0;
+       } else {
+               if (s < flash_region_start ||
+                       e > flash_region_end) {
+                       diag_printf("** WARNING: Enable 0x%08llx..0x%08llx outside enabled flash region 0x%08llx..0x%08llx\n",
+                                               (u64)s, (u64)e, (u64)flash_region_start, (u64)flash_region_end);
+               }
+       }
+}
+
+void mxc_flash_disable(void *start, void *end)
+{
+       flash_addr_t s = (unsigned long)start & MXC_NAND_ADDR_MASK;
+       flash_addr_t e = (unsigned long)end & MXC_NAND_ADDR_MASK;
+
+       if (flash_enable) {
+               if (--flash_enable == 0) {
+                       diag_printf1("Disabling flash region 0x%08llx..0x%08llx\n",
+                                                (u64)s, (u64)e);
+                       if (s != flash_region_start ||
+                               e != flash_region_end) {
+                               diag_printf("** Error: Disable 0x%08llx..0x%08llx not equal to enabled flash region 0x%08llx..0x%08llx\n",
+                                               (u64)s, (u64)e, (u64)flash_region_start, (u64)flash_region_end);
+                       }
+               }
+       } else {
+               diag_printf("** Error: unbalanced call to flash_disable()\n");
+       }
+}
+
 int
 #ifndef MXCFLASH_SELECT_MULTI
 flash_hwr_init(void)
@@ -668,7 +744,7 @@ static int nfc_is_badblock(u32 block, u8 *buf)
                res = (buf[off] >> sft) & 0x3;
                if (res) {
                        addr = BLOCK_TO_OFFSET(block);
-                       diag_printf1("Block %u at %08llx is marked %s (%d) in BBT@%p[%02x] mask %02x\n",
+                       diag_printf1("Block %u at 0x%08llx is marked %s (%d) in BBT@%p[%02x] mask %02x\n",
                                                 block, (u64)addr, res == BLK_RESERVED ? "reserved" :
                                                 res == BLK_BAD_FACTORY ? "factory bad" : "runtime bad",
                                                 res, buf, off, 3 << sft);
@@ -989,7 +1065,7 @@ static int nfc_program_blk(u32 ra, u8 *buf, u32 len)
  */
 int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose)
 {
-       u32 sz, blk, update = 0, skip = 0, j = 0;
+       u32 sz, blk, update = 0, j = 0;
 
        nfc_printf(NFC_DEBUG_MED, "%s: addr=0x%08llx len=0x%08x\n",
                           __FUNCTION__, (u64)addr, len);
@@ -1005,18 +1081,17 @@ int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose)
        addr &= MXC_NAND_ADDR_MASK;
        // now addr has to be block aligned
        for (sz = 0; sz < len; addr += NF_BLK_SZ, j++, sz += NF_BLK_SZ) {
+               if (!flash_addr_valid(addr)) {
+                       return 0;
+               }
                blk = OFFSET_TO_BLOCK(addr);
                if (skip_bad && nfc_is_badblock(blk, g_bbt)) {
-                       if (skip++ >= flash_dev_info->max_bad_blk) {
-                               diag_printf("\nToo many bad blocks encountered\n");
-                               return FLASH_ERR_PROTOCOL;
-                       }
                        diag_printf("\nSkipping bad block %u at addr 0x%08llx\n",
                                                blk, (u64)addr);
                        continue;
                }
                if (nfc_erase_blk(addr) != 0) {
-                       diag_printf("\nError: Failed to erase block %u at addr 0x%08llx\n",
+                       diag_printf("\n** Error: Failed to erase block %u at addr 0x%08llx\n",
                                            blk, (u64)addr);
                        mark_blk_bad(blk, g_bbt, BLK_BAD_RUNTIME);
                        // we don't need to update the table immediately here since even
@@ -1033,7 +1108,7 @@ int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose)
        if (update) {
                if (program_bbt_to_flash() != 0) {
                        diag_printf("\nError: Failed to update bad block table\n");
-                       return -1;
+                       return FLASH_ERR_PROGRAM;
                }
                diag_printf("\nnew bad blocks=%d\n", update);
        }
@@ -1049,9 +1124,10 @@ int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose)
  */
 int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len)
 {
-       u32 sz, blk, update = 0, skip = 0, partial_block_size;
+       u32 sz, blk, update = 0, partial_block_size;
 
-       diag_printf1("%s: addr=0x%08llx, len=0x%08x\n", __FUNCTION__, (u64)addr, len);
+       nfc_printf(NFC_DEBUG_MED, "%s: addr=0x%08llx, len=0x%08x\n",
+                          __FUNCTION__, (u64)addr, len);
 
        if ((addr % (NF_PG_SZ / num_of_nand_chips)) != 0) {
                diag_printf("Error: flash address 0x%08llx not page aligned\n", (u64)addr);
@@ -1064,15 +1140,16 @@ int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len)
 
        partial_block_size = addr % NF_BLK_SZ;
 
-       addr &= MXC_NAND_ADDR_MASK;
-       // now addr has to be block aligned
+       mxc_nfc_buf_clear(NAND_SPAR_BUF0, 0xff, NF_SPARE_SZ);
+       addr = nfc_l_to_p(addr);
        while (1) {
+               if (!flash_addr_valid(addr)) {
+                       diag_printf("\nToo many bad blocks in flash region 0x%08llx..0x%08llx\n",
+                                               (u64)flash_region_start, (u64)flash_region_end);
+                       return FLASH_ERR_INVALID;
+               }
                blk = OFFSET_TO_BLOCK(addr);
                if (nfc_is_badblock(blk, g_bbt)) {
-                       if (skip++ >= flash_dev_info->max_bad_blk) {
-                               diag_printf("\nToo many bad blocks encountered\n");
-                               return FLASH_ERR_PROTOCOL;
-                       }
                        diag_printf("\nSkipping bad block %u at addr 0x%08llx\n", blk, addr);
                        goto incr_address;
                }
@@ -1084,10 +1161,6 @@ int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len)
                        diag_printf("\nError: Failed to program flash block %u at addr 0x%08llx\n",
                                                blk, (u64)addr);
                        mark_blk_bad(blk, g_bbt, BLK_BAD_RUNTIME);
-                       if (skip + update > flash_dev_info->max_bad_blk) {
-                               diag_printf("\nToo many bad blocks encountered\n");
-                               return FLASH_ERR_PROTOCOL;
-                       }
                        // we don't need to update the table immediately here since even
                        // with power loss now, we should see the same program error again.
                        goto incr_address;
@@ -1102,17 +1175,14 @@ int nfc_program_region(flash_addr_t addr, u8 *buf, u32 len)
 incr_address:
                addr += partial_block_size;
                partial_block_size = NF_BLK_SZ;
+               g_block_offset++;
        }
        if (update) {
                if (program_bbt_to_flash() != 0) {
                        diag_printf("\nError: Failed to update bad block table\n");
                        return -1;
                }
-               diag_printf("\nnew bad blocks: %d\n", update);
        }
-       if (skip)
-               diag_printf("\nbad blocks skipped: %d\n", skip);
-
        return FLASH_ERR_OK;
 }
 
@@ -1121,68 +1191,75 @@ incr_address:
  * in flash address will be masked off inside the function.
  * It skips bad blocks and read good blocks of data for "len" bytes.
  *
- * @param addr                 NAND flash address. it has to be page aligned
+ * @param addr                 NAND flash address.
  * @param buf                  memory buf where data will be copied to
  * @param len                  number of bytes
  * @return                             FLASH_ERR_OK (0) if successful; non-zero otherwise
  */
 int nfc_read_region(flash_addr_t addr, u8 *buf, u32 len)
 {
-       u32 blk, bad = 0, start_point = 0, pg_no;
-       unsigned long offset = addr % NF_PG_SZ;
+       u32 start_point = 0, pg_no;
+       unsigned int offset = addr % NF_PG_SZ;
+       int chk_bad = 1;
 
-       diag_printf1("%s: addr=0x%08llx, buf=0x%p, len=0x%08x\n",
-                                __FUNCTION__, addr, buf, len);
+       nfc_printf(NFC_DEBUG_MED, "%s: addr=0x%08llx, offset=%03x buf=0x%p, len=0x%08x\n",
+                          __FUNCTION__, addr, offset, buf, len);
 
+       addr = nfc_l_to_p(addr);
        if (addr < (u32)flash_info.start || (addr + len) > (u32)flash_info.end || len == 0) {
-               diag_printf("Error: flash address 0x%08llx..0x%08llx outside valid range %p..%p\n",
+               diag_printf("** Error: flash address 0x%08llx..0x%08llx outside valid range %p..%p\n",
                                        (u64)addr, (u64)addr + len - 1, flash_info.start, flash_info.end);
                return FLASH_ERR_INVALID;
        }
 
-       addr = (addr & MXC_NAND_ADDR_MASK) - offset;
-       blk = OFFSET_TO_BLOCK(addr);
        while (len > 0) {
                int i;
 
-               if ((addr % NF_BLK_SZ) == 0) {
-                       // only need to test block aligned page address
-                       blk = OFFSET_TO_BLOCK(addr);
+               if (!flash_addr_valid(addr)) {
+                       diag_printf("Too many bad blocks in flash region 0x%08llx..0x%08llx\n",
+                                               (u64)flash_region_start, (u64)flash_region_end);
+                       return FLASH_ERR_INVALID;
+               }
+               if (chk_bad) {
+                       int blk = OFFSET_TO_BLOCK(addr);
+
                        if (nfc_is_badblock(blk, g_bbt)) {
-                               if (bad++ >= flash_dev_info->max_bad_blk) {
-                                       diag_printf("\nToo many bad blocks encountered\n");
-                                       return FLASH_ERR_PROTOCOL;
-                               }
-                               diag_printf("\nSkipping bad block %u at addr 0x%08llx\n", blk, (u64)addr);
+                               diag_printf("Skipping bad block %u at addr 0x%08llx\n", blk, (u64)addr);
                                addr += NF_BLK_SZ;
+                               g_block_offset++;
                                continue;
                        }
+                       chk_bad = 0;
                }
 
                pg_no = addr / NF_PG_SZ;
-               if ((addr % NF_PG_SZ) != 0) {
+               if (offset != 0) {
                        /* Find which interleaved NAND device */
-                       start_point = (addr - (pg_no * NF_PG_SZ)) / (NF_PG_SZ / num_of_nand_chips);
+                       start_point = offset / (NF_PG_SZ / num_of_nand_chips);
                } else {
                        start_point = 0;
                }
                for (i = start_point; i < num_of_nand_chips; i++) {
-                       int chunk_size = len > NF_PG_SZ / num_of_nand_chips ?
-                               NF_PG_SZ / num_of_nand_chips : len;
+                       int chunk_size = (NF_PG_SZ - offset) / num_of_nand_chips;
 
+                       if (chunk_size > len)
+                               chunk_size = len;
+                       nfc_printf(NFC_DEBUG_MED, "Reading page %d addr 0x%08llx chip %d len 0x%03x\n",
+                                          pg_no, (u64)addr, i, chunk_size);
                        if (nfc_read_page(i, pg_no, 0) != 0) {
-                               diag_printf("\nError: Failed to read flash block %u at addr 0x%08llx\n",
-                                                       blk, (u64)addr);
+                               diag_printf("** Error: Failed to read flash block %u at addr 0x%08llx\n",
+                                                       OFFSET_TO_BLOCK(addr), (u64)addr);
                                return FLASH_ERR_INVALID;
                        }
                        // now do the copying
-                       nfc_buf_read(buf, NAND_MAIN_BUF0, chunk_size);
+                       nfc_buf_read(buf, NAND_MAIN_BUF0 + offset, chunk_size);
 
                        buf += chunk_size;
                        len -= chunk_size;
                        addr += NF_PG_SZ / num_of_nand_chips - offset;
                        offset = 0;
                }
+               chk_bad = (addr % NF_BLK_SZ) == 0;
        }
 
        return FLASH_ERR_OK;
@@ -1321,6 +1398,9 @@ static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line,
        u8 t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, t8 = 0;
        int res = 0;
 
+       nfc_printf(NFC_DEBUG_MAX, "%s: reading page %u offset 0x%03x (addr 0x%08llx)\n",
+                          __FUNCTION__, pg_no, pg_off, (flash_addr_t)pg_no * NF_PG_SZ + pg_off);
+
        if (ecc_force == ECC_FORCE_OFF || pg_off != 0 )
                ecc = 0;
 
@@ -1346,8 +1426,8 @@ static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line,
 
                if (ecc && ((t1 & 0xA) != 0x0 || (t2 & 0xA) != 0x0 ||
                                        (t3 & 0xA) != 0x0 || (t4 & 0xA) != 0x0)) {
-                       diag_printf("\n** Error: %s(page=%d, col=%d): ECC status=0x%x:0x%x:0x%x:0x%x\n",
-                                               __FUNCTION__, pg_no, pg_off, t1, t2, t3, t4);
+                       diag_printf("\n** Error: ECC error page %u, col %u: ECC status=0x%x:0x%x:0x%x:0x%x\n",
+                                               pg_no, pg_off, t1, t2, t3, t4);
                        res = -1;
                        goto out;
                }
@@ -1520,45 +1600,6 @@ void mxc_nfc_print_info(void)
                                NF_PG_PER_BLK, NF_PG_SZ);
 }
 
-static inline void mxc_clr_block_offset(void *start, void *end)
-{
-       nfc_printf(NFC_DEBUG_MIN, "Clearing block offset %lu for %p..%p\n",
-                          g_block_offset, start, end);
-       g_block_offset = 0;
-}
-
-static void *flash_region_start;
-static void *flash_region_end;
-static int flash_enable;
-
-void mxc_flash_enable(void *start, void *end)
-{
-       if (flash_enable++ == 0) {
-               flash_region_start = start;
-               flash_region_end = end;
-               mxc_clr_block_offset(start, end);
-       } else {
-               if (start < flash_region_start || end > flash_region_end) {
-                       diag_printf("** WARNING: Enable %p..%p outside enabled flash region %p..%p\n",
-                                               start, end, flash_region_start, flash_region_end);
-               }
-       }
-}
-
-void mxc_flash_disable(void *start, void *end)
-{
-       if (flash_enable) {
-               if (--flash_enable == 0) {
-                       if (start != flash_region_start || end != flash_region_end) {
-                               diag_printf("** Error: Disable %p..%p not equal to enabled flash region %p..%p\n",
-                                                       start, end, flash_region_start, flash_region_end);
-                       }
-               }
-       } else {
-               diag_printf("** Error: unbalanced call to flash_disable()\n");
-       }
-}
-
 static int mxc_nfc_isbad_bbt(u16 *bbt, int block)
 {
        cyg_uint8 res;
@@ -1698,7 +1739,7 @@ local_cmd_entry("info",
 
 local_cmd_entry("show",
                                "Show a page main/spare areas or spare area only (-s)",
-                               "-f <raw page address> [-s]",
+                               "-f <raw page address> | -b <block> [-s]",
                                nand_show,
                                NAND_cmds
                   );
@@ -1783,24 +1824,33 @@ static void nand_usage(char *why)
 static u32 curr_addr;
 static void nand_show(int argc, char *argv[])
 {
-       u32 ra;
+       u32 ra, block;
        bool flash_addr_set = false;
+       bool block_set = false;
        bool spar_only = false;
-       struct option_info opts[2];
+       struct option_info opts[3];
 
        init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
                          &ra, &flash_addr_set, "NAND FLASH memory byte address");
-       init_opts(&opts[1], 's', false, OPTION_ARG_TYPE_FLG,
+       init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM,
+                         &block, &block_set, "NAND FLASH memory block number");
+       init_opts(&opts[2], 's', false, OPTION_ARG_TYPE_FLG,
                          &spar_only, NULL, "Spare only");
 
-       if (!scan_opts(argc, argv, 2, opts, 2, 0, 0, 0)) {
+       if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) {
                return;
        }
-       if (!flash_addr_set) {
+       if (flash_addr_set && block_set) {
+               nand_usage("options -f and -b are mutually exclusive");
+               return;
+       } else if (flash_addr_set) {
+               curr_addr = ra;
+       } else if (block_set) {
+               ra = BLOCK_TO_OFFSET(block) + (unsigned long)flash_info.start;
+               curr_addr = ra;
+       } else {
                ra = curr_addr;
                curr_addr += NF_PG_SZ;
-       } else {
-               curr_addr = ra;
        }
 
        if (ra % NF_PG_SZ) {
@@ -1840,7 +1890,7 @@ static void nand_read(int argc, char *argv[])
        init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_NUM,
                          &col, &col_set, "column addr");
 
-       if (!scan_opts(argc, argv, 2, opts, 4, 0, 0, 0)) {
+       if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) {
                nand_usage("invalid arguments");
                return;
        }
@@ -1883,6 +1933,12 @@ static void nand_read(int argc, char *argv[])
                        diag_printf("\n** Error: flash address: 0x%08x out of range\n", ra);
                        return;
                }
+               if (nfc_is_badblock(OFFSET_TO_BLOCK(ra), g_bbt)) {
+                       diag_printf("\nSkipping bad block %u at addr=0x%08llx\n",
+                                               OFFSET_TO_BLOCK(ra), (u64)ra);
+                       ra = (OFFSET_TO_BLOCK(ra) + 1) *  NF_BLK_SZ;
+                       continue;
+               }
                pg_no = ra / NF_PG_SZ;
                pg_off = ra % NF_PG_SZ;
                for (i = 0; i < num_of_nand_chips; i++) {
@@ -1916,7 +1972,6 @@ static void nand_write(int argc, char *argv[])
        bool col_set = false;
        struct option_info opts[4];
        bool ecc_status = g_ecc_enable;
-       int skip = 0;
 
        init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
                          &mem_addr, &mem_addr_set, "memory base address");
@@ -1926,7 +1981,7 @@ static void nand_write(int argc, char *argv[])
                          &len, &length_set, "image length [in FLASH]");
        init_opts(&opts[3], 'c', true, OPTION_ARG_TYPE_NUM,
                          &col, &col_set, "column addr");
-       if (!scan_opts(argc, argv, 2, opts, 4, 0, 0, 0)) {
+       if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) {
                nand_usage("invalid arguments");
                return;
        }
@@ -1937,8 +1992,9 @@ static void nand_write(int argc, char *argv[])
        }
 
        if ((mem_addr < (CYG_ADDRESS)ram_start) ||
-               ((mem_addr+len) >= (CYG_ADDRESS)ram_end)) {
-               diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
+               ((mem_addr + len) >= (CYG_ADDRESS)ram_end)) {
+               diag_printf("** WARNING: RAM address range: %p..%p may be invalid\n",
+                                       (void *)mem_addr, (void *)(mem_addr + len));
                diag_printf("   valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
        }
 
@@ -1963,16 +2019,14 @@ static void nand_write(int argc, char *argv[])
        mem_addr_st = mem_addr;
        len_st = len;
        ra &= MXC_NAND_ADDR_MASK;
+
+       mxc_nfc_buf_clear(NAND_SPAR_BUF0, 0xff, NF_SPARE_SZ);
        do {
                if (OFFSET_TO_BLOCK(ra) > (NF_BLK_CNT - 1)) {
-                       diag_printf("Out of range: addr=0x%x\n", ra);
+                       diag_printf("\nFlash address 0x%08x out of range\n", ra);
                        return;
                }
                if (nfc_is_badblock(OFFSET_TO_BLOCK(ra), g_bbt)) {
-                       if (skip++ >= flash_dev_info->max_bad_blk) {
-                               diag_printf("\nToo many bad blocks encountered\n");
-                               return;
-                       }
                        diag_printf("\nSkipping bad block %u at addr=0x%08llx\n",
                                                OFFSET_TO_BLOCK(ra), (u64)ra);
                        ra = (OFFSET_TO_BLOCK(ra) + 1) *  NF_BLK_SZ;
@@ -1985,11 +2039,11 @@ static void nand_write(int argc, char *argv[])
                }
                if (nfc_write_pg_random(ra / NF_PG_SZ, ra % NF_PG_SZ, (u8 *)mem_addr, 0) != 0) {
                        if (g_nfc_debug_level >= NFC_DEBUG_DEF) {
-                               diag_printf("Warning %d: program error at addr 0x%x\n", __LINE__, ra);
+                               diag_printf("\nWarning %d: program error at addr 0x%x\n", __LINE__, ra);
                        }
                        mark_blk_bad(OFFSET_TO_BLOCK(ra), g_bbt, BLK_BAD_RUNTIME);
                        ra = (OFFSET_TO_BLOCK(ra) + 1) *  NF_BLK_SZ; //make sure block size aligned
-                       mem_addr = mem_addr_st; // rewind to blocl boundary
+                       mem_addr = mem_addr_st; // rewind to block boundary
                        len = len_st;
                        continue;
                }
@@ -2001,9 +2055,6 @@ static void nand_write(int argc, char *argv[])
                ra += NF_PG_SZ;
                mem_addr += NF_PG_SZ;
        } while (len > 0);
-       if (skip) {
-               diag_printf("\n%s(skip bad blocks=%d\n\n", __FUNCTION__, skip);
-       }
        diag_printf("\n");
 }
 
@@ -2080,7 +2131,7 @@ static void nand_erase(int argc, char *argv[])
        init_opts(&opts[2], 'o', false, OPTION_ARG_TYPE_FLG,
                  &force_erase_set, &force_erase_set, "force erases block");
 
-       if (!scan_opts(argc, argv, 2, opts, 4, 0, 0, 0)) {
+       if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) {
                nand_usage("invalid arguments");
                return;
        }
@@ -2089,19 +2140,26 @@ static void nand_erase(int argc, char *argv[])
                nand_usage("missing argument");
                return;
        }
-       if ((ra % NF_BLK_SZ) != 0 ||
-               (len % NF_BLK_SZ) != 0 || len == 0) {
-               diag_printf("Address or length is not block aligned or length is zero!\n");
+       if ((ra % NF_BLK_SZ) != 0) {
+               diag_printf("Address must be block aligned!\n");
+               diag_printf("Block size is 0x%x\n", NF_BLK_SZ);
+               return;
+       }
+       if ((len % NF_BLK_SZ) != 0) {
+               diag_printf("length must be block aligned!\n");
                diag_printf("Block size is 0x%x\n", NF_BLK_SZ);
                return;
        }
+       if (len == 0) {
+               diag_printf("length must be > 0!\n");
+               return;
+       }
 
-       if (!verify_action("About to erase 0x%x bytes from nand offset 0x%x\n", len, ra)) {
+       if (!verify_action("About to erase 0x%08x bytes from nand offset 0x%08x", len, ra)) {
                diag_printf("** Aborted\n");
                return;
        }
 
-       // now ra is block aligned
        if (force_erase_set == true) {
                diag_printf("Force erase ...");
                nfc_erase_region(ra, len, 0, 1);
@@ -2125,7 +2183,7 @@ static void nand_scan(int argc, char *argv[])
        init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG,
                  &force_rescan, NULL, "force low level re-scan");
 
-       if (!scan_opts(argc, argv, 2, opts, 2, 0, 0, 0)) {
+       if (!scan_opts(argc, argv, 2, opts, NUM_ELEMS(opts), NULL, 0, NULL)) {
                nand_usage("invalid arguments");
                return;
        }
@@ -2188,7 +2246,7 @@ static void nand_info(int argc, char *argv[])
        for (i = 0; i < NF_BLK_CNT; i++) {
                int res = nfc_is_badblock(i, g_bbt);
                if (res & ~BLK_RESERVED) {
-                       diag_printf("block %d at offset 0x%x is a %s bad block\n",
+                       diag_printf("block %d at offset 0x%08x is a %s bad block\n",
                                                i, i * NF_BLK_SZ, res == BLK_BAD_FACTORY ? "factory" : "runtime");
                        j++;
                }
@@ -2328,29 +2386,24 @@ static void print_page(u32 addr, bool spare_only)
                diag_printf("Non page-aligned read not supported here: 0x%x\n", addr);
                return;
        }
-       if (spare_only) {
-               diag_printf("Error %d: Not supported\n", __LINE__);
-               return;
-       } else {
-               pg_no = addr / NF_PG_SZ;
-               pg_off = addr % NF_PG_SZ;
-               for (i = 0; i < num_of_nand_chips; i++) {
-                       if (nfc_read_page(i, pg_no, pg_off) != 0) {
-                               diag_printf("Error %d: uncorrectable. But still printing ...\n", __LINE__);
-                       }
-                       pg_off = 0;
-                       diag_printf("\n============ Printing block(%d) page(%d)  ==============\n",
-                                                                 blk_num, pg_num);
-
-                       diag_printf("<<<<<<<<< spare area >>>>>>>>>\n");
-                       print_pkt_16((u16*)NAND_SPAR_BUF0, NF_SPARE_SZ);
+       pg_no = addr / NF_PG_SZ;
+       pg_off = addr % NF_PG_SZ;
+       for (i = 0; i < num_of_nand_chips; i++) {
+               if (nfc_read_page(i, pg_no, pg_off) != 0) {
+                       diag_printf("Error %d: uncorrectable. But still printing ...\n", __LINE__);
+               }
+               pg_off = 0;
+               diag_printf("\n============ Printing block(%d) page(%d)  ==============\n",
+                                       blk_num, pg_num);
 
-                       if (!spare_only) {
-                               diag_printf("<<<<<<<<< main area >>>>>>>>>\n");
-                               print_pkt_16((u16*)NAND_MAIN_BUF0, NF_PG_SZ / num_of_nand_chips);
-                       }
+               diag_printf("<<<<<<<<< spare area >>>>>>>>>\n");
+               print_pkt_16((u16*)NAND_SPAR_BUF0, NF_SPARE_SZ);
 
-                       diag_printf("\n");
+               if (!spare_only) {
+                       diag_printf("<<<<<<<<< main area >>>>>>>>>\n");
+                       print_pkt_16((u16*)NAND_MAIN_BUF0, NF_PG_SZ / num_of_nand_chips);
                }
+
+               diag_printf("\n");
        }
 }