Starterkit 5 Release 1.6
[karo-tx-redboot.git] / packages / devs / flash / arm / mxc / v2_0 / src / mxc_nfc.c
index f7890f5..4bcf006 100644 (file)
@@ -322,7 +322,7 @@ static int flash_enable;
 static flash_addr_t nfc_l_to_p(flash_addr_t addr)
 {
        if (g_block_offset == 0) {
-               return addr;
+               return addr & MXC_NAND_ADDR_MASK;
        } else {
                flash_addr_t ra;
                u32 block = (addr & MXC_NAND_ADDR_MASK) / NF_BLK_SZ;
@@ -340,11 +340,16 @@ static flash_addr_t nfc_l_to_p(flash_addr_t addr)
 
 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 addr >= flash_region_start && addr < flash_region_end;
+       return 1;
 }
 
 /* FIXME: we should pass flash_addr_t as arguments */
@@ -739,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);
@@ -1073,9 +1078,12 @@ int nfc_erase_region(flash_addr_t addr, u32 len, bool skip_bad, bool verbose)
                diag_printf("Error: invalid length %u (must be > 0 and block aligned)\n", len);
                return FLASH_ERR_INVALID;
        }
-       addr = nfc_l_to_p(addr);
+       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)) {
                        diag_printf("\nSkipping bad block %u at addr 0x%08llx\n",
@@ -1731,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
                   );
@@ -1816,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) {
@@ -1873,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;
        }
@@ -1916,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++) {
@@ -1958,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;
        }
@@ -1969,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);
        }
 
@@ -1995,9 +2019,11 @@ 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("\nOut of range: addr=0x%08x\n", ra);
+                       diag_printf("\nFlash address 0x%08x out of range\n", ra);
                        return;
                }
                if (nfc_is_badblock(OFFSET_TO_BLOCK(ra), g_bbt)) {
@@ -2017,7 +2043,7 @@ static void nand_write(int argc, char *argv[])
                        }
                        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;
                }
@@ -2105,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;
        }
@@ -2114,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);
@@ -2150,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;
        }
@@ -2353,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");
        }
 }