+/***************************************************************************\r
+ * Copyright (C) 2008 Øyvind Harboe *\r
+ * oyvind.harboe@zylin.com *\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 "replacements.h"\r
+\r
+\r
+#include "flash.h"\r
+\r
+#include "target.h"\r
+\r
+#include "flash.h"\r
+#include "target.h"\r
+#include "log.h"\r
+#include "binarybuffer.h"\r
+#include "../target/embeddedice.h"\r
+#include "types.h"\r
+\r
+\r
+\r
+int ecosflash_register_commands(struct command_context_s *cmd_ctx);\r
+int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
+int ecosflash_erase(struct flash_bank_s *bank, int first, int last);\r
+int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last);\r
+int ecosflash_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
+int ecosflash_probe(struct flash_bank_s *bank);\r
+int ecosflash_erase_check(struct flash_bank_s *bank);\r
+int ecosflash_protect_check(struct flash_bank_s *bank);\r
+int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
+\r
+u32 ecosflash_get_flash_status(flash_bank_t *bank);\r
+void ecosflash_set_flash_mode(flash_bank_t *bank,int mode);\r
+u32 ecosflash_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);\r
+int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+flash_driver_t ecosflash_flash =\r
+{\r
+ .name = "ecosflash",\r
+ .register_commands = ecosflash_register_commands,\r
+ .flash_bank_command = ecosflash_flash_bank_command,\r
+ .erase = ecosflash_erase,\r
+ .protect = ecosflash_protect,\r
+ .write = ecosflash_write,\r
+ .probe = ecosflash_probe,\r
+ .auto_probe = ecosflash_probe,\r
+ .erase_check = ecosflash_erase_check,\r
+ .protect_check = ecosflash_protect_check,\r
+ .info = ecosflash_info\r
+};\r
+\r
+typedef struct ecosflash_flash_bank_s\r
+{\r
+ struct target_s *target;\r
+ working_area_t *write_algorithm;\r
+ working_area_t *erase_check_algorithm;\r
+ char *driverPath;\r
+ u32 start_address;\r
+} ecosflash_flash_bank_t;\r
+\r
+static const int sectorSize=0x10000;\r
+\r
+#define FLASH_ERR_OK 0x00 // No error - operation complete\r
+#define FLASH_ERR_INVALID 0x01 // Invalid FLASH address\r
+#define FLASH_ERR_ERASE 0x02 // Error trying to erase\r
+#define FLASH_ERR_LOCK 0x03 // Error trying to lock/unlock\r
+#define FLASH_ERR_PROGRAM 0x04 // Error trying to program\r
+#define FLASH_ERR_PROTOCOL 0x05 // Generic error\r
+#define FLASH_ERR_PROTECT 0x06 // Device/region is write-protected\r
+#define FLASH_ERR_NOT_INIT 0x07 // FLASH info not yet initialized\r
+#define FLASH_ERR_HWR 0x08 // Hardware (configuration?) problem\r
+#define FLASH_ERR_ERASE_SUSPEND 0x09 // Device is in erase suspend mode\r
+#define FLASH_ERR_PROGRAM_SUSPEND 0x0a // Device is in in program suspend mode\r
+#define FLASH_ERR_DRV_VERIFY 0x0b // Driver failed to verify data\r
+#define FLASH_ERR_DRV_TIMEOUT 0x0c // Driver timed out waiting for device\r
+#define FLASH_ERR_DRV_WRONG_PART 0x0d // Driver does not support device\r
+#define FLASH_ERR_LOW_VOLTAGE 0x0e // Not enough juice to complete job\r
+\r
+\r
+char *\r
+flash_errmsg(int err)\r
+{\r
+ switch (err) {\r
+ case FLASH_ERR_OK:\r
+ return "No error - operation complete";\r
+ case FLASH_ERR_ERASE_SUSPEND:\r
+ return "Device is in erase suspend state";\r
+ case FLASH_ERR_PROGRAM_SUSPEND:\r
+ return "Device is in program suspend state";\r
+ case FLASH_ERR_INVALID:\r
+ return "Invalid FLASH address";\r
+ case FLASH_ERR_ERASE:\r
+ return "Error trying to erase";\r
+ case FLASH_ERR_LOCK:\r
+ return "Error trying to lock/unlock";\r
+ case FLASH_ERR_PROGRAM:\r
+ return "Error trying to program";\r
+ case FLASH_ERR_PROTOCOL:\r
+ return "Generic error";\r
+ case FLASH_ERR_PROTECT:\r
+ return "Device/region is write-protected";\r
+ case FLASH_ERR_NOT_INIT:\r
+ return "FLASH sub-system not initialized";\r
+ case FLASH_ERR_DRV_VERIFY:\r
+ return "Data verify failed after operation";\r
+ case FLASH_ERR_DRV_TIMEOUT:\r
+ return "Driver timed out waiting for device";\r
+ case FLASH_ERR_DRV_WRONG_PART:\r
+ return "Driver does not support device";\r
+ case FLASH_ERR_LOW_VOLTAGE:\r
+ return "Device reports low voltage";\r
+ default:\r
+ return "Unknown error";\r
+ }\r
+}\r
+\r
+\r
+/* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>\r
+ */\r
+int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
+{\r
+ ecosflash_flash_bank_t *info;\r
+ \r
+ if (argc < 7)\r
+ {\r
+ WARNING("incomplete flash_bank ecosflash configuration");\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ info = malloc(sizeof(ecosflash_flash_bank_t));\r
+ if(info == NULL)\r
+ {\r
+ ERROR("no memory for flash bank info");\r
+ exit(-1);\r
+ }\r
+ bank->driver_priv = info;\r
+ info->driverPath=strdup(args[6]);\r
+\r
+ // eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as \r
+ // a way to improve impeadance matach between OpenOCD and eCos flash\r
+ // driver\r
+ int i = 0;\r
+ u32 offset = 0;\r
+ bank->num_sectors=bank->size/sectorSize;\r
+ bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);\r
+ for (i = 0; i < bank->num_sectors; i++)\r
+ {\r
+ bank->sectors[i].offset = offset;\r
+ bank->sectors[i].size = sectorSize;\r
+ offset += bank->sectors[i].size;\r
+ bank->sectors[i].is_erased = -1;\r
+ bank->sectors[i].is_protected = 0;\r
+ }\r
+ \r
+ info->target = get_target_by_num(strtoul(args[5], NULL, 0));\r
+ if (info->target == NULL)\r
+ {\r
+ ERROR("no target '%i' configured", (int)strtoul(args[5], NULL, 0));\r
+ exit(-1);\r
+ }\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+int loadDriver(ecosflash_flash_bank_t *info)\r
+{\r
+ u32 buf_cnt;\r
+ u32 image_size;\r
+ image_t image; \r
+ \r
+ image.base_address_set = 0;\r
+ image.start_address_set = 0;\r
+ target_t *target=info->target;\r
+ \r
+ if (image_open(&image, info->driverPath, NULL) != ERROR_OK)\r
+ {\r
+ ERROR("load_image error: %s", image.error_str);\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ \r
+ info->start_address=image.start_address;\r
+ \r
+ image_size = 0x0;\r
+ int i;\r
+ for (i = 0; i < image.num_sections; i++)\r
+ {\r
+ void *buffer = malloc(image.sections[i].size);\r
+ int retval;\r
+ if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)\r
+ {\r
+ ERROR("image_read_section failed with error code: %i", retval);\r
+ free(buffer);\r
+ image_close(&image);\r
+ return ERROR_FLASH_BANK_INVALID;\r
+ }\r
+ target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);\r
+ image_size += buf_cnt;\r
+ DEBUG("%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address);\r
+ \r
+ free(buffer);\r
+ }\r
+\r
+ image_close(&image);\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+static int const OFFSET_ERASE=0x0;\r
+static int const OFFSET_ERASE_SIZE=0x8;\r
+static int const OFFSET_FLASH=0xc;\r
+static int const OFFSET_FLASH_SIZE=0x8;\r
+static int const OFFSET_GET_WORKAREA=0x18;\r
+static int const OFFSET_GET_WORKAREA_SIZE=0x4;\r
+\r
+\r
+int runCode(ecosflash_flash_bank_t *info, \r
+ u32 codeStart, u32 codeStop, u32 r0, u32 r1, u32 r2, \r
+ u32 *result,\r
+ // timeout in ms\r
+ int timeout)\r
+{\r
+ target_t *target=info->target;\r
+\r
+ reg_param_t reg_params[3];\r
+ armv4_5_algorithm_t armv4_5_info;\r
+ armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;\r
+ armv4_5_info.core_mode = ARMV4_5_MODE_SVC;\r
+ armv4_5_info.core_state = ARMV4_5_STATE_ARM;\r
+ \r
+ init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);\r
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);\r
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);\r
+ \r
+ buf_set_u32(reg_params[0].value, 0, 32, r0);\r
+ buf_set_u32(reg_params[1].value, 0, 32, r1);\r
+ buf_set_u32(reg_params[2].value, 0, 32, r2);\r
+ \r
+ int retval;\r
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params,\r
+ codeStart,\r
+ codeStop, timeout, \r
+ &armv4_5_info)) != ERROR_OK)\r
+ {\r
+ ERROR("error executing eCos flash algorithm");\r
+ return retval;\r
+ }\r
+ \r
+ *result=buf_get_u32(reg_params[0].value, 0, 32);\r
+ \r
+ destroy_reg_param(®_params[0]);\r
+ destroy_reg_param(®_params[1]);\r
+ destroy_reg_param(®_params[2]);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+int eCosBoard_erase(ecosflash_flash_bank_t *info, u32 address, u32 len)\r
+{\r
+ int retval;\r
+ int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/ \r
+\r
+ retval=loadDriver(info);\r
+ if (retval!=ERROR_OK)\r
+ return retval;\r
+ \r
+ u32 flashErr;\r
+ retval=runCode(info, \r
+ info->start_address+OFFSET_ERASE,\r
+ info->start_address+OFFSET_ERASE+OFFSET_ERASE_SIZE,\r
+ address,\r
+ len,\r
+ 0,\r
+ &flashErr,\r
+ timeout\r
+ );\r
+ if (retval!=ERROR_OK)\r
+ return retval;\r
+ \r
+ if (flashErr != 0x0)\r
+ {\r
+ ERROR("Flash erase failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));\r
+ return ERROR_JTAG_DEVICE_ERROR;\r
+ }\r
+\r
+ return ERROR_OK;\r
+}\r
+\r
+int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, u32 address, u32 len)\r
+{\r
+ target_t *target=info->target;\r
+ const int chunk=8192;\r
+ int retval=ERROR_OK;\r
+ int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/\r
+ \r
+ retval=loadDriver(info);\r
+ if (retval!=ERROR_OK)\r
+ return retval;\r
+ \r
+ u32 buffer;\r
+ retval=runCode(info, \r
+ info->start_address+OFFSET_GET_WORKAREA,\r
+ info->start_address+OFFSET_GET_WORKAREA+OFFSET_GET_WORKAREA_SIZE,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ &buffer,\r
+ 1000);\r
+ if (retval!=ERROR_OK)\r
+ return retval;\r
+ \r
+ \r
+ int i;\r
+ for (i=0; i<len; i+=chunk)\r
+ {\r
+ int t=len-i;\r
+ if (t>chunk)\r
+ {\r
+ t=chunk;\r
+ }\r
+ \r
+ int retval;\r
+ retval=target_write_buffer(target, buffer, t, ((char *)data)+i);\r
+ if (retval != ERROR_OK)\r
+ return retval;\r
+ \r
+ u32 flashErr;\r
+ retval=runCode(info, \r
+ info->start_address+OFFSET_FLASH,\r
+ info->start_address+OFFSET_FLASH+OFFSET_FLASH_SIZE,\r
+ buffer,\r
+ address+i,\r
+ t,\r
+ &flashErr,\r
+ timeout);\r
+ if (retval != ERROR_OK)\r
+ return retval;\r
+\r
+ if (flashErr != 0x0)\r
+ {\r
+ ERROR("Flash prog failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));\r
+ return ERROR_JTAG_DEVICE_ERROR;\r
+ }\r
+ }\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+int ecosflash_probe(struct flash_bank_s *bank)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+int ecosflash_register_commands(struct command_context_s *cmd_ctx)\r
+{\r
+ register_command(cmd_ctx, NULL, "ecosflash", NULL, COMMAND_ANY, NULL);\r
+ \r
+ return ERROR_OK;\r
+}\r
+\r
+/*\r
+static void command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)\r
+{\r
+ ecosflash_flash_bank_t *info = bank->driver_priv;\r
+ int i;\r
+ \r
+ if (info->target->endianness == TARGET_LITTLE_ENDIAN)\r
+ {\r
+ for (i = bank->bus_width; i > 0; i--)\r
+ {\r
+ *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i = 1; i <= bank->bus_width; i++)\r
+ {\r
+ *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;\r
+ }\r
+ }\r
+}\r
+*/\r
+\r
+u32 ecosflash_address(struct flash_bank_s *bank, u32 address)\r
+{\r
+ u32 retval = 0;\r
+ switch(bank->bus_width)\r
+ {\r
+ case 4:\r
+ retval = address & 0xfffffffc;\r
+ case 2:\r
+ retval = address & 0xfffffffe;\r
+ case 1:\r
+ retval = address;\r
+ }\r
+ \r
+ return retval + bank->base;\r
+} \r
+\r
+\r
+int ecosflash_erase(struct flash_bank_s *bank, int first, int last)\r
+{\r
+ struct flash_bank_s *c=bank;\r
+ ecosflash_flash_bank_t *info = bank->driver_priv;\r
+ return eCosBoard_erase(info, c->base+first*sectorSize, sectorSize*(last-first+1)); \r
+}\r
+\r
+int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+int ecosflash_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
+{\r
+ ecosflash_flash_bank_t *info = bank->driver_priv;\r
+ struct flash_bank_s *c=bank;\r
+ return eCosBoard_flash(info, buffer, c->base+offset, count);\r
+}\r
+\r
+\r
+int ecosflash_erase_check(struct flash_bank_s *bank)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int ecosflash_protect_check(struct flash_bank_s *bank)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
+{\r
+ ecosflash_flash_bank_t *info = bank->driver_priv;\r
+ snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+u32 ecosflash_get_flash_status(flash_bank_t *bank)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+void ecosflash_set_flash_mode(flash_bank_t *bank,int mode)\r
+{\r
+ \r
+}\r
+\r
+u32 ecosflash_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+ return ERROR_OK;\r
+}\r
+\r
+\r
+\r
+\r