-/***************************************************************************\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 "replacements.h"\r
-\r
-#include "str9xpec.h"\r
-#include "flash.h"\r
-#include "target.h"\r
-#include "log.h"\r
-#include "armv4_5.h"\r
-#include "arm7_9_common.h"\r
-#include "jtag.h"\r
-#include "binarybuffer.h"\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <unistd.h>\r
-#include <getopt.h>\r
-\r
-str9xpec_mem_layout_t mem_layout_str9pec[] = {\r
- {0x00000000, 0x10000, 0},\r
- {0x00010000, 0x10000, 1},\r
- {0x00020000, 0x10000, 2},\r
- {0x00030000, 0x10000, 3},\r
- {0x00040000, 0x10000, 4},\r
- {0x00050000, 0x10000, 5},\r
- {0x00060000, 0x10000, 6},\r
- {0x00070000, 0x10000, 7},\r
- {0x00080000, 0x02000, 32},\r
- {0x00082000, 0x02000, 33},\r
- {0x00084000, 0x02000, 34},\r
- {0x00086000, 0x02000, 35}\r
-};\r
-\r
-int str9xpec_register_commands(struct command_context_s *cmd_ctx);\r
-int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
-int str9xpec_erase(struct flash_bank_s *bank, int first, int last);\r
-int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last);\r
-int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
-int str9xpec_probe(struct flash_bank_s *bank);\r
-int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_protect_check(struct flash_bank_s *bank);\r
-int str9xpec_erase_check(struct flash_bank_s *bank);\r
-int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
-\r
-int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last);\r
-int str9xpec_set_address(struct flash_bank_s *bank, u8 sector);\r
-int str9xpec_write_options(struct flash_bank_s *bank);\r
-\r
-int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
-\r
-flash_driver_t str9xpec_flash =\r
-{\r
- .name = "str9xpec",\r
- .register_commands = str9xpec_register_commands,\r
- .flash_bank_command = str9xpec_flash_bank_command,\r
- .erase = str9xpec_erase,\r
- .protect = str9xpec_protect,\r
- .write = str9xpec_write,\r
- .probe = str9xpec_probe,\r
- .auto_probe = str9xpec_probe,\r
- .erase_check = str9xpec_erase_check,\r
- .protect_check = str9xpec_protect_check,\r
- .info = str9xpec_info\r
-};\r
-\r
-int str9xpec_register_commands(struct command_context_s *cmd_ctx)\r
-{\r
- command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec", NULL, COMMAND_ANY, "str9xpec flash specific commands");\r
- \r
- register_command(cmd_ctx, str9xpec_cmd, "enable_turbo", str9xpec_handle_flash_enable_turbo_command, COMMAND_EXEC,\r
- "enable str9xpec turbo mode");\r
- register_command(cmd_ctx, str9xpec_cmd, "disable_turbo", str9xpec_handle_flash_disable_turbo_command, COMMAND_EXEC,\r
- "disable str9xpec turbo mode");\r
- register_command(cmd_ctx, str9xpec_cmd, "options_cmap", str9xpec_handle_flash_options_cmap_command, COMMAND_EXEC,\r
- "configure str9xpec boot sector");\r
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd", str9xpec_handle_flash_options_lvdthd_command, COMMAND_EXEC,\r
- "configure str9xpec lvd threshold");\r
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel", str9xpec_handle_flash_options_lvdsel_command, COMMAND_EXEC,\r
- "configure str9xpec lvd selection");\r
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn", str9xpec_handle_flash_options_lvdwarn_command, COMMAND_EXEC,\r
- "configure str9xpec lvd warning");\r
- register_command(cmd_ctx, str9xpec_cmd, "options_read", str9xpec_handle_flash_options_read_command, COMMAND_EXEC,\r
- "read str9xpec options");\r
- register_command(cmd_ctx, str9xpec_cmd, "options_write", str9xpec_handle_flash_options_write_command, COMMAND_EXEC,\r
- "write str9xpec options");\r
- register_command(cmd_ctx, str9xpec_cmd, "lock", str9xpec_handle_flash_lock_command, COMMAND_EXEC,\r
- "lock str9xpec device");\r
- register_command(cmd_ctx, str9xpec_cmd, "unlock", str9xpec_handle_flash_unlock_command, COMMAND_EXEC,\r
- "unlock str9xpec device");\r
- register_command(cmd_ctx, str9xpec_cmd, "part_id", str9xpec_handle_part_id_command, COMMAND_EXEC,\r
- "print part id of str9xpec flash bank <num>");\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_set_instr(int chain_pos, u32 new_instr, enum tap_state end_state)\r
-{\r
- jtag_device_t *device = jtag_get_device(chain_pos);\r
- \r
- if (device == NULL)\r
- {\r
- DEBUG("Invalid Target");\r
- return ERROR_TARGET_INVALID;\r
- }\r
- \r
- if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)\r
- {\r
- scan_field_t field;\r
- \r
- field.device = chain_pos;\r
- field.num_bits = device->ir_length;\r
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);\r
- buf_set_u32(field.out_value, 0, field.num_bits, new_instr);\r
- field.out_mask = NULL;\r
- field.in_value = NULL;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_ir_scan(1, &field, end_state);\r
- \r
- free(field.out_value);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-u8 str9xpec_isc_status(int chain_pos)\r
-{\r
- scan_field_t field;\r
- u8 status;\r
- \r
- if (str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI) != ERROR_OK)\r
- return ISC_STATUS_ERROR;\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 8;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = &status;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- jtag_execute_queue();\r
- \r
- DEBUG("status: 0x%2.2x", status);\r
- \r
- if (status & ISC_STATUS_SECURITY)\r
- INFO("Device Security Bit Set");\r
- \r
- return status;\r
-}\r
-\r
-int str9xpec_isc_enable(struct flash_bank_s *bank)\r
-{\r
- u8 status;\r
- u32 chain_pos;\r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- if (str9xpec_info->isc_enable)\r
- return ERROR_OK;\r
- \r
- /* enter isc mode */\r
- if (str9xpec_set_instr(chain_pos, ISC_ENABLE, TAP_RTI) != ERROR_OK)\r
- return ERROR_TARGET_INVALID;\r
- \r
- /* check ISC status */\r
- status = str9xpec_isc_status(chain_pos);\r
- if (status & ISC_STATUS_MODE)\r
- {\r
- /* we have entered isc mode */\r
- str9xpec_info->isc_enable = 1;\r
- DEBUG("ISC_MODE Enabled");\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_isc_disable(struct flash_bank_s *bank)\r
-{\r
- u8 status;\r
- u32 chain_pos;\r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- if (!str9xpec_info->isc_enable)\r
- return ERROR_OK;\r
- \r
- if (str9xpec_set_instr(chain_pos, ISC_DISABLE, TAP_RTI) != ERROR_OK)\r
- return ERROR_TARGET_INVALID;\r
- \r
- /* delay to handle aborts */\r
- jtag_add_sleep(50);\r
- \r
- /* check ISC status */\r
- status = str9xpec_isc_status(chain_pos);\r
- if (!(status & ISC_STATUS_MODE))\r
- {\r
- /* we have left isc mode */\r
- str9xpec_info->isc_enable = 0;\r
- DEBUG("ISC_MODE Disabled");\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_read_config(struct flash_bank_s *bank)\r
-{\r
- scan_field_t field;\r
- u8 status;\r
- u32 chain_pos;\r
- \r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- DEBUG("ISC_CONFIGURATION");\r
- \r
- /* execute ISC_CONFIGURATION command */\r
- str9xpec_set_instr(chain_pos, ISC_CONFIGURATION, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 64;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = str9xpec_info->options;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- jtag_execute_queue();\r
- \r
- status = str9xpec_isc_status(chain_pos);\r
- \r
- return status;\r
-}\r
-\r
-int str9xpec_build_block_list(struct flash_bank_s *bank)\r
-{\r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- int i;\r
- int num_sectors = 0, b0_sectors = 0;\r
- \r
- switch (bank->size)\r
- {\r
- case (256 * 1024):\r
- b0_sectors = 4;\r
- break;\r
- case (512 * 1024):\r
- b0_sectors = 8;\r
- break;\r
- default:\r
- ERROR("BUG: unknown bank->size encountered");\r
- exit(-1);\r
- }\r
- \r
- /* include bank 1 sectors */\r
- num_sectors = b0_sectors + 4;\r
- bank->size += (32 * 1024);\r
- \r
- bank->num_sectors = num_sectors;\r
- bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);\r
- str9xpec_info->sector_bits = malloc(sizeof(u32) * num_sectors);\r
- \r
- num_sectors = 0;\r
- \r
- for (i = 0; i < b0_sectors; i++)\r
- {\r
- bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start;\r
- bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;\r
- bank->sectors[num_sectors].is_erased = -1;\r
- bank->sectors[num_sectors].is_protected = 1;\r
- str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;\r
- }\r
- \r
- for (i = 8; i < 12; i++)\r
- {\r
- bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start;\r
- bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;\r
- bank->sectors[num_sectors].is_erased = -1;\r
- bank->sectors[num_sectors].is_protected = 1;\r
- str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-/* flash bank str9x <base> <size> 0 0 <target#>\r
- */\r
-int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
-{\r
- str9xpec_flash_controller_t *str9xpec_info;\r
- armv4_5_common_t *armv4_5 = NULL;\r
- arm7_9_common_t *arm7_9 = NULL;\r
- arm_jtag_t *jtag_info = NULL;\r
- \r
- if (argc < 6)\r
- {\r
- WARNING("incomplete flash_bank str9x configuration");\r
- return ERROR_FLASH_BANK_INVALID;\r
- }\r
- \r
- str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t));\r
- bank->driver_priv = str9xpec_info;\r
- \r
- if (bank->base != 0x00000000)\r
- {\r
- WARNING("overriding flash base address for STR91x device with 0x00000000");\r
- bank->base = 0x00000000;\r
- }\r
-\r
- /* find out jtag position of flash controller\r
- * it is always after the arm966 core */\r
- \r
- armv4_5 = bank->target->arch_info;\r
- arm7_9 = armv4_5->arch_info;\r
- jtag_info = &arm7_9->jtag_info;\r
- \r
- str9xpec_info->chain_pos = (jtag_info->chain_pos - 1);\r
- str9xpec_info->isc_enable = 0;\r
- str9xpec_info->devarm = NULL;\r
- \r
- str9xpec_build_block_list(bank);\r
- \r
- /* clear option byte register */\r
- buf_set_u32(str9xpec_info->options, 0, 64, 0);\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last)\r
-{\r
- scan_field_t field;\r
- u8 status;\r
- u32 chain_pos;\r
- int i;\r
- u8 *buffer = NULL;\r
- \r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- str9xpec_isc_enable( bank );\r
- }\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- }\r
- \r
- buffer = calloc(CEIL(64, 8), 1);\r
-\r
- DEBUG("blank check: first_bank: %i, last_bank: %i", first, last);\r
- \r
- for (i = first; i <= last; i++) {\r
- buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);\r
- }\r
- \r
- /* execute ISC_BLANK_CHECK command */\r
- str9xpec_set_instr(chain_pos, ISC_BLANK_CHECK, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 64;\r
- field.out_value = buffer;\r
- field.out_mask = NULL;\r
- field.in_value = NULL;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- jtag_add_sleep(40000);\r
- \r
- /* read blank check result */\r
- field.device = chain_pos;\r
- field.num_bits = 64;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = buffer;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_PI);\r
- jtag_execute_queue();\r
- \r
- status = str9xpec_isc_status(chain_pos);\r
- \r
- for (i = first; i <= last; i++)\r
- {\r
- if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1))\r
- bank->sectors[i].is_erased = 0;\r
- else\r
- bank->sectors[i].is_erased = 1;\r
- }\r
- \r
- free(buffer);\r
- \r
- str9xpec_isc_disable(bank);\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED; \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_protect_check(struct flash_bank_s *bank)\r
-{\r
- u8 status;\r
- int i;\r
- \r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- status = str9xpec_read_config(bank);\r
- \r
- for (i = 0; i < bank->num_sectors; i++)\r
- {\r
- if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1))\r
- bank->sectors[i].is_protected = 1;\r
- else\r
- bank->sectors[i].is_protected = 0;\r
- }\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last)\r
-{\r
- scan_field_t field;\r
- u8 status;\r
- u32 chain_pos;\r
- int i;\r
- u8 *buffer = NULL;\r
- \r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- str9xpec_isc_enable( bank );\r
- }\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- return ISC_STATUS_ERROR;\r
- }\r
- \r
- buffer = calloc(CEIL(64, 8), 1);\r
- \r
- DEBUG("erase: first_bank: %i, last_bank: %i", first, last);\r
- \r
- /* last bank: 0xFF signals a full erase (unlock complete device) */\r
- /* last bank: 0xFE signals a option byte erase */\r
- if (last == 0xFF)\r
- {\r
- for (i = 0; i < 64; i++) {\r
- buf_set_u32(buffer, i, 1, 1);\r
- } \r
- }\r
- else if (last == 0xFE)\r
- {\r
- buf_set_u32(buffer, 49, 1, 1);\r
- }\r
- else\r
- { \r
- for (i = first; i <= last; i++) {\r
- buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);\r
- }\r
- }\r
- \r
- DEBUG("ISC_ERASE");\r
- \r
- /* execute ISC_ERASE command */\r
- str9xpec_set_instr(chain_pos, ISC_ERASE, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 64;\r
- field.out_value = buffer;\r
- field.out_mask = NULL;\r
- field.in_value = NULL;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- jtag_execute_queue();\r
- \r
- jtag_add_sleep(10);\r
- \r
- /* wait for erase completion */\r
- while (!((status = str9xpec_isc_status(chain_pos)) & ISC_STATUS_BUSY)) {\r
- usleep(1000);\r
- }\r
- \r
- free(buffer);\r
- \r
- str9xpec_isc_disable(bank);\r
- \r
- return status;\r
-}\r
-\r
-int str9xpec_erase(struct flash_bank_s *bank, int first, int last)\r
-{\r
- int status;\r
- \r
- status = str9xpec_erase_area(bank, first, last);\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_lock_device(struct flash_bank_s *bank)\r
-{\r
- scan_field_t field;\r
- u8 status;\r
- u32 chain_pos;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- str9xpec_info = bank->driver_priv;\r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- str9xpec_isc_enable( bank );\r
- }\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- return ISC_STATUS_ERROR;\r
- }\r
- \r
- /* set security address */\r
- str9xpec_set_address(bank, 0x80);\r
- \r
- /* execute ISC_PROGRAM command */\r
- str9xpec_set_instr(chain_pos, ISC_PROGRAM_SECURITY, TAP_RTI);\r
- \r
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
- \r
- do {\r
- field.device = chain_pos;\r
- field.num_bits = 8;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = &status;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, -1);\r
- jtag_execute_queue();\r
- \r
- } while(!(status & ISC_STATUS_BUSY));\r
- \r
- str9xpec_isc_disable(bank);\r
- \r
- return status;\r
-}\r
-\r
-int str9xpec_unlock_device(struct flash_bank_s *bank)\r
-{\r
- u8 status;\r
- \r
- status = str9xpec_erase_area(bank, 0, 255);\r
- \r
- return status;\r
-}\r
-\r
-int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last)\r
-{\r
- u8 status;\r
- int i;\r
- \r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- status = str9xpec_read_config(bank);\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
-\r
- DEBUG("protect: first_bank: %i, last_bank: %i", first, last);\r
- \r
- /* last bank: 0xFF signals a full device protect */\r
- if (last == 0xFF)\r
- {\r
- if( set )\r
- {\r
- status = str9xpec_lock_device(bank);\r
- }\r
- else\r
- {\r
- /* perform full erase to unlock device */\r
- status = str9xpec_unlock_device(bank);\r
- }\r
- }\r
- else\r
- { \r
- for (i = first; i <= last; i++)\r
- {\r
- if( set )\r
- buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1);\r
- else\r
- buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0);\r
- }\r
- \r
- status = str9xpec_write_options(bank);\r
- }\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_set_address(struct flash_bank_s *bank, u8 sector)\r
-{\r
- u32 chain_pos;\r
- scan_field_t field;\r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- /* set flash controller address */\r
- str9xpec_set_instr(chain_pos, ISC_ADDRESS_SHIFT, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 8;\r
- field.out_value = §or;\r
- field.out_mask = NULL;\r
- field.in_value = NULL;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, -1);\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
-{\r
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;\r
- u32 dwords_remaining = (count / 8);\r
- u32 bytes_remaining = (count & 0x00000007);\r
- u32 bytes_written = 0;\r
- u8 status;\r
- u32 check_address = offset;\r
- u32 chain_pos;\r
- scan_field_t field;\r
- u8 *scanbuf;\r
- int i;\r
- u32 first_sector = 0;\r
- u32 last_sector = 0;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- str9xpec_isc_enable(bank);\r
- }\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- }\r
- \r
- if (offset & 0x7)\r
- {\r
- WARNING("offset 0x%x breaks required 8-byte alignment", offset);\r
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
- }\r
- \r
- for (i = 0; i < bank->num_sectors; i++)\r
- {\r
- u32 sec_start = bank->sectors[i].offset;\r
- u32 sec_end = sec_start + bank->sectors[i].size;\r
- \r
- /* check if destination falls within the current sector */\r
- if ((check_address >= sec_start) && (check_address < sec_end))\r
- {\r
- /* check if destination ends in the current sector */\r
- if (offset + count < sec_end)\r
- check_address = offset + count;\r
- else\r
- check_address = sec_end;\r
- }\r
- \r
- if ((offset >= sec_start) && (offset < sec_end)){\r
- first_sector = i;\r
- }\r
- \r
- if ((offset + count >= sec_start) && (offset + count < sec_end)){\r
- last_sector = i;\r
- }\r
- }\r
- \r
- if (check_address != offset + count)\r
- return ERROR_FLASH_DST_OUT_OF_BANK;\r
-\r
- DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);\r
- \r
- scanbuf = calloc(CEIL(64, 8), 1);\r
- \r
- DEBUG("ISC_PROGRAM");\r
- \r
- for (i = first_sector; i <= last_sector; i++)\r
- {\r
- str9xpec_set_address(bank, str9xpec_info->sector_bits[i]);\r
- \r
- dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8);\r
-\r
- while (dwords_remaining > 0)\r
- { \r
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 64;\r
- field.out_value = (buffer + bytes_written);\r
- field.out_mask = NULL;\r
- field.in_value = NULL;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- \r
- /* small delay before polling */\r
- jtag_add_sleep(50);\r
- \r
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
- \r
- do {\r
- field.device = chain_pos;\r
- field.num_bits = 8;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = scanbuf;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, -1);\r
- jtag_execute_queue();\r
- \r
- status = buf_get_u32(scanbuf, 0, 8);\r
- \r
- } while(!(status & ISC_STATUS_BUSY));\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)\r
- // return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- dwords_remaining--;\r
- bytes_written += 8;\r
- }\r
- }\r
- \r
- if (bytes_remaining)\r
- {\r
- u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
- int i = 0;\r
- \r
- while(bytes_remaining > 0)\r
- {\r
- last_dword[i++] = *(buffer + bytes_written); \r
- bytes_remaining--;\r
- bytes_written++;\r
- }\r
- \r
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 64;\r
- field.out_value = last_dword;\r
- field.out_mask = NULL;\r
- field.in_value = NULL;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- \r
- /* small delay before polling */\r
- jtag_add_sleep(50);\r
- \r
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
- \r
- do {\r
- field.device = chain_pos;\r
- field.num_bits = 8;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = scanbuf;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, -1);\r
- jtag_execute_queue();\r
- \r
- status = buf_get_u32(scanbuf, 0, 8);\r
- \r
- } while(!(status & ISC_STATUS_BUSY));\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)\r
- // return ERROR_FLASH_OPERATION_FAILED;\r
- }\r
-\r
- free(scanbuf);\r
-\r
- str9xpec_isc_disable(bank);\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_probe(struct flash_bank_s *bank)\r
-{\r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- scan_field_t field;\r
- u8 *buffer = NULL;\r
- u32 chain_pos;\r
- u32 idcode;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
-\r
- if (argc < 1)\r
- {\r
- return ERROR_COMMAND_SYNTAX_ERROR;\r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- buffer = calloc(CEIL(32, 8), 1);\r
- \r
- str9xpec_set_instr(chain_pos, ISC_IDCODE, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 32;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = buffer;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- jtag_execute_queue();\r
- \r
- idcode = buf_get_u32(buffer, 0, 32);\r
- \r
- command_print(cmd_ctx, "str9xpec part id: 0x%8.8x", idcode);\r
- \r
- free(buffer);\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_erase_check(struct flash_bank_s *bank)\r
-{\r
- return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);\r
-}\r
-\r
-int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
-{\r
- snprintf(buf, buf_size, "str9xpec flash driver info" );\r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- u8 status;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- if (argc < 1)\r
- {\r
- command_print(cmd_ctx, "str9xpec options_read <bank>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- \r
- status = str9xpec_read_config(bank);\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- /* boot bank */\r
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1))\r
- command_print(cmd_ctx, "CS Map: bank1");\r
- else\r
- command_print(cmd_ctx, "CS Map: bank0");\r
- \r
- /* OTP lock */\r
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1))\r
- command_print(cmd_ctx, "OTP Lock: OTP Locked");\r
- else\r
- command_print(cmd_ctx, "OTP Lock: OTP Unlocked");\r
- \r
- /* LVD Threshold */\r
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1))\r
- command_print(cmd_ctx, "LVD Threshold: 2.7v");\r
- else\r
- command_print(cmd_ctx, "LVD Threshold: 2.4v");\r
- \r
- /* LVD reset warning */\r
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1))\r
- command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs");\r
- else\r
- command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only");\r
- \r
- /* LVD reset select */\r
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1))\r
- command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs");\r
- else\r
- command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only");\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_write_options(struct flash_bank_s *bank)\r
-{\r
- scan_field_t field;\r
- u8 status;\r
- u32 chain_pos;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- str9xpec_info = bank->driver_priv;\r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- /* erase config options first */\r
- status = str9xpec_erase_area( bank, 0xFE, 0xFE );\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return status; \r
- \r
- if (!str9xpec_info->isc_enable) {\r
- str9xpec_isc_enable( bank );\r
- }\r
- \r
- if (!str9xpec_info->isc_enable) {\r
- return ISC_STATUS_ERROR;\r
- }\r
- \r
- /* according to data 64th bit has to be set */\r
- buf_set_u32(str9xpec_info->options, 63, 1, 1);\r
- \r
- /* set option byte address */\r
- str9xpec_set_address(bank, 0x50);\r
- \r
- /* execute ISC_PROGRAM command */\r
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);\r
- \r
- field.device = chain_pos;\r
- field.num_bits = 64;\r
- field.out_value = str9xpec_info->options;\r
- field.out_mask = NULL;\r
- field.in_value = NULL;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, TAP_RTI);\r
- \r
- /* small delay before polling */\r
- jtag_add_sleep(50);\r
- \r
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);\r
- \r
- do {\r
- field.device = chain_pos;\r
- field.num_bits = 8;\r
- field.out_value = NULL;\r
- field.out_mask = NULL;\r
- field.in_value = &status;\r
- field.in_check_value = NULL;\r
- field.in_check_mask = NULL;\r
- field.in_handler = NULL;\r
- field.in_handler_priv = NULL;\r
- \r
- jtag_add_dr_scan(1, &field, -1);\r
- jtag_execute_queue();\r
- \r
- } while(!(status & ISC_STATUS_BUSY));\r
- \r
- str9xpec_isc_disable(bank);\r
- \r
- return status;\r
-}\r
-\r
-int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- u8 status;\r
- \r
- if (argc < 1)\r
- {\r
- command_print(cmd_ctx, "str9xpec options_write <bank>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- status = str9xpec_write_options(bank);\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- if (argc < 2)\r
- {\r
- command_print(cmd_ctx, "str9xpec options_cmap <bank> <bank0|bank1>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- \r
- if (strcmp(args[1], "bank1") == 0)\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1);\r
- }\r
- else\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- if (argc < 2)\r
- {\r
- command_print(cmd_ctx, "str9xpec options_lvdthd <bank> <2.4v|2.7v>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- \r
- if (strcmp(args[1], "2.7v") == 0)\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1);\r
- }\r
- else\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- if (argc < 2)\r
- {\r
- command_print(cmd_ctx, "str9xpec options_lvdsel <bank> <vdd|vdd_vddq>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- \r
- if (strcmp(args[1], "vdd_vddq") == 0)\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1);\r
- }\r
- else\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- if (argc < 2)\r
- {\r
- command_print(cmd_ctx, "str9xpec options_lvdwarn <bank> <vdd|vdd_vddq>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- \r
- if (strcmp(args[1], "vdd_vddq") == 0)\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1);\r
- }\r
- else\r
- {\r
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0);\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- u8 status;\r
- flash_bank_t *bank;\r
- \r
- if (argc < 1)\r
- {\r
- command_print(cmd_ctx, "str9xpec lock <bank>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- status = str9xpec_lock_device(bank);\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- u8 status;\r
- flash_bank_t *bank;\r
- \r
- if (argc < 1)\r
- {\r
- command_print(cmd_ctx, "str9xpec unlock <bank>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- status = str9xpec_unlock_device(bank);\r
- \r
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)\r
- return ERROR_FLASH_OPERATION_FAILED;\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- u32 chain_pos;\r
- jtag_device_t* dev0;\r
- jtag_device_t* dev2;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- if (argc < 1)\r
- {\r
- command_print(cmd_ctx, "str9xpec enable_turbo <bank>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- /* remove arm core from chain - enter turbo mode */\r
- \r
- str9xpec_set_instr(chain_pos+2, 0xD, TAP_RTI);\r
- jtag_execute_queue();\r
- \r
- /* modify scan chain - str9 core has been removed */\r
- dev0 = jtag_get_device(chain_pos);\r
- str9xpec_info->devarm = jtag_get_device(chain_pos+1);\r
- dev2 = jtag_get_device(chain_pos+2);\r
- dev0->next = dev2;\r
- jtag_num_devices--;\r
- \r
- return ERROR_OK;\r
-}\r
-\r
-int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
-{\r
- flash_bank_t *bank;\r
- u32 chain_pos;\r
- jtag_device_t* dev0;\r
- str9xpec_flash_controller_t *str9xpec_info = NULL;\r
- \r
- if (argc < 1)\r
- {\r
- command_print(cmd_ctx, "str9xpec disable_turbo <bank>");\r
- return ERROR_OK; \r
- }\r
- \r
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
- if (!bank)\r
- {\r
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
- return ERROR_OK;\r
- }\r
- \r
- str9xpec_info = bank->driver_priv;\r
- \r
- chain_pos = str9xpec_info->chain_pos;\r
- \r
- dev0 = jtag_get_device(chain_pos);\r
- \r
- /* exit turbo mode via TLR */\r
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_TLR);\r
- jtag_execute_queue();\r
- \r
- /* restore previous scan chain */\r
- if( str9xpec_info->devarm ) {\r
- dev0->next = str9xpec_info->devarm;\r
- jtag_num_devices++;\r
- str9xpec_info->devarm = NULL;\r
- }\r
- \r
- return ERROR_OK;\r
-}\r
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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 "str9xpec.h"
+#include "arm7_9_common.h"
+
+
+static int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last);
+static int str9xpec_set_address(struct flash_bank_s *bank, uint8_t sector);
+static int str9xpec_write_options(struct flash_bank_s *bank);
+
+int str9xpec_set_instr(jtag_tap_t *tap, uint32_t new_instr, tap_state_t end_state)
+{
+ if (tap == NULL) {
+ return ERROR_TARGET_INVALID;
+ }
+
+ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr)
+ {
+ scan_field_t field;
+
+ field.tap = tap;
+ field.num_bits = tap->ir_length;
+ field.out_value = calloc(CEIL(field.num_bits, 8), 1);
+ buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+
+ jtag_add_ir_scan(1, &field, end_state);
+
+ free(field.out_value);
+ }
+
+ return ERROR_OK;
+}
+
+static uint8_t str9xpec_isc_status(jtag_tap_t *tap)
+{
+ scan_field_t field;
+ uint8_t status;
+
+ if (str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE) != ERROR_OK)
+ return ISC_STATUS_ERROR;
+
+ field.tap = tap;
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = &status;
+
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+ jtag_execute_queue();
+
+ LOG_DEBUG("status: 0x%2.2x", status);
+
+ if (status & ISC_STATUS_SECURITY)
+ LOG_INFO("Device Security Bit Set");
+
+ return status;
+}
+
+static int str9xpec_isc_enable(struct flash_bank_s *bank)
+{
+ uint8_t status;
+ jtag_tap_t *tap;
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ tap = str9xpec_info->tap;
+
+ if (str9xpec_info->isc_enable)
+ return ERROR_OK;
+
+ /* enter isc mode */
+ if (str9xpec_set_instr(tap, ISC_ENABLE, TAP_IDLE) != ERROR_OK)
+ return ERROR_TARGET_INVALID;
+
+ /* check ISC status */
+ status = str9xpec_isc_status(tap);
+ if (status & ISC_STATUS_MODE)
+ {
+ /* we have entered isc mode */
+ str9xpec_info->isc_enable = 1;
+ LOG_DEBUG("ISC_MODE Enabled");
+ }
+
+ return ERROR_OK;
+}
+
+static int str9xpec_isc_disable(struct flash_bank_s *bank)
+{
+ uint8_t status;
+ jtag_tap_t *tap;
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ tap = str9xpec_info->tap;
+
+ if (!str9xpec_info->isc_enable)
+ return ERROR_OK;
+
+ if (str9xpec_set_instr(tap, ISC_DISABLE, TAP_IDLE) != ERROR_OK)
+ return ERROR_TARGET_INVALID;
+
+ /* delay to handle aborts */
+ jtag_add_sleep(50);
+
+ /* check ISC status */
+ status = str9xpec_isc_status(tap);
+ if (!(status & ISC_STATUS_MODE))
+ {
+ /* we have left isc mode */
+ str9xpec_info->isc_enable = 0;
+ LOG_DEBUG("ISC_MODE Disabled");
+ }
+
+ return ERROR_OK;
+}
+
+static int str9xpec_read_config(struct flash_bank_s *bank)
+{
+ scan_field_t field;
+ uint8_t status;
+ jtag_tap_t *tap;
+
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ tap = str9xpec_info->tap;
+
+ LOG_DEBUG("ISC_CONFIGURATION");
+
+ /* execute ISC_CONFIGURATION command */
+ str9xpec_set_instr(tap, ISC_CONFIGURATION, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 64;
+ field.out_value = NULL;
+ field.in_value = str9xpec_info->options;
+
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+ jtag_execute_queue();
+
+ status = str9xpec_isc_status(tap);
+
+ return status;
+}
+
+static int str9xpec_build_block_list(struct flash_bank_s *bank)
+{
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ int i;
+ int num_sectors;
+ int b0_sectors = 0, b1_sectors = 0;
+ uint32_t offset = 0;
+ int b1_size = 0x2000;
+
+ switch (bank->size)
+ {
+ case (256 * 1024):
+ b0_sectors = 4;
+ break;
+ case (512 * 1024):
+ b0_sectors = 8;
+ break;
+ case (1024 * 1024):
+ b0_sectors = 16;
+ break;
+ case (2048 * 1024):
+ b0_sectors = 32;
+ break;
+ case (128 * 1024):
+ b1_size = 0x4000;
+ b1_sectors = 8;
+ break;
+ case (32 * 1024):
+ b1_sectors = 4;
+ break;
+ default:
+ LOG_ERROR("BUG: unknown bank->size encountered");
+ exit(-1);
+ }
+
+ num_sectors = b0_sectors + b1_sectors;
+
+ bank->num_sectors = num_sectors;
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
+ str9xpec_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
+
+ num_sectors = 0;
+
+ for (i = 0; i < b0_sectors; i++)
+ {
+ bank->sectors[num_sectors].offset = offset;
+ bank->sectors[num_sectors].size = 0x10000;
+ offset += bank->sectors[i].size;
+ bank->sectors[num_sectors].is_erased = -1;
+ bank->sectors[num_sectors].is_protected = 1;
+ str9xpec_info->sector_bits[num_sectors++] = i;
+ }
+
+ for (i = 0; i < b1_sectors; i++)
+ {
+ bank->sectors[num_sectors].offset = offset;
+ bank->sectors[num_sectors].size = b1_size;
+ offset += bank->sectors[i].size;
+ bank->sectors[num_sectors].is_erased = -1;
+ bank->sectors[num_sectors].is_protected = 1;
+ str9xpec_info->sector_bits[num_sectors++] = i + 32;
+ }
+
+ return ERROR_OK;
+}
+
+/* flash bank str9x <base> <size> 0 0 <target#>
+ */
+static int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+ str9xpec_flash_controller_t *str9xpec_info;
+ armv4_5_common_t *armv4_5 = NULL;
+ arm7_9_common_t *arm7_9 = NULL;
+ arm_jtag_t *jtag_info = NULL;
+
+ if (argc < 6)
+ {
+ LOG_WARNING("incomplete flash_bank str9x configuration");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t));
+ bank->driver_priv = str9xpec_info;
+
+ /* REVISIT verify that the jtag position of flash controller is
+ * right after *THIS* core, which must be a STR9xx core ...
+ */
+ armv4_5 = bank->target->arch_info;
+ arm7_9 = armv4_5->arch_info;
+ jtag_info = &arm7_9->jtag_info;
+
+ str9xpec_info->tap = bank->target->tap;
+ str9xpec_info->isc_enable = 0;
+
+ str9xpec_build_block_list(bank);
+
+ /* clear option byte register */
+ buf_set_u32(str9xpec_info->options, 0, 64, 0);
+
+ return ERROR_OK;
+}
+
+static int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last)
+{
+ scan_field_t field;
+ uint8_t status;
+ jtag_tap_t *tap;
+ int i;
+ uint8_t *buffer = NULL;
+
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ tap = str9xpec_info->tap;
+
+ if (!str9xpec_info->isc_enable) {
+ str9xpec_isc_enable(bank);
+ }
+
+ if (!str9xpec_info->isc_enable) {
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ buffer = calloc(CEIL(64, 8), 1);
+
+ LOG_DEBUG("blank check: first_bank: %i, last_bank: %i", first, last);
+
+ for (i = first; i <= last; i++) {
+ buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
+ }
+
+ /* execute ISC_BLANK_CHECK command */
+ str9xpec_set_instr(tap, ISC_BLANK_CHECK, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 64;
+ field.out_value = buffer;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+ jtag_add_sleep(40000);
+
+ /* read blank check result */
+ field.tap = tap;
+ field.num_bits = 64;
+ field.out_value = NULL;
+ field.in_value = buffer;
+
+ jtag_add_dr_scan(1, &field, TAP_IRPAUSE);
+ jtag_execute_queue();
+
+ status = str9xpec_isc_status(tap);
+
+ for (i = first; i <= last; i++)
+ {
+ if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1))
+ bank->sectors[i].is_erased = 0;
+ else
+ bank->sectors[i].is_erased = 1;
+ }
+
+ free(buffer);
+
+ str9xpec_isc_disable(bank);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+ return ERROR_OK;
+}
+
+static int str9xpec_protect_check(struct flash_bank_s *bank)
+{
+ uint8_t status;
+ int i;
+
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ status = str9xpec_read_config(bank);
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1))
+ bank->sectors[i].is_protected = 1;
+ else
+ bank->sectors[i].is_protected = 0;
+ }
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+ return ERROR_OK;
+}
+
+static int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last)
+{
+ scan_field_t field;
+ uint8_t status;
+ jtag_tap_t *tap;
+ int i;
+ uint8_t *buffer = NULL;
+
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ tap = str9xpec_info->tap;
+
+ if (!str9xpec_info->isc_enable) {
+ str9xpec_isc_enable(bank);
+ }
+
+ if (!str9xpec_info->isc_enable) {
+ return ISC_STATUS_ERROR;
+ }
+
+ buffer = calloc(CEIL(64, 8), 1);
+
+ LOG_DEBUG("erase: first_bank: %i, last_bank: %i", first, last);
+
+ /* last bank: 0xFF signals a full erase (unlock complete device) */
+ /* last bank: 0xFE signals a option byte erase */
+ if (last == 0xFF)
+ {
+ for (i = 0; i < 64; i++) {
+ buf_set_u32(buffer, i, 1, 1);
+ }
+ }
+ else if (last == 0xFE)
+ {
+ buf_set_u32(buffer, 49, 1, 1);
+ }
+ else
+ {
+ for (i = first; i <= last; i++) {
+ buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
+ }
+ }
+
+ LOG_DEBUG("ISC_ERASE");
+
+ /* execute ISC_ERASE command */
+ str9xpec_set_instr(tap, ISC_ERASE, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 64;
+ field.out_value = buffer;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+ jtag_execute_queue();
+
+ jtag_add_sleep(10);
+
+ /* wait for erase completion */
+ while (!((status = str9xpec_isc_status(tap)) & ISC_STATUS_BUSY)) {
+ alive_sleep(1);
+ }
+
+ free(buffer);
+
+ str9xpec_isc_disable(bank);
+
+ return status;
+}
+
+static int str9xpec_erase(struct flash_bank_s *bank, int first, int last)
+{
+ int status;
+
+ status = str9xpec_erase_area(bank, first, last);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+static int str9xpec_lock_device(struct flash_bank_s *bank)
+{
+ scan_field_t field;
+ uint8_t status;
+ jtag_tap_t *tap;
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ str9xpec_info = bank->driver_priv;
+ tap = str9xpec_info->tap;
+
+ if (!str9xpec_info->isc_enable) {
+ str9xpec_isc_enable(bank);
+ }
+
+ if (!str9xpec_info->isc_enable) {
+ return ISC_STATUS_ERROR;
+ }
+
+ /* set security address */
+ str9xpec_set_address(bank, 0x80);
+
+ /* execute ISC_PROGRAM command */
+ str9xpec_set_instr(tap, ISC_PROGRAM_SECURITY, TAP_IDLE);
+
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+ do {
+ field.tap = tap;
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = &status;
+
+ jtag_add_dr_scan(1, &field, jtag_get_end_state());
+ jtag_execute_queue();
+
+ } while (!(status & ISC_STATUS_BUSY));
+
+ str9xpec_isc_disable(bank);
+
+ return status;
+}
+
+static int str9xpec_unlock_device(struct flash_bank_s *bank)
+{
+ uint8_t status;
+
+ status = str9xpec_erase_area(bank, 0, 255);
+
+ return status;
+}
+
+static int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+ uint8_t status;
+ int i;
+
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ status = str9xpec_read_config(bank);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ LOG_DEBUG("protect: first_bank: %i, last_bank: %i", first, last);
+
+ /* last bank: 0xFF signals a full device protect */
+ if (last == 0xFF)
+ {
+ if (set)
+ {
+ status = str9xpec_lock_device(bank);
+ }
+ else
+ {
+ /* perform full erase to unlock device */
+ status = str9xpec_unlock_device(bank);
+ }
+ }
+ else
+ {
+ for (i = first; i <= last; i++)
+ {
+ if (set)
+ buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1);
+ else
+ buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0);
+ }
+
+ status = str9xpec_write_options(bank);
+ }
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+static int str9xpec_set_address(struct flash_bank_s *bank, uint8_t sector)
+{
+ jtag_tap_t *tap;
+ scan_field_t field;
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+
+ tap = str9xpec_info->tap;
+
+ /* set flash controller address */
+ str9xpec_set_instr(tap, ISC_ADDRESS_SHIFT, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 8;
+ field.out_value = §or;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(1, &field, jtag_get_end_state());
+
+ return ERROR_OK;
+}
+
+static int str9xpec_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
+ uint32_t dwords_remaining = (count / 8);
+ uint32_t bytes_remaining = (count & 0x00000007);
+ uint32_t bytes_written = 0;
+ uint8_t status;
+ uint32_t check_address = offset;
+ jtag_tap_t *tap;
+ scan_field_t field;
+ uint8_t *scanbuf;
+ int i;
+ int first_sector = 0;
+ int last_sector = 0;
+
+ tap = str9xpec_info->tap;
+
+ if (!str9xpec_info->isc_enable) {
+ str9xpec_isc_enable(bank);
+ }
+
+ if (!str9xpec_info->isc_enable) {
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (offset & 0x7)
+ {
+ LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ }
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ uint32_t sec_start = bank->sectors[i].offset;
+ uint32_t sec_end = sec_start + bank->sectors[i].size;
+
+ /* check if destination falls within the current sector */
+ if ((check_address >= sec_start) && (check_address < sec_end))
+ {
+ /* check if destination ends in the current sector */
+ if (offset + count < sec_end)
+ check_address = offset + count;
+ else
+ check_address = sec_end;
+ }
+
+ if ((offset >= sec_start) && (offset < sec_end)) {
+ first_sector = i;
+ }
+
+ if ((offset + count >= sec_start) && (offset + count < sec_end)) {
+ last_sector = i;
+ }
+ }
+
+ if (check_address != offset + count)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
+
+ scanbuf = calloc(CEIL(64, 8), 1);
+
+ LOG_DEBUG("ISC_PROGRAM");
+
+ for (i = first_sector; i <= last_sector; i++)
+ {
+ str9xpec_set_address(bank, str9xpec_info->sector_bits[i]);
+
+ dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8);
+
+ while (dwords_remaining > 0)
+ {
+ str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 64;
+ field.out_value = (buffer + bytes_written);
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+
+ /* small delay before polling */
+ jtag_add_sleep(50);
+
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+ do {
+ field.tap = tap;
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = scanbuf;
+
+ jtag_add_dr_scan(1, &field, jtag_get_end_state());
+ jtag_execute_queue();
+
+ status = buf_get_u32(scanbuf, 0, 8);
+
+ } while (!(status & ISC_STATUS_BUSY));
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
+ return ERROR_FLASH_OPERATION_FAILED; */
+
+ dwords_remaining--;
+ bytes_written += 8;
+ }
+ }
+
+ if (bytes_remaining)
+ {
+ uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ int i = 0;
+
+ while (bytes_remaining > 0)
+ {
+ last_dword[i++] = *(buffer + bytes_written);
+ bytes_remaining--;
+ bytes_written++;
+ }
+
+ str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 64;
+ field.out_value = last_dword;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+
+ /* small delay before polling */
+ jtag_add_sleep(50);
+
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+ do {
+ field.tap = tap;
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = scanbuf;
+
+ jtag_add_dr_scan(1, &field, jtag_get_end_state());
+ jtag_execute_queue();
+
+ status = buf_get_u32(scanbuf, 0, 8);
+
+ } while (!(status & ISC_STATUS_BUSY));
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
+ return ERROR_FLASH_OPERATION_FAILED; */
+ }
+
+ free(scanbuf);
+
+ str9xpec_isc_disable(bank);
+
+ return ERROR_OK;
+}
+
+static int str9xpec_probe(struct flash_bank_s *bank)
+{
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_part_id_command)
+{
+ scan_field_t field;
+ uint8_t *buffer = NULL;
+ jtag_tap_t *tap;
+ uint32_t idcode;
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+ tap = str9xpec_info->tap;
+
+ buffer = calloc(CEIL(32, 8), 1);
+
+ str9xpec_set_instr(tap, ISC_IDCODE, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = buffer;
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+ jtag_execute_queue();
+
+ idcode = buf_get_u32(buffer, 0, 32);
+
+ command_print(cmd_ctx, "str9xpec part id: 0x%8.8" PRIx32 "", idcode);
+
+ free(buffer);
+
+ return ERROR_OK;
+}
+
+static int str9xpec_erase_check(struct flash_bank_s *bank)
+{
+ return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+static int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+ snprintf(buf, buf_size, "str9xpec flash driver info");
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_read_command)
+{
+ uint8_t status;
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "str9xpec options_read <bank>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ status = str9xpec_read_config(bank);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ /* boot bank */
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1))
+ command_print(cmd_ctx, "CS Map: bank1");
+ else
+ command_print(cmd_ctx, "CS Map: bank0");
+
+ /* OTP lock */
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1))
+ command_print(cmd_ctx, "OTP Lock: OTP Locked");
+ else
+ command_print(cmd_ctx, "OTP Lock: OTP Unlocked");
+
+ /* LVD Threshold */
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1))
+ command_print(cmd_ctx, "LVD Threshold: 2.7v");
+ else
+ command_print(cmd_ctx, "LVD Threshold: 2.4v");
+
+ /* LVD reset warning */
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1))
+ command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs");
+ else
+ command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only");
+
+ /* LVD reset select */
+ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1))
+ command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs");
+ else
+ command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only");
+
+ return ERROR_OK;
+}
+
+static int str9xpec_write_options(struct flash_bank_s *bank)
+{
+ scan_field_t field;
+ uint8_t status;
+ jtag_tap_t *tap;
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ str9xpec_info = bank->driver_priv;
+ tap = str9xpec_info->tap;
+
+ /* erase config options first */
+ status = str9xpec_erase_area(bank, 0xFE, 0xFE);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return status;
+
+ if (!str9xpec_info->isc_enable) {
+ str9xpec_isc_enable(bank);
+ }
+
+ if (!str9xpec_info->isc_enable) {
+ return ISC_STATUS_ERROR;
+ }
+
+ /* according to data 64th bit has to be set */
+ buf_set_u32(str9xpec_info->options, 63, 1, 1);
+
+ /* set option byte address */
+ str9xpec_set_address(bank, 0x50);
+
+ /* execute ISC_PROGRAM command */
+ str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
+
+ field.tap = tap;
+ field.num_bits = 64;
+ field.out_value = str9xpec_info->options;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(1, &field, jtag_set_end_state(TAP_IDLE));
+
+ /* small delay before polling */
+ jtag_add_sleep(50);
+
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+ do {
+ field.tap = tap;
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = &status;
+
+ jtag_add_dr_scan(1, &field, jtag_get_end_state());
+ jtag_execute_queue();
+
+ } while (!(status & ISC_STATUS_BUSY));
+
+ str9xpec_isc_disable(bank);
+
+ return status;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_write_command)
+{
+ uint8_t status;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "str9xpec options_write <bank>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ status = str9xpec_write_options(bank);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_cmap_command)
+{
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 2)
+ {
+ command_print(cmd_ctx, "str9xpec options_cmap <bank> <bank0 | bank1>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(args[1], "bank1") == 0)
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1);
+ }
+ else
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0);
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_lvdthd_command)
+{
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 2)
+ {
+ command_print(cmd_ctx, "str9xpec options_lvdthd <bank> <2.4v | 2.7v>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(args[1], "2.7v") == 0)
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1);
+ }
+ else
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0);
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_lvdsel_command)
+{
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 2)
+ {
+ command_print(cmd_ctx, "str9xpec options_lvdsel <bank> <vdd | vdd_vddq>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(args[1], "vdd_vddq") == 0)
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1);
+ }
+ else
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0);
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_lvdwarn_command)
+{
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 2)
+ {
+ command_print(cmd_ctx, "str9xpec options_lvdwarn <bank> <vdd | vdd_vddq>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(args[1], "vdd_vddq") == 0)
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1);
+ }
+ else
+ {
+ buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0);
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_lock_command)
+{
+ uint8_t status;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "str9xpec lock <bank>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ status = str9xpec_lock_device(bank);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_unlock_command)
+{
+ uint8_t status;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "str9xpec unlock <bank>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ status = str9xpec_unlock_device(bank);
+
+ if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_enable_turbo_command)
+{
+ jtag_tap_t *tap0;
+ jtag_tap_t *tap1;
+ jtag_tap_t *tap2;
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "str9xpec enable_turbo <bank>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ tap0 = str9xpec_info->tap;
+
+ /* remove arm core from chain - enter turbo mode */
+ tap1 = tap0->next_tap;
+ if (tap1 == NULL)
+ {
+ /* things are *WRONG* */
+ command_print(cmd_ctx,"**STR9FLASH** (tap1) invalid chain?");
+ return ERROR_OK;
+ }
+ tap2 = tap1->next_tap;
+ if (tap2 == NULL)
+ {
+ /* things are *WRONG* */
+ command_print(cmd_ctx,"**STR9FLASH** (tap2) invalid chain?");
+ return ERROR_OK;
+ }
+
+ /* enable turbo mode - TURBO-PROG-ENABLE */
+ str9xpec_set_instr(tap2, 0xD, TAP_IDLE);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ return retval;
+
+ /* modify scan chain - str9 core has been removed */
+ tap1->enabled = 0;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_disable_turbo_command)
+{
+ jtag_tap_t *tap;
+ str9xpec_flash_controller_t *str9xpec_info = NULL;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "str9xpec disable_turbo <bank>");
+ return ERROR_OK;
+ }
+
+ flash_bank_t *bank;
+ int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+ tap = str9xpec_info->tap;
+
+ if (tap == NULL)
+ return ERROR_FAIL;
+
+ /* exit turbo mode via RESET */
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IDLE);
+ jtag_add_tlr();
+ jtag_execute_queue();
+
+ /* restore previous scan chain */
+ if (tap->next_tap) {
+ tap->next_tap->enabled = 1;
+ }
+
+ return ERROR_OK;
+}
+
+static int str9xpec_register_commands(struct command_context_s *cmd_ctx)
+{
+ command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec",
+ NULL, COMMAND_ANY, "str9xpec flash specific commands");
+
+ register_command(cmd_ctx, str9xpec_cmd, "enable_turbo",
+ str9xpec_handle_flash_enable_turbo_command,
+ COMMAND_EXEC, "enable str9xpec turbo mode");
+ register_command(cmd_ctx, str9xpec_cmd, "disable_turbo",
+ str9xpec_handle_flash_disable_turbo_command,
+ COMMAND_EXEC, "disable str9xpec turbo mode");
+ register_command(cmd_ctx, str9xpec_cmd, "options_cmap",
+ str9xpec_handle_flash_options_cmap_command,
+ COMMAND_EXEC, "configure str9xpec boot sector");
+ register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd",
+ str9xpec_handle_flash_options_lvdthd_command,
+ COMMAND_EXEC, "configure str9xpec lvd threshold");
+ register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel",
+ str9xpec_handle_flash_options_lvdsel_command,
+ COMMAND_EXEC, "configure str9xpec lvd selection");
+ register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn",
+ str9xpec_handle_flash_options_lvdwarn_command,
+ COMMAND_EXEC, "configure str9xpec lvd warning");
+ register_command(cmd_ctx, str9xpec_cmd, "options_read",
+ str9xpec_handle_flash_options_read_command,
+ COMMAND_EXEC, "read str9xpec options");
+ register_command(cmd_ctx, str9xpec_cmd, "options_write",
+ str9xpec_handle_flash_options_write_command,
+ COMMAND_EXEC, "write str9xpec options");
+ register_command(cmd_ctx, str9xpec_cmd, "lock",
+ str9xpec_handle_flash_lock_command,
+ COMMAND_EXEC, "lock str9xpec device");
+ register_command(cmd_ctx, str9xpec_cmd, "unlock",
+ str9xpec_handle_flash_unlock_command,
+ COMMAND_EXEC, "unlock str9xpec device");
+ register_command(cmd_ctx, str9xpec_cmd, "part_id",
+ str9xpec_handle_part_id_command,
+ COMMAND_EXEC, "print part id of str9xpec flash bank <num>");
+
+ return ERROR_OK;
+}
+
+flash_driver_t str9xpec_flash = {
+ .name = "str9xpec",
+ .register_commands = &str9xpec_register_commands,
+ .flash_bank_command = &str9xpec_flash_bank_command,
+ .erase = &str9xpec_erase,
+ .protect = &str9xpec_protect,
+ .write = &str9xpec_write,
+ .probe = &str9xpec_probe,
+ .auto_probe = &str9xpec_probe,
+ .erase_check = &str9xpec_erase_check,
+ .protect_check = &str9xpec_protect_check,
+ .info = &str9xpec_info,
+ };