You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ad...@apache.org on 2016/06/15 22:03:57 UTC
[14/51] [partial] incubator-mynewt-site git commit: Fixed broken
Quick Start link and added OpenOCD option for Arduino Primo debugging
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str7x.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str7x.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str7x.c
new file mode 100755
index 0000000..d8a4cd4
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str7x.c
@@ -0,0 +1,817 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * Copyright (C) 2008 by Spencer Oliver *
+ * spen@spen-soft.co.uk *
+ * *
+ * Copyright (C) 2010 �yvind Harboe *
+ * oyvind.harboe@zylin.com *
+ * *
+ * 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., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <target/arm.h>
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+
+/* Flash registers */
+
+#define FLASH_CR0 0x00000000
+#define FLASH_CR1 0x00000004
+#define FLASH_DR0 0x00000008
+#define FLASH_DR1 0x0000000C
+#define FLASH_AR 0x00000010
+#define FLASH_ER 0x00000014
+#define FLASH_NVWPAR 0x0000DFB0
+#define FLASH_NVAPR0 0x0000DFB8
+#define FLASH_NVAPR1 0x0000DFBC
+
+/* FLASH_CR0 register bits */
+
+#define FLASH_WMS 0x80000000
+#define FLASH_SUSP 0x40000000
+#define FLASH_WPG 0x20000000
+#define FLASH_DWPG 0x10000000
+#define FLASH_SER 0x08000000
+#define FLASH_SPR 0x01000000
+#define FLASH_BER 0x04000000
+#define FLASH_MER 0x02000000
+#define FLASH_LOCK 0x00000010
+#define FLASH_BSYA1 0x00000004
+#define FLASH_BSYA0 0x00000002
+
+/* FLASH_CR1 register bits */
+
+#define FLASH_B1S 0x02000000
+#define FLASH_B0S 0x01000000
+#define FLASH_B1F1 0x00020000
+#define FLASH_B1F0 0x00010000
+#define FLASH_B0F7 0x00000080
+#define FLASH_B0F6 0x00000040
+#define FLASH_B0F5 0x00000020
+#define FLASH_B0F4 0x00000010
+#define FLASH_B0F3 0x00000008
+#define FLASH_B0F2 0x00000004
+#define FLASH_B0F1 0x00000002
+#define FLASH_B0F0 0x00000001
+
+/* FLASH_ER register bits */
+
+#define FLASH_WPF 0x00000100
+#define FLASH_RESER 0x00000080
+#define FLASH_SEQER 0x00000040
+#define FLASH_10ER 0x00000008
+#define FLASH_PGER 0x00000004
+#define FLASH_ERER 0x00000002
+#define FLASH_ERR 0x00000001
+
+
+struct str7x_flash_bank {
+ uint32_t *sector_bits;
+ uint32_t disable_bit;
+ uint32_t busy_bits;
+ uint32_t register_base;
+};
+
+struct str7x_mem_layout {
+ uint32_t sector_start;
+ uint32_t sector_size;
+ uint32_t sector_bit;
+};
+
+enum str7x_status_codes {
+ STR7X_CMD_SUCCESS = 0,
+ STR7X_INVALID_COMMAND = 1,
+ STR7X_SRC_ADDR_ERROR = 2,
+ STR7X_DST_ADDR_ERROR = 3,
+ STR7X_SRC_ADDR_NOT_MAPPED = 4,
+ STR7X_DST_ADDR_NOT_MAPPED = 5,
+ STR7X_COUNT_ERROR = 6,
+ STR7X_INVALID_SECTOR = 7,
+ STR7X_SECTOR_NOT_BLANK = 8,
+ STR7X_SECTOR_NOT_PREPARED = 9,
+ STR7X_COMPARE_ERROR = 10,
+ STR7X_BUSY = 11
+};
+
+static const struct str7x_mem_layout mem_layout_str7bank0[] = {
+ {0x00000000, 0x02000, 0x01},
+ {0x00002000, 0x02000, 0x02},
+ {0x00004000, 0x02000, 0x04},
+ {0x00006000, 0x02000, 0x08},
+ {0x00008000, 0x08000, 0x10},
+ {0x00010000, 0x10000, 0x20},
+ {0x00020000, 0x10000, 0x40},
+ {0x00030000, 0x10000, 0x80}
+};
+
+static const struct str7x_mem_layout mem_layout_str7bank1[] = {
+ {0x00000000, 0x02000, 0x10000},
+ {0x00002000, 0x02000, 0x20000}
+};
+
+static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg)
+{
+ struct str7x_flash_bank *str7x_info = bank->driver_priv;
+ return str7x_info->register_base | reg;
+}
+
+static int str7x_build_block_list(struct flash_bank *bank)
+{
+ struct str7x_flash_bank *str7x_info = bank->driver_priv;
+
+ int i;
+ int num_sectors;
+ int b0_sectors = 0, b1_sectors = 0;
+
+ switch (bank->size) {
+ case 16 * 1024:
+ b1_sectors = 2;
+ break;
+ case 64 * 1024:
+ b0_sectors = 5;
+ break;
+ case 128 * 1024:
+ b0_sectors = 6;
+ break;
+ case 256 * 1024:
+ b0_sectors = 8;
+ 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(struct flash_sector) * num_sectors);
+ str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
+
+ num_sectors = 0;
+
+ for (i = 0; i < b0_sectors; i++) {
+ bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start;
+ bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size;
+ bank->sectors[num_sectors].is_erased = -1;
+ /* the reset_init handler marks all the sectors unprotected,
+ * matching hardware after reset; keep the driver in sync
+ */
+ bank->sectors[num_sectors].is_protected = 0;
+ str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit;
+ }
+
+ for (i = 0; i < b1_sectors; i++) {
+ bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start;
+ bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size;
+ bank->sectors[num_sectors].is_erased = -1;
+ /* the reset_init handler marks all the sectors unprotected,
+ * matching hardware after reset; keep the driver in sync
+ */
+ bank->sectors[num_sectors].is_protected = 0;
+ str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit;
+ }
+
+ return ERROR_OK;
+}
+
+/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
+ */
+FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command)
+{
+ struct str7x_flash_bank *str7x_info;
+
+ if (CMD_ARGC < 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ str7x_info = malloc(sizeof(struct str7x_flash_bank));
+ bank->driver_priv = str7x_info;
+
+ /* set default bits for str71x flash */
+ str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0);
+ str7x_info->disable_bit = (1 << 1);
+
+ if (strcmp(CMD_ARGV[6], "STR71x") == 0)
+ str7x_info->register_base = 0x40100000;
+ else if (strcmp(CMD_ARGV[6], "STR73x") == 0) {
+ str7x_info->register_base = 0x80100000;
+ str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0);
+ } else if (strcmp(CMD_ARGV[6], "STR75x") == 0) {
+ str7x_info->register_base = 0x20100000;
+ str7x_info->disable_bit = (1 << 0);
+ } else {
+ LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]);
+ free(str7x_info);
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ str7x_build_block_list(bank);
+
+ return ERROR_OK;
+}
+
+/* wait for flash to become idle or report errors.
+
+ FIX!!! what's the maximum timeout??? The documentation doesn't
+ state any maximum time.... by inspection it seems > 1000ms is to be
+ expected.
+
+ 10000ms is long enough that it should cover anything, yet not
+ quite be equivalent to an infinite loop.
+
+ */
+static int str7x_waitbusy(struct flash_bank *bank)
+{
+ int err;
+ int i;
+ struct target *target = bank->target;
+ struct str7x_flash_bank *str7x_info = bank->driver_priv;
+
+ for (i = 0 ; i < 10000; i++) {
+ uint32_t retval;
+ err = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
+ if (err != ERROR_OK)
+ return err;
+
+ if ((retval & str7x_info->busy_bits) == 0)
+ return ERROR_OK;
+
+ alive_sleep(1);
+ }
+ LOG_ERROR("Timed out waiting for str7x flash");
+ return ERROR_FAIL;
+}
+
+
+static int str7x_result(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ uint32_t flash_flags;
+
+ int retval;
+ retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &flash_flags);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (flash_flags & FLASH_WPF) {
+ LOG_ERROR("str7x hw write protection set");
+ retval = ERROR_FAIL;
+ }
+ if (flash_flags & FLASH_RESER) {
+ LOG_ERROR("str7x suspended program erase not resumed");
+ retval = ERROR_FAIL;
+ }
+ if (flash_flags & FLASH_10ER) {
+ LOG_ERROR("str7x trying to set bit to 1 when it is already 0");
+ retval = ERROR_FAIL;
+ }
+ if (flash_flags & FLASH_PGER) {
+ LOG_ERROR("str7x program error");
+ retval = ERROR_FAIL;
+ }
+ if (flash_flags & FLASH_ERER) {
+ LOG_ERROR("str7x erase error");
+ retval = ERROR_FAIL;
+ }
+ if (retval == ERROR_OK) {
+ if (flash_flags & FLASH_ERR) {
+ /* this should always be set if one of the others are set... */
+ LOG_ERROR("str7x write operation failed / bad setup");
+ retval = ERROR_FAIL;
+ }
+ }
+
+ return retval;
+}
+
+static int str7x_protect_check(struct flash_bank *bank)
+{
+ struct str7x_flash_bank *str7x_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ int i;
+ uint32_t flash_flags;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ int retval;
+ retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &flash_flags);
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (i = 0; i < bank->num_sectors; i++) {
+ if (flash_flags & str7x_info->sector_bits[i])
+ bank->sectors[i].is_protected = 0;
+ else
+ bank->sectors[i].is_protected = 1;
+ }
+
+ return ERROR_OK;
+}
+
+static int str7x_erase(struct flash_bank *bank, int first, int last)
+{
+ struct str7x_flash_bank *str7x_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ int i;
+ uint32_t cmd;
+ uint32_t sectors = 0;
+ int err;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ for (i = first; i <= last; i++)
+ sectors |= str7x_info->sector_bits[i];
+
+ LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors);
+
+ /* clear FLASH_ER register */
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
+ if (err != ERROR_OK)
+ return err;
+
+ cmd = FLASH_SER;
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+ if (err != ERROR_OK)
+ return err;
+
+ cmd = sectors;
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
+ if (err != ERROR_OK)
+ return err;
+
+ cmd = FLASH_SER | FLASH_WMS;
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+ if (err != ERROR_OK)
+ return err;
+
+ err = str7x_waitbusy(bank);
+ if (err != ERROR_OK)
+ return err;
+
+ err = str7x_result(bank);
+ if (err != ERROR_OK)
+ return err;
+
+ for (i = first; i <= last; i++)
+ bank->sectors[i].is_erased = 1;
+
+ return ERROR_OK;
+}
+
+static int str7x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+ struct str7x_flash_bank *str7x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ int i;
+ uint32_t cmd;
+ uint32_t protect_blocks;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ protect_blocks = 0xFFFFFFFF;
+
+ if (set) {
+ for (i = first; i <= last; i++)
+ protect_blocks &= ~(str7x_info->sector_bits[i]);
+ }
+
+ /* clear FLASH_ER register */
+ int err;
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
+ if (err != ERROR_OK)
+ return err;
+
+ cmd = FLASH_SPR;
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+ if (err != ERROR_OK)
+ return err;
+
+ cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);
+ if (err != ERROR_OK)
+ return err;
+
+ cmd = protect_blocks;
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
+ if (err != ERROR_OK)
+ return err;
+
+ cmd = FLASH_SPR | FLASH_WMS;
+ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+ if (err != ERROR_OK)
+ return err;
+
+ err = str7x_waitbusy(bank);
+ if (err != ERROR_OK)
+ return err;
+
+ err = str7x_result(bank);
+ if (err != ERROR_OK)
+ return err;
+
+ return ERROR_OK;
+}
+
+static int str7x_write_block(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct str7x_flash_bank *str7x_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t buffer_size = 32768;
+ struct working_area *write_algorithm;
+ struct working_area *source;
+ uint32_t address = bank->base + offset;
+ struct reg_param reg_params[6];
+ struct arm_algorithm arm_algo;
+ int retval = ERROR_OK;
+
+ /* see contib/loaders/flash/str7x.s for src */
+
+ static const uint32_t str7x_flash_write_code[] = {
+ /* write: */
+ 0xe3a04201, /* mov r4, #0x10000000 */
+ 0xe5824000, /* str r4, [r2, #0x0] */
+ 0xe5821010, /* str r1, [r2, #0x10] */
+ 0xe4904004, /* ldr r4, [r0], #4 */
+ 0xe5824008, /* str r4, [r2, #0x8] */
+ 0xe4904004, /* ldr r4, [r0], #4 */
+ 0xe582400c, /* str r4, [r2, #0xc] */
+ 0xe3a04209, /* mov r4, #0x90000000 */
+ 0xe5824000, /* str r4, [r2, #0x0] */
+ /* busy: */
+ 0xe5924000, /* ldr r4, [r2, #0x0] */
+ 0xe1140005, /* tst r4, r5 */
+ 0x1afffffc, /* bne busy */
+ 0xe5924014, /* ldr r4, [r2, #0x14] */
+ 0xe31400ff, /* tst r4, #0xff */
+ 0x03140c01, /* tsteq r4, #0x100 */
+ 0x1a000002, /* bne exit */
+ 0xe2811008, /* add r1, r1, #0x8 */
+ 0xe2533001, /* subs r3, r3, #1 */
+ 0x1affffec, /* bne write */
+ /* exit: */
+ 0xeafffffe, /* b exit */
+ };
+
+ /* flash write code */
+ if (target_alloc_working_area_try(target, sizeof(str7x_flash_write_code),
+ &write_algorithm) != ERROR_OK) {
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ uint8_t code[sizeof(str7x_flash_write_code)];
+ target_buffer_set_u32_array(target, code, ARRAY_SIZE(str7x_flash_write_code),
+ str7x_flash_write_code);
+ target_write_buffer(target, write_algorithm->address, sizeof(code), code);
+
+ /* memory buffer */
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+ buffer_size /= 2;
+ if (buffer_size <= 256) {
+ /* we already allocated the writing code, but failed to get a
+ * buffer, free the algorithm */
+ target_free_working_area(target, write_algorithm);
+
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+ }
+
+ arm_algo.common_magic = ARM_COMMON_MAGIC;
+ arm_algo.core_mode = ARM_MODE_SVC;
+ arm_algo.core_state = ARM_STATE_ARM;
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
+ init_reg_param(®_params[4], "r4", 32, PARAM_IN);
+ init_reg_param(®_params[5], "r5", 32, PARAM_OUT);
+
+ while (count > 0) {
+ uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
+
+ target_write_buffer(target, source->address, thisrun_count * 8, buffer);
+
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);
+ buf_set_u32(reg_params[1].value, 0, 32, address);
+ buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
+ buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
+ buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);
+
+ retval = target_run_algorithm(target, 0, NULL, 6, reg_params,
+ write_algorithm->address,
+ write_algorithm->address + (sizeof(str7x_flash_write_code) - 4),
+ 10000, &arm_algo);
+ if (retval != ERROR_OK)
+ break;
+
+ if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00) {
+ retval = str7x_result(bank);
+ break;
+ }
+
+ buffer += thisrun_count * 8;
+ address += thisrun_count * 8;
+ count -= thisrun_count;
+ }
+
+ target_free_working_area(target, source);
+ target_free_working_area(target, write_algorithm);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+ destroy_reg_param(®_params[5]);
+
+ return retval;
+}
+
+static int str7x_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ uint32_t dwords_remaining = (count / 8);
+ uint32_t bytes_remaining = (count & 0x00000007);
+ uint32_t address = bank->base + offset;
+ uint32_t bytes_written = 0;
+ uint32_t cmd;
+ int retval;
+ uint32_t check_address = offset;
+ int i;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ 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 (check_address != offset + count)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ /* clear FLASH_ER register */
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
+
+ /* multiple dwords (8-byte) to be programmed? */
+ if (dwords_remaining > 0) {
+ /* try using a block write */
+ retval = str7x_write_block(bank, buffer, offset, dwords_remaining);
+ if (retval != ERROR_OK) {
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+ /* if block write failed (no sufficient working area),
+ * we use normal (slow) single dword accesses */
+ LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+ } else {
+ return retval;
+ }
+ } else {
+ buffer += dwords_remaining * 8;
+ address += dwords_remaining * 8;
+ dwords_remaining = 0;
+ }
+ }
+
+ while (dwords_remaining > 0) {
+ /* command */
+ cmd = FLASH_DWPG;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+ /* address */
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
+
+ /* data word 1 */
+ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0),
+ 4, 1, buffer + bytes_written);
+ bytes_written += 4;
+
+ /* data word 2 */
+ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1),
+ 4, 1, buffer + bytes_written);
+ bytes_written += 4;
+
+ /* start programming cycle */
+ cmd = FLASH_DWPG | FLASH_WMS;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+ int err;
+ err = str7x_waitbusy(bank);
+ if (err != ERROR_OK)
+ return err;
+
+ err = str7x_result(bank);
+ if (err != ERROR_OK)
+ return err;
+
+ dwords_remaining--;
+ address += 8;
+ }
+
+ if (bytes_remaining) {
+ uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ /* copy the last remaining bytes into the write buffer */
+ memcpy(last_dword, buffer+bytes_written, bytes_remaining);
+
+ /* command */
+ cmd = FLASH_DWPG;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+ /* address */
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
+
+ /* data word 1 */
+ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0),
+ 4, 1, last_dword);
+
+ /* data word 2 */
+ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1),
+ 4, 1, last_dword + 4);
+
+ /* start programming cycle */
+ cmd = FLASH_DWPG | FLASH_WMS;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
+
+ int err;
+ err = str7x_waitbusy(bank);
+ if (err != ERROR_OK)
+ return err;
+
+ err = str7x_result(bank);
+ if (err != ERROR_OK)
+ return err;
+ }
+
+ return ERROR_OK;
+}
+
+static int str7x_probe(struct flash_bank *bank)
+{
+ return ERROR_OK;
+}
+
+#if 0
+COMMAND_HANDLER(str7x_handle_part_id_command)
+{
+ return ERROR_OK;
+}
+#endif
+
+static int get_str7x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ /* Setting the write protection on a sector is a permanent change but it
+ * can be disabled temporarily. FLASH_NVWPAR reflects the permanent
+ * protection state of the sectors, not the temporary.
+ */
+ snprintf(buf, buf_size, "STR7x flash protection info is only valid after a power cycle, "
+ "clearing the protection is only temporary and may not be reflected in the current "
+ "info returned.");
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str7x_handle_disable_jtag_command)
+{
+ struct target *target = NULL;
+ struct str7x_flash_bank *str7x_info = NULL;
+
+ uint32_t flash_cmd;
+ uint16_t ProtectionLevel = 0;
+ uint16_t ProtectionRegs;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str7x_info = bank->driver_priv;
+
+ target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* first we get protection status */
+ uint32_t reg;
+ target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), ®);
+
+ if (!(reg & str7x_info->disable_bit))
+ ProtectionLevel = 1;
+
+ target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), ®);
+ ProtectionRegs = ~(reg >> 16);
+
+ while (((ProtectionRegs) != 0) && (ProtectionLevel < 16)) {
+ ProtectionRegs >>= 1;
+ ProtectionLevel++;
+ }
+
+ if (ProtectionLevel == 0) {
+ flash_cmd = FLASH_SPR;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8);
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD);
+ flash_cmd = FLASH_SPR | FLASH_WMS;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+ } else {
+ flash_cmd = FLASH_SPR;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0),
+ ~(1 << (15 + ProtectionLevel)));
+ flash_cmd = FLASH_SPR | FLASH_WMS;
+ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
+ }
+
+ return ERROR_OK;
+}
+
+static const struct command_registration str7x_exec_command_handlers[] = {
+ {
+ .name = "disable_jtag",
+ .usage = "<bank>",
+ .handler = str7x_handle_disable_jtag_command,
+ .mode = COMMAND_EXEC,
+ .help = "disable jtag access",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration str7x_command_handlers[] = {
+ {
+ .name = "str7x",
+ .mode = COMMAND_ANY,
+ .help = "str7x flash command group",
+ .usage = "",
+ .chain = str7x_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver str7x_flash = {
+ .name = "str7x",
+ .commands = str7x_command_handlers,
+ .flash_bank_command = str7x_flash_bank_command,
+ .erase = str7x_erase,
+ .protect = str7x_protect,
+ .write = str7x_write,
+ .read = default_flash_read,
+ .probe = str7x_probe,
+ .auto_probe = str7x_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = str7x_protect_check,
+ .info = get_str7x_info,
+};
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9x.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9x.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9x.c
new file mode 100755
index 0000000..b3f08b0
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9x.c
@@ -0,0 +1,684 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * Copyright (C) 2008 by Spencer Oliver *
+ * spen@spen-soft.co.uk *
+ *
+ * Copyright (C) 2008 by Oyvind Harboe *
+ * oyvind.harboe@zylin.com *
+ * *
+ * 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., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <target/arm966e.h>
+#include <target/algorithm.h>
+
+/* Flash registers */
+
+#define FLASH_BBSR 0x54000000 /* Boot Bank Size Register */
+#define FLASH_NBBSR 0x54000004 /* Non-Boot Bank Size Register */
+#define FLASH_BBADR 0x5400000C /* Boot Bank Base Address Register */
+#define FLASH_NBBADR 0x54000010 /* Non-Boot Bank Base Address Register */
+#define FLASH_CR 0x54000018 /* Control Register */
+#define FLASH_SR 0x5400001C /* Status Register */
+#define FLASH_BCE5ADDR 0x54000020 /* BC Fifth Entry Target Address Register */
+
+struct str9x_flash_bank {
+ uint32_t *sector_bits;
+ int variant;
+ int bank1;
+};
+
+enum str9x_status_codes {
+ STR9X_CMD_SUCCESS = 0,
+ STR9X_INVALID_COMMAND = 1,
+ STR9X_SRC_ADDR_ERROR = 2,
+ STR9X_DST_ADDR_ERROR = 3,
+ STR9X_SRC_ADDR_NOT_MAPPED = 4,
+ STR9X_DST_ADDR_NOT_MAPPED = 5,
+ STR9X_COUNT_ERROR = 6,
+ STR9X_INVALID_SECTOR = 7,
+ STR9X_SECTOR_NOT_BLANK = 8,
+ STR9X_SECTOR_NOT_PREPARED = 9,
+ STR9X_COMPARE_ERROR = 10,
+ STR9X_BUSY = 11
+};
+
+static uint32_t bank1start = 0x00080000;
+
+static int str9x_build_block_list(struct flash_bank *bank)
+{
+ struct str9x_flash_bank *str9x_info = bank->driver_priv;
+
+ int i;
+ int num_sectors;
+ int b0_sectors = 0, b1_sectors = 0;
+ uint32_t offset = 0;
+
+ /* set if we have large flash str9 */
+ str9x_info->variant = 0;
+ str9x_info->bank1 = 0;
+
+ switch (bank->size) {
+ case (256 * 1024):
+ b0_sectors = 4;
+ break;
+ case (512 * 1024):
+ b0_sectors = 8;
+ break;
+ case (1024 * 1024):
+ bank1start = 0x00100000;
+ str9x_info->variant = 1;
+ b0_sectors = 16;
+ break;
+ case (2048 * 1024):
+ bank1start = 0x00200000;
+ str9x_info->variant = 1;
+ b0_sectors = 32;
+ break;
+ case (128 * 1024):
+ str9x_info->variant = 1;
+ str9x_info->bank1 = 1;
+ b1_sectors = 8;
+ bank1start = bank->base;
+ break;
+ case (32 * 1024):
+ str9x_info->bank1 = 1;
+ b1_sectors = 4;
+ bank1start = bank->base;
+ 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(struct flash_sector) * num_sectors);
+ str9x_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;
+ str9x_info->sector_bits[num_sectors++] = (1 << i);
+ }
+
+ for (i = 0; i < b1_sectors; i++) {
+ bank->sectors[num_sectors].offset = offset;
+ bank->sectors[num_sectors].size = str9x_info->variant == 0 ? 0x2000 : 0x4000;
+ offset += bank->sectors[i].size;
+ bank->sectors[num_sectors].is_erased = -1;
+ bank->sectors[num_sectors].is_protected = 1;
+ if (str9x_info->variant)
+ str9x_info->sector_bits[num_sectors++] = (1 << i);
+ else
+ str9x_info->sector_bits[num_sectors++] = (1 << (i + 8));
+ }
+
+ return ERROR_OK;
+}
+
+/* flash bank str9x <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(str9x_flash_bank_command)
+{
+ struct str9x_flash_bank *str9x_info;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ str9x_info = malloc(sizeof(struct str9x_flash_bank));
+ bank->driver_priv = str9x_info;
+
+ str9x_build_block_list(bank);
+
+ return ERROR_OK;
+}
+
+static int str9x_protect_check(struct flash_bank *bank)
+{
+ int retval;
+ struct str9x_flash_bank *str9x_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ int i;
+ uint32_t adr;
+ uint32_t status = 0;
+ uint16_t hstatus = 0;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* read level one protection */
+
+ if (str9x_info->variant) {
+ if (str9x_info->bank1) {
+ adr = bank1start + 0x18;
+ retval = target_write_u16(target, adr, 0x90);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_read_u16(target, adr, &hstatus);
+ if (retval != ERROR_OK)
+ return retval;
+ status = hstatus;
+ } else {
+ adr = bank1start + 0x14;
+ retval = target_write_u16(target, adr, 0x90);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_read_u32(target, adr, &status);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ } else {
+ adr = bank1start + 0x10;
+ retval = target_write_u16(target, adr, 0x90);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_read_u16(target, adr, &hstatus);
+ if (retval != ERROR_OK)
+ return retval;
+ status = hstatus;
+ }
+
+ /* read array command */
+ retval = target_write_u16(target, adr, 0xFF);
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (i = 0; i < bank->num_sectors; i++) {
+ if (status & str9x_info->sector_bits[i])
+ bank->sectors[i].is_protected = 1;
+ else
+ bank->sectors[i].is_protected = 0;
+ }
+
+ return ERROR_OK;
+}
+
+static int str9x_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ int i;
+ uint32_t adr;
+ uint8_t status;
+ uint8_t erase_cmd;
+ int total_timeout;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Check if we can erase whole bank */
+ if ((first == 0) && (last == (bank->num_sectors - 1))) {
+ /* Optimize to run erase bank command instead of sector */
+ erase_cmd = 0x80;
+ /* Add timeout duration since erase bank takes more time */
+ total_timeout = 1000 * bank->num_sectors;
+ } else {
+ /* Erase sector command */
+ erase_cmd = 0x20;
+ total_timeout = 1000;
+ }
+
+ /* this is so the compiler can *know* */
+ assert(total_timeout > 0);
+
+ for (i = first; i <= last; i++) {
+ int retval;
+ adr = bank->base + bank->sectors[i].offset;
+
+ /* erase sectors or block */
+ retval = target_write_u16(target, adr, erase_cmd);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_write_u16(target, adr, 0xD0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* get status */
+ retval = target_write_u16(target, adr, 0x70);
+ if (retval != ERROR_OK)
+ return retval;
+
+ int timeout;
+ for (timeout = 0; timeout < total_timeout; timeout++) {
+ retval = target_read_u8(target, adr, &status);
+ if (retval != ERROR_OK)
+ return retval;
+ if (status & 0x80)
+ break;
+ alive_sleep(1);
+ }
+ if (timeout == total_timeout) {
+ LOG_ERROR("erase timed out");
+ return ERROR_FAIL;
+ }
+
+ /* clear status, also clear read array */
+ retval = target_write_u16(target, adr, 0x50);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* read array command */
+ retval = target_write_u16(target, adr, 0xFF);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (status & 0x22) {
+ LOG_ERROR("error erasing flash bank, status: 0x%x", status);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* If we ran erase bank command, we are finished */
+ if (erase_cmd == 0x80)
+ break;
+ }
+
+ for (i = first; i <= last; i++)
+ bank->sectors[i].is_erased = 1;
+
+ return ERROR_OK;
+}
+
+static int str9x_protect(struct flash_bank *bank,
+ int set, int first, int last)
+{
+ struct target *target = bank->target;
+ int i;
+ uint32_t adr;
+ uint8_t status;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ for (i = first; i <= last; i++) {
+ /* Level One Protection */
+
+ adr = bank->base + bank->sectors[i].offset;
+
+ target_write_u16(target, adr, 0x60);
+ if (set)
+ target_write_u16(target, adr, 0x01);
+ else
+ target_write_u16(target, adr, 0xD0);
+
+ /* query status */
+ target_read_u8(target, adr, &status);
+
+ /* clear status, also clear read array */
+ target_write_u16(target, adr, 0x50);
+
+ /* read array command */
+ target_write_u16(target, adr, 0xFF);
+ }
+
+ return ERROR_OK;
+}
+
+static int str9x_write_block(struct flash_bank *bank,
+ const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ uint32_t buffer_size = 32768;
+ struct working_area *write_algorithm;
+ struct working_area *source;
+ uint32_t address = bank->base + offset;
+ struct reg_param reg_params[4];
+ struct arm_algorithm arm_algo;
+ int retval = ERROR_OK;
+
+ /* see contib/loaders/flash/str9x.s for src */
+
+ static const uint32_t str9x_flash_write_code[] = {
+ /* write: */
+ 0xe3c14003, /* bic r4, r1, #3 */
+ 0xe3a03040, /* mov r3, #0x40 */
+ 0xe1c430b0, /* strh r3, [r4, #0] */
+ 0xe0d030b2, /* ldrh r3, [r0], #2 */
+ 0xe0c130b2, /* strh r3, [r1], #2 */
+ 0xe3a03070, /* mov r3, #0x70 */
+ 0xe1c430b0, /* strh r3, [r4, #0] */
+ /* busy: */
+ 0xe5d43000, /* ldrb r3, [r4, #0] */
+ 0xe3130080, /* tst r3, #0x80 */
+ 0x0afffffc, /* beq busy */
+ 0xe3a05050, /* mov r5, #0x50 */
+ 0xe1c450b0, /* strh r5, [r4, #0] */
+ 0xe3a050ff, /* mov r5, #0xFF */
+ 0xe1c450b0, /* strh r5, [r4, #0] */
+ 0xe3130012, /* tst r3, #0x12 */
+ 0x1a000001, /* bne exit */
+ 0xe2522001, /* subs r2, r2, #1 */
+ 0x1affffed, /* bne write */
+ /* exit: */
+ 0xe1200070, /* bkpt #0 */
+ };
+
+ /* flash write code */
+ if (target_alloc_working_area(target, sizeof(str9x_flash_write_code),
+ &write_algorithm) != ERROR_OK) {
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ uint8_t code[sizeof(str9x_flash_write_code)];
+ target_buffer_set_u32_array(target, code, ARRAY_SIZE(str9x_flash_write_code),
+ str9x_flash_write_code);
+ target_write_buffer(target, write_algorithm->address, sizeof(code), code);
+
+ /* memory buffer */
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+ buffer_size /= 2;
+ if (buffer_size <= 256) {
+ /* we already allocated the writing code, but failed to get a
+ * buffer, free the algorithm */
+ target_free_working_area(target, write_algorithm);
+
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+ }
+
+ arm_algo.common_magic = ARM_COMMON_MAGIC;
+ arm_algo.core_mode = ARM_MODE_SVC;
+ arm_algo.core_state = ARM_STATE_ARM;
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(®_params[3], "r3", 32, PARAM_IN);
+
+ while (count > 0) {
+ uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
+
+ target_write_buffer(target, source->address, thisrun_count * 2, buffer);
+
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);
+ buf_set_u32(reg_params[1].value, 0, 32, address);
+ buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
+
+ retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
+ write_algorithm->address,
+ 0, 10000, &arm_algo);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("error executing str9x flash write algorithm");
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ break;
+ }
+
+ if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80) {
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ break;
+ }
+
+ buffer += thisrun_count * 2;
+ address += thisrun_count * 2;
+ count -= thisrun_count;
+ }
+
+ target_free_working_area(target, source);
+ target_free_working_area(target, write_algorithm);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+
+ return retval;
+}
+
+static int str9x_write(struct flash_bank *bank,
+ const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ uint32_t words_remaining = (count / 2);
+ uint32_t bytes_remaining = (count & 0x00000001);
+ uint32_t address = bank->base + offset;
+ uint32_t bytes_written = 0;
+ uint8_t status;
+ int retval;
+ uint32_t check_address = offset;
+ uint32_t bank_adr;
+ int i;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset & 0x1) {
+ LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-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 (check_address != offset + count)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ /* multiple half words (2-byte) to be programmed? */
+ if (words_remaining > 0) {
+ /* try using a block write */
+ retval = str9x_write_block(bank, buffer, offset, words_remaining);
+ if (retval != ERROR_OK) {
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+ /* if block write failed (no sufficient working area),
+ * we use normal (slow) single dword accesses */
+ LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+ } else if (retval == ERROR_FLASH_OPERATION_FAILED) {
+ LOG_ERROR("flash writing failed");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ } else {
+ buffer += words_remaining * 2;
+ address += words_remaining * 2;
+ words_remaining = 0;
+ }
+ }
+
+ while (words_remaining > 0) {
+ bank_adr = address & ~0x03;
+
+ /* write data command */
+ target_write_u16(target, bank_adr, 0x40);
+ target_write_memory(target, address, 2, 1, buffer + bytes_written);
+
+ /* get status command */
+ target_write_u16(target, bank_adr, 0x70);
+
+ int timeout;
+ for (timeout = 0; timeout < 1000; timeout++) {
+ target_read_u8(target, bank_adr, &status);
+ if (status & 0x80)
+ break;
+ alive_sleep(1);
+ }
+ if (timeout == 1000) {
+ LOG_ERROR("write timed out");
+ return ERROR_FAIL;
+ }
+
+ /* clear status reg and read array */
+ target_write_u16(target, bank_adr, 0x50);
+ target_write_u16(target, bank_adr, 0xFF);
+
+ if (status & 0x10)
+ return ERROR_FLASH_OPERATION_FAILED;
+ else if (status & 0x02)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ bytes_written += 2;
+ words_remaining--;
+ address += 2;
+ }
+
+ if (bytes_remaining) {
+ uint8_t last_halfword[2] = {0xff, 0xff};
+
+ /* copy the last remaining bytes into the write buffer */
+ memcpy(last_halfword, buffer+bytes_written, bytes_remaining);
+
+ bank_adr = address & ~0x03;
+
+ /* write data command */
+ target_write_u16(target, bank_adr, 0x40);
+ target_write_memory(target, address, 2, 1, last_halfword);
+
+ /* query status command */
+ target_write_u16(target, bank_adr, 0x70);
+
+ int timeout;
+ for (timeout = 0; timeout < 1000; timeout++) {
+ target_read_u8(target, bank_adr, &status);
+ if (status & 0x80)
+ break;
+ alive_sleep(1);
+ }
+ if (timeout == 1000) {
+ LOG_ERROR("write timed out");
+ return ERROR_FAIL;
+ }
+
+ /* clear status reg and read array */
+ target_write_u16(target, bank_adr, 0x50);
+ target_write_u16(target, bank_adr, 0xFF);
+
+ if (status & 0x10)
+ return ERROR_FLASH_OPERATION_FAILED;
+ else if (status & 0x02)
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+static int str9x_probe(struct flash_bank *bank)
+{
+ return ERROR_OK;
+}
+
+#if 0
+COMMAND_HANDLER(str9x_handle_part_id_command)
+{
+ return ERROR_OK;
+}
+#endif
+
+COMMAND_HANDLER(str9x_handle_flash_config_command)
+{
+ struct target *target = NULL;
+
+ if (CMD_ARGC < 5)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t bbsr, nbbsr, bbadr, nbbadr;
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], bbsr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], nbbsr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], bbadr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], nbbadr);
+
+ target = bank->target;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* config flash controller */
+ target_write_u32(target, FLASH_BBSR, bbsr);
+ target_write_u32(target, FLASH_NBBSR, nbbsr);
+ target_write_u32(target, FLASH_BBADR, bbadr >> 2);
+ target_write_u32(target, FLASH_NBBADR, nbbadr >> 2);
+
+ /* set bit 18 instruction TCM order as per flash programming manual */
+ arm966e_write_cp15(target, 62, 0x40000);
+
+ /* enable flash bank 1 */
+ target_write_u32(target, FLASH_CR, 0x18);
+ return ERROR_OK;
+}
+
+static const struct command_registration str9x_config_command_handlers[] = {
+ {
+ .name = "flash_config",
+ .handler = str9x_handle_flash_config_command,
+ .mode = COMMAND_EXEC,
+ .help = "Configure str9x flash controller, prior to "
+ "programming the flash.",
+ .usage = "bank_id BBSR NBBSR BBADR NBBADR",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration str9x_command_handlers[] = {
+ {
+ .name = "str9x",
+ .mode = COMMAND_ANY,
+ .help = "str9x flash command group",
+ .usage = "",
+ .chain = str9x_config_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver str9x_flash = {
+ .name = "str9x",
+ .commands = str9x_command_handlers,
+ .flash_bank_command = str9x_flash_bank_command,
+ .erase = str9x_erase,
+ .protect = str9x_protect,
+ .write = str9x_write,
+ .read = default_flash_read,
+ .probe = str9x_probe,
+ .auto_probe = str9x_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = str9x_protect_check,
+};
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/e302582d/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9xpec.c
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9xpec.c b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9xpec.c
new file mode 100755
index 0000000..f0af53a
--- /dev/null
+++ b/docs/os/tutorials/downloads/openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4/src/flash/nor/str9xpec.c
@@ -0,0 +1,1212 @@
+/***************************************************************************
+ * 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., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <target/arm7_9_common.h>
+
+/* ISC commands */
+
+#define ISC_IDCODE 0xFE
+#define ISC_MFG_READ 0x4C
+#define ISC_CONFIGURATION 0x07
+#define ISC_ENABLE 0x0C
+#define ISC_DISABLE 0x0F
+#define ISC_NOOP 0x10
+#define ISC_ADDRESS_SHIFT 0x11
+#define ISC_CLR_STATUS 0x13
+#define ISC_PROGRAM 0x20
+#define ISC_PROGRAM_SECURITY 0x22
+#define ISC_PROGRAM_UC 0x23
+#define ISC_ERASE 0x30
+#define ISC_READ 0x50
+#define ISC_BLANK_CHECK 0x60
+
+/* ISC_DEFAULT bit definitions */
+
+#define ISC_STATUS_SECURITY 0x40
+#define ISC_STATUS_INT_ERROR 0x30
+#define ISC_STATUS_MODE 0x08
+#define ISC_STATUS_BUSY 0x04
+#define ISC_STATUS_ERROR 0x03
+
+/* Option bytes definitions */
+
+#define STR9XPEC_OPT_CSMAPBIT 48
+#define STR9XPEC_OPT_LVDTHRESBIT 49
+#define STR9XPEC_OPT_LVDSELBIT 50
+#define STR9XPEC_OPT_LVDWARNBIT 51
+#define STR9XPEC_OPT_OTPBIT 63
+
+enum str9xpec_status_codes {
+ STR9XPEC_INVALID_COMMAND = 1,
+ STR9XPEC_ISC_SUCCESS = 2,
+ STR9XPEC_ISC_DISABLED = 3,
+ STR9XPEC_ISC_INTFAIL = 32,
+};
+
+struct str9xpec_flash_controller {
+ struct jtag_tap *tap;
+ uint32_t *sector_bits;
+ int chain_pos;
+ int isc_enable;
+ uint8_t options[8];
+};
+
+static int str9xpec_erase_area(struct flash_bank *bank, int first, int last);
+static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector);
+static int str9xpec_write_options(struct flash_bank *bank);
+
+static int str9xpec_set_instr(struct jtag_tap *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) {
+ struct scan_field field;
+
+ field.num_bits = tap->ir_length;
+ void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+ field.out_value = t;
+ buf_set_u32(t, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+
+ jtag_add_ir_scan(tap, &field, end_state);
+
+ free(t);
+ }
+
+ return ERROR_OK;
+}
+
+static uint8_t str9xpec_isc_status(struct jtag_tap *tap)
+{
+ struct scan_field field;
+ uint8_t status;
+
+ if (str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE) != ERROR_OK)
+ return ISC_STATUS_ERROR;
+
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = &status;
+
+
+ jtag_add_dr_scan(tap, 1, &field, 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 *bank)
+{
+ uint8_t status;
+ struct jtag_tap *tap;
+ struct str9xpec_flash_controller *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 *bank)
+{
+ uint8_t status;
+ struct jtag_tap *tap;
+ struct str9xpec_flash_controller *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 *bank)
+{
+ struct scan_field field;
+ uint8_t status;
+ struct jtag_tap *tap;
+
+ struct str9xpec_flash_controller *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.num_bits = 64;
+ field.out_value = NULL;
+ field.in_value = str9xpec_info->options;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_execute_queue();
+
+ status = str9xpec_isc_status(tap);
+
+ return status;
+}
+
+static int str9xpec_build_block_list(struct flash_bank *bank)
+{
+ struct str9xpec_flash_controller *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(struct flash_sector) * 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#>
+ */
+FLASH_BANK_COMMAND_HANDLER(str9xpec_flash_bank_command)
+{
+ struct str9xpec_flash_controller *str9xpec_info;
+ struct arm *arm = NULL;
+ struct arm7_9_common *arm7_9 = NULL;
+ struct arm_jtag *jtag_info = NULL;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ str9xpec_info = malloc(sizeof(struct str9xpec_flash_controller));
+ 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 ...
+ */
+ arm = bank->target->arch_info;
+ arm7_9 = arm->arch_info;
+ jtag_info = &arm7_9->jtag_info;
+
+ /* The core is the next tap after the flash controller in the chain */
+ str9xpec_info->tap = jtag_tap_by_position(jtag_info->tap->abs_chain_position - 1);
+ 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 *bank, int first, int last)
+{
+ struct scan_field field;
+ uint8_t status;
+ struct jtag_tap *tap;
+ int i;
+ uint8_t *buffer = NULL;
+
+ struct str9xpec_flash_controller *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(DIV_ROUND_UP(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.num_bits = 64;
+ field.out_value = buffer;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_sleep(40000);
+
+ /* read blank check result */
+ field.num_bits = 64;
+ field.out_value = NULL;
+ field.in_value = buffer;
+
+ jtag_add_dr_scan(tap, 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 *bank)
+{
+ uint8_t status;
+ int i;
+
+ struct str9xpec_flash_controller *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 *bank, int first, int last)
+{
+ struct scan_field field;
+ uint8_t status;
+ struct jtag_tap *tap;
+ int i;
+ uint8_t *buffer = NULL;
+
+ struct str9xpec_flash_controller *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(DIV_ROUND_UP(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.num_bits = 64;
+ field.out_value = buffer;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(tap, 1, &field, 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 *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 *bank)
+{
+ struct scan_field field;
+ uint8_t status;
+ struct jtag_tap *tap;
+ struct str9xpec_flash_controller *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.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = &status;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_execute_queue();
+
+ } while (!(status & ISC_STATUS_BUSY));
+
+ str9xpec_isc_disable(bank);
+
+ return status;
+}
+
+static int str9xpec_unlock_device(struct flash_bank *bank)
+{
+ uint8_t status;
+
+ status = str9xpec_erase_area(bank, 0, 255);
+
+ return status;
+}
+
+static int str9xpec_protect(struct flash_bank *bank, int set, int first, int last)
+{
+ uint8_t status;
+ int i;
+
+ struct str9xpec_flash_controller *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 *bank, uint8_t sector)
+{
+ struct jtag_tap *tap;
+ struct scan_field field;
+ struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
+
+ tap = str9xpec_info->tap;
+
+ /* set flash controller address */
+ str9xpec_set_instr(tap, ISC_ADDRESS_SHIFT, TAP_IRPAUSE);
+
+ field.num_bits = 8;
+ field.out_value = §or;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE);
+
+ return ERROR_OK;
+}
+
+static int str9xpec_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct str9xpec_flash_controller *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;
+ struct jtag_tap *tap;
+ struct scan_field 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(DIV_ROUND_UP(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.num_bits = 64;
+ field.out_value = (buffer + bytes_written);
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+
+ /* small delay before polling */
+ jtag_add_sleep(50);
+
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+ do {
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = scanbuf;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE);
+ 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};
+
+ /* copy the last remaining bytes into the write buffer */
+ memcpy(last_dword, buffer+bytes_written, bytes_remaining);
+
+ str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE);
+
+ field.num_bits = 64;
+ field.out_value = last_dword;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+
+ /* small delay before polling */
+ jtag_add_sleep(50);
+
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+ do {
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = scanbuf;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE);
+ 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 *bank)
+{
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_part_id_command)
+{
+ struct scan_field field;
+ uint8_t *buffer = NULL;
+ struct jtag_tap *tap;
+ uint32_t idcode;
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+ tap = str9xpec_info->tap;
+
+ buffer = calloc(DIV_ROUND_UP(32, 8), 1);
+
+ str9xpec_set_instr(tap, ISC_IDCODE, TAP_IRPAUSE);
+
+ field.num_bits = 32;
+ field.out_value = NULL;
+ field.in_value = buffer;
+
+ jtag_add_dr_scan(tap, 1, &field, 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 *bank)
+{
+ return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_read_command)
+{
+ uint8_t status;
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 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 *bank)
+{
+ struct scan_field field;
+ uint8_t status;
+ struct jtag_tap *tap;
+ struct str9xpec_flash_controller *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.num_bits = 64;
+ field.out_value = str9xpec_info->options;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+
+ /* small delay before polling */
+ jtag_add_sleep(50);
+
+ str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE);
+
+ do {
+ field.num_bits = 8;
+ field.out_value = NULL;
+ field.in_value = &status;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE);
+ 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 (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 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;
+
+ command_print(CMD_CTX, "str9xpec write options complete.\n"
+ "INFO: a reset or power cycle is required "
+ "for the new settings to take effect.");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_options_cmap_command)
+{
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(CMD_ARGV[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)
+{
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(CMD_ARGV[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)
+{
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(CMD_ARGV[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)
+{
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ if (strcmp(CMD_ARGV[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 (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 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 (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 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;
+
+ command_print(CMD_CTX, "str9xpec unlocked.\n"
+ "INFO: a reset or power cycle is required "
+ "for the new settings to take effect.");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(str9xpec_handle_flash_enable_turbo_command)
+{
+ struct jtag_tap *tap0;
+ struct jtag_tap *tap1;
+ struct jtag_tap *tap2;
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ str9xpec_info = bank->driver_priv;
+
+ /* remove arm core from chain - enter turbo mode */
+ tap0 = str9xpec_info->tap;
+ if (tap0 == NULL) {
+ /* things are *WRONG* */
+ command_print(CMD_CTX, "**STR9FLASH** (tap0) invalid chain?");
+ return ERROR_FAIL;
+ }
+ tap1 = tap0->next_tap;
+ if (tap1 == NULL) {
+ /* things are *WRONG* */
+ command_print(CMD_CTX, "**STR9FLASH** (tap1) invalid chain?");
+ return ERROR_FAIL;
+ }
+ tap2 = tap1->next_tap;
+ if (tap2 == NULL) {
+ /* things are *WRONG* */
+ command_print(CMD_CTX, "**STR9FLASH** (tap2) invalid chain?");
+ return ERROR_FAIL;
+ }
+
+ /* enable turbo mode - TURBO-PROG-ENABLE */
+ str9xpec_set_instr(tap2, 0xD, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != 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)
+{
+ struct jtag_tap *tap;
+ struct str9xpec_flash_controller *str9xpec_info = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 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 const struct command_registration str9xpec_config_command_handlers[] = {
+ {
+ .name = "enable_turbo",
+ .usage = "<bank>",
+ .handler = str9xpec_handle_flash_enable_turbo_command,
+ .mode = COMMAND_EXEC,
+ .help = "enable str9xpec turbo mode",
+ },
+ {
+ .name = "disable_turbo",
+ .usage = "<bank>",
+ .handler = str9xpec_handle_flash_disable_turbo_command,
+ .mode = COMMAND_EXEC,
+ .help = "disable str9xpec turbo mode",
+ },
+ {
+ .name = "options_cmap",
+ .usage = "<bank> <bank0 | bank1>",
+ .handler = str9xpec_handle_flash_options_cmap_command,
+ .mode = COMMAND_EXEC,
+ .help = "configure str9xpec boot sector",
+ },
+ {
+ .name = "options_lvdthd",
+ .usage = "<bank> <2.4v | 2.7v>",
+ .handler = str9xpec_handle_flash_options_lvdthd_command,
+ .mode = COMMAND_EXEC,
+ .help = "configure str9xpec lvd threshold",
+ },
+ {
+ .name = "options_lvdsel",
+ .usage = "<bank> <vdd | vdd_vddq>",
+ .handler = str9xpec_handle_flash_options_lvdsel_command,
+ .mode = COMMAND_EXEC,
+ .help = "configure str9xpec lvd selection",
+ },
+ {
+ .name = "options_lvdwarn",
+ .usage = "<bank> <vdd | vdd_vddq>",
+ .handler = str9xpec_handle_flash_options_lvdwarn_command,
+ .mode = COMMAND_EXEC,
+ .help = "configure str9xpec lvd warning",
+ },
+ {
+ .name = "options_read",
+ .usage = "<bank>",
+ .handler = str9xpec_handle_flash_options_read_command,
+ .mode = COMMAND_EXEC,
+ .help = "read str9xpec options",
+ },
+ {
+ .name = "options_write",
+ .usage = "<bank>",
+ .handler = str9xpec_handle_flash_options_write_command,
+ .mode = COMMAND_EXEC,
+ .help = "write str9xpec options",
+ },
+ {
+ .name = "lock",
+ .usage = "<bank>",
+ .handler = str9xpec_handle_flash_lock_command,
+ .mode = COMMAND_EXEC,
+ .help = "lock str9xpec device",
+ },
+ {
+ .name = "unlock",
+ .usage = "<bank>",
+ .handler = str9xpec_handle_flash_unlock_command,
+ .mode = COMMAND_EXEC,
+ .help = "unlock str9xpec device",
+ },
+ {
+ .name = "part_id",
+ .handler = str9xpec_handle_part_id_command,
+ .mode = COMMAND_EXEC,
+ .help = "print part id of str9xpec flash bank <num>",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration str9xpec_command_handlers[] = {
+ {
+ .name = "str9xpec",
+ .mode = COMMAND_ANY,
+ .help = "str9xpec flash command group",
+ .usage = "",
+ .chain = str9xpec_config_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver str9xpec_flash = {
+ .name = "str9xpec",
+ .commands = str9xpec_command_handlers,
+ .flash_bank_command = str9xpec_flash_bank_command,
+ .erase = str9xpec_erase,
+ .protect = str9xpec_protect,
+ .write = str9xpec_write,
+ .read = default_flash_read,
+ .probe = str9xpec_probe,
+ .auto_probe = str9xpec_probe,
+ .erase_check = str9xpec_erase_check,
+ .protect_check = str9xpec_protect_check,
+};