-/***************************************************************************\r
- * Copyright (C) 2005 by Dominic Rath *\r
- * Dominic.Rath@gmx.de *\r
- * *\r
- * This program is free software; you can redistribute it and/or modify *\r
- * it under the terms of the GNU General Public License as published by *\r
- * the Free Software Foundation; either version 2 of the License, or *\r
- * (at your option) any later version. *\r
- * *\r
- * This program is distributed in the hope that it will be useful, *\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *\r
- * GNU General Public License for more details. *\r
- * *\r
- * You should have received a copy of the GNU General Public License *\r
- * along with this program; if not, write to the *\r
- * Free Software Foundation, Inc., *\r
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *\r
- ***************************************************************************/\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-#include "flash.h"\r
-#include "command.h"\r
-#include "target.h"\r
-#include "time_support.h"\r
-#include "fileio.h"\r
-#include "image.h"\r
-#include "log.h"\r
-\r
-#include <string.h>\r
-#include <unistd.h>\r
-#include <stdlib.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-#include <errno.h>\r
-#include <inttypes.h>\r
-\r
-/* command handlers */\r
-int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);\r
-\r
-/* flash drivers\r
- */\r
-extern flash_driver_t lpc2000_flash;\r
-extern flash_driver_t cfi_flash;\r
-extern flash_driver_t at91sam7_flash;\r
-extern flash_driver_t str7x_flash;\r
-extern flash_driver_t str9x_flash;\r
-extern flash_driver_t stellaris_flash;\r
-extern flash_driver_t str9xpec_flash;\r
-extern flash_driver_t stm32x_flash;\r
-extern flash_driver_t tms470_flash;\r
-\r
-flash_driver_t *flash_drivers[] =\r
-{\r
- &lpc2000_flash,\r
- &cfi_flash,\r
- &at91sam7_flash,\r
- &str7x_flash,\r
- &str9x_flash,\r
- &stellaris_flash,\r
- &str9xpec_flash,\r
- &stm32x_flash,\r
- &tms470_flash,\r
- NULL,\r
-};\r
-\r
-flash_bank_t *flash_banks;\r
-static command_t *flash_cmd;\r
-static int auto_erase = 0;\r
-\r
-/* wafer thin wrapper for invoking the flash driver */\r
-static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
-{\r
- int retval=ERROR_OK;\r
- if (bank->target->state != TARGET_HALTED)\r
- {\r
- ERROR("target not halted - aborting flash write");\r
- retval=ERROR_TARGET_NOT_HALTED;\r
- } else\r
- {\r
- retval=bank->driver->write(bank, buffer, offset, count);\r
- }\r
- if (retval!=ERROR_OK)\r
- {\r
- ERROR("Writing to flash bank at address 0x%08x at offset 0x%8.8x", bank->base, offset);\r
- }\r
- return retval;\r
-}\r
-\r
-static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)\r
-{\r
- int retval=ERROR_OK;\r
- if (bank->target->state != TARGET_HALTED)\r
- {\r
- ERROR("target not halted - aborting flash erase");\r
- retval=ERROR_TARGET_NOT_HALTED;\r
- } else if ((first < 0) || (last < first) || (last >= bank->num_sectors))\r
- {\r
- ERROR("invalid flash sector");\r
- retval=ERROR_FLASH_SECTOR_INVALID;\r
- } else \r
- {\r
- retval=bank->driver->erase(bank, first, last);\r
- }\r
- if (retval!=ERROR_OK)\r
- {\r
- ERROR("Failed erasing banks %d to %d", first, last);\r
- }\r
- return retval;\r
-}\r
-\r
-int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last)\r
-{\r
- int retval;\r
- if (bank->target->state != TARGET_HALTED)\r
- {\r
- ERROR("target not halted - aborting flash erase");\r
- retval=ERROR_TARGET_NOT_HALTED;\r
- } else if ((first < 0) || (last < first) || (last >= bank->num_sectors))\r
- {\r
- ERROR("invalid flash sector");\r
- retval=ERROR_FLASH_SECTOR_INVALID;\r
- } else \r
- {\r
- retval=bank->driver->protect(bank, set, first, last);\r
- }\r
- if (retval!=ERROR_OK)\r
- {\r
- ERROR("Failed protecting banks %d to %d", first, last);\r
- }\r
- return retval;\r
-}\r
-\r
-\r
-int flash_register_commands(struct command_context_s *cmd_ctx)\r
-{\r
- flash_cmd = register_command(cmd_ctx, NULL, "flash", NULL, COMMAND_ANY, NULL);\r
- \r
- register_command(cmd_ctx, flash_cmd, "bank", handle_flash_bank_command, COMMAND_CONFIG, "flash_bank <driver> <base> <size> <chip_width> <bus_width> <target> [driver_options ...]");\r
- register_command(cmd_ctx, flash_cmd, "auto_erase", handle_flash_auto_erase_command, COMMAND_ANY,\r
- "auto erase flash sectors <on|off>");\r
- return ERROR_OK;\r
-}\r
-\r
-int flash_init_drivers(struct command_context_s *cmd_ctx)\r
-{\r
- if (flash_banks)\r
- {\r
- register_command(cmd_ctx, flash_cmd, "banks", handle_flash_banks_command, COMMAND_EXEC,\r
- "list configured flash banks ");\r
- register_command(cmd_ctx, flash_cmd, "info", handle_flash_info_command, COMMAND_EXEC,\r
- "print info about flash bank <num>");\r
- register_command(cmd_ctx, flash_cmd, "probe", handle_flash_probe_command, COMMAND_EXEC,\r
- "identify flash bank <num>");\r
- register_command(cmd_ctx, flash_cmd, "erase_check", handle_flash_erase_check_command, COMMAND_EXEC,\r
- "check erase state of sectors in flash bank <num>");\r
- register_command(cmd_ctx, flash_cmd, "protect_check", handle_flash_protect_check_command, COMMAND_EXEC,\r
- "check protection state of sectors in flash bank <num>");\r
- register_command(cmd_ctx, flash_cmd, "erase_sector", handle_flash_erase_command, COMMAND_EXEC,\r
- "erase sectors at <bank> <first> <last>");\r
- register_command(cmd_ctx, flash_cmd, "erase_address", handle_flash_erase_address_command, COMMAND_EXEC,\r
- "erase address range <address> <length>");\r
- register_command(cmd_ctx, flash_cmd, "write_bank", handle_flash_write_bank_command, COMMAND_EXEC,\r
- "write binary data to <bank> <file> <offset>");\r
- register_command(cmd_ctx, flash_cmd, "write_image", handle_flash_write_image_command, COMMAND_EXEC,\r
- "write_image <file> [offset] [type]");\r
- register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,\r
- "set protection of sectors at <bank> <first> <last> <on|off>");\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-flash_bank_t *get_flash_bank_by_num_noprobe(int num)\r
-{\r
- flash_bank_t *p;\r
- int i = 0;\r
-\r
- for (p = flash_banks; p; p = p->next)\r
- {\r
- if (i++ == num)\r
- {\r
- return p;\r
- }\r
- }\r
- ERROR("Flash bank %d does not exist", num);\r
- return NULL;\r
-}\r
-\r
-flash_bank_t *get_flash_bank_by_num(int num)\r
-{\r
- flash_bank_t *p = get_flash_bank_by_num_noprobe(num);\r
- int retval;\r
- \r
- if (p == NULL)\r
- return NULL;\r
- \r
- retval = p->driver->auto_probe(p);\r
- \r
- if (retval != ERROR_OK)\r
- {\r
- ERROR("auto_probe failed %d\n", retval);\r
- return NULL;\r
- }\r
- return p;\r
-}\r
-\r
-int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- int i;\r
- int found = 0;\r
- target_t *target;\r
- \r
- if (argc < 6)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- if ((target = get_target_by_num(strtoul(args[5], NULL, 0))) == NULL)\r
- {\r
- ERROR("target %lu not defined", strtoul(args[5], NULL, 0));\r
- return ERROR_OK;\r
- }\r
- \r
- for (i = 0; flash_drivers[i]; i++)\r
- {\r
- if (strcmp(args[0], flash_drivers[i]->name) == 0)\r
- {\r
- flash_bank_t *p, *c;\r
- \r
- /* register flash specific commands */\r
- if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)\r
- {\r
- ERROR("couldn't register '%s' commands", args[0]);\r
- exit(-1);\r
- }\r
- \r
- c = malloc(sizeof(flash_bank_t));\r
- c->target = target;\r
- c->driver = flash_drivers[i];\r
- c->driver_priv = NULL;\r
- c->base = strtoul(args[1], NULL, 0);\r
- c->size = strtoul(args[2], NULL, 0);\r
- c->chip_width = strtoul(args[3], NULL, 0);\r
- c->bus_width = strtoul(args[4], NULL, 0);\r
- c->num_sectors = 0;\r
- c->sectors = NULL;\r
- c->next = NULL;\r
- \r
- if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)\r
- {\r
- ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);\r
- free(c);\r
- return ERROR_OK;\r
- }\r
- \r
- /* put flash bank in linked list */\r
- if (flash_banks)\r
- {\r
- /* find last flash bank */\r
- for (p = flash_banks; p && p->next; p = p->next);\r
- if (p)\r
- p->next = c;\r
- }\r
- else\r
- {\r
- flash_banks = c;\r
- }\r
- \r
- found = 1;\r
- }\r
- }\r
- \r
- /* no matching flash driver found */\r
- if (!found)\r
- {\r
- ERROR("flash driver '%s' not found", args[0]);\r
- exit(-1);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *p;\r
- int i = 0;\r
- \r
- if (!flash_banks)\r
- {\r
- command_print(cmd_ctx, "no flash banks configured");\r
- return ERROR_OK;\r
- }\r
- \r
- for (p = flash_banks; p; p = p->next)\r
- {\r
- command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",\r
- i++, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *p;\r
- int i = 0;\r
- int j = 0;\r
- \r
- if (argc != 1)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- for (p = flash_banks; p; p = p->next, i++)\r
- {\r
- if (i == strtoul(args[0], NULL, 0))\r
- {\r
- char buf[1024];\r
- \r
- /* attempt auto probe */\r
- p->driver->auto_probe(p);\r
- \r
- command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",\r
- i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);\r
- for (j = 0; j < p->num_sectors; j++)\r
- {\r
- char *erase_state, *protect_state;\r
- \r
- if (p->sectors[j].is_erased == 0)\r
- erase_state = "not erased";\r
- else if (p->sectors[j].is_erased == 1)\r
- erase_state = "erased";\r
- else\r
- erase_state = "erase state unknown";\r
- \r
- if (p->sectors[j].is_protected == 0)\r
- protect_state = "not protected";\r
- else if (p->sectors[j].is_protected == 1)\r
- protect_state = "protected";\r
- else\r
- protect_state = "protection state unknown";\r
-\r
- command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s, %s",\r
- j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,\r
- erase_state, protect_state);\r
- }\r
- \r
- p->driver->info(p, buf, 1024);\r
- command_print(cmd_ctx, "%s", buf);\r
- }\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *p;\r
- int retval;\r
- \r
- if (argc != 1)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- p = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));\r
- if (p)\r
- {\r
- if ((retval = p->driver->probe(p)) == ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);\r
- }\r
- else if (retval == ERROR_FLASH_BANK_INVALID)\r
- {\r
- command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",\r
- args[0], p->base);\r
- }\r
- else\r
- {\r
- command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",\r
- args[0], p->base);\r
- }\r
- }\r
- else\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *p;\r
- int retval;\r
- \r
- if (argc != 1)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (p)\r
- {\r
- if ((retval = p->driver->erase_check(p)) == ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);\r
- }\r
- else\r
- {\r
- command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",\r
- args[0], p->base);\r
- }\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *p;\r
- int retval;\r
- int address;\r
- int length;\r
- duration_t duration;\r
- char *duration_text;\r
- \r
- target_t *target = get_current_target(cmd_ctx);\r
-\r
- if (argc != 2)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- address = strtoul(args[0], NULL, 0);\r
- length = strtoul(args[1], NULL, 0);\r
- if (length <= 0)\r
- {\r
- command_print(cmd_ctx, "Length must be >0");\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
-\r
- p = get_flash_bank_by_addr(target, address);\r
- if (p == NULL)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- /* We can't know if we did a resume + halt, in which case we no longer know the erased state */\r
- flash_set_dirty();\r
- \r
- duration_start_measure(&duration);\r
- \r
- if ((retval = flash_erase_address_range(target, address, length)) == ERROR_OK)\r
- {\r
- duration_stop_measure(&duration, &duration_text); \r
- command_print(cmd_ctx, "erased address 0x%8.8x length %i in %s", address, length, duration_text);\r
- free(duration_text);\r
- }\r
- \r
- return retval;\r
-}\r
-\r
-int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *p;\r
- int retval;\r
- \r
- if (argc != 1)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (p)\r
- {\r
- if ((retval = p->driver->protect_check(p)) == ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "successfully checked protect state");\r
- }\r
- else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
- {\r
- command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);\r
- }\r
- else\r
- {\r
- command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);\r
- }\r
- }\r
- else\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- if (argc > 2)\r
- {\r
- int first = strtoul(args[1], NULL, 0);\r
- int last = strtoul(args[2], NULL, 0);\r
- int retval;\r
- flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- duration_t duration;\r
- char *duration_text;\r
- \r
- duration_start_measure(&duration);\r
- \r
- if (!p)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)\r
- {\r
- duration_stop_measure(&duration, &duration_text); \r
- \r
- command_print(cmd_ctx, "erased sectors %i through %i on flash bank %i in %s", first, last, strtoul(args[0], 0, 0), duration_text);\r
- free(duration_text);\r
- }\r
- }\r
- else\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
-\r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- if (argc > 3)\r
- {\r
- int first = strtoul(args[1], NULL, 0);\r
- int last = strtoul(args[2], NULL, 0);\r
- int set;\r
- int retval;\r
- flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!p)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- if (strcmp(args[3], "on") == 0)\r
- set = 1;\r
- else if (strcmp(args[3], "off") == 0)\r
- set = 0;\r
- else\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- retval = flash_driver_protect(p, set, first, last);\r
- if (retval == ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "%s protection for sectors %i through %i on flash bank %i", (set) ? "set" : "cleared", first, last, strtoul(args[0], 0, 0));\r
- }\r
- }\r
- else\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
-\r
- }\r
-\r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- target_t *target = get_current_target(cmd_ctx);\r
- \r
- image_t image;\r
- u32 written;\r
- \r
- duration_t duration;\r
- char *duration_text;\r
- \r
- int retval;\r
-\r
- if (argc < 1)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
-\r
- }\r
- \r
- if (!target)\r
- {\r
- ERROR("no target selected");\r
- return ERROR_OK;\r
- }\r
- \r
- duration_start_measure(&duration);\r
- \r
- if (argc >= 2)\r
- {\r
- image.base_address_set = 1;\r
- image.base_address = strtoul(args[1], NULL, 0);\r
- }\r
- else\r
- {\r
- image.base_address_set = 0;\r
- image.base_address = 0x0;\r
- }\r
- \r
- image.start_address_set = 0;\r
-\r
- retval = image_open(&image, args[0], (argc == 3) ? args[2] : NULL);\r
- if (retval != ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "image_open error: %s", image.error_str);\r
- return retval;\r
- }\r
- \r
- retval = flash_write(target, &image, &written, auto_erase);\r
-\r
- if (retval != ERROR_OK)\r
- {\r
- image_close(&image);\r
- return retval;\r
- }\r
- \r
- duration_stop_measure(&duration, &duration_text);\r
- if (retval == ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "wrote %u byte from file %s in %s (%f kb/s)",\r
- written, args[0], duration_text,\r
- (float)written / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));\r
- }\r
- free(duration_text);\r
-\r
- image_close(&image);\r
- \r
- return retval;\r
-}\r
-\r
-int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- u32 offset;\r
- u8 *buffer;\r
- u32 buf_cnt;\r
-\r
- fileio_t fileio;\r
- \r
- duration_t duration;\r
- char *duration_text;\r
- \r
- int retval;\r
- flash_bank_t *p;\r
-\r
- if (argc != 3)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- duration_start_measure(&duration);\r
- \r
- offset = strtoul(args[2], NULL, 0);\r
- p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!p)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);\r
- return ERROR_OK;\r
- }\r
- \r
- buffer = malloc(fileio.size);\r
- if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);\r
- return ERROR_OK;\r
- }\r
- \r
- retval = flash_driver_write(p, buffer, offset, buf_cnt);\r
- \r
- free(buffer);\r
- \r
- duration_stop_measure(&duration, &duration_text);\r
- if (retval!=ERROR_OK)\r
- {\r
- command_print(cmd_ctx, "wrote %"PRIi64" byte from file %s to flash bank %i at offset 0x%8.8x in %s (%f kb/s)",\r
- fileio.size, args[1], strtoul(args[0], NULL, 0), offset, duration_text,\r
- (float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));\r
- }\r
- free(duration_text);\r
-\r
- fileio_close(&fileio);\r
- \r
- return retval;\r
-}\r
-\r
-void flash_set_dirty(void)\r
-{\r
- flash_bank_t *c;\r
- int i;\r
- \r
- /* set all flash to require erasing */\r
- for (c = flash_banks; c; c = c->next)\r
- {\r
- for (i = 0; i < c->num_sectors; i++)\r
- {\r
- c->sectors[i].is_erased = 0; \r
- }\r
- }\r
-}\r
-\r
-/* lookup flash bank by address */\r
-flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr)\r
-{\r
- flash_bank_t *c;\r
-\r
- /* cycle through bank list */\r
- for (c = flash_banks; c; c = c->next)\r
- {\r
- int retval;\r
- retval = c->driver->auto_probe(c);\r
- \r
- if (retval != ERROR_OK)\r
- {\r
- ERROR("auto_probe failed %d\n", retval);\r
- return NULL;\r
- }\r
- /* check whether address belongs to this flash bank */\r
- if ((addr >= c->base) && (addr < c->base + c->size) && target == c->target)\r
- return c;\r
- }\r
- ERROR("No flash at address 0x%08x\n", addr);\r
- return NULL;\r
-}\r
-\r
-/* erase given flash region, selects proper bank according to target and address */\r
-int flash_erase_address_range(target_t *target, u32 addr, u32 length)\r
-{\r
- flash_bank_t *c;\r
- int first = -1;\r
- int last = -1;\r
- int i;\r
- \r
- if ((c = get_flash_bank_by_addr(target, addr)) == NULL)\r
- return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */\r
-\r
- if (c->size == 0 || c->num_sectors == 0)\r
- return ERROR_FLASH_BANK_INVALID;\r
- \r
- if (length == 0)\r
- {\r
- /* special case, erase whole bank when length is zero */\r
- if (addr != c->base)\r
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
- \r
- return flash_driver_erase(c, 0, c->num_sectors - 1);\r
- }\r
-\r
- /* check whether it fits */\r
- if (addr + length > c->base + c->size)\r
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
- \r
- addr -= c->base;\r
- \r
- for (i = 0; i < c->num_sectors; i++)\r
- { \r
- /* check whether sector overlaps with the given range and is not yet erased */\r
- if (addr < c->sectors[i].offset + c->sectors[i].size && addr + length > c->sectors[i].offset && c->sectors[i].is_erased != 1) {\r
- /* if first is not set yet then this is the first sector */\r
- if (first == -1)\r
- first = i;\r
- last = i; /* and it is the last one so far in any case */\r
- }\r
- }\r
- \r
- if( first == -1 || last == -1 )\r
- return ERROR_OK;\r
- \r
- return flash_driver_erase(c, first, last);\r
-}\r
-\r
-/* write (optional verify) an image to flash memory of the given target */\r
-int flash_write(target_t *target, image_t *image, u32 *written, int erase)\r
-{\r
- int retval;\r
-\r
- int section;\r
- u32 section_offset;\r
- flash_bank_t *c;\r
- \r
- section = 0;\r
- section_offset = 0;\r
-\r
- if (written)\r
- *written = 0;\r
- \r
- if (erase)\r
- {\r
- /* assume all sectors need erasing - stops any problems\r
- * when flash_write is called multiple times */\r
- \r
- flash_set_dirty();\r
- }\r
- \r
- /* loop until we reach end of the image */\r
- while (section < image->num_sections)\r
- {\r
- u32 buffer_size;\r
- u8 *buffer;\r
- int section_first;\r
- int section_last;\r
- u32 run_address = image->sections[section].base_address + section_offset;\r
- u32 run_size = image->sections[section].size - section_offset;\r
-\r
- if (image->sections[section].size == 0)\r
- {\r
- WARNING("empty section %d", section);\r
- section++;\r
- section_offset = 0;\r
- continue;\r
- }\r
-\r
- /* find the corresponding flash bank */\r
- if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)\r
- {\r
- section++; /* and skip it */\r
- section_offset = 0;\r
- continue;\r
- }\r
-\r
- /* collect consecutive sections which fall into the same bank */\r
- section_first = section;\r
- section_last = section;\r
- while ((run_address + run_size < c->base + c->size)\r
- && (section_last + 1 < image->num_sections))\r
- {\r
- if (image->sections[section_last + 1].base_address < (run_address + run_size))\r
- {\r
- DEBUG("section %d out of order(very slightly surprising, but supported)", section_last + 1);\r
- break;\r
- }\r
- if (image->sections[section_last + 1].base_address != (run_address + run_size))\r
- break;\r
- run_size += image->sections[++section_last].size;\r
- }\r
-\r
- /* fit the run into bank constraints */\r
- if (run_address + run_size > c->base + c->size)\r
- run_size = c->base + c->size - run_address;\r
-\r
- /* allocate buffer */\r
- buffer = malloc(run_size);\r
- buffer_size = 0;\r
-\r
- /* read sections to the buffer */\r
- while (buffer_size < run_size)\r
- {\r
- u32 size_read;\r
- \r
- if (buffer_size - run_size <= image->sections[section].size - section_offset)\r
- size_read = buffer_size - run_size;\r
- else\r
- size_read = image->sections[section].size - section_offset;\r
- \r
- if ((retval = image_read_section(image, section, section_offset,\r
- size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)\r
- {\r
- free(buffer);\r
- \r
- return retval;\r
- }\r
-\r
- buffer_size += size_read;\r
- section_offset += size_read;\r
-\r
- if (section_offset >= image->sections[section].size)\r
- {\r
- section++;\r
- section_offset = 0;\r
- }\r
- }\r
-\r
- retval = ERROR_OK;\r
- \r
- if (erase)\r
- {\r
- /* calculate and erase sectors */\r
- retval = flash_erase_address_range( target, run_address, run_size );\r
- }\r
- \r
- if (retval == ERROR_OK)\r
- {\r
- /* write flash sectors */\r
- retval = flash_driver_write(c, buffer, run_address - c->base, run_size);\r
- }\r
- \r
- free(buffer);\r
-\r
- if (retval != ERROR_OK)\r
- {\r
- return retval; /* abort operation */\r
- }\r
-\r
- if (written != NULL)\r
- *written += run_size; /* add run size to total written counter */\r
- }\r
-\r
- return ERROR_OK;\r
-}\r
-\r
-int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- if (argc != 1)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
-\r
- }\r
- \r
- if (strcmp(args[0], "on") == 0)\r
- auto_erase = 1;\r
- else if (strcmp(args[0], "off") == 0)\r
- auto_erase = 0;\r
- else \r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- \r
- return ERROR_OK;\r
-}\r
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * Copyright (C) 2007,2008 Øyvind Harboe *
+ * oyvind.harboe@zylin.com *
+ * *
+ * Copyright (C) 2008 by Spencer Oliver *
+ * spen@spen-soft.co.uk *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "flash.h"
+#include "common.h"
+#include <target/image.h>
+#include <helper/time_support.h>
+
+/* flash drivers
+ */
+extern struct flash_driver lpc2000_flash;
+extern struct flash_driver lpc288x_flash;
+extern struct flash_driver lpc2900_flash;
+extern struct flash_driver cfi_flash;
+extern struct flash_driver at91sam3_flash;
+extern struct flash_driver at91sam7_flash;
+extern struct flash_driver str7x_flash;
+extern struct flash_driver str9x_flash;
+extern struct flash_driver aduc702x_flash;
+extern struct flash_driver stellaris_flash;
+extern struct flash_driver str9xpec_flash;
+extern struct flash_driver stm32x_flash;
+extern struct flash_driver tms470_flash;
+extern struct flash_driver ecosflash_flash;
+extern struct flash_driver ocl_flash;
+extern struct flash_driver pic32mx_flash;
+extern struct flash_driver avr_flash;
+extern struct flash_driver faux_flash;
+
+struct flash_driver *flash_drivers[] = {
+ &lpc2000_flash,
+ &lpc288x_flash,
+ &lpc2900_flash,
+ &cfi_flash,
+ &at91sam7_flash,
+ &at91sam3_flash,
+ &str7x_flash,
+ &str9x_flash,
+ &aduc702x_flash,
+ &stellaris_flash,
+ &str9xpec_flash,
+ &stm32x_flash,
+ &tms470_flash,
+ &ecosflash_flash,
+ &ocl_flash,
+ &pic32mx_flash,
+ &avr_flash,
+ &faux_flash,
+ NULL,
+};
+
+struct flash_bank *flash_banks;
+
+struct flash_bank *get_flash_bank_by_num_noprobe(int num)
+{
+ struct flash_bank *p;
+ int i = 0;
+
+ for (p = flash_banks; p; p = p->next)
+ {
+ if (i++ == num)
+ {
+ return p;
+ }
+ }
+ LOG_ERROR("flash bank %d does not exist", num);
+ return NULL;
+}
+
+int flash_get_bank_count(void)
+{
+ struct flash_bank *p;
+ int i = 0;
+ for (p = flash_banks; p; p = p->next)
+ {
+ i++;
+ }
+ return i;
+}
+
+struct flash_bank *get_flash_bank_by_name(const char *name)
+{
+ unsigned requested = get_flash_name_index(name);
+ unsigned found = 0;
+
+ struct flash_bank *bank;
+ for (bank = flash_banks; NULL != bank; bank = bank->next)
+ {
+ if (strcmp(bank->name, name) == 0)
+ return bank;
+ if (!flash_driver_name_matches(bank->driver->name, name))
+ continue;
+ if (++found < requested)
+ continue;
+ return bank;
+ }
+ return NULL;
+}
+
+struct flash_bank *get_flash_bank_by_num(int num)
+{
+ struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
+ int retval;
+
+ if (p == NULL)
+ return NULL;
+
+ retval = p->driver->auto_probe(p);
+
+ if (retval != ERROR_OK)
+ {
+ LOG_ERROR("auto_probe failed %d\n", retval);
+ return NULL;
+ }
+ return p;
+}
+
+/* lookup flash bank by address */
+struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr)
+{
+ struct flash_bank *c;
+
+ /* cycle through bank list */
+ for (c = flash_banks; c; c = c->next)
+ {
+ int retval;
+ retval = c->driver->auto_probe(c);
+
+ if (retval != ERROR_OK)
+ {
+ LOG_ERROR("auto_probe failed %d\n", retval);
+ return NULL;
+ }
+ /* check whether address belongs to this flash bank */
+ if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
+ return c;
+ }
+ LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
+ return NULL;
+}
+
+int default_flash_mem_blank_check(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ const int buffer_size = 1024;
+ int i;
+ uint32_t nBytes;
+ int retval = ERROR_OK;
+
+ if (bank->target->state != TARGET_HALTED)
+ {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ uint8_t *buffer = malloc(buffer_size);
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ uint32_t j;
+ bank->sectors[i].is_erased = 1;
+
+ for (j = 0; j < bank->sectors[i].size; j += buffer_size)
+ {
+ uint32_t chunk;
+ chunk = buffer_size;
+ if (chunk > (j - bank->sectors[i].size))
+ {
+ chunk = (j - bank->sectors[i].size);
+ }
+
+ retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
+ if (retval != ERROR_OK)
+ {
+ goto done;
+ }
+
+ for (nBytes = 0; nBytes < chunk; nBytes++)
+ {
+ if (buffer[nBytes] != 0xFF)
+ {
+ bank->sectors[i].is_erased = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ done:
+ free(buffer);
+
+ return retval;
+}
+
+int default_flash_blank_check(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ int i;
+ int retval;
+ int fast_check = 0;
+ uint32_t blank;
+
+ if (bank->target->state != TARGET_HALTED)
+ {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ uint32_t address = bank->base + bank->sectors[i].offset;
+ uint32_t size = bank->sectors[i].size;
+
+ if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK)
+ {
+ fast_check = 0;
+ break;
+ }
+ if (blank == 0xFF)
+ bank->sectors[i].is_erased = 1;
+ else
+ bank->sectors[i].is_erased = 0;
+ fast_check = 1;
+ }
+
+ if (!fast_check)
+ {
+ LOG_USER("Running slow fallback erase check - add working memory");
+ return default_flash_mem_blank_check(bank);
+ }
+
+ return ERROR_OK;
+}