]> git.sur5r.net Git - openocd/blobdiff - src/flash/nand.c
Improve str7x config command argument parsing.
[openocd] / src / flash / nand.c
index f27224115c4d6685bceb931f0a5a2d029bcf22ad..7fb7c99e7ae8e9dd42e661d922f2ad297d8c9783 100644 (file)
@@ -52,6 +52,7 @@ extern nand_flash_controller_t s3c2410_nand_controller;
 extern nand_flash_controller_t s3c2412_nand_controller;
 extern nand_flash_controller_t s3c2440_nand_controller;
 extern nand_flash_controller_t s3c2443_nand_controller;
+extern nand_flash_controller_t imx31_nand_flash_controller;
 
 /* extern nand_flash_controller_t boundary_scan_nand_controller; */
 
@@ -64,6 +65,7 @@ static nand_flash_controller_t *nand_flash_controllers[] =
        &s3c2412_nand_controller,
        &s3c2440_nand_controller,
        &s3c2443_nand_controller,
+       &imx31_nand_flash_controller,
 /*     &boundary_scan_nand_controller, */
        NULL
 };
@@ -307,8 +309,9 @@ int nand_init(struct command_context_s *cmd_ctx)
                                                 "identify NAND flash device <num>");
                register_command(cmd_ctx, nand_cmd, "check_bad_blocks", handle_nand_check_bad_blocks_command, COMMAND_EXEC,
                                                 "check NAND flash device <num> for bad blocks [<offset> <length>]");
-               register_command(cmd_ctx, nand_cmd, "erase", handle_nand_erase_command, COMMAND_EXEC,
-                                                "erase blocks on NAND flash device <num> <offset> <length>");
+               register_command(cmd_ctx, nand_cmd, "erase",
+                               handle_nand_erase_command, COMMAND_EXEC,
+                               "erase blocks on NAND flash device <num> [<offset> <length>]");
                register_command(cmd_ctx, nand_cmd, "dump", handle_nand_dump_command, COMMAND_EXEC,
                                                 "dump from NAND flash device <num> <filename> "
                                                 "<offset> <length> [oob_raw | oob_only]");
@@ -337,6 +340,19 @@ nand_device_t *get_nand_device_by_num(int num)
        return NULL;
 }
 
+int nand_command_get_device_by_num(struct command_context_s *cmd_ctx,
+               char *str, nand_device_t **device)
+{
+       unsigned num;
+       COMMAND_PARSE_NUMBER(uint, str, num);
+       *device = get_nand_device_by_num(num);
+       if (!*device) {
+               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", str);
+               return ERROR_INVALID_ARGUMENTS;
+       }
+       return ERROR_OK;
+}
+
 static int nand_build_bbt(struct nand_device_s *device, int first, int last)
 {
        uint32_t page = 0x0;
@@ -635,7 +651,7 @@ int nand_probe(struct nand_device_s *device)
        return ERROR_OK;
 }
 
-int nand_erase(struct nand_device_s *device, int first_block, int last_block)
+static int nand_erase(struct nand_device_s *device, int first_block, int last_block)
 {
        int i;
        uint32_t page;
@@ -710,8 +726,11 @@ int nand_erase(struct nand_device_s *device, int first_block, int last_block)
 
                if (status & 0x1)
                {
-                       LOG_ERROR("erase operation didn't pass, status: 0x%2.2x", status);
-                       return ERROR_NAND_OPERATION_FAILED;
+                       LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
+                                       (device->blocks[i].is_bad == 1)
+                                               ? "bad " : "",
+                                       i, status);
+                       /* continue; other blocks might still be erasable */
                }
 
                device->blocks[i].is_erased = 1;
@@ -1073,8 +1092,12 @@ int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char
        for (p = nand_devices, i = 0; p; p = p->next, i++)
        {
                if (p->device)
-                       command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
-                               i, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
+                       command_print(cmd_ctx, "#%i: %s (%s) "
+                               "pagesize: %i, buswidth: %i,\n\t"
+                               "blocksize: %i, blocks: %i",
+                               i, p->device->name, p->manufacturer->name,
+                               p->page_size, p->bus_width,
+                               p->erase_size, p->num_blocks);
                else
                        command_print(cmd_ctx, "#%i: not probed", i);
        }
@@ -1084,12 +1107,16 @@ int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char
 
 static int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       nand_device_t *p;
        int i = 0;
        int j = 0;
        int first = -1;
        int last = -1;
 
+       nand_device_t *p;
+       int retval = nand_command_get_device_by_num(cmd_ctx, args[0], &p);
+       if (ERROR_OK != retval)
+               return retval;
+
        switch (argc) {
        default:
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1098,15 +1125,16 @@ static int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd
                last = INT32_MAX;
                break;
        case 2:
-               first = last = strtoul(args[1], NULL, 0);
+               COMMAND_PARSE_NUMBER(int, args[1], i);
+               first = last = i;
+               i = 0;
                break;
        case 3:
-               first = strtoul(args[1], NULL, 0);
-               last = strtoul(args[2], NULL, 0);
+               COMMAND_PARSE_NUMBER(int, args[1], first);
+               COMMAND_PARSE_NUMBER(int, args[2], last);
                break;
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
        if (p)
        {
                if (p->device)
@@ -1158,15 +1186,16 @@ static int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd
 
 static int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       nand_device_t *p;
-       int retval;
-
        if (argc != 1)
        {
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       nand_device_t *p;
+       int retval = nand_command_get_device_by_num(cmd_ctx, args[0], &p);
+       if (ERROR_OK != retval)
+               return retval;
+
        if (p)
        {
                if ((retval = nand_probe(p)) == ERROR_OK)
@@ -1182,53 +1211,55 @@ static int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cm
                        command_print(cmd_ctx, "unknown error when probing NAND flash device");
                }
        }
-       else
-       {
-               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
-       }
 
        return ERROR_OK;
 }
 
 static int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       nand_device_t *p;
-       int retval;
-
-       if (argc != 3)
+       if (argc != 1 && argc != 3)
        {
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       nand_device_t *p;
+       int retval = nand_command_get_device_by_num(cmd_ctx, args[0], &p);
+       if (ERROR_OK != retval)
+               return retval;
+
        if (p)
        {
-               char *cp;
                unsigned long offset;
                unsigned long length;
 
-               offset = strtoul(args[1], &cp, 0);
-               if (*cp || offset == ULONG_MAX || offset % p->erase_size)
-               {
-                       return ERROR_INVALID_ARGUMENTS;
-               }
-               offset /= p->erase_size;
+               /* erase specified part of the chip; or else everything */
+               if (argc == 3) {
+                       unsigned long size = p->erase_size * p->num_blocks;
 
-               length = strtoul(args[2], &cp, 0);
-               if (*cp || length == ULONG_MAX || length % p->erase_size)
-               {
-                       return ERROR_INVALID_ARGUMENTS;
+                       COMMAND_PARSE_NUMBER(ulong, args[1], offset);
+                       if ((offset % p->erase_size) != 0 || offset >= size)
+                               return ERROR_INVALID_ARGUMENTS;
+
+                       COMMAND_PARSE_NUMBER(ulong, args[2], length);
+                       if ((length == 0) || (length % p->erase_size) != 0
+                                       || (length + offset) > size)
+                               return ERROR_INVALID_ARGUMENTS;
+
+                       offset /= p->erase_size;
+                       length /= p->erase_size;
+               } else {
+                       offset = 0;
+                       length = p->num_blocks;
                }
-               length -= 1;
-               length /= p->erase_size;
 
-               retval = nand_erase(p, offset, offset + length);
+               retval = nand_erase(p, offset, offset + length - 1);
                if (retval == ERROR_OK)
                {
-                       command_print(cmd_ctx, "successfully erased blocks "
-                                       "%lu to %lu on NAND flash device '%s'",
-                                       offset, offset + length, p->device->name);
+                       command_print(cmd_ctx, "erased blocks %lu to %lu "
+                                       "on NAND flash device #%s '%s'",
+                                       offset, offset + length,
+                                       args[0], p->device->name);
                }
                else if (retval == ERROR_NAND_OPERATION_FAILED)
                {
@@ -1239,18 +1270,12 @@ static int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cm
                        command_print(cmd_ctx, "unknown error when erasing NAND flash device");
                }
        }
-       else
-       {
-               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
-       }
 
        return ERROR_OK;
 }
 
 int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       nand_device_t *p;
-       int retval;
        int first = -1;
        int last = -1;
 
@@ -1260,31 +1285,25 @@ int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char
 
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
-       if (!p) {
-               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds",
-                               args[0]);
-               return ERROR_INVALID_ARGUMENTS;
-       }
+       nand_device_t *p;
+       int retval = nand_command_get_device_by_num(cmd_ctx, args[0], &p);
+       if (ERROR_OK != retval)
+               return retval;
 
        if (argc == 3)
        {
-               char *cp;
                unsigned long offset;
                unsigned long length;
 
-               offset = strtoul(args[1], &cp, 0);
-               if (*cp || offset == ULONG_MAX || offset % p->erase_size)
-               {
+               COMMAND_PARSE_NUMBER(ulong, args[1], offset);
+               if (offset % p->erase_size)
                        return ERROR_INVALID_ARGUMENTS;
-               }
                offset /= p->erase_size;
 
-               length = strtoul(args[2], &cp, 0);
-               if (*cp || length == ULONG_MAX || length % p->erase_size)
-               {
+               COMMAND_PARSE_NUMBER(ulong, args[2], length);
+               if (length % p->erase_size)
                        return ERROR_INVALID_ARGUMENTS;
-               }
+
                length -= 1;
                length /= p->erase_size;
 
@@ -1324,15 +1343,16 @@ static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cm
        duration_t duration;
        char *duration_text;
 
-       nand_device_t *p;
-
        if (argc < 3)
        {
                return ERROR_COMMAND_SYNTAX_ERROR;
-
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       nand_device_t *p;
+       int retval = nand_command_get_device_by_num(cmd_ctx, args[0], &p);
+       if (ERROR_OK != retval)
+               return retval;
+
        if (p)
        {
                uint8_t *page = NULL;
@@ -1341,7 +1361,7 @@ static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cm
                uint32_t oob_size = 0;
                const int *eccpos = NULL;
 
-               offset = strtoul(args[2], NULL, 0);
+               COMMAND_PARSE_NUMBER(u32, args[2], offset);
 
                if (argc > 3)
                {
@@ -1476,24 +1496,22 @@ static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cm
                free(duration_text);
                duration_text = NULL;
        }
-       else
-       {
-               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
-       }
 
        return ERROR_OK;
 }
 
 static int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       nand_device_t *p;
-
        if (argc < 4)
        {
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       nand_device_t *p;
+       int retval = nand_command_get_device_by_num(cmd_ctx, args[0], &p);
+       if (ERROR_OK != retval)
+               return retval;
+
        if (p)
        {
                if (p->device)
@@ -1507,8 +1525,10 @@ static int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd
                        uint32_t page_size = 0;
                        uint8_t *oob = NULL;
                        uint32_t oob_size = 0;
-                       uint32_t address = strtoul(args[2], NULL, 0);
-                       uint32_t size = strtoul(args[3], NULL, 0);
+                       uint32_t address;
+                       COMMAND_PARSE_NUMBER(u32, args[2], address);
+                       uint32_t size;
+                       COMMAND_PARSE_NUMBER(u32, args[3], size);
                        uint32_t bytes_done = 0;
                        enum oob_formats oob_format = NAND_OOB_NONE;
 
@@ -1598,24 +1618,22 @@ static int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd
                        command_print(cmd_ctx, "#%s: not probed", args[0]);
                }
        }
-       else
-       {
-               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
-       }
 
        return ERROR_OK;
 }
 
 static int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       nand_device_t *p;
-
        if ((argc < 1) || (argc > 2))
        {
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
+       nand_device_t *p;
+       int retval = nand_command_get_device_by_num(cmd_ctx, args[0], &p);
+       if (ERROR_OK != retval)
+               return retval;
+
        if (p)
        {
                if (p->device)
@@ -1643,10 +1661,6 @@ static int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, cha
                        command_print(cmd_ctx, "#%s: not probed", args[0]);
                }
        }
-       else
-       {
-               command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
-       }
 
        return ERROR_OK;
 }