From e78b33e3ca2fe05e82f974fcd6e745dbcfa6ca37 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 10 May 2017 14:31:18 +0000 Subject: [PATCH 01/54] telnet_server: drop unused options They're never used, so just drop them. Change-Id: Ie137deed3e7258f9d6af7e0cb508e73df0f53ee0 Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/4131 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/server/telnet_server.c | 1 - src/server/telnet_server.h | 3 --- src/target/openrisc/jsp_server.c | 1 - 3 files changed, 5 deletions(-) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index e33188b5e..7507afea8 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -222,7 +222,6 @@ static int telnet_new_connection(struct connection *connection) telnet_connection->closed = 0; telnet_connection->line_size = 0; telnet_connection->line_cursor = 0; - telnet_connection->option_size = 0; telnet_connection->prompt = strdup("> "); telnet_connection->state = TELNET_STATE_DATA; diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index 04ba96570..e43d6bcf8 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -29,7 +29,6 @@ #define TELNET_BUFFER_SIZE (1024) -#define TELNET_OPTION_MAX_SIZE (128) #define TELNET_LINE_HISTORY_SIZE (128) #define TELNET_LINE_MAX_SIZE (256) @@ -51,8 +50,6 @@ struct telnet_connection { char line[TELNET_LINE_MAX_SIZE]; int line_size; int line_cursor; - char option[TELNET_OPTION_MAX_SIZE]; - int option_size; char last_escape; char *history[TELNET_LINE_HISTORY_SIZE]; int next_history; diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index e581fb870..2d90114fa 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -88,7 +88,6 @@ static int jsp_new_connection(struct connection *connection) telnet_connection->closed = 0; telnet_connection->line_size = 0; telnet_connection->line_cursor = 0; - telnet_connection->option_size = 0; telnet_connection->state = TELNET_STATE_DATA; /* negotiate telnet options */ From bf5258d8761c93e4101aa933b90344d854868ff1 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 10 May 2017 14:37:51 +0000 Subject: [PATCH 02/54] telnet_server: increase buffer sizes to allow longer commands. A common use case seen in the wild is echoing a string of commands to an existing openocd instance via netcat. The sequence of ; separated commands can easily run over the line limit of only 256 chars. Increasing this dramatically reduces surprises, at the expense of a tiny amount of extra ram usage. Change-Id: I2389d99d316a96b5fa03f0894b43c412308e12c4 Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/4132 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/server/telnet_server.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index e43d6bcf8..f8fb82689 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -27,10 +27,10 @@ #include -#define TELNET_BUFFER_SIZE (1024) +#define TELNET_BUFFER_SIZE (10*1024) #define TELNET_LINE_HISTORY_SIZE (128) -#define TELNET_LINE_MAX_SIZE (256) +#define TELNET_LINE_MAX_SIZE (10*256) enum telnet_states { TELNET_STATE_DATA, From 83772f32ad0f46d9c21485178c112cc832449a3c Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sun, 11 Jun 2017 16:18:27 +0300 Subject: [PATCH 03/54] configure: bring back all default JimTcl extensions This partially reverts commit 56d163ce79510c7756567df00ae54155757eaa0f. That change certainly caused more pain than gain. Change-Id: Ifb126abd1e6b89d29db8bf6a7b8af5dfc815c163 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4159 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Spencer Oliver --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c680bda7a..56109b103 100644 --- a/configure.ac +++ b/configure.ac @@ -571,7 +571,7 @@ AS_IF([test "x$build_buspirate" = "xyes"], [ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [ - AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim --with-ext="eventloop array clock regexp stdlib tclcompat" --without-ext="default"]) + AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim]) ], [ AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.]) ]) From 1ab0303dbc6d00f8fd0036170dd7a10b32fc8713 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 21 Aug 2017 20:56:43 +0200 Subject: [PATCH 04/54] helper/options: Add missing #include for MinGW and MSYS2 Change-Id: I3bb295f52706b641661241e3e047306811ca915e Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4201 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/helper/options.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/helper/options.c b/src/helper/options.c index 1cfa55376..12755e010 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -37,6 +37,9 @@ #ifdef HAVE_SYS_SYSCTL_H #include #endif +#if IS_WIN32 && !IS_CYGWIN +#include +#endif static int help_flag, version_flag; From 4dc09d98d0cab5feb189667b189832d5ce519cba Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 28 Jul 2017 17:34:07 +0200 Subject: [PATCH 05/54] libjaylink: Update to latest Git version Update to latest Git version and bump required libjaylink package version to 0.2.0. This version introduces support for devices with TCP/IP interface (e.g. SEGGER Flasher ARM) and an additional debug level for I/O messages. Change-Id: I030236aa704a91d1bb1843dd30010865947747e0 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4202 Tested-by: jenkins Reviewed-by: Spencer Oliver --- configure.ac | 2 +- src/jtag/drivers/libjaylink | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 56109b103..fd06a0b3f 100644 --- a/configure.ac +++ b/configure.ac @@ -628,7 +628,7 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [use_libftdi=yes], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.1], +PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) m4_define([PROCESS_ADAPTERS], [ diff --git a/src/jtag/drivers/libjaylink b/src/jtag/drivers/libjaylink index 699b7001d..8645845c1 160000 --- a/src/jtag/drivers/libjaylink +++ b/src/jtag/drivers/libjaylink @@ -1 +1 @@ -Subproject commit 699b7001d34a79c8e7064503dde1bede786fd7f0 +Subproject commit 8645845c1abebd004e991ba9a7f808f4fd0c608b From ba24c1fc05c8bb244abab513b880c7e9ec50ea73 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Wed, 26 Jul 2017 23:51:22 +0200 Subject: [PATCH 06/54] jlink: Make use of debug level for I/O messages Change-Id: Iba08c119a80041f9c1b4c9bd7e83bb4f9bbb7199 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4203 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index bd3c5e03c..c05141a1e 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -523,6 +523,9 @@ static int jaylink_log_handler(const struct jaylink_context *ctx, case JAYLINK_LOG_LEVEL_DEBUG: tmp = LOG_LVL_DEBUG; break; + case JAYLINK_LOG_LEVEL_DEBUG_IO: + tmp = LOG_LVL_DEBUG_IO; + break; default: tmp = LOG_LVL_WARNING; } From 7d8d2654e6168a56a8e5e53aa4a8b64a66576c55 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 20 May 2017 14:34:21 +0200 Subject: [PATCH 07/54] jlink: Make libusb optional libusb is now optional for libjaylink because support for TCP/IP devices is always available. Change-Id: I03f2566f8e1703276671ac0f353f72394d21f2f0 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4204 Tested-by: jenkins Reviewed-by: Spencer Oliver --- configure.ac | 2 +- src/jtag/drivers/jlink.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index fd06a0b3f..562ec5a7c 100644 --- a/configure.ac +++ b/configure.ac @@ -655,7 +655,7 @@ PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) -PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_libusb1" = "xyes" -a "x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libusb-1.x or libjaylink-0.1]) +PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.1]) AS_IF([test "x$build_openjtag" = "xyes"], [ AS_IF([test "x$use_libusb1" != "xyes" -a "x$use_libusb0" != "xyes"], [ diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index c05141a1e..893d43ec4 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -551,6 +551,11 @@ static int jlink_init(void) LOG_DEBUG("Using libjaylink %s (compiled with %s).", jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); + if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) { + LOG_ERROR("J-Link driver does not support USB devices."); + return ERROR_JTAG_INIT_FAILED; + } + ret = jaylink_init(&jayctx); if (ret != JAYLINK_OK) { @@ -610,7 +615,9 @@ static int jlink_init(void) if (use_usb_address) { ret = jaylink_device_get_usb_address(devs[i], &address); - if (ret != JAYLINK_OK) { + if (ret == JAYLINK_ERR_NOT_SUPPORTED) { + continue; + } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_usb_address() failed: %s.", jaylink_strerror_name(ret)); continue; From f981730fe76c1b8341f84f2ab004bedc0082f99e Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 2 Sep 2017 09:50:44 +0200 Subject: [PATCH 08/54] jlink: Use error description in log messages Use a human-readable error description rather than just the error name in log messages. Change-Id: Iab4ff7a7e4d9993983a07eab9f462820d4ee8190 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4212 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 77 ++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 893d43ec4..955adf8aa 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -322,7 +322,7 @@ static int jlink_speed(int speed) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_speeds() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } @@ -349,7 +349,7 @@ static int jlink_speed(int speed) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_set_speed() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } @@ -378,7 +378,7 @@ static bool read_device_config(struct device_config *cfg) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_read_raw_config() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return false; } @@ -409,7 +409,7 @@ static int select_interface(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_available_interfaces() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } @@ -422,7 +422,7 @@ static int select_interface(void) if (ret < 0) { LOG_ERROR("jaylink_select_interface() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } @@ -442,8 +442,7 @@ static int jlink_register(void) ret = jaylink_register(devh, &conn, connlist, &count); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_register() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_register() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -482,7 +481,7 @@ static bool adjust_swd_buffer_size(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return false; } @@ -559,8 +558,7 @@ static int jlink_init(void) ret = jaylink_init(&jayctx); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_init() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_init() failed: %s.", jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } @@ -568,7 +566,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_log_set_callback() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } @@ -577,7 +575,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_discovery_scan() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } @@ -585,8 +583,7 @@ static int jlink_init(void) ret = jaylink_get_devices(jayctx, &devs, NULL); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_devices() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } @@ -604,7 +601,7 @@ static int jlink_init(void) continue; } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_serial_number() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); continue; } @@ -619,7 +616,7 @@ static int jlink_init(void) continue; } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_usb_address() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); continue; } @@ -634,7 +631,7 @@ static int jlink_init(void) break; } - LOG_ERROR("Failed to open device: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("Failed to open device: %s.", jaylink_strerror(ret)); } jaylink_free_devices(devs, true); @@ -654,7 +651,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_firmware_version() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -669,7 +666,7 @@ static int jlink_init(void) ret = jaylink_get_caps(devh, caps); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -680,7 +677,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_extended_caps() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -694,7 +691,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("Failed to retrieve hardware version: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -735,7 +732,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_hardware_status() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -796,8 +793,7 @@ static int jlink_quit(void) ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) - LOG_ERROR("jaylink_swo_stop() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret)); } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) { @@ -805,7 +801,7 @@ static int jlink_quit(void) if (ret != JAYLINK_OK) LOG_ERROR("jaylink_unregister() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); } jaylink_close(devh); @@ -954,7 +950,7 @@ COMMAND_HANDLER(jlink_serial_command) return ERROR_FAIL; } else if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_parse_serial_number() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -973,7 +969,7 @@ COMMAND_HANDLER(jlink_handle_hwstatus_command) if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_get_hardware_status() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1005,7 +1001,7 @@ COMMAND_HANDLER(jlink_handle_free_memory_command) if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_get_free_memory() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1087,7 +1083,7 @@ COMMAND_HANDLER(jlink_handle_target_power_command) if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_set_target_power() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1193,7 +1189,7 @@ static int poll_trace(uint8_t *buf, size_t *size) ret = jaylink_swo_read(devh, buf, &length); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1214,7 +1210,7 @@ static uint32_t calculate_trace_buffer_size(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1278,7 +1274,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1304,7 +1300,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_swo_get_speeds() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1320,8 +1316,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, buffer_size); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_start_swo() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_start_swo() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1580,7 +1575,7 @@ COMMAND_HANDLER(jlink_handle_config_write_command) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_write_raw_config() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1665,8 +1660,7 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command) LOG_ERROR("Channel not supported by the device."); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to write to channel: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("Failed to write to channel: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1714,8 +1708,7 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command) free(buf); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to read from channel: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("Failed to read from channel: %s.", jaylink_strerror(ret)); free(buf); return ERROR_FAIL; } @@ -1982,7 +1975,7 @@ static int jlink_flush(void) tap_length, jtag_command_version); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror(ret)); jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } @@ -2088,7 +2081,7 @@ static int jlink_swd_run_queue(void) ret = jaylink_swd_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror(ret)); goto skip; } From 98e63cdc86243cf91fc0da56479acef240313d19 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 2 Sep 2017 10:10:00 +0200 Subject: [PATCH 09/54] jlink: Disable automatic device selection If multiple devices are attached, do not automatically use the first device found. Otherwise, a user may unintentionally operate on the wrong device. Change-Id: I08c4110b82e911e9e3e744d41830ffc6c56c44bf Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4213 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 955adf8aa..ac6e997ef 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -546,6 +546,7 @@ static int jlink_init(void) struct jaylink_hardware_status hwstatus; enum jaylink_usb_address address; size_t length; + size_t num_devices; LOG_DEBUG("Using libjaylink %s (compiled with %s).", jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); @@ -580,7 +581,7 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - ret = jaylink_get_devices(jayctx, &devs, NULL); + ret = jaylink_get_devices(jayctx, &devs, &num_devices); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret)); @@ -588,10 +589,14 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - found_device = false; + if (!use_serial_number && !use_usb_address && num_devices > 1) { + LOG_ERROR("Multiple devices found, specify the desired device."); + jaylink_free_devices(devs, true); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } - if (!use_serial_number && !use_usb_address) - LOG_INFO("No device selected, using first device."); + found_device = false; for (i = 0; devs[i]; i++) { if (use_serial_number) { From b0dcff5e345cf255d0ccdc5b473dff408af4b5ed Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 2 Sep 2017 10:16:41 +0200 Subject: [PATCH 10/54] jlink: Disable TCP/IP discovery If no serial number is specified, disable TCP/IP device discovery to ensure that a user does not unintentionally operate on a remote device. Change-Id: I6a7e913b8b679fae003825468cd86d2014849b29 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4214 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index ac6e997ef..132ef06e9 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -547,6 +547,7 @@ static int jlink_init(void) enum jaylink_usb_address address; size_t length; size_t num_devices; + uint32_t host_interfaces; LOG_DEBUG("Using libjaylink %s (compiled with %s).", jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); @@ -572,7 +573,12 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - ret = jaylink_discovery_scan(jayctx, 0); + host_interfaces = JAYLINK_HIF_USB; + + if (use_serial_number) + host_interfaces |= JAYLINK_HIF_TCP; + + ret = jaylink_discovery_scan(jayctx, host_interfaces); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_discovery_scan() failed: %s.", From 18a94a1a8a37c38fda98aceae39e652f9df9bdd9 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 9 Jun 2016 09:23:10 -0700 Subject: [PATCH 11/54] Fix typo in comment. Change-Id: I6567f85f399315e1dac98881765dfaa6eab5facb Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4238 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/helper/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/log.c b/src/helper/log.c index 49b9bd98f..c8a3a6c55 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -104,7 +104,7 @@ static void log_forward(const char *file, unsigned line, const char *function, c } } -/* The log_puts() serves to somewhat different goals: +/* The log_puts() serves two somewhat different goals: * * - logging * - feeding low-level info to the user in GDB or Telnet From 5fd8eaadf919f867b95682373d8e60da417f4556 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 24 Aug 2017 17:42:28 +0200 Subject: [PATCH 12/54] stm32f2x: Fix left shift of negative value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use unsigned constant for left shift operation in order to avoid the following error with GCC >= 6.0: ../src/flash/nor/stm32f2x.c: In function ‘stm32x_handle_unlock_command’: ../src/flash/nor/stm32f2x.c:1324:67: error: left shift of negative value [-Werror=shift-negative-value] stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1 << bank->num_sectors); Change-Id: I0ac082bd0dbb8dc2f61ffff8fdf486ab7962d2e0 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4207 Tested-by: jenkins Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver Reviewed-by: Anton Fosselius Reviewed-by: Esben Haabendal --- src/flash/nor/stm32f2x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 0e4abb533..65cb212b6 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1321,7 +1321,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) * this will also force a device unlock if set */ stm32x_info->option_bytes.RDP = 0xAA; if (stm32x_info->has_optcr2_pcrop) { - stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1 << bank->num_sectors); + stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1U << bank->num_sectors); } if (stm32x_write_options(bank) != ERROR_OK) { From e8b6aaa8e59208aea6cead31760895d67c1226ee Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Fri, 11 Aug 2017 13:17:03 -0300 Subject: [PATCH 13/54] Add missing break MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ie1de679fe6ab5ace05fc3e156c71f34b296b3d3b Signed-off-by: Fabio Utzig Reviewed-on: http://openocd.zylin.com/4200 Tested-by: jenkins Reviewed-by: Andreas Färber Reviewed-by: Spencer Oliver Reviewed-by: Esben Haabendal --- src/target/armv7a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/armv7a.c b/src/target/armv7a.c index 6021def4e..db72afd21 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -355,7 +355,7 @@ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, break; case 7: LOG_INFO("inner: Write-Back, no Write-Allocate"); - + break; default: LOG_INFO("inner: %" PRIx32 " ???", INNER); } From f95f8b70fbd0f7e9c91a2d9006b1abb2dd07ebf2 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Sun, 27 Aug 2017 19:12:21 +0100 Subject: [PATCH 14/54] tcl/interface/ftdi/sheevaplug: Fix FTDI channel configuration The migration from the old ft2232 driver to the new generic ftdi driver ended up breaking support for the SheevaPlug device. The old driver defaulted to channel 1, but numbered the channels 1 to 4. The new driver starts at 0. The SheevaPlug JTAG is on interface A (interface B is the serial console), so it should be using channel 0. Fix this. Confirmed as working; serial console remains available and a new u-boot image can be transferred across using the JTAG link. See also Debian Bug#837989; https://bugs.debian.org/837989 Change-Id: I4ac2bfeb0d1e7e99d70fa47dc55f186e6af2c542 Signed-off-by: Jonathan McDowell Reviewed-on: http://openocd.zylin.com/4206 Reviewed-by: Paul Fertser Tested-by: jenkins --- tcl/interface/ftdi/sheevaplug.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/interface/ftdi/sheevaplug.cfg b/tcl/interface/ftdi/sheevaplug.cfg index f299f27a9..625aad398 100644 --- a/tcl/interface/ftdi/sheevaplug.cfg +++ b/tcl/interface/ftdi/sheevaplug.cfg @@ -7,7 +7,7 @@ interface ftdi ftdi_device_desc "SheevaPlug JTAGKey FT2232D B" ftdi_vid_pid 0x9e88 0x9e8f -ftdi_channel 1 +ftdi_channel 0 ftdi_layout_init 0x0608 0x0f1b ftdi_layout_signal nTRST -data 0x0200 From 10a3b24daf379162caf84fe757f849d7ba48c379 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Wed, 1 Mar 2017 11:32:07 +0100 Subject: [PATCH 15/54] flash: efm32: add support for EFR-familty (e.g. bluegecko) This patch adds support for Blue Gecko and Mighty Gecko chips from Silabs. They have different EFM32_MSC_REGBASE and LOCK register offset. Based on the original patch from Andreas Kemnade. Change-Id: I166c14960ced7c880b68083badd1b31372fefabe Cc: Andreas Kemnade Signed-off-by: Andrea Merello Reviewed-on: http://openocd.zylin.com/4034 Reviewed-by: Jonas Norling Tested-by: jenkins Reviewed-by: Fredrik Hederstierna Reviewed-by: Spencer Oliver Reviewed-by: chrysn --- contrib/loaders/flash/efm32.S | 4 -- src/flash/nor/efm32.c | 99 +++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 32 deletions(-) diff --git a/contrib/loaders/flash/efm32.S b/contrib/loaders/flash/efm32.S index 25d63010a..c5de55c27 100644 --- a/contrib/loaders/flash/efm32.S +++ b/contrib/loaders/flash/efm32.S @@ -44,11 +44,7 @@ #define EFM32_MSC_ADDRB_OFFSET 0x010 #define EFM32_MSC_WDATA_OFFSET 0x018 #define EFM32_MSC_STATUS_OFFSET 0x01c -#define EFM32_MSC_LOCK_OFFSET 0x03c - /* unlock MSC */ - ldr r6, =#0x1b71 - str r6, [r0, #EFM32_MSC_LOCK_OFFSET] /* set WREN to 1 */ movs r6, #1 str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 117cd8a1b..b8453e1dd 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -49,6 +49,8 @@ #define EZR_FAMILY_ID_WONDER_GECKO 120 #define EZR_FAMILY_ID_LEOPARD_GECKO 121 #define EZR_FAMILY_ID_HAPPY_GECKO 122 +#define EFR_FAMILY_ID_MIGHTY_GECKO 16 +#define EFR_FAMILY_ID_BLUE_GECKO 20 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 @@ -72,27 +74,31 @@ #define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) #define EFM32_MSC_REGBASE 0x400c0000 -#define EFM32_MSC_WRITECTRL (EFM32_MSC_REGBASE+0x008) +#define EFR32_MSC_REGBASE 0x400e0000 +#define EFM32_MSC_REG_WRITECTRL 0x008 #define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 -#define EFM32_MSC_WRITECMD (EFM32_MSC_REGBASE+0x00c) +#define EFM32_MSC_REG_WRITECMD 0x00c #define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1 #define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2 #define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8 -#define EFM32_MSC_ADDRB (EFM32_MSC_REGBASE+0x010) -#define EFM32_MSC_WDATA (EFM32_MSC_REGBASE+0x018) -#define EFM32_MSC_STATUS (EFM32_MSC_REGBASE+0x01c) +#define EFM32_MSC_REG_ADDRB 0x010 +#define EFM32_MSC_REG_WDATA 0x018 +#define EFM32_MSC_REG_STATUS 0x01c #define EFM32_MSC_STATUS_BUSY_MASK 0x1 #define EFM32_MSC_STATUS_LOCKED_MASK 0x2 #define EFM32_MSC_STATUS_INVADDR_MASK 0x4 #define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8 #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 -#define EFM32_MSC_LOCK (EFM32_MSC_REGBASE+0x03c) +#define EFM32_MSC_REG_LOCK 0x03c +#define EFR32_MSC_REG_LOCK 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 struct efm32x_flash_bank { int probed; uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; + uint32_t reg_base; + uint32_t reg_lock; }; struct efm32_info { @@ -132,11 +138,30 @@ static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev); } +static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t *value) +{ + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + uint32_t base = efm32x_info->reg_base; + + return target_read_u32(bank->target, base + offset, value); +} + +static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t value) +{ + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + uint32_t base = efm32x_info->reg_base; + + return target_write_u32(bank->target, base + offset, value); +} + static int efm32x_read_info(struct flash_bank *bank, struct efm32_info *efm32_info) { int ret; uint32_t cpuid = 0; + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; memset(efm32_info, 0, sizeof(struct efm32_info)); @@ -175,6 +200,15 @@ static int efm32x_read_info(struct flash_bank *bank, if (ERROR_OK != ret) return ret; + if (EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { + efm32x_info->reg_base = EFR32_MSC_REGBASE; + efm32x_info->reg_lock = EFR32_MSC_REG_LOCK; + } else { + efm32x_info->reg_base = EFM32_MSC_REGBASE; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + } + if (EFM_FAMILY_ID_GECKO == efm32_info->part_family || EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family) efm32_info->page_size = 512; @@ -208,7 +242,9 @@ static int efm32x_read_info(struct flash_bank *bank, } } else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) { + EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); @@ -241,6 +277,10 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "EZR32 "); break; + case EFR_FAMILY_ID_MIGHTY_GECKO: + case EFR_FAMILY_ID_BLUE_GECKO: + printed = snprintf(buf, buf_size, "EFR32 "); + break; default: printed = snprintf(buf, buf_size, "EFM32 "); } @@ -276,6 +316,12 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "Happy Gecko"); break; + case EFR_FAMILY_ID_BLUE_GECKO: + printed = snprintf(buf, buf_size, "Blue Gecko"); + break; + case EFR_FAMILY_ID_MIGHTY_GECKO: + printed = snprintf(buf, buf_size, "Mighty Gecko"); + break; } buf += printed; @@ -319,7 +365,7 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, int ret = 0; uint32_t reg_val = 0; - ret = target_read_u32(bank->target, reg, ®_val); + ret = efm32x_read_reg_u32(bank, reg, ®_val); if (ERROR_OK != ret) return ret; @@ -328,18 +374,19 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, else reg_val &= ~bitmask; - return target_write_u32(bank->target, reg, reg_val); + return efm32x_write_reg_u32(bank, reg, reg_val); } static int efm32x_set_wren(struct flash_bank *bank, int write_enable) { - return efm32x_set_reg_bits(bank, EFM32_MSC_WRITECTRL, + return efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECTRL, EFM32_MSC_WRITECTRL_WREN_MASK, write_enable); } static int efm32x_msc_lock(struct flash_bank *bank, int lock) { - return target_write_u32(bank->target, EFM32_MSC_LOCK, + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + return efm32x_write_reg_u32(bank, efm32x_info->reg_lock, (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY)); } @@ -350,7 +397,7 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout, uint32_t status = 0; while (1) { - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) break; @@ -389,16 +436,16 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); - ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ERROR_OK != ret) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) return ret; @@ -412,7 +459,7 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) return ERROR_FAIL; } - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); if (ERROR_OK != ret) return ret; @@ -589,6 +636,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; int ret = ERROR_OK; /* see contrib/loaders/flash/efm32.S for src */ @@ -598,10 +646,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, /* #define EFM32_MSC_ADDRB_OFFSET 0x010 */ /* #define EFM32_MSC_WDATA_OFFSET 0x018 */ /* #define EFM32_MSC_STATUS_OFFSET 0x01c */ - /* #define EFM32_MSC_LOCK_OFFSET 0x03c */ - 0x15, 0x4e, /* ldr r6, =#0x1b71 */ - 0xc6, 0x63, /* str r6, [r0, #EFM32_MSC_LOCK_OFFSET] */ 0x01, 0x26, /* movs r6, #1 */ 0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */ @@ -660,11 +705,9 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, /* exit: */ 0x30, 0x46, /* mov r0, r6 */ 0x00, 0xbe, /* bkpt #0 */ - - /* LOCKKEY */ - 0x71, 0x1b, 0x00, 0x00 }; + /* flash write code */ if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code), &write_algorithm) != ERROR_OK) { @@ -697,7 +740,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ - buf_set_u32(reg_params[0].value, 0, 32, EFM32_MSC_REGBASE); + buf_set_u32(reg_params[0].value, 0, 32, efm32x_info->reg_base); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); @@ -762,16 +805,16 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, /* if not called, GDB errors will be reported during large writes */ keep_alive(); - ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ERROR_OK != ret) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) return ret; @@ -792,13 +835,13 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, return ret; } - ret = target_write_u32(bank->target, EFM32_MSC_WDATA, val); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val); if (ERROR_OK != ret) { LOG_ERROR("WDATA write failed"); return ret; } - ret = target_write_u32(bank->target, EFM32_MSC_WRITECMD, + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_WRITEONCE_MASK); if (ERROR_OK != ret) { LOG_ERROR("WRITECMD write failed"); From 5a6f0495db71ef1c05a912cd87e52e3d62e641a3 Mon Sep 17 00:00:00 2001 From: Diego Herranz Date: Thu, 3 Aug 2017 07:37:41 +0100 Subject: [PATCH 16/54] tcl/interface/ftdi: improve minimodule config - Tested on a real FT2232H MiniModule, so warning removed. - Every pin initially set to high impedance except TCK, TDI, TDO and TMS: Safest values given it's an evaluation board and the rest of pins might be connected to something else. - Reset is now initially de-asserted (it was asserted which is not recommended). - nRST pin choice is arbitrary so comment added (wondering if it should be an "echo"). - "-oe" option added to NRST signal so it can be set as high impedance (tri-stated). Change-Id: I967ab0c7bbccf72dbf6d6d78b3180b74e016e0d6 Signed-off-by: Diego Herranz Reviewed-on: http://openocd.zylin.com/4185 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/interface/ftdi/minimodule.cfg | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tcl/interface/ftdi/minimodule.cfg b/tcl/interface/ftdi/minimodule.cfg index 57249dfc1..7df096d9c 100644 --- a/tcl/interface/ftdi/minimodule.cfg +++ b/tcl/interface/ftdi/minimodule.cfg @@ -4,14 +4,13 @@ # http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf # -echo "WARNING!" -echo "This file was not tested with real interface, it is based on code in ft2232.c." -echo "Please report your experience with this file to openocd-devel mailing list," -echo "so it could be marked as working or fixed." - interface ftdi ftdi_device_desc "FT2232H MiniModule" ftdi_vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0018 0x05fb -ftdi_layout_signal nSRST -data 0x0020 +# Every pin set as high impedance except TCK, TDI, TDO and TMS +ftdi_layout_init 0x0008 0x000b + +# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip) +# This choice is arbitrary. Use other GPIO pin if desired. +ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 From f712098323c46213a7658f6b91b3775055bc6d6a Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Wed, 7 Jun 2017 16:49:29 -0400 Subject: [PATCH 17/54] server: Add port number to socket bind error Make this error message more useful by providing the port number that we tried to bind to. Change-Id: Ieb18adf0725a6ae99c77ebfaadc49d64ed407bbe Signed-off-by: Robert Foss Reviewed-on: http://openocd.zylin.com/4157 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/server/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server.c b/src/server/server.c index 8009d408f..517d62a79 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -273,7 +273,7 @@ int add_service(char *name, c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { - LOG_ERROR("couldn't bind %s to socket: %s", name, strerror(errno)); + LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; From f441f58ad6e58aefd3045810371d432acbd5b0f8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 6 Aug 2017 07:58:31 +0200 Subject: [PATCH 18/54] board: tp-link_tl-mr3020: add ath79 support Finally we can use this driver by default! Change-Id: I09d215d1bd1dc16873a7379637e6869af65ad8f1 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4193 Tested-by: jenkins Reviewed-by: Dmytro Reviewed-by: Spencer Oliver --- tcl/board/tp-link_tl-mr3020.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tcl/board/tp-link_tl-mr3020.cfg b/tcl/board/tp-link_tl-mr3020.cfg index b7d8d5b61..7e040b325 100644 --- a/tcl/board/tp-link_tl-mr3020.cfg +++ b/tcl/board/tp-link_tl-mr3020.cfg @@ -42,3 +42,5 @@ $_TARGETNAME configure -event reset-init { set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 + +flash bank flash0 ath79 0 0 0 0 $_TARGETNAME cs0 From e548d17f627666c7bd87dd114133de020a5da48d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 15 Jul 2017 17:52:01 +0200 Subject: [PATCH 19/54] target: add atheros_ar9344.cfg Change-Id: I005b4c78ccb0fec8d38a25430cb49c580dcd8df5 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4191 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/target/atheros_ar9344.cfg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tcl/target/atheros_ar9344.cfg diff --git a/tcl/target/atheros_ar9344.cfg b/tcl/target/atheros_ar9344.cfg new file mode 100644 index 000000000..f273fb05d --- /dev/null +++ b/tcl/target/atheros_ar9344.cfg @@ -0,0 +1,16 @@ +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME ar9344 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x00000001 +} + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME From ffa745b8350d88e8c45c6100f18b2ea81786480f Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 15 Jul 2017 17:53:37 +0200 Subject: [PATCH 20/54] board: add TP-Link WDR4300 config tested on TP-Link WDR4300 v1.7 Change-Id: If2b456afac835ab3a3987d434d20824c7ba75b93 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4192 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/board/tp-link_wdr4300.cfg | 160 ++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 tcl/board/tp-link_wdr4300.cfg diff --git a/tcl/board/tp-link_wdr4300.cfg b/tcl/board/tp-link_wdr4300.cfg new file mode 100644 index 000000000..c31791620 --- /dev/null +++ b/tcl/board/tp-link_wdr4300.cfg @@ -0,0 +1,160 @@ +source [find target/atheros_ar9344.cfg] + +reset_config trst_only separate + +proc ar9344_40mhz_pll_init {} { + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0x13210f00 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x03000000 + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0x13210f00 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000000 + # QCA_PLL_SRIF_BB_DPLL_BASE_REG + mww 0xb8116188 0x03000000 + + # QCA_PLL_CPU_DDR_CLK_CTRL_REG + mww 0xb8050008 0x0130001C + mww 0xb8050008 0x0130001C + mww 0xb8050008 0x0130001C + + # QCA_PLL_CPU_PLL_CFG_REG + mww 0xb8050000 0x40021380 + # QCA_PLL_DDR_PLL_CFG_REG + mww 0xb8050004 0x40815800 + # QCA_PLL_CPU_DDR_CLK_CTRL_REG + mww 0xb8050008 0x0130801C + + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0x10810F00 + mww 0xb81161C0 0x41C00000 + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0xD0810F00 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x03000000 + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0xD0800F00 + + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x03000000 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x43000000 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x030003E8 + + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0x10810F00 + mww 0xb8116240 0x41680000 + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0xD0810F00 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000000 + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0xD0800F00 + + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000000 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x43000000 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000718 + + # QCA_PLL_CPU_DDR_CLK_CTRL_REG + mww 0xb8050008 0x01308018 + mww 0xb8050008 0x01308010 + mww 0xb8050008 0x01308000 + + # QCA_PLL_DDR_PLL_DITHER_REG + mww 0xb8050044 0x78180200 + # QCA_PLL_CPU_PLL_DITHER_REG + mww 0xb8050048 0x41C00000 + +} + +proc ar9344_ddr_init {} { + # QCA_DDR_CTRL_CFG_REG + mww 0xb8000108 0x40 + # QCA_DDR_RD_DATA_THIS_CYCLE_REG + mww 0xb8000018 0xFF + # QCA_DDR_BURST_REG + mww 0xb80000C4 0x74444444 + # QCA_DDR_BURST2_REG + mww 0xb80000C8 0x0222 + # QCA_AHB_MASTER_TOUT_MAX_REG + mww 0xb80000CC 0xFFFFF + + # QCA_DDR_CFG_REG + mww 0xb8000000 0xC7D48CD0 + # QCA_DDR_CFG2_REG + mww 0xb8000004 0x9DD0E6A8 + + # QCA_DDR_DDR2_CFG_REG + mww 0xb80000B8 0x0E59 + # QCA_DDR_CFG2_REG + mww 0xb8000004 0x9DD0E6A8 + + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x08 + mww 0xb8000010 0x08 + mww 0xb8000010 0x10 + mww 0xb8000010 0x20 + # QCA_DDR_EMR_REG + mww 0xb800000C 0x02 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x02 + + # QCA_DDR_MR_REG + mww 0xb8000008 0x0133 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x1 + mww 0xb8000010 0x8 + mww 0xb8000010 0x8 + mww 0xb8000010 0x4 + mww 0xb8000010 0x4 + + # QCA_DDR_MR_REG + mww 0xb8000008 0x33 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x1 + + # QCA_DDR_EMR_REG + mww 0xb800000C 0x0382 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x2 + # QCA_DDR_EMR_REG + mww 0xb800000C 0x0402 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x2 + + # QCA_DDR_REFRESH_REG + mww 0xb8000014 0x4270 + + # QCA_DDR_TAP_CTRL_0_REG + mww 0xb800001C 0x0e + # QCA_DDR_TAP_CTRL_1_REG + mww 0xb8000020 0x0e + # QCA_DDR_TAP_CTRL_2_REG + mww 0xb8000024 0x0e + # QCA_DDR_TAP_CTRL_3_REG + mww 0xb8000028 0x0e +} + +$_TARGETNAME configure -event reset-init { + + # mww 0xb806001c 0x1000000 + ar9344_40mhz_pll_init + sleep 100 + + # flash remap + # SPI_CONTROL_ADDR + mww 0xbF000004 0x43 + + ar9344_ddr_init + sleep 100 +} + +set ram_boot_address 0xa0000000 +$_TARGETNAME configure -work-area-phys 0x1d000000 -work-area-size 0x1000 + +flash bank flash0 ath79 0 0 0 0 $_TARGETNAME cs0 From 5384d2c20929d7217d884070e505ae38108c1a21 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 6 Aug 2017 09:50:05 +0200 Subject: [PATCH 21/54] target: atheros_ar9344: add simple uart0 test in some cases we need something to test if uart is actually properly connected. Change-Id: I5a16b053164b34bb30ae8370753be12887a85c51 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4194 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/target/atheros_ar9344.cfg | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tcl/target/atheros_ar9344.cfg b/tcl/target/atheros_ar9344.cfg index f273fb05d..b698f2503 100644 --- a/tcl/target/atheros_ar9344.cfg +++ b/tcl/target/atheros_ar9344.cfg @@ -14,3 +14,26 @@ jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME + +proc test_ar9344_uart0_tx {} { + echo "configuring uart0.." + mww 0xb802000c 0x87 + mww 0xb8020000 0x15 + mww 0xb8020004 0 + mww 0xb802000c 7 + mww 0xb8020004 0 + + echo "send message: hallo world" + mww 0xb8020000 0x68 + mww 0xb8020000 0x65 + mww 0xb8020000 0x6c + mww 0xb8020000 0x6c + mww 0xb8020000 0x6f + mww 0xb8020000 0x20 + mww 0xb8020000 0x77 + mww 0xb8020000 0x6f + mww 0xb8020000 0x72 + mww 0xb8020000 0x6c + mww 0xb8020000 0x64 + mww 0xb8020000 0x0a +} From 9bbe299b35be0e086fdafb9c44669b1c36f935f9 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Mon, 14 Nov 2016 19:12:38 +0100 Subject: [PATCH 22/54] stm32lx.c: Read IDcode at appropriate address. Trying to read the L0 idcode at the L1 idcode address 0xE0042000 often resulted in an uncatched error. Reading at the right L0 address 0x40015800 afterwards results in reading 0. So access to the device is denied.. Change-Id: I6de92cf99a5d5d46c72f9ba055613cbc5753a951 Signed-off-by: Uwe Bonnes Reviewed-on: http://openocd.zylin.com/3883 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/flash/nor/stm32lx.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 0c2fddc92..fdfaad4cf 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -726,16 +726,13 @@ reset_pg_and_lock: static int stm32lx_read_id_code(struct target *target, uint32_t *id) { - /* read stm32 device id register */ - int retval = target_read_u32(target, DBGMCU_IDCODE, id); - if (retval != ERROR_OK) - return retval; - - /* STM32L0 parts will have 0 there, try reading the L0's location for - * DBG_IDCODE in case this is an L0 part. */ - if (*id == 0) + struct armv7m_common *armv7m = target_to_armv7m(target); + int retval; + if (armv7m->arm.is_armv6m == true) retval = target_read_u32(target, DBGMCU_IDCODE_L0, id); - + else + /* read stm32 device id register */ + retval = target_read_u32(target, DBGMCU_IDCODE, id); return retval; } From 52885d2b538dcd4184aae14cf2706fb97acccbd9 Mon Sep 17 00:00:00 2001 From: Slowcoder Date: Thu, 31 Aug 2017 20:53:57 +0200 Subject: [PATCH 23/54] nrf51: Refactor device-list This cleans up the list of supported nrf51 chips considerably. Change-Id: Ic74685657bb72a8703c0a49df4c48c54604ec2a7 Signed-off-by: Slowcoder Reviewed-on: http://openocd.zylin.com/4208 Tested-by: jenkins Reviewed-by: Fredrik Hederstierna Reviewed-by: Spencer Oliver --- src/flash/nor/nrf51.c | 304 +++++++----------------------------------- 1 file changed, 45 insertions(+), 259 deletions(-) diff --git a/src/flash/nor/nrf51.c b/src/flash/nor/nrf51.c index 7b7acf479..350957c90 100644 --- a/src/flash/nor/nrf51.c +++ b/src/flash/nor/nrf51.c @@ -126,6 +126,15 @@ struct nrf51_device_spec { unsigned int flash_size_kb; }; +#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ +{ \ +.hwid = (id), \ +.part = pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +} + /* The known devices table below is derived from the "nRF51 Series * Compatibility Matrix" document, which can be found by searching for * ATTN-51 on the Nordic Semi website: @@ -140,279 +149,56 @@ struct nrf51_device_spec { */ static const struct nrf51_device_spec nrf51_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ - { - .hwid = 0x001D, - .part = "51822", - .variant = "QFAA", - .build_code = "CA/C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0026, - .part = "51822", - .variant = "QFAB", - .build_code = "AA", - .flash_size_kb = 128, - }, - { - .hwid = 0x0027, - .part = "51822", - .variant = "QFAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0020, - .part = "51822", - .variant = "CEAA", - .build_code = "BA", - .flash_size_kb = 256, - }, - { - .hwid = 0x002F, - .part = "51822", - .variant = "CEAA", - .build_code = "B0", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), + NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), + NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), + NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), + NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* nRF51822 Devices (IC rev 2). */ - { - .hwid = 0x002A, - .part = "51822", - .variant = "QFAA", - .build_code = "FA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0044, - .part = "51822", - .variant = "QFAA", - .build_code = "GC0", - .flash_size_kb = 256, - }, - { - .hwid = 0x003C, - .part = "51822", - .variant = "QFAA", - .build_code = "G0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0057, - .part = "51822", - .variant = "QFAA", - .build_code = "G2", - .flash_size_kb = 256, - }, - { - .hwid = 0x0058, - .part = "51822", - .variant = "QFAA", - .build_code = "G3", - .flash_size_kb = 256, - }, - { - .hwid = 0x004C, - .part = "51822", - .variant = "QFAB", - .build_code = "B0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0040, - .part = "51822", - .variant = "CEAA", - .build_code = "CA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0047, - .part = "51822", - .variant = "CEAA", - .build_code = "DA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x004D, - .part = "51822", - .variant = "CEAA", - .build_code = "D00", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), + NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), + NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), + NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), + NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), + NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), + NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), + NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ - { - .hwid = 0x0072, - .part = "51822", - .variant = "QFAA", - .build_code = "H0", - .flash_size_kb = 256, - }, - { - .hwid = 0x007B, - .part = "51822", - .variant = "QFAB", - .build_code = "C0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0083, - .part = "51822", - .variant = "QFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0084, - .part = "51822", - .variant = "QFAC", - .build_code = "A1", - .flash_size_kb = 256, - }, - { - .hwid = 0x007D, - .part = "51822", - .variant = "CDAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0079, - .part = "51822", - .variant = "CEAA", - .build_code = "E0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0087, - .part = "51822", - .variant = "CFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x008F, - .part = "51822", - .variant = "QFAA", - .build_code = "H1", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), + NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), + NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), + NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), /* nRF51422 Devices (IC rev 1). */ - { - .hwid = 0x001E, - .part = "51422", - .variant = "QFAA", - .build_code = "CA", - .flash_size_kb = 256, - }, - { - .hwid = 0x0024, - .part = "51422", - .variant = "QFAA", - .build_code = "C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0031, - .part = "51422", - .variant = "CEAA", - .build_code = "A0A", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), + NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), + NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ - { - .hwid = 0x002D, - .part = "51422", - .variant = "QFAA", - .build_code = "DAA", - .flash_size_kb = 256, - }, - { - .hwid = 0x002E, - .part = "51422", - .variant = "QFAA", - .build_code = "E0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0061, - .part = "51422", - .variant = "QFAB", - .build_code = "A00", - .flash_size_kb = 128, - }, - { - .hwid = 0x0050, - .part = "51422", - .variant = "CEAA", - .build_code = "B0", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), + NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), + NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), + NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ - { - .hwid = 0x0073, - .part = "51422", - .variant = "QFAA", - .build_code = "F0", - .flash_size_kb = 256, - }, - { - .hwid = 0x007C, - .part = "51422", - .variant = "QFAB", - .build_code = "B0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0085, - .part = "51422", - .variant = "QFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0086, - .part = "51422", - .variant = "QFAC", - .build_code = "A1", - .flash_size_kb = 256, - }, - { - .hwid = 0x007E, - .part = "51422", - .variant = "CDAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x007A, - .part = "51422", - .variant = "CEAA", - .build_code = "C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0088, - .part = "51422", - .variant = "CFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), + NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), + NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ - { - .hwid = 0x0071, - .part = "51822", - .variant = "QFAC", - .build_code = "AB", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), }; static int nrf51_bank_is_probed(struct flash_bank *bank) From d43308af7513fa98f6ef1cae75393c8766bd370d Mon Sep 17 00:00:00 2001 From: Slowcoder Date: Thu, 31 Aug 2017 21:09:42 +0200 Subject: [PATCH 24/54] nrf51: Rename to nrf5 Renaming of all nrf51 NOR flash code to nrf5, as to prepare the code for being able to flash nrf51 and nrf52 chips. The nrf51 command is retained for backwards compatability. "nRF5" is also the name Nordic Semiconductor uses to describe both the nrf51 and nrf52 chips. Change-Id: I5f4e3f1ec780184b28ad44f735a746e68908c502 Signed-off-by: Slowcoder Reviewed-on: http://openocd.zylin.com/4209 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Spencer Oliver --- doc/openocd.texi | 10 +- src/flash/nor/Makefile.am | 2 +- src/flash/nor/drivers.c | 2 + src/flash/nor/{nrf51.c => nrf5.c} | 578 ++++++++++++++++-------------- 4 files changed, 310 insertions(+), 282 deletions(-) rename src/flash/nor/{nrf51.c => nrf5.c} (61%) diff --git a/doc/openocd.texi b/doc/openocd.texi index 89ee5eb45..39b81ea85 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5767,17 +5767,19 @@ Show information about flash driver. @end deffn -@deffn {Flash Driver} nrf51 +@deffn {Flash Driver} nrf5 All members of the nRF51 microcontroller families from Nordic Semiconductor include internal flash and use ARM Cortex-M0 core. +Also, the nRF52832 microcontroller from Nordic Semiconductor, which include +internal flash and use an ARM Cortex-M4F core. @example -flash bank $_FLASHNAME nrf51 0 0x00000000 0 0 $_TARGETNAME +flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME @end example -Some nrf51-specific commands are defined: +Some nrf5-specific commands are defined: -@deffn Command {nrf51 mass_erase} +@deffn Command {nrf5 mass_erase} Erases the contents of the code memory and user information configuration registers as well. It must be noted that this command works only for chips that do not have factory pre-programmed region 0 diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 5a992feef..4dac110c4 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -36,7 +36,7 @@ NOR_DRIVERS = \ %D%/mrvlqspi.c \ %D%/niietcm4.c \ %D%/non_cfi.c \ - %D%/nrf51.c \ + %D%/nrf5.c \ %D%/numicro.c \ %D%/ocl.c \ %D%/pic32mx.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 4ad1d92b9..9594ed9a3 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -48,6 +48,7 @@ extern struct flash_driver lpcspifi_flash; extern struct flash_driver mdr_flash; extern struct flash_driver mrvlqspi_flash; extern struct flash_driver niietcm4_flash; +extern struct flash_driver nrf5_flash; extern struct flash_driver nrf51_flash; extern struct flash_driver numicro_flash; extern struct flash_driver ocl_flash; @@ -101,6 +102,7 @@ static struct flash_driver *flash_drivers[] = { &mdr_flash, &mrvlqspi_flash, &niietcm4_flash, + &nrf5_flash, &nrf51_flash, &numicro_flash, &ocl_flash, diff --git a/src/flash/nor/nrf51.c b/src/flash/nor/nrf5.c similarity index 61% rename from src/flash/nor/nrf51.c rename to src/flash/nor/nrf5.c index 350957c90..8441c2a07 100644 --- a/src/flash/nor/nrf51.c +++ b/src/flash/nor/nrf5.c @@ -28,97 +28,97 @@ #include enum { - NRF51_FLASH_BASE = 0x00000000, + NRF5_FLASH_BASE = 0x00000000, }; -enum nrf51_ficr_registers { - NRF51_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ +enum nrf5_ficr_registers { + NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ -#define NRF51_FICR_REG(offset) (NRF51_FICR_BASE + offset) +#define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset) - NRF51_FICR_CODEPAGESIZE = NRF51_FICR_REG(0x010), - NRF51_FICR_CODESIZE = NRF51_FICR_REG(0x014), - NRF51_FICR_CLENR0 = NRF51_FICR_REG(0x028), - NRF51_FICR_PPFC = NRF51_FICR_REG(0x02C), - NRF51_FICR_NUMRAMBLOCK = NRF51_FICR_REG(0x034), - NRF51_FICR_SIZERAMBLOCK0 = NRF51_FICR_REG(0x038), - NRF51_FICR_SIZERAMBLOCK1 = NRF51_FICR_REG(0x03C), - NRF51_FICR_SIZERAMBLOCK2 = NRF51_FICR_REG(0x040), - NRF51_FICR_SIZERAMBLOCK3 = NRF51_FICR_REG(0x044), - NRF51_FICR_CONFIGID = NRF51_FICR_REG(0x05C), - NRF51_FICR_DEVICEID0 = NRF51_FICR_REG(0x060), - NRF51_FICR_DEVICEID1 = NRF51_FICR_REG(0x064), - NRF51_FICR_ER0 = NRF51_FICR_REG(0x080), - NRF51_FICR_ER1 = NRF51_FICR_REG(0x084), - NRF51_FICR_ER2 = NRF51_FICR_REG(0x088), - NRF51_FICR_ER3 = NRF51_FICR_REG(0x08C), - NRF51_FICR_IR0 = NRF51_FICR_REG(0x090), - NRF51_FICR_IR1 = NRF51_FICR_REG(0x094), - NRF51_FICR_IR2 = NRF51_FICR_REG(0x098), - NRF51_FICR_IR3 = NRF51_FICR_REG(0x09C), - NRF51_FICR_DEVICEADDRTYPE = NRF51_FICR_REG(0x0A0), - NRF51_FICR_DEVICEADDR0 = NRF51_FICR_REG(0x0A4), - NRF51_FICR_DEVICEADDR1 = NRF51_FICR_REG(0x0A8), - NRF51_FICR_OVERRIDEN = NRF51_FICR_REG(0x0AC), - NRF51_FICR_NRF_1MBIT0 = NRF51_FICR_REG(0x0B0), - NRF51_FICR_NRF_1MBIT1 = NRF51_FICR_REG(0x0B4), - NRF51_FICR_NRF_1MBIT2 = NRF51_FICR_REG(0x0B8), - NRF51_FICR_NRF_1MBIT3 = NRF51_FICR_REG(0x0BC), - NRF51_FICR_NRF_1MBIT4 = NRF51_FICR_REG(0x0C0), - NRF51_FICR_BLE_1MBIT0 = NRF51_FICR_REG(0x0EC), - NRF51_FICR_BLE_1MBIT1 = NRF51_FICR_REG(0x0F0), - NRF51_FICR_BLE_1MBIT2 = NRF51_FICR_REG(0x0F4), - NRF51_FICR_BLE_1MBIT3 = NRF51_FICR_REG(0x0F8), - NRF51_FICR_BLE_1MBIT4 = NRF51_FICR_REG(0x0FC), + NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010), + NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014), + NRF5_FICR_CLENR0 = NRF5_FICR_REG(0x028), + NRF5_FICR_PPFC = NRF5_FICR_REG(0x02C), + NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), + NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), + NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), + NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), + NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), + NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), + NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060), + NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064), + NRF5_FICR_ER0 = NRF5_FICR_REG(0x080), + NRF5_FICR_ER1 = NRF5_FICR_REG(0x084), + NRF5_FICR_ER2 = NRF5_FICR_REG(0x088), + NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C), + NRF5_FICR_IR0 = NRF5_FICR_REG(0x090), + NRF5_FICR_IR1 = NRF5_FICR_REG(0x094), + NRF5_FICR_IR2 = NRF5_FICR_REG(0x098), + NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C), + NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0), + NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4), + NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8), + NRF5_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), + NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), + NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), + NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), + NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), + NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), + NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), + NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), + NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), + NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), + NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), }; -enum nrf51_uicr_registers { - NRF51_UICR_BASE = 0x10001000, /* User Information +enum nrf5_uicr_registers { + NRF5_UICR_BASE = 0x10001000, /* User Information * Configuration Regsters */ - NRF51_UICR_SIZE = 0x100, + NRF5_UICR_SIZE = 0x100, -#define NRF51_UICR_REG(offset) (NRF51_UICR_BASE + offset) +#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) - NRF51_UICR_CLENR0 = NRF51_UICR_REG(0x000), - NRF51_UICR_RBPCONF = NRF51_UICR_REG(0x004), - NRF51_UICR_XTALFREQ = NRF51_UICR_REG(0x008), - NRF51_UICR_FWID = NRF51_UICR_REG(0x010), + NRF5_UICR_CLENR0 = NRF5_UICR_REG(0x000), + NRF5_UICR_RBPCONF = NRF5_UICR_REG(0x004), + NRF5_UICR_XTALFREQ = NRF5_UICR_REG(0x008), + NRF5_UICR_FWID = NRF5_UICR_REG(0x010), }; -enum nrf51_nvmc_registers { - NRF51_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory +enum nrf5_nvmc_registers { + NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory * Controller Regsters */ -#define NRF51_NVMC_REG(offset) (NRF51_NVMC_BASE + offset) +#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) - NRF51_NVMC_READY = NRF51_NVMC_REG(0x400), - NRF51_NVMC_CONFIG = NRF51_NVMC_REG(0x504), - NRF51_NVMC_ERASEPAGE = NRF51_NVMC_REG(0x508), - NRF51_NVMC_ERASEALL = NRF51_NVMC_REG(0x50C), - NRF51_NVMC_ERASEUICR = NRF51_NVMC_REG(0x514), + NRF5_NVMC_READY = NRF5_NVMC_REG(0x400), + NRF5_NVMC_CONFIG = NRF5_NVMC_REG(0x504), + NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), + NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), + NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), }; -enum nrf51_nvmc_config_bits { - NRF51_NVMC_CONFIG_REN = 0x00, - NRF51_NVMC_CONFIG_WEN = 0x01, - NRF51_NVMC_CONFIG_EEN = 0x02, +enum nrf5_nvmc_config_bits { + NRF5_NVMC_CONFIG_REN = 0x00, + NRF5_NVMC_CONFIG_WEN = 0x01, + NRF5_NVMC_CONFIG_EEN = 0x02, }; -struct nrf51_info { +struct nrf5_info { uint32_t code_page_size; struct { bool probed; int (*write) (struct flash_bank *bank, - struct nrf51_info *chip, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count); } bank[2]; struct target *target; }; -struct nrf51_device_spec { +struct nrf5_device_spec { uint16_t hwid; const char *part; const char *variant; @@ -126,7 +126,7 @@ struct nrf51_device_spec { unsigned int flash_size_kb; }; -#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ +#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \ { \ .hwid = (id), \ .part = pt, \ @@ -147,71 +147,71 @@ struct nrf51_device_spec { * shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is * for x==0, x!=0 means different (unspecified) HWIDs. */ -static const struct nrf51_device_spec nrf51_known_devices_table[] = { +static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ - NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), - NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), - NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), - NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), - NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), + NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), + NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), + NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), + NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), + NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* nRF51822 Devices (IC rev 2). */ - NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), - NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), - NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), - NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), - NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), - NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), - NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), - NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), - NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), + NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), + NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), + NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), + NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), + NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), + NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), + NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), + NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), + NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ - NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), - NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), - NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), - NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), - NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), - NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), - NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), + NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), + NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), + NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), + NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), + NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), /* nRF51422 Devices (IC rev 1). */ - NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), - NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), - NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), + NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), + NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), + NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ - NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), - NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), - NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), - NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), + NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), + NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), + NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), + NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ - NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), - NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), - NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), - NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), - NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), - NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), - NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), + NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), + NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), + NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), + NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), + NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ - NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), + NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), }; -static int nrf51_bank_is_probed(struct flash_bank *bank) +static int nrf5_bank_is_probed(struct flash_bank *bank) { - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; assert(chip != NULL); return chip->bank[bank->bank_number].probed; } -static int nrf51_probe(struct flash_bank *bank); +static int nrf5_probe(struct flash_bank *bank); -static int nrf51_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf51_info **chip) +static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -220,23 +220,23 @@ static int nrf51_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf51 *chip = bank->driver_priv; - int probed = nrf51_bank_is_probed(bank); + int probed = nrf5_bank_is_probed(bank); if (probed < 0) return probed; else if (!probed) - return nrf51_probe(bank); + return nrf5_probe(bank); else return ERROR_OK; } -static int nrf51_wait_for_nvmc(struct nrf51_info *chip) +static int nrf5_wait_for_nvmc(struct nrf5_info *chip) { uint32_t ready; int res; int timeout = 100; do { - res = target_read_u32(chip->target, NRF51_NVMC_READY, &ready); + res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); if (res != ERROR_OK) { LOG_ERROR("Couldn't read NVMC_READY register"); return res; @@ -252,12 +252,12 @@ static int nrf51_wait_for_nvmc(struct nrf51_info *chip) return ERROR_FLASH_BUSY; } -static int nrf51_nvmc_erase_enable(struct nrf51_info *chip) +static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_EEN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_EEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable erase operation"); @@ -268,19 +268,19 @@ static int nrf51_nvmc_erase_enable(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Erase enable did not complete"); return res; } -static int nrf51_nvmc_write_enable(struct nrf51_info *chip) +static int nrf5_nvmc_write_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_WEN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_WEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable write operation"); @@ -291,19 +291,19 @@ static int nrf51_nvmc_write_enable(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Write enable did not complete"); return res; } -static int nrf51_nvmc_read_only(struct nrf51_info *chip) +static int nrf5_nvmc_read_only(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_REN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_REN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable read-only operation"); @@ -313,19 +313,19 @@ static int nrf51_nvmc_read_only(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Read only enable did not complete"); return res; } -static int nrf51_nvmc_generic_erase(struct nrf51_info *chip, +static int nrf5_nvmc_generic_erase(struct nrf5_info *chip, uint32_t erase_register, uint32_t erase_value) { int res; - res = nrf51_nvmc_erase_enable(chip); + res = nrf5_nvmc_erase_enable(chip); if (res != ERROR_OK) goto error; @@ -335,34 +335,34 @@ static int nrf51_nvmc_generic_erase(struct nrf51_info *chip, if (res != ERROR_OK) goto set_read_only; - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) goto set_read_only; - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); set_read_only: - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); error: LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32, erase_register, erase_value); return ERROR_FAIL; } -static int nrf51_protect_check(struct flash_bank *bank) +static int nrf5_protect_check(struct flash_bank *bank) { int res; uint32_t clenr0; /* UICR cannot be write protected so just return early */ - if (bank->base == NRF51_UICR_BASE) + if (bank->base == NRF5_UICR_BASE) return ERROR_OK; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; assert(chip != NULL); - res = target_read_u32(chip->target, NRF51_FICR_CLENR0, + res = target_read_u32(chip->target, NRF5_FICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); @@ -370,7 +370,7 @@ static int nrf51_protect_check(struct flash_bank *bank) } if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(chip->target, NRF5_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -385,17 +385,17 @@ static int nrf51_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) +static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) { int res; uint32_t clenr0, ppfc; - struct nrf51_info *chip; + struct nrf5_info *chip; /* UICR cannot be write protected so just bail out early */ - if (bank->base == NRF51_UICR_BASE) + if (bank->base == NRF5_UICR_BASE) return ERROR_FAIL; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -404,7 +404,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(chip->target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -416,7 +416,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(chip->target, NRF5_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -424,7 +424,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) } if (clenr0 == 0xFFFFFFFF) { - res = target_write_u32(chip->target, NRF51_UICR_CLENR0, + res = target_write_u32(chip->target, NRF5_UICR_CLENR0, clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't write code region 0 size[UICR]"); @@ -435,18 +435,18 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) LOG_ERROR("You need to perform chip erase before changing the protection settings"); } - nrf51_protect_check(bank); + nrf5_protect_check(bank); return ERROR_OK; } -static int nrf51_probe(struct flash_bank *bank) +static int nrf5_probe(struct flash_bank *bank) { uint32_t hwid; int res; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; - res = target_read_u32(chip->target, NRF51_FICR_CONFIGID, &hwid); + res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read CONFIGID register"); return res; @@ -455,10 +455,10 @@ static int nrf51_probe(struct flash_bank *bank) hwid &= 0xFFFF; /* HWID is stored in the lower two * bytes of the CONFIGID register */ - const struct nrf51_device_spec *spec = NULL; - for (size_t i = 0; i < ARRAY_SIZE(nrf51_known_devices_table); i++) { - if (hwid == nrf51_known_devices_table[i].hwid) { - spec = &nrf51_known_devices_table[i]; + const struct nrf5_device_spec *spec = NULL; + for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { + if (hwid == nrf5_known_devices_table[i].hwid) { + spec = &nrf5_known_devices_table[i]; break; } } @@ -472,9 +472,9 @@ static int nrf51_probe(struct flash_bank *bank) LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid); } - if (bank->base == NRF51_FLASH_BASE) { - /* The value stored in NRF51_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ - res = target_read_u32(chip->target, NRF51_FICR_CODEPAGESIZE, + if (bank->base == NRF5_FLASH_BASE) { + /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, &chip->code_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); @@ -482,9 +482,9 @@ static int nrf51_probe(struct flash_bank *bank) } /* Note the register name is misleading, - * NRF51_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ + * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ uint32_t num_sectors; - res = target_read_u32(chip->target, NRF51_FICR_CODESIZE, &num_sectors); + res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; @@ -501,7 +501,7 @@ static int nrf51_probe(struct flash_bank *bank) if (!bank->sectors) return ERROR_FLASH_BANK_NOT_PROBED; - /* Fill out the sector information: all NRF51 sectors are the same size and + /* Fill out the sector information: all NRF5 sectors are the same size and * there is always a fixed number of them. */ for (int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = chip->code_page_size; @@ -512,11 +512,11 @@ static int nrf51_probe(struct flash_bank *bank) bank->sectors[i].is_protected = -1; } - nrf51_protect_check(bank); + nrf5_protect_check(bank); chip->bank[0].probed = true; } else { - bank->size = NRF51_UICR_SIZE; + bank->size = NRF5_UICR_SIZE; bank->num_sectors = 1; bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0])); @@ -536,21 +536,21 @@ static int nrf51_probe(struct flash_bank *bank) return ERROR_OK; } -static int nrf51_auto_probe(struct flash_bank *bank) +static int nrf5_auto_probe(struct flash_bank *bank) { - int probed = nrf51_bank_is_probed(bank); + int probed = nrf5_bank_is_probed(bank); if (probed < 0) return probed; else if (probed) return ERROR_OK; else - return nrf51_probe(bank); + return nrf5_probe(bank); } -static struct flash_sector *nrf51_find_sector_by_address(struct flash_bank *bank, uint32_t address) +static struct flash_sector *nrf5_find_sector_by_address(struct flash_bank *bank, uint32_t address) { - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; for (int i = 0; i < bank->num_sectors; i++) if (bank->sectors[i].offset <= address && @@ -559,16 +559,16 @@ static struct flash_sector *nrf51_find_sector_by_address(struct flash_bank *bank return NULL; } -static int nrf51_erase_all(struct nrf51_info *chip) +static int nrf5_erase_all(struct nrf5_info *chip) { LOG_DEBUG("Erasing all non-volatile memory"); - return nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEALL, + return nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEALL, 0x00000001); } -static int nrf51_erase_page(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_erase_page(struct flash_bank *bank, + struct nrf5_info *chip, struct flash_sector *sector) { int res; @@ -579,9 +579,9 @@ static int nrf51_erase_page(struct flash_bank *bank, return ERROR_FAIL; } - if (bank->base == NRF51_UICR_BASE) { + if (bank->base == NRF5_UICR_BASE) { uint32_t ppfc; - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(chip->target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -599,14 +599,14 @@ static int nrf51_erase_page(struct flash_bank *bank, return ERROR_FAIL; } - res = nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEUICR, + res = nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEUICR, 0x00000001); } else { - res = nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEPAGE, + res = nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEPAGE, sector->offset); } @@ -616,7 +616,7 @@ static int nrf51_erase_page(struct flash_bank *bank, return res; } -static const uint8_t nrf51_flash_write_code[] = { +static const uint8_t nrf5_flash_write_code[] = { /* See contrib/loaders/flash/cortex-m0.S */ /* : */ 0x0d, 0x68, /* ldr r5, [r1, #0] */ @@ -641,13 +641,13 @@ static const uint8_t nrf51_flash_write_code[] = { /* Start a low level flash write for the specified region */ -static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) +static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; - uint32_t address = NRF51_FLASH_BASE + offset; + uint32_t address = NRF5_FLASH_BASE + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -657,7 +657,7 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const assert(bytes % 4 == 0); /* allocate working area with flash programming code */ - if (target_alloc_working_area(target, sizeof(nrf51_flash_write_code), + if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, falling back to slow memory writes"); @@ -666,7 +666,7 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const if (retval != ERROR_OK) return retval; - retval = nrf51_wait_for_nvmc(chip); + retval = nrf5_wait_for_nvmc(chip); if (retval != ERROR_OK) return retval; @@ -679,11 +679,11 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const LOG_WARNING("using fast async flash loader. This is currently supported"); LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add"); - LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg to disable it"); + LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it"); retval = target_write_buffer(target, write_algorithm->address, - sizeof(nrf51_flash_write_code), - nrf51_flash_write_code); + sizeof(nrf5_flash_write_code), + nrf5_flash_write_code); if (retval != ERROR_OK) return retval; @@ -734,10 +734,10 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const /* Check and erase flash sectors in specified range then start a low level page write. start/end must be sector aligned. */ -static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) +static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) { int res = ERROR_FAIL; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; struct flash_sector *sector; uint32_t offset; @@ -746,7 +746,7 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e /* Erase all sectors */ for (offset = start; offset < end; offset += chip->code_page_size) { - sector = nrf51_find_sector_by_address(bank, offset); + sector = nrf5_find_sector_by_address(bank, offset); if (!sector) { LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset); return ERROR_FLASH_SECTOR_INVALID; @@ -758,7 +758,7 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e } if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */ - res = nrf51_erase_page(bank, chip, sector); + res = nrf5_erase_page(bank, chip, sector); if (res != ERROR_OK) { LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset); goto error; @@ -767,41 +767,41 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e sector->is_erased = 0; } - res = nrf51_nvmc_write_enable(chip); + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; - res = nrf51_ll_flash_write(chip, start, buffer, (end - start)); + res = nrf5_ll_flash_write(chip, start, buffer, (end - start)); if (res != ERROR_OK) goto set_read_only; - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); set_read_only: - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); error: - LOG_ERROR("Failed to write to nrf51 flash"); + LOG_ERROR("Failed to write to nrf5 flash"); return res; } -static int nrf51_erase(struct flash_bank *bank, int first, int last) +static int nrf5_erase(struct flash_bank *bank, int first, int last) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; /* For each sector to be erased */ for (int s = first; s <= last && res == ERROR_OK; s++) - res = nrf51_erase_page(bank, chip, &bank->sectors[s]); + res = nrf5_erase_page(bank, chip, &bank->sectors[s]); return res; } -static int nrf51_code_flash_write(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_code_flash_write(struct flash_bank *bank, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -848,58 +848,58 @@ static int nrf51_code_flash_write(struct flash_bank *bank, return res; } - return nrf51_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); + return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); } -static int nrf51_uicr_flash_write(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_uicr_flash_write(struct flash_bank *bank, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; - uint8_t uicr[NRF51_UICR_SIZE]; + uint8_t uicr[NRF5_UICR_SIZE]; struct flash_sector *sector = &bank->sectors[0]; - if ((offset + count) > NRF51_UICR_SIZE) + if ((offset + count) > NRF5_UICR_SIZE) return ERROR_FAIL; res = target_read_memory(bank->target, - NRF51_UICR_BASE, + NRF5_UICR_BASE, 1, - NRF51_UICR_SIZE, + NRF5_UICR_SIZE, uicr); if (res != ERROR_OK) return res; if (sector->is_erased != 1) { - res = nrf51_erase_page(bank, chip, sector); + res = nrf5_erase_page(bank, chip, sector); if (res != ERROR_OK) return res; } - res = nrf51_nvmc_write_enable(chip); + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) return res; memcpy(&uicr[offset], buffer, count); - res = nrf51_ll_flash_write(chip, NRF51_UICR_BASE, uicr, NRF51_UICR_SIZE); + res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE); if (res != ERROR_OK) { - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); return res; } - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); } -static int nrf51_write(struct flash_bank *bank, const uint8_t *buffer, +static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -907,15 +907,15 @@ static int nrf51_write(struct flash_bank *bank, const uint8_t *buffer, } -FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) +FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) { - static struct nrf51_info *chip; + static struct nrf5_info *chip; switch (bank->base) { - case NRF51_FLASH_BASE: + case NRF5_FLASH_BASE: bank->bank_number = 0; break; - case NRF51_UICR_BASE: + case NRF5_UICR_BASE: bank->bank_number = 1; break; default: @@ -933,11 +933,11 @@ FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) } switch (bank->base) { - case NRF51_FLASH_BASE: - chip->bank[bank->bank_number].write = nrf51_code_flash_write; + case NRF5_FLASH_BASE: + chip->bank[bank->bank_number].write = nrf5_code_flash_write; break; - case NRF51_UICR_BASE: - chip->bank[bank->bank_number].write = nrf51_uicr_flash_write; + case NRF5_UICR_BASE: + chip->bank[bank->bank_number].write = nrf5_uicr_flash_write; break; } @@ -947,27 +947,27 @@ FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) return ERROR_OK; } -COMMAND_HANDLER(nrf51_handle_mass_erase_command) +COMMAND_HANDLER(nrf5_handle_mass_erase_command) { int res; struct flash_bank *bank = NULL; struct target *target = get_current_target(CMD_CTX); - res = get_flash_bank_by_addr(target, NRF51_FLASH_BASE, true, &bank); + res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); if (res != ERROR_OK) return res; assert(bank != NULL); - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; uint32_t ppfc; - res = target_read_u32(target, NRF51_FICR_PPFC, + res = target_read_u32(target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -980,23 +980,23 @@ COMMAND_HANDLER(nrf51_handle_mass_erase_command) return ERROR_FAIL; } - res = nrf51_erase_all(chip); + res = nrf5_erase_all(chip); if (res != ERROR_OK) { LOG_ERROR("Failed to erase the chip"); - nrf51_protect_check(bank); + nrf5_protect_check(bank); return res; } for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; - res = nrf51_protect_check(bank); + res = nrf5_protect_check(bank); if (res != ERROR_OK) { LOG_ERROR("Failed to check chip's write protection"); return res; } - res = get_flash_bank_by_addr(target, NRF51_UICR_BASE, true, &bank); + res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank); if (res != ERROR_OK) return res; @@ -1005,13 +1005,13 @@ COMMAND_HANDLER(nrf51_handle_mass_erase_command) return ERROR_OK; } -static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) +static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -1019,45 +1019,45 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) const uint32_t address; uint32_t value; } ficr[] = { - { .address = NRF51_FICR_CODEPAGESIZE }, - { .address = NRF51_FICR_CODESIZE }, - { .address = NRF51_FICR_CLENR0 }, - { .address = NRF51_FICR_PPFC }, - { .address = NRF51_FICR_NUMRAMBLOCK }, - { .address = NRF51_FICR_SIZERAMBLOCK0 }, - { .address = NRF51_FICR_SIZERAMBLOCK1 }, - { .address = NRF51_FICR_SIZERAMBLOCK2 }, - { .address = NRF51_FICR_SIZERAMBLOCK3 }, - { .address = NRF51_FICR_CONFIGID }, - { .address = NRF51_FICR_DEVICEID0 }, - { .address = NRF51_FICR_DEVICEID1 }, - { .address = NRF51_FICR_ER0 }, - { .address = NRF51_FICR_ER1 }, - { .address = NRF51_FICR_ER2 }, - { .address = NRF51_FICR_ER3 }, - { .address = NRF51_FICR_IR0 }, - { .address = NRF51_FICR_IR1 }, - { .address = NRF51_FICR_IR2 }, - { .address = NRF51_FICR_IR3 }, - { .address = NRF51_FICR_DEVICEADDRTYPE }, - { .address = NRF51_FICR_DEVICEADDR0 }, - { .address = NRF51_FICR_DEVICEADDR1 }, - { .address = NRF51_FICR_OVERRIDEN }, - { .address = NRF51_FICR_NRF_1MBIT0 }, - { .address = NRF51_FICR_NRF_1MBIT1 }, - { .address = NRF51_FICR_NRF_1MBIT2 }, - { .address = NRF51_FICR_NRF_1MBIT3 }, - { .address = NRF51_FICR_NRF_1MBIT4 }, - { .address = NRF51_FICR_BLE_1MBIT0 }, - { .address = NRF51_FICR_BLE_1MBIT1 }, - { .address = NRF51_FICR_BLE_1MBIT2 }, - { .address = NRF51_FICR_BLE_1MBIT3 }, - { .address = NRF51_FICR_BLE_1MBIT4 }, + { .address = NRF5_FICR_CODEPAGESIZE }, + { .address = NRF5_FICR_CODESIZE }, + { .address = NRF5_FICR_CLENR0 }, + { .address = NRF5_FICR_PPFC }, + { .address = NRF5_FICR_NUMRAMBLOCK }, + { .address = NRF5_FICR_SIZERAMBLOCK0 }, + { .address = NRF5_FICR_SIZERAMBLOCK1 }, + { .address = NRF5_FICR_SIZERAMBLOCK2 }, + { .address = NRF5_FICR_SIZERAMBLOCK3 }, + { .address = NRF5_FICR_CONFIGID }, + { .address = NRF5_FICR_DEVICEID0 }, + { .address = NRF5_FICR_DEVICEID1 }, + { .address = NRF5_FICR_ER0 }, + { .address = NRF5_FICR_ER1 }, + { .address = NRF5_FICR_ER2 }, + { .address = NRF5_FICR_ER3 }, + { .address = NRF5_FICR_IR0 }, + { .address = NRF5_FICR_IR1 }, + { .address = NRF5_FICR_IR2 }, + { .address = NRF5_FICR_IR3 }, + { .address = NRF5_FICR_DEVICEADDRTYPE }, + { .address = NRF5_FICR_DEVICEADDR0 }, + { .address = NRF5_FICR_DEVICEADDR1 }, + { .address = NRF5_FICR_OVERRIDEN }, + { .address = NRF5_FICR_NRF_1MBIT0 }, + { .address = NRF5_FICR_NRF_1MBIT1 }, + { .address = NRF5_FICR_NRF_1MBIT2 }, + { .address = NRF5_FICR_NRF_1MBIT3 }, + { .address = NRF5_FICR_NRF_1MBIT4 }, + { .address = NRF5_FICR_BLE_1MBIT0 }, + { .address = NRF5_FICR_BLE_1MBIT1 }, + { .address = NRF5_FICR_BLE_1MBIT2 }, + { .address = NRF5_FICR_BLE_1MBIT3 }, + { .address = NRF5_FICR_BLE_1MBIT4 }, }, uicr[] = { - { .address = NRF51_UICR_CLENR0, }, - { .address = NRF51_UICR_RBPCONF }, - { .address = NRF51_UICR_XTALFREQ }, - { .address = NRF51_UICR_FWID }, + { .address = NRF5_UICR_CLENR0, }, + { .address = NRF5_UICR_RBPCONF }, + { .address = NRF5_UICR_XTALFREQ }, + { .address = NRF5_UICR_FWID }, }; for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { @@ -1129,38 +1129,62 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -static const struct command_registration nrf51_exec_command_handlers[] = { +static const struct command_registration nrf5_exec_command_handlers[] = { { .name = "mass_erase", - .handler = nrf51_handle_mass_erase_command, + .handler = nrf5_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase all flash contents of the chip.", }, COMMAND_REGISTRATION_DONE }; -static const struct command_registration nrf51_command_handlers[] = { +static const struct command_registration nrf5_command_handlers[] = { + { + .name = "nrf5", + .mode = COMMAND_ANY, + .help = "nrf5 flash command group", + .usage = "", + .chain = nrf5_exec_command_handlers, + }, { .name = "nrf51", .mode = COMMAND_ANY, .help = "nrf51 flash command group", .usage = "", - .chain = nrf51_exec_command_handlers, + .chain = nrf5_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; +struct flash_driver nrf5_flash = { + .name = "nrf5", + .commands = nrf5_command_handlers, + .flash_bank_command = nrf5_flash_bank_command, + .info = nrf5_info, + .erase = nrf5_erase, + .protect = nrf5_protect, + .write = nrf5_write, + .read = default_flash_read, + .probe = nrf5_probe, + .auto_probe = nrf5_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = nrf5_protect_check, +}; + +/* We need to retain the flash-driver name as well as the commands + * for backwards compatability */ struct flash_driver nrf51_flash = { .name = "nrf51", - .commands = nrf51_command_handlers, - .flash_bank_command = nrf51_flash_bank_command, - .info = nrf51_info, - .erase = nrf51_erase, - .protect = nrf51_protect, - .write = nrf51_write, + .commands = nrf5_command_handlers, + .flash_bank_command = nrf5_flash_bank_command, + .info = nrf5_info, + .erase = nrf5_erase, + .protect = nrf5_protect, + .write = nrf5_write, .read = default_flash_read, - .probe = nrf51_probe, - .auto_probe = nrf51_auto_probe, + .probe = nrf5_probe, + .auto_probe = nrf5_auto_probe, .erase_check = default_flash_blank_check, - .protect_check = nrf51_protect_check, + .protect_check = nrf5_protect_check, }; From 2168c475ff7ca0f2914bee39700952600014ac40 Mon Sep 17 00:00:00 2001 From: Slowcoder Date: Thu, 31 Aug 2017 22:34:16 +0200 Subject: [PATCH 25/54] nrf5: Add nRF52832-QFAA support Change-Id: Ica9e34e873cac182662b1e32a9b3164dbc0c935f Signed-off-by: Slowcoder Reviewed-on: http://openocd.zylin.com/4210 Reviewed-by: Tomas Vanek Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/flash/nor/nrf5.c | 3 +++ tcl/target/nrf52.cfg | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 8441c2a07..11e57291c 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -195,6 +195,9 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + /* nRF52832 Devices */ + NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), + /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index c1cbf1a21..e73017503 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -10,6 +10,14 @@ if { [info exists CHIPNAME] } { set _CHIPNAME nrf52 } +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { @@ -21,8 +29,13 @@ swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME -adapter_khz 10000 +adapter_khz 1000 + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if { ![using_hla] } { cortex_m reset_config sysresetreq } + +flash bank $_CHIPNAME.flash nrf5 0x00000000 0 1 1 $_TARGETNAME +flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 1 1 $_TARGETNAME From 0e02fe40c64ad7488aeb351641723e1eb9ae49cb Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 12 Jun 2017 16:28:03 +0100 Subject: [PATCH 26/54] tcl: add hi3798 target and Tocoding Poplar board config This config covers the 4x Cortex A53 CPUs. A custom connector is required from J14 to standard ARM JTAG on v1 boards. However v2 hardware should have a standard FTSH-105-01-L-DV connector. Pinmuxing code to enable JTAG pins is included in l-loader-poplar repository, so board is flashed with open source code, JTAG is available at very early boot. Alternatively the following pokes can be issued from U-Boot to enable JTAG (e.g. to debug hisilicon SDK). mw 0xf8a210ec 0x130; mw 0xf8a210f0 0x130; mw 0xf8a210f4 0x130; mw 0xf8a210f8 0x130; mw 0xf8a210fc 0x130; mw 0xf8a21100 0x130; Change-Id: I2b83dfcb3dc5461c1620f94dd99aa7b31fdda59b Signed-off-by: Peter Griffin Reviewed-on: http://openocd.zylin.com/4161 Tested-by: jenkins Reviewed-by: Jiri Kastner Reviewed-by: Paul Fertser --- tcl/board/tocoding_poplar.cfg | 28 ++++++++++++++++++++ tcl/target/hi3798.cfg | 49 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tcl/board/tocoding_poplar.cfg create mode 100644 tcl/target/hi3798.cfg diff --git a/tcl/board/tocoding_poplar.cfg b/tcl/board/tocoding_poplar.cfg new file mode 100644 index 000000000..fd6615605 --- /dev/null +++ b/tcl/board/tocoding_poplar.cfg @@ -0,0 +1,28 @@ +# +# board configuration for Tocoding Poplar +# + +# board does not feature anything but JTAG +transport select jtag + +adapter_khz 10000 + +# SRST-only reset configuration +reset_config srst_only srst_push_pull + +source [find tcl/target/hi3798.cfg] + +# halt the cores when gdb attaches +${_TARGETNAME}0 configure -event gdb-attach "halt" + +# make sure the default target is the boot core +targets ${_TARGETNAME}0 + +proc core_up { args } { + global _TARGETNAME + + # examine remaining cores + foreach _core [set args] { + ${_TARGETNAME}$_core arp_examine + } +} diff --git a/tcl/target/hi3798.cfg b/tcl/target/hi3798.cfg new file mode 100644 index 000000000..9eda15035 --- /dev/null +++ b/tcl/target/hi3798.cfg @@ -0,0 +1,49 @@ +# Hisilicon Hi3798 Target + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME hi3798 +} + +# +# Main DAP +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +# declare the one JTAG tap to access the DAP +jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable + +# declare the 4 main application cores +set _TARGETNAME $_CHIPNAME.cpu +set _smp_command "" + +set $_TARGETNAME.cti(0) 0x80020000 +set $_TARGETNAME.cti(1) 0x80120000 +set $_TARGETNAME.cti(2) 0x80220000 +set $_TARGETNAME.cti(3) 0x80320000 + +set _cores 4 +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + + set _command "target create ${_TARGETNAME}$_core aarch64 \ + -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_core)]" + + if { $_core != 0 } { + # non-boot core examination may fail + #set _command "$_command -defer-examine" + set _smp_command "$_smp_command ${_TARGETNAME}$_core" + } else { + # uncomment when "hawt" rtos is merged + # set _command "$_command -rtos hawt" + set _smp_command "target smp ${_TARGETNAME}$_core" + } + + eval $_command +} + +eval $_smp_command From 1356be121ef97509a3318c62380930689b0b3f76 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Sun, 8 Oct 2017 12:03:25 -0700 Subject: [PATCH 27/54] Document `struct reg` fields. Change-Id: I286316079e2e4d4f09427a4ffbecadb48c5dc9d9 Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4250 Tested-by: jenkins Reviewed-by: Liviu Ionescu Reviewed-by: Andreas Fritiofson --- src/target/register.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/target/register.h b/src/target/register.h index d3b2c31c2..dc18e9a89 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -114,17 +114,32 @@ struct reg_data_type { }; struct reg { + /* Canonical name of the register. */ const char *name; + /* Number that gdb uses to access this register. */ uint32_t number; + /* TODO. This should probably be const. */ struct reg_feature *feature; + /* TODO: When true, the caller will save this register before running any algorithm. */ bool caller_save; + /* Pointer to place where the value is stored, in the format understood by + * the binarybuffer.h functions. */ void *value; + /* The stored value needs to be written to the target. */ bool dirty; + /* When true, value is valid. */ bool valid; + /* When false, the register doesn't actually exist in the target. */ bool exist; + /* Size of the register in bits. */ uint32_t size; + /* Used for generating XML description of registers. Can be set to NULL for + * targets that don't use that. */ struct reg_data_type *reg_data_type; + /* Used for generating XML description of registers. Can be set to NULL for + * targets that don't use that. */ const char *group; + /* Pointer to architecture-specific info for this register. */ void *arch_info; const struct reg_arch_type *type; }; From 1662508911bdf8f86a4f19f6b9eb701c58e9d328 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 6 Oct 2017 14:36:34 -0700 Subject: [PATCH 28/54] Differentiate "target not halted" messages. Change-Id: I8728fa007289d7af5c6791142e76eb5777c83ca4 Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4244 Tested-by: jenkins Reviewed-by: Liviu Ionescu Reviewed-by: Andreas Fritiofson --- src/target/target.c | 16 ++++++++-------- src/target/target_type.h | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 8f9766694..07fe453d9 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1098,7 +1098,7 @@ int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); @@ -1108,7 +1108,7 @@ int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add context breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); @@ -1118,7 +1118,7 @@ int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add hybrid breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); @@ -1134,7 +1134,7 @@ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add watchpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); @@ -1148,7 +1148,7 @@ int target_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (hit watchpoint)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } @@ -1177,7 +1177,7 @@ int target_step(struct target *target, int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (gdb fileio)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->get_gdb_fileio_info(target, fileio_info); @@ -1186,7 +1186,7 @@ int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fi int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (gdb fileio end)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c); @@ -1196,7 +1196,7 @@ int target_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (profiling)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->profiling(target, samples, max_num_samples, diff --git a/src/target/target_type.h b/src/target/target_type.h index 34e2778ad..0960e6d59 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -53,6 +53,7 @@ struct target_type { /* halt will log a warning, but return ERROR_OK if the target is already halted. */ int (*halt)(struct target *target); + /* See target.c target_resume() for documentation. */ int (*resume)(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int (*step)(struct target *target, int current, target_addr_t address, From ef49b34b2af5bae85e5ee887c49eed02eb227feb Mon Sep 17 00:00:00 2001 From: Andreas Fritiofson Date: Wed, 28 Dec 2016 23:43:53 +0100 Subject: [PATCH 29/54] arm: semihosting: set command line arguments Add "arm semihosting_cmdline [argv0 argv1 ...]" for setting the command line arguments for the debuggee. [andreas.fritiofson@gmail.com]: Dynamic allocation, empty default Change-Id: I831ddd161d602f251940e29608a154e9590fdee1 Signed-off-by: Christian Groessler Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/3106 Tested-by: jenkins --- doc/openocd.texi | 14 ++++++++++++ src/target/arm.h | 3 +++ src/target/arm_semihosting.c | 2 +- src/target/armv4_5.c | 43 ++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 39b81ea85..e452fa3b3 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7604,6 +7604,20 @@ requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn +@deffn Command {arm semihosting_cmdline} [@option{enable}|@option{disable}] +@cindex ARM semihosting +Set the command line to be passed to the debuggee. + +@example +arm semihosting_cmdline argv0 argv1 argv2 ... +@end example + +This option lets one set the command line arguments to be passed to +the program. The first argument (argv0) is the program name in a +standard C environment (argv[0]). Depending on the program (not much +programs look at argv[0]), argv0 is ignored and can be any string. +@end deffn + @deffn Command {arm semihosting_fileio} [@option{enable}|@option{disable}] @cindex ARM semihosting Display status of semihosting fileio, after optionally changing that diff --git a/src/target/arm.h b/src/target/arm.h index d63ead215..f89aa6884 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -157,6 +157,9 @@ struct arm { int (*setup_semihosting)(struct target *target, int enable); + /** Semihosting command line. */ + char *semihosting_cmdline; + /** Backpointer to the target. */ struct target *target; diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 252511962..f31f901f0 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -465,7 +465,7 @@ static int do_semihosting(struct target *target) else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); - char *arg = "foobar"; + char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : ""; uint32_t s = strlen(arg) + 1; if (l < s) arm->semihosting_result = -1; diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 2029ca92a..48050b078 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1091,6 +1091,42 @@ COMMAND_HANDLER(handle_arm_semihosting_fileio_command) return ERROR_OK; } +COMMAND_HANDLER(handle_arm_semihosting_cmdline) +{ + struct target *target = get_current_target(CMD_CTX); + unsigned int i; + + if (target == NULL) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct arm *arm = target_to_arm(target); + + if (!is_arm(arm)) { + command_print(CMD_CTX, "current target isn't an ARM"); + return ERROR_FAIL; + } + + if (!arm->setup_semihosting) { + command_print(CMD_CTX, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + free(arm->semihosting_cmdline); + arm->semihosting_cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL; + + for (i = 1; i < CMD_ARGC; i++) { + char *cmdline = alloc_printf("%s %s", arm->semihosting_cmdline, CMD_ARGV[i]); + if (cmdline == NULL) + break; + free(arm->semihosting_cmdline); + arm->semihosting_cmdline = cmdline; + } + + return ERROR_OK; +} + static const struct command_registration arm_exec_command_handlers[] = { { .name = "reg", @@ -1133,6 +1169,13 @@ static const struct command_registration arm_exec_command_handlers[] = { .usage = "['enable'|'disable']", .help = "activate support for semihosting operations", }, + { + "semihosting_cmdline", + .handler = handle_arm_semihosting_cmdline, + .mode = COMMAND_EXEC, + .usage = "arguments", + .help = "command line arguments to be passed to program", + }, { "semihosting_fileio", .handler = handle_arm_semihosting_fileio_command, From 9364b0dba451c3cee653f985b96b9f0535997346 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 29 Jun 2017 23:48:19 +0200 Subject: [PATCH 30/54] Fix GCC7 warnings about switch-case fallthroughs GCC7 with -Wextra warns about switch-case blocks which fallthrough with "this statement may fall through [-Werror=implicit-fallthrough=]". This can be fixed by adding "special" comments: "/* fallthrough */". See https://gcc.gnu.org/gcc-7/changes.html Change-Id: Iba0be791dbdd86984489b2d9a0592bb59828da1e Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/4174 Tested-by: jenkins --- src/flash/mflash.c | 4 ++-- src/flash/nand/mx3.c | 1 + src/flash/nor/kinetis.c | 1 + src/helper/command.c | 2 +- src/jtag/drivers/ftdi.c | 1 + src/jtag/drivers/kitprog.c | 1 + src/svf/svf.c | 2 ++ src/target/arm_adi_v5.c | 6 ++++++ src/target/arm_disassembler.c | 1 + src/target/target.c | 2 +- 10 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/flash/mflash.c b/src/flash/mflash.c index b69995542..4c95d216c 100644 --- a/src/flash/mflash.c +++ b/src/flash/mflash.c @@ -259,11 +259,11 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var) case mg_io_wait_rdy: if (status & mg_io_rbit_status_ready) return ERROR_OK; - + /* fallthrough */ case mg_io_wait_drq: if (status & mg_io_rbit_status_data_req) return ERROR_OK; - + /* fallthrough */ default: break; } diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index b61e47535..5fdc92305 100644 --- a/src/flash/nand/mx3.c +++ b/src/flash/nand/mx3.c @@ -281,6 +281,7 @@ static int imx31_command(struct nand_device *nand, uint8_t command) * offset == one half of page size */ in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); + break; default: in_sram_address = MX3_NF_MAIN_BUFFER0; } diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 4ef438507..455e7b1b0 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -2126,6 +2126,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX1: /* errata 7534 - should be K63 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX2: /* errata 7534 - should be K64 */ subfamid += 2; /* errata 7534 fix */ + /* fallthrough */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX3: /* K63FN1M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX4: diff --git a/src/helper/command.c b/src/helper/command.c index 5deaee859..40e8b0582 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -1456,8 +1456,8 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); return ERROR_COMMAND_SYNTAX_ERROR; } - /* fall through */ } + /* fallthrough */ case 0: LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); break; diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 342e32102..75a3ce43e 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -855,6 +855,7 @@ COMMAND_HANDLER(ftdi_handle_set_signal_command) ftdi_set_signal(sig, *CMD_ARGV[1]); break; } + /* fallthrough */ default: LOG_ERROR("unknown signal level '%s', use 0, 1 or z", CMD_ARGV[1]); return ERROR_COMMAND_SYNTAX_ERROR; diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index c689848c8..584da8c94 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -657,6 +657,7 @@ static int kitprog_swd_switch_seq(enum swd_special_seq seq) LOG_DEBUG("JTAG to SWD not supported"); /* Fall through to fix target reset issue */ } + /* fallthrough */ case LINE_RESET: LOG_DEBUG("SWD line reset"); if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) diff --git a/src/svf/svf.c b/src/svf/svf.c index e7e815c10..1d686ba61 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -661,11 +661,13 @@ static int svf_read_command_from_file(FILE *fd) if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; i = -1; + /* fallthrough */ case '\r': slash = 0; /* Don't save '\r' and '\n' if no data is parsed */ if (!cmd_pos) break; + /* fallthrough */ default: /* The parsing code currently expects a space * before parentheses -- "TDI (123)". Also a diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index eafc2ddc0..88491196d 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -346,8 +346,10 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz case 4: outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); + /* fallthrough */ case 2: outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); + /* fallthrough */ case 1: outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); } @@ -509,8 +511,10 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint case 4: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); + /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); + /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); } @@ -519,8 +523,10 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint case 4: *buffer++ = *read_ptr >> 8 * (address++ & 3); *buffer++ = *read_ptr >> 8 * (address++ & 3); + /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (address++ & 3); + /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (address++ & 3); } diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 5277b94d8..3f1daca4d 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -3299,6 +3299,7 @@ static int t2ev_data_immed(uint32_t opcode, uint32_t address, case 0x10: case 0x12: is_signed = true; + /* fallthrough */ case 0x18: case 0x1a: /* signed/unsigned saturated add */ diff --git a/src/target/target.c b/src/target/target.c index 07fe453d9..36318d88e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3684,7 +3684,7 @@ COMMAND_HANDLER(handle_bp_command) addr = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); } - + /* fallthrough */ case 4: hw = BKPT_HARD; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); From 079d78f7de917e33b58c5ea6147c818e573b3dc4 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 29 Jun 2017 23:49:03 +0200 Subject: [PATCH 31/54] Fix GCC7 warnings about string truncation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC7 with -Wall warns about possible string truncation with snprint()-type functions with "directive output may be truncated writing 1 byte into a region of size between 0 and 9 [-Werror=format-truncation=]" + "note: ‘snprintf’ output between 5 and 14 bytes into a destination of size 12" (or similar). Fix this by increasing sizes of buffers. See https://gcc.gnu.org/gcc-7/changes.html Change-Id: Ib848f2a56dd658783534158947ae1be7c0e99d45 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/4175 Reviewed-by: Andreas Fritiofson Tested-by: jenkins Reviewed-by: Andreas Bolsch --- src/flash/nor/kinetis.c | 2 +- src/flash/nor/xmc4xxx.c | 4 ++-- src/target/arm_adi_v5.c | 2 +- src/target/nds32_cmd.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 455e7b1b0..5c0ffbd6f 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -1959,7 +1959,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) unsigned cpu_mhz = 120; unsigned idx; bool use_nvm_marking = false; - char flash_marking[8], nvm_marking[2]; + char flash_marking[11], nvm_marking[2]; char name[40]; k_chip->probed = false; diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c index 02df46a3f..5677ef0f1 100644 --- a/src/flash/nor/xmc4xxx.c +++ b/src/flash/nor/xmc4xxx.c @@ -931,13 +931,13 @@ static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_ /* If OTP Write protection is enabled (User 2), list each * sector that has it enabled */ - char otp_str[8]; + char otp_str[14]; if (otp_enabled) { strcat(prot_str, "\nOTP Protection is enabled for sectors:\n"); for (int i = 0; i < bank->num_sectors; i++) { if (fb->write_prot_otp[i]) { snprintf(otp_str, sizeof(otp_str), "- %d\n", i); - strncat(prot_str, otp_str, ARRAY_SIZE(otp_str)); + strncat(prot_str, otp_str, sizeof(prot_str) - strlen(prot_str) - 1); } } } diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 88491196d..200629023 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1059,7 +1059,7 @@ static int dap_rom_display(struct command_context *cmd_ctx, int retval; uint64_t pid; uint32_t cid; - char tabs[7] = ""; + char tabs[16] = ""; if (depth > 16) { command_print(cmd_ctx, "\tTables too deep"); diff --git a/src/target/nds32_cmd.c b/src/target/nds32_cmd.c index edb4872e4..500651dbc 100644 --- a/src/target/nds32_cmd.c +++ b/src/target/nds32_cmd.c @@ -816,7 +816,7 @@ static int jim_nds32_bulk_read(Jim_Interp *interp, int argc, Jim_Obj * const *ar uint32_t *data = malloc(count * sizeof(uint32_t)); int result; result = target_read_buffer(target, address, count * 4, (uint8_t *)data); - char data_str[11]; + char data_str[12]; jim_wide i; Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); From 02df0abb547a71e34f7b5bee8ffbc4ded44572de Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 3 Oct 2017 12:59:06 -0700 Subject: [PATCH 32/54] Cortex-M: fix stale DHCSR cache values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cortex_m_assert_reset, in two locations, DHCSR is written directly using mem_ap_write_u32. This means that the cached version, target_to_cm(target)->dcb_dhcsr, is not updated when these writes are performed, so subsequent writes to DHCSR that use cortex_m_write_debug_halt_mask will change those bits back to their old values which, unless modified in that particular invocation, come from the cache. This causes an actual, observable bug on an STM32F7 in which running “reset run” immediately after “program” can in some cases result in execution proceeding with C_MASKINTS set (it is cleared on line 1021 but is then set immediately afterward in cortex_m_clear_halt), causing failure of the application. Replace these mem_ap_write_u32 calls with cortex_m_write_debug_halt_mask calls to do the same jobs. Change-Id: Id35ca7f6057c2df2ba9cd67c53a73b50816d0b71 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4239 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index e80cd2356..11dbf24f2 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -242,7 +242,7 @@ static int cortex_m_endreset_event(struct target *target) if (retval != ERROR_OK) return retval; if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); if (retval != ERROR_OK) return retval; } @@ -1005,12 +1005,12 @@ static int cortex_m_assert_reset(struct target *target) /* Store important errors instead of failing and proceed to reset assert */ if (retval != ERROR_OK || !(cortex_m->dcb_dhcsr & C_DEBUGEN)) - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); /* If the processor is sleeping in a WFI or WFE instruction, the * C_HALT bit must be asserted to regain control */ if (retval == ERROR_OK && (cortex_m->dcb_dhcsr & S_SLEEP)) - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, C_HALT, 0); mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); /* Ignore less important errors */ @@ -1018,8 +1018,7 @@ static int cortex_m_assert_reset(struct target *target) if (!target->reset_halt) { /* Set/Clear C_MASKINTS in a separate operation */ if (cortex_m->dcb_dhcsr & C_MASKINTS) - mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, - DBGKEY | C_DEBUGEN | C_HALT); + cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS); /* clear any debug flags before resuming */ cortex_m_clear_halt(target); From bca67d107fb92f583fd906ae974e5ed0d7438c5b Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 3 Oct 2017 13:23:57 -0700 Subject: [PATCH 33/54] Cortex-M: Delete an unnecessary local variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dhcsr_save variable was used to save the value of cortex_m->dcb_dhcsr so it could be restored later. However, all writes in between the save and the restore use mem_ap_write_atomic_u32, not cortex_m_write_debug_halt_mask, which means cortex_m->dcb_dhcsr isn’t changed anyway. Delete the unnecessary local. Change-Id: I064a3134e21398e1ecfc9f1fa7efd7b020b52341 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4240 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 11dbf24f2..2f8c2a2c8 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -168,12 +168,8 @@ static int cortex_m_single_step_core(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; - uint32_t dhcsr_save; int retval; - /* backup dhcsr reg */ - dhcsr_save = cortex_m->dcb_dhcsr; - /* Mask interrupts before clearing halt, if done already. This avoids * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing * HALT can put the core into an unknown state. @@ -191,7 +187,6 @@ static int cortex_m_single_step_core(struct target *target) LOG_DEBUG(" "); /* restore dhcsr reg */ - cortex_m->dcb_dhcsr = dhcsr_save; cortex_m_clear_halt(target); return ERROR_OK; From c0881ba2d5752ce747a4f74daf7531662f9360a9 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Fri, 13 Oct 2017 07:53:32 +0100 Subject: [PATCH 34/54] tcl/interface/ftdi/openrd: Fix FTDI channel + device description Similar to the Sheevaplug fix inf95f8b70fbd0f7e9c91a2d9006b1abb2dd07ebf2 the OpenRD device has its JTAG interface on the first channel of the ft2232, which is 0 for the new driver but was 1 for the old one. Correct the config file appropriately. Also the device description was missing the trailing " B" and thus not picking up the device correctly. Finally add an adapter_khz setting in the OpenRD board configuration file - set to 2MHz to match the Sheeva variant. Confirmed as working thanks to Phil Hands providing me access to his hardware to test on. See also Debian Bug#793214; https://bugs.debian.org/793214 Change-Id: Ifacf53124eaa330bbbdf36dfa79e3256bf2a5201 Signed-off-by: Jonathan McDowell Reviewed-on: http://openocd.zylin.com/4254 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/board/openrd.cfg | 2 ++ tcl/interface/ftdi/openrd.cfg | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tcl/board/openrd.cfg b/tcl/board/openrd.cfg index 1051c25d9..db3cb0326 100644 --- a/tcl/board/openrd.cfg +++ b/tcl/board/openrd.cfg @@ -3,6 +3,8 @@ source [find interface/ftdi/openrd.cfg] source [find target/feroceon.cfg] +adapter_khz 2000 + $_TARGETNAME configure \ -work-area-phys 0x10000000 \ -work-area-size 65536 \ diff --git a/tcl/interface/ftdi/openrd.cfg b/tcl/interface/ftdi/openrd.cfg index 8c1a80596..9ec5b5f65 100644 --- a/tcl/interface/ftdi/openrd.cfg +++ b/tcl/interface/ftdi/openrd.cfg @@ -4,15 +4,10 @@ # http://www.marvell.com/products/embedded_processors/developer/kirkwood/openrd.jsp # -echo "WARNING!" -echo "This file was not tested with real interface, it is based on code in ft2232.c." -echo "Please report your experience with this file to openocd-devel mailing list," -echo "so it could be marked as working or fixed." - interface ftdi -ftdi_device_desc "OpenRD JTAGKey FT2232D" +ftdi_device_desc "OpenRD JTAGKey FT2232D B" ftdi_vid_pid 0x0403 0x9e90 -ftdi_channel 1 +ftdi_channel 0 ftdi_layout_init 0x0608 0x0f1b ftdi_layout_signal nTRST -data 0x0200 From 41092636d1a10d7fe55a986f0d5556a4c34b58d2 Mon Sep 17 00:00:00 2001 From: Jonas Norling Date: Wed, 25 Oct 2017 11:33:06 +0200 Subject: [PATCH 35/54] ftdi: Enable SWDIO output before sending data on it The SWDIO buffer has to be enabled, by setting SWDIO_OE, for data on SWDIO to reach the target. Explicitly do this before sending the switch sequences for JTAG-to-SWD, etc. This makes the code insensitive to the state of SWDIO_OE specified in ftdi_layout_init. It used to work only on adapters with a non-inverted SWDIO_OE inited to 1, or inverted SWDIO_OE inited to 0. Change-Id: I4b9e520ac1c7ce2a437251a05fc036bc68de718e Signed-off-by: Jonas Norling Reviewed-on: http://openocd.zylin.com/4270 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Andreas Fritiofson --- src/jtag/drivers/ftdi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 75a3ce43e..32876bac5 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1218,14 +1218,17 @@ static int ftdi_swd_switch_seq(enum swd_special_seq seq) switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); + ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_line_reset, 0, swd_seq_line_reset_len, SWD_MODE); break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); + ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len, SWD_MODE); break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); + ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len, SWD_MODE); break; default: From 7e6445109763d47707e1d31620b3733b5137faba Mon Sep 17 00:00:00 2001 From: Jonas Norling Date: Wed, 25 Oct 2017 10:38:49 +0200 Subject: [PATCH 36/54] adi_v5_swd: Add error message when SWD fails to connect Error message instead of failing silently. Change-Id: Ie54a5bf68459d3c0e96cc38080ffad8de0a4b5ce Signed-off-by: Jonas Norling Reviewed-on: http://openocd.zylin.com/4269 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/adi_v5_swd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 41ddbd789..a6aada326 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -427,7 +427,10 @@ static int swd_init(struct command_context *ctx) /* First connect after init is not reconnecting. */ dap->do_reconnect = false; - return swd_connect(dap); + int retval = swd_connect(dap); + if (retval != ERROR_OK) + LOG_ERROR("SWD connect failed"); + return retval; } static struct transport swd_transport = { From dba9293a8907516bfec826464ac2896ffaba6da6 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 29 Oct 2017 11:39:51 +0100 Subject: [PATCH 37/54] rtos: Use 'bool' as return type for detect_rtos() Change-Id: I91ad0431d44ed94f48d20c4690f8642d66f52a9b Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4274 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/rtos/ChibiOS.c | 10 +++++----- src/rtos/FreeRTOS.c | 8 ++++---- src/rtos/ThreadX.c | 8 ++++---- src/rtos/eCos.c | 8 ++++---- src/rtos/embKernel.c | 8 ++++---- src/rtos/linux.c | 4 ++-- src/rtos/mqx.c | 8 ++++---- src/rtos/rtos.h | 2 +- src/rtos/uCOS-III.c | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c index 1bc1af8fc..ef0bb16cf 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/ChibiOS.c @@ -103,7 +103,7 @@ static struct ChibiOS_params ChibiOS_params_list[] = { }; #define CHIBIOS_NUM_PARAMS ((int)(sizeof(ChibiOS_params_list)/sizeof(struct ChibiOS_params))) -static int ChibiOS_detect_rtos(struct target *target); +static bool ChibiOS_detect_rtos(struct target *target); static int ChibiOS_create(struct target *target); static int ChibiOS_update_threads(struct rtos *rtos); static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -510,7 +510,7 @@ static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) return 0; } -static int ChibiOS_detect_rtos(struct target *target) +static bool ChibiOS_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && ((target->rtos->symbols[ChibiOS_VAL_rlist].address != 0) || @@ -519,14 +519,14 @@ static int ChibiOS_detect_rtos(struct target *target) if (target->rtos->symbols[ChibiOS_VAL_ch_debug].address == 0) { LOG_INFO("It looks like the target may be running ChibiOS " "without ch_debug."); - return 0; + return false; } /* looks like ChibiOS with memory map enabled.*/ - return 1; + return true; } - return 0; + return false; } static int ChibiOS_create(struct target *target) diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index 83961eb95..6027d6739 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -99,7 +99,7 @@ static const struct FreeRTOS_params FreeRTOS_params_list[] = { #define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params))) -static int FreeRTOS_detect_rtos(struct target *target); +static bool FreeRTOS_detect_rtos(struct target *target); static int FreeRTOS_create(struct target *target); static int FreeRTOS_update_threads(struct rtos *rtos); static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -528,14 +528,14 @@ static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_i #endif -static int FreeRTOS_detect_rtos(struct target *target) +static bool FreeRTOS_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) { /* looks like FreeRTOS */ - return 1; + return true; } - return 0; + return false; } static int FreeRTOS_create(struct target *target) diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index ab8a66e93..b7dbe6d11 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -35,7 +35,7 @@ static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const st static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id); static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id); -static int ThreadX_detect_rtos(struct target *target); +static bool ThreadX_detect_rtos(struct target *target); static int ThreadX_create(struct target *target); static int ThreadX_update_threads(struct rtos *rtos); static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -492,14 +492,14 @@ static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) return 0; } -static int ThreadX_detect_rtos(struct target *target) +static bool ThreadX_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) { /* looks like ThreadX */ - return 1; + return true; } - return 0; + return false; } #if 0 diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c index edc3d8b51..9e41030ee 100644 --- a/src/rtos/eCos.c +++ b/src/rtos/eCos.c @@ -27,7 +27,7 @@ #include "helper/types.h" #include "rtos_ecos_stackings.h" -static int eCos_detect_rtos(struct target *target); +static bool eCos_detect_rtos(struct target *target); static int eCos_create(struct target *target); static int eCos_update_threads(struct rtos *rtos); static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -363,14 +363,14 @@ static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) return 0; } -static int eCos_detect_rtos(struct target *target) +static bool eCos_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[eCos_VAL_thread_list].address != 0)) { /* looks like eCos */ - return 1; + return true; } - return 0; + return false; } static int eCos_create(struct target *target) diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index e515383ac..a40c86c3f 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -31,7 +31,7 @@ #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64) -static int embKernel_detect_rtos(struct target *target); +static bool embKernel_detect_rtos(struct target *target); static int embKernel_create(struct target *target); static int embKernel_update_threads(struct rtos *rtos); static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -107,13 +107,13 @@ static const struct embKernel_params embKernel_params_list[] = { } }; -static int embKernel_detect_rtos(struct target *target) +static bool embKernel_detect_rtos(struct target *target) { if (target->rtos->symbols != NULL) { if (target->rtos->symbols[SYMBOL_ID_sCurrentTask].address != 0) - return 1; + return true; } - return 0; + return false; } static int embKernel_create(struct target *target) diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 3efaab133..3b2a2b0c3 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -309,10 +309,10 @@ static int linux_os_thread_reg_list(struct rtos *rtos, return ERROR_OK; } -static int linux_os_detect(struct target *target) +static bool linux_os_detect(struct target *target) { LOG_INFO("should no be called"); - return 0; + return false; } static int linux_os_smp_init(struct target *target); diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index 63a48c54b..531b03b57 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -244,9 +244,9 @@ static int mqx_is_scheduler_running( } /* - * API function, return 1 if MQX is present + * API function, return true if MQX is present */ -static int mqx_detect_rtos( +static bool mqx_detect_rtos( struct target *target ) { @@ -254,9 +254,9 @@ static int mqx_detect_rtos( (target->rtos->symbols != NULL) && (target->rtos->symbols[mqx_VAL_mqx_kernel_data].address != 0) ) { - return 1; + return true; } - return 0; + return false; } /* diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 70c1193e5..87aa5027d 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -59,7 +59,7 @@ struct rtos { struct rtos_type { const char *name; - int (*detect_rtos)(struct target *target); + bool (*detect_rtos)(struct target *target); int (*create)(struct target *target); int (*smp_init)(struct target *target); int (*update_threads)(struct rtos *rtos); diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 0a0fb3e9e..8e63ea4e6 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -241,7 +241,7 @@ static int uCOS_III_update_thread_offsets(struct rtos *rtos) return ERROR_OK; } -static int uCOS_III_detect_rtos(struct target *target) +static bool uCOS_III_detect_rtos(struct target *target) { return target->rtos->symbols != NULL && target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0; From 2fcbe3b8f7309d3263e58bf2e3e0125d0bacc8d9 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 29 Oct 2017 15:58:41 +0100 Subject: [PATCH 38/54] target: Constify parameter of is_armv7m() Change-Id: Ieea1b0dec88818e9e8d5c8c5d54aa8959556d77b Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4275 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Andreas Fritiofson --- src/target/armv7m.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 284bb9caa..6f5d6f995 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -174,7 +174,7 @@ target_to_armv7m(struct target *target) return container_of(target->arch_info, struct armv7m_common, arm); } -static inline bool is_armv7m(struct armv7m_common *armv7m) +static inline bool is_armv7m(const struct armv7m_common *armv7m) { return armv7m->common_magic == ARMV7M_COMMON_MAGIC; } From 8bb7021ca8ef9ec9db8ce629a5d4dad5b73b6b07 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 22 Sep 2016 22:36:28 +0200 Subject: [PATCH 39/54] server/gdb: Use get_target_from_connection() Change-Id: I2c66bf6da734a3b71e358553943e9fc3c6578c39 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4277 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/server/gdb_server.c | 67 +++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 483e5510b..d7fff66a0 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -917,10 +917,11 @@ static int gdb_target_callback_event_handler(struct target *target, static int gdb_new_connection(struct connection *connection) { struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection)); - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; int retval; int initial_ack; + target = get_target_from_connection(connection); connection->priv = gdb_connection; /* initialize gdb connection information */ @@ -949,12 +950,12 @@ static int gdb_new_connection(struct connection *connection) * GDB session could leave dangling breakpoints if e.g. communication * timed out. */ - breakpoint_clear_target(gdb_service->target); - watchpoint_clear_target(gdb_service->target); + breakpoint_clear_target(target); + watchpoint_clear_target(target); /* clean previous rtos session if supported*/ - if ((gdb_service->target->rtos) && (gdb_service->target->rtos->type->clean)) - gdb_service->target->rtos->type->clean(gdb_service->target); + if ((target->rtos) && (target->rtos->type->clean)) + target->rtos->type->clean(target); /* remove the initial ACK from the incoming buffer */ retval = gdb_get_char(connection, &initial_ack); @@ -966,7 +967,7 @@ static int gdb_new_connection(struct connection *connection) */ if (initial_ack != '+') gdb_putback_char(connection, initial_ack); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH); + target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH); if (gdb_use_memory_map) { /* Connect must fail if the memory map can't be set up correctly. @@ -978,7 +979,7 @@ static int gdb_new_connection(struct connection *connection) for (i = 0; i < flash_get_bank_count(); i++) { struct flash_bank *p; p = get_flash_bank_by_num_noprobe(i); - if (p->target != gdb_service->target) + if (p->target != target) continue; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { @@ -992,8 +993,8 @@ static int gdb_new_connection(struct connection *connection) gdb_actual_connections++; LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s", gdb_actual_connections, - target_name(gdb_service->target), - target_state_name(gdb_service->target)); + target_name(target), + target_state_name(target)); /* DANGER! If we fail subsequently, we must remove this handler, * otherwise we occasionally see crashes as the timer can invoke the @@ -1007,9 +1008,11 @@ static int gdb_new_connection(struct connection *connection) static int gdb_connection_closed(struct connection *connection) { - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; struct gdb_connection *gdb_connection = connection->priv; + target = get_target_from_connection(connection); + /* we're done forwarding messages. Tear down callback before * cleaning up connection. */ @@ -1017,8 +1020,8 @@ static int gdb_connection_closed(struct connection *connection) gdb_actual_connections--; LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", - target_name(gdb_service->target), - target_state_name(gdb_service->target), + target_name(target), + target_state_name(target), gdb_actual_connections); /* see if an image built with vFlash commands is left */ @@ -1029,7 +1032,7 @@ static int gdb_connection_closed(struct connection *connection) } /* if this connection registered a debug-message receiver delete it */ - delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target); + delete_debug_msg_receiver(connection->cmd_ctx, target); if (connection->priv) { free(connection->priv); @@ -1039,9 +1042,9 @@ static int gdb_connection_closed(struct connection *connection) target_unregister_event_callback(gdb_target_callback_event_handler, connection); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END); + target_call_event_callbacks(target, TARGET_EVENT_GDB_END); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); + target_call_event_callbacks(target, TARGET_EVENT_GDB_DETACH); return ERROR_OK; } @@ -2558,9 +2561,11 @@ static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; int result; + target = get_target_from_connection(connection); + /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { @@ -2597,18 +2602,18 @@ static int gdb_v_packet(struct connection *connection, flash_set_dirty(); /* perform any target specific operations before the erase */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_START); /* vFlashErase:addr,length messages require region start and * end to be "block" aligned ... if padding is ever needed, * GDB will have become dangerously confused. */ - result = flash_erase_address_range(gdb_service->target, - false, addr, length); + result = flash_erase_address_range(target, false, addr, + length); /* perform any target specific operations after the erase */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_END); /* perform erase */ @@ -2663,10 +2668,12 @@ static int gdb_v_packet(struct connection *connection, /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_WRITE_START); - result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END); + result = flash_write(target, gdb_connection->vflash_image, + &written, 0); + target_call_event_callbacks(target, + TARGET_EVENT_GDB_FLASH_WRITE_END); if (result != ERROR_OK) { if (result == ERROR_FLASH_DST_OUT_OF_BANK) gdb_put_packet(connection, "E.memtype", 9); @@ -2690,9 +2697,8 @@ static int gdb_v_packet(struct connection *connection, static int gdb_detach(struct connection *connection) { - struct gdb_service *gdb_service = connection->service->priv; - - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); + target_call_event_callbacks(get_target_from_connection(connection), + TARGET_EVENT_GDB_DETACH); return gdb_put_packet(connection, "OK", 2); } @@ -2771,14 +2777,15 @@ static int gdb_input_inner(struct connection *connection) /* Do not allocate this on the stack */ static char gdb_packet_buffer[GDB_BUFFER_SIZE]; - struct gdb_service *gdb_service = connection->service->priv; - struct target *target = gdb_service->target; + struct target *target; char const *packet = gdb_packet_buffer; int packet_size; int retval; struct gdb_connection *gdb_con = connection->priv; static int extended_protocol; + target = get_target_from_connection(connection); + /* drain input buffer. If one of the packets fail, then an error * packet is replied, if applicable. * @@ -2948,8 +2955,8 @@ static int gdb_input_inner(struct connection *connection) break; case 'R': /* handle extended restart packet */ - breakpoint_clear_target(gdb_service->target); - watchpoint_clear_target(gdb_service->target); + breakpoint_clear_target(target); + watchpoint_clear_target(target); command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); /* set connection as attached after reset */ From 5679dc657c9f4530d2137c1b94f8077ab7fb7146 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 29 Oct 2017 19:54:00 +0100 Subject: [PATCH 40/54] server/gdb: Use 'bool' instead of 'int' for boolean values Change-Id: I71c2f2553a29e9ef167ff3313cc06c7b31c64190 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4278 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/server/gdb_server.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index d7fff66a0..626179c3c 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -71,8 +71,8 @@ struct gdb_connection { int ctrl_c; enum target_state frontend_state; struct image *vflash_image; - int closed; - int busy; + bool closed; + bool busy; int noack_mode; /* set flag to true if you want the next stepi to return immediately. * allowing GDB to pick up a fresh set of register values from the target @@ -215,7 +215,7 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) if (gdb_con->buf_cnt > 0) break; if (gdb_con->buf_cnt == 0) { - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } @@ -227,10 +227,10 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) usleep(1000); break; case WSAECONNABORTED: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; case WSAECONNRESET: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %d", errno); @@ -242,14 +242,14 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) usleep(1000); break; case ECONNABORTED: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; case ECONNRESET: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %s", strerror(errno)); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } #endif @@ -341,7 +341,7 @@ static int gdb_write(struct connection *connection, void *data, int len) if (connection_write(connection, data, len) == len) return ERROR_OK; - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } @@ -448,7 +448,7 @@ static int gdb_put_packet_inner(struct connection *connection, return ERROR_OK; } else { LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } else if (reply == '$') { @@ -458,7 +458,7 @@ static int gdb_put_packet_inner(struct connection *connection, } else { LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } @@ -471,9 +471,9 @@ static int gdb_put_packet_inner(struct connection *connection, int gdb_put_packet(struct connection *connection, char *buffer, int len) { struct gdb_connection *gdb_con = connection->priv; - gdb_con->busy = 1; + gdb_con->busy = true; int retval = gdb_put_packet_inner(connection, buffer, len); - gdb_con->busy = 0; + gdb_con->busy = false; /* we sent some data, reset timer for keep alive messages */ kept_alive(); @@ -679,9 +679,9 @@ static int gdb_get_packet_inner(struct connection *connection, static int gdb_get_packet(struct connection *connection, char *buffer, int *len) { struct gdb_connection *gdb_con = connection->priv; - gdb_con->busy = 1; + gdb_con->busy = true; int retval = gdb_get_packet_inner(connection, buffer, len); - gdb_con->busy = 0; + gdb_con->busy = false; return retval; } @@ -930,8 +930,8 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->ctrl_c = 0; gdb_connection->frontend_state = TARGET_HALTED; gdb_connection->vflash_image = NULL; - gdb_connection->closed = 0; - gdb_connection->busy = 0; + gdb_connection->closed = false; + gdb_connection->busy = false; gdb_connection->noack_mode = 0; gdb_connection->sync = false; gdb_connection->mem_write_error = false; From 5d6bf8704ce7ed9a7e471e601ab91061c39f88c6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 20 Aug 2016 05:49:49 +0800 Subject: [PATCH 41/54] spi: add n25q256 flash * 256 MBit SPI flash * https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/mt25q/die-rev-a/mt25q_qljs_l_256_aba_0.pdf spells out the entire zoo of IDs * used e.g. on Xilinx KCU105 Change-Id: I18b19292b4869627adb9071266271962fec68fb4 Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4186 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/spi.c | 98 +++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 6501fbc18..273e8508f 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -31,52 +31,54 @@ * from device datasheets and Linux SPI flash drivers. */ const struct flash_device flash_devices[] = { /* name, erase_cmd, chip_erase_cmd, device_id, pagesize, sectorsize, size_in_bytes */ - FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), - FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), - FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), - FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), - FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), - FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), - FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), - FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), - FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), - FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), - FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), - FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), - FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), - FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), - FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), - FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), - FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), - FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), - FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), - FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), - FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), - FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), - FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), - FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), - FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), - FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), - FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), - FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), - FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), - FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), - FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), - FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) + FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), + FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), + FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), + FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), + FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), + FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), + FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), + FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), + FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), + FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), + FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), + FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), + FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), + FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), + FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), + FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), + FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), + FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), + FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), + FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), + FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), + FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), + FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), + FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), + FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), + FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), + FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), + FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), + FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), + FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), + FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), + FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), + FLASH_ID("micron n25q256 3v", 0xd8, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000), + FLASH_ID("micron n25q256 1.8v", 0xd8, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000), + FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), + FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), + FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), + FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), + FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), + FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), + FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), + FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), + FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), + FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) }; From 06aebfacda1f60052f6ea0f3d09936184e1bfab8 Mon Sep 17 00:00:00 2001 From: Bas Vermeulen Date: Tue, 21 Nov 2017 17:12:24 +0100 Subject: [PATCH 42/54] Only call cmsis_dap_cmd_DAP_SWD_Configure when swd_mode is enabled The CMSIS-DAP used by NXP's LS1012ARDB board only supports JTAG, and not SWD. Calling cmsis_dap_cmd_DAP_SWD_Configure returns with an error (and doesn't actually do anything in the debugger). Wrap the call to cmsis_dap_cmd_DAP_SWD_Configure in a check for swd_mode, to make sure initialisation doesn't fail needlessly. Change-Id: Id7e568cb6e36886bd7c5b3699d198a77a51c28c9 Signed-off-by: Bas Vermeulen Reviewed-on: http://openocd.zylin.com/4294 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Matthias Welwarsky --- src/jtag/drivers/cmsis_dap_usb.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 19c3b19c9..345c1fd7e 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -958,11 +958,14 @@ static int cmsis_dap_init(void) retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0); if (retval != ERROR_OK) return ERROR_FAIL; - /* Data Phase (bit 2) must be set to 1 if sticky overrun - * detection is enabled */ - retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ - if (retval != ERROR_OK) - return ERROR_FAIL; + + if (swd_mode) { + /* Data Phase (bit 2) must be set to 1 if sticky overrun + * detection is enabled */ + retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ + if (retval != ERROR_OK) + return ERROR_FAIL; + } retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */ if (retval != ERROR_OK) From 6a66cccbad7e51ac1b3ea929ab0c86dd02617797 Mon Sep 17 00:00:00 2001 From: Alexandre Torgue Date: Mon, 13 Nov 2017 14:05:28 +0100 Subject: [PATCH 43/54] flash: Add new stm32h7x driver support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add basic support for: -STM32H7x (Embedded flash 2M) Erase and write tested on stm32h743. Change-Id: Ie8d8786227cdeee39fcf5663167a053ad8dcef4c Signed-off-by: Rémi Prud'homme Signed-off-by: Alexandre TORGUE Reviewed-on: http://openocd.zylin.com/4181 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/loaders/flash/stm32h7x.S | 121 +++ doc/openocd.texi | 27 + src/flash/nor/Makefile.am | 1 + src/flash/nor/drivers.c | 2 + src/flash/nor/stm32h7x.c | 1183 ++++++++++++++++++++++++++++++ 5 files changed, 1334 insertions(+) create mode 100644 contrib/loaders/flash/stm32h7x.S create mode 100644 src/flash/nor/stm32h7x.c diff --git a/contrib/loaders/flash/stm32h7x.S b/contrib/loaders/flash/stm32h7x.S new file mode 100644 index 000000000..0f5ea996f --- /dev/null +++ b/contrib/loaders/flash/stm32h7x.S @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2017 by STMicroelectronics * + * * + * 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. * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m7 + .thumb + .thumb_func + +/* + * To assemble: + * arm-none-eabi-gcc -c stm32h7x.S + * + * To disassemble: + * arm-none-eabi-objdump -d stm32h7x.o + * + * To generate binary file: + * arm-none-eabi-objcopy -O binary stm32h7x.o stm32h7_flash_write_code.bin + * + * To generate include file: + * xxd -i stm32h7_flash_write_code.bin + */ + +/* + * Code limitations: + * The workarea must have size multiple of 4 bytes, since R/W + * operations are all at 32 bits. + * The workarea must be big enough to contain 32 bytes of data, + * thus the minimum size is (rp, wp, data) = 4 + 4 + 32 = 40 bytes. + * To benefit from concurrent host write-to-buffer and target + * write-to-flash, the workarea must be way bigger than the minimum. + */ + +/* + * Params : + * r0 = workarea start, status (out) + * r1 = workarea end + * r2 = target address + * r3 = count (256 bit words) + * r4 = flash reg base + * + * Clobbered: + * r5 - rp + * r6 - wp, status, tmp + * r7 - loop index, tmp + */ + +#define STM32_FLASH_CR_OFFSET 0x0C /* offset of CR register in FLASH struct */ +#define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register in FLASH struct */ +#define STM32_CR_PROG 0x00000032 /* PSIZE64 | PG */ +#define STM32_SR_BUSY_MASK 0x00000001 /* BSY */ +#define STM32_SR_ERROR_MASK 0x03ee0000 /* DBECCERR | SNECCERR | RDSERR | RDPERR | OPERR + | INCERR | STRBERR | PGSERR | WRPERR */ + +code: + ldr r5, [r0, #4] /* read rp */ + +wait_fifo: + ldr r6, [r0, #0] /* read wp */ + cbz r6, exit /* abort if wp == 0, status = 0 */ + subs r6, r6, r5 /* number of bytes available for read in r6 */ + ittt mi /* if wrapped around */ + addmi r6, r1 /* add size of buffer */ + submi r6, r0 + submi r6, #8 + cmp r6, #32 /* wait until 32 bytes are available */ + bcc wait_fifo + + mov r6, #STM32_CR_PROG + str r6, [r4, #STM32_FLASH_CR_OFFSET] + + mov r7, #8 /* program by 8 words = 32 bytes */ +write_flash: + ldr r6, [r5], #0x04 /* read one word from src, increment ptr */ + str r6, [r2], #0x04 /* write one word to dst, increment ptr */ + dsb + cmp r5, r1 /* if rp >= end of buffer ... */ + it cs + addcs r5, r0, #8 /* ... then wrap at buffer start */ + subs r7, r7, #1 /* decrement loop index */ + bne write_flash /* loop if not done */ + +busy: + ldr r6, [r4, #STM32_FLASH_SR_OFFSET] + tst r6, #STM32_SR_BUSY_MASK + bne busy /* operation in progress, wait ... */ + + ldr r7, stm32_sr_error_mask + tst r6, r7 + bne error /* fail... */ + + str r5, [r0, #4] /* store rp */ + subs r3, r3, #1 /* decrement count */ + bne wait_fifo /* loop if not done */ + b exit + +error: + movs r7, #0 + str r7, [r0, #4] /* set rp = 0 on error */ + +exit: + mov r0, r6 /* return status in r0 */ + bkpt #0x00 + +stm32_sr_error_mask: + .word STM32_SR_ERROR_MASK diff --git a/doc/openocd.texi b/doc/openocd.texi index e452fa3b3..2719c2d97 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6009,6 +6009,33 @@ The @var{num} parameter is a value shown by @command{flash banks}, @var{optcr2} @end deffn @end deffn +@deffn {Flash Driver} stm32h7x +All members of the STM32H7 microcontroller families from ST Microelectronics +include internal flash and use ARM Cortex-M7 core. +The driver automatically recognizes a number of these chips using +the chip identification register, and autoconfigures itself. + +Note that some devices have been found that have a flash size register that contains +an invalid value, to workaround this issue you can override the probed value used by +the flash driver. + +@example +flash bank $_FLASHNAME stm32h7x 0 0x20000 0 0 $_TARGETNAME +@end example + +Some stm32h7x-specific commands are defined: + +@deffn Command {stm32h7x lock} num +Locks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32h7x unlock} num +Unlocks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn +@end deffn + @deffn {Flash Driver} stm32lx All members of the STM32L microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 4dac110c4..ebf47756f 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -49,6 +49,7 @@ NOR_DRIVERS = \ %D%/stm32f2x.c \ %D%/stm32lx.c \ %D%/stm32l4x.c \ + %D%/stm32h7x.c \ %D%/str7x.c \ %D%/str9x.c \ %D%/str9xpec.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 9594ed9a3..eacca0346 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -60,6 +60,7 @@ extern struct flash_driver stm32f1x_flash; extern struct flash_driver stm32f2x_flash; extern struct flash_driver stm32lx_flash; extern struct flash_driver stm32l4x_flash; +extern struct flash_driver stm32h7x_flash; extern struct flash_driver stmsmi_flash; extern struct flash_driver str7x_flash; extern struct flash_driver str9x_flash; @@ -114,6 +115,7 @@ static struct flash_driver *flash_drivers[] = { &stm32f2x_flash, &stm32lx_flash, &stm32l4x_flash, + &stm32h7x_flash, &stmsmi_flash, &str7x_flash, &str9x_flash, diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c new file mode 100644 index 000000000..01e6f06dc --- /dev/null +++ b/src/flash/nor/stm32h7x.c @@ -0,0 +1,1183 @@ +/*************************************************************************** + * Copyright (C) 2017 by STMicroelectronics * + * * + * 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, see . * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include + + +/* Erase time can be as high as 1000ms, 10x this and it's toast... */ +#define FLASH_ERASE_TIMEOUT 10000 +#define FLASH_WRITE_TIMEOUT 5 + +/* RM 433 */ +/* Same Flash registers for both banks, */ +/* access depends on Flash Base address */ +#define FLASH_ACR 0x00 +#define FLASH_KEYR 0x04 +#define FLASH_OPTKEYR 0x08 +#define FLASH_CR 0x0C +#define FLASH_SR 0x10 +#define FLASH_CCR 0x14 +#define FLASH_OPTCR 0x18 +#define FLASH_OPTCUR 0x1C +#define FLASH_OPTPRG 0x20 +#define FLASH_OPTCCR 0x24 +#define FLASH_WPSNCUR 0x38 +#define FLASH_WPSNPRG 0x3C + + +/* FLASH_CR register bits */ +#define FLASH_LOCK (1 << 0) +#define FLASH_PG (1 << 1) +#define FLASH_SER (1 << 2) +#define FLASH_BER_CMD (1 << 3) +#define FLASH_PSIZE_8 (0 << 4) +#define FLASH_PSIZE_16 (1 << 4) +#define FLASH_PSIZE_32 (2 << 4) +#define FLASH_PSIZE_64 (3 << 4) +#define FLASH_FW (1 << 6) +#define FLASH_START (1 << 7) + +#define FLASH_SNB(a) ((a) << 8) + +/* FLASH_SR register bits */ +#define FLASH_BSY (1 << 0) /* Operation in progress */ +#define FLASH_WRPERR (1 << 17) /* Write protection error */ +#define FLASH_PGSERR (1 << 18) /* Programming sequence error */ +#define FLASH_STRBERR (1 << 19) /* Strobe error */ +#define FLASH_INCERR (1 << 21) /* Increment error */ +#define FLASH_OPERR (1 << 22) /* Operation error */ +#define FLASH_RDPERR (1 << 23) /* Read Protection error */ +#define FLASH_RDSERR (1 << 24) /* Secure Protection error */ +#define FLASH_SNECCERR (1 << 25) /* Single ECC error */ +#define FLASH_DBECCERR (1 << 26) /* Double ECC error */ + +#define FLASH_ERROR (FLASH_WRPERR | FLASH_PGSERR | FLASH_STRBERR | FLASH_INCERR | FLASH_OPERR | \ + FLASH_RDPERR | FLASH_RDSERR | FLASH_SNECCERR | FLASH_DBECCERR) + +/* FLASH_OPTCR register bits */ +#define OPT_LOCK (1 << 0) +#define OPT_START (1 << 1) + +/* FLASH_OPTCUR bit definitions (reading) */ +#define IWDG1_HW (1 << 4) + +/* register unlock keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* option register unlock key */ +#define OPTKEY1 0x08192A3B +#define OPTKEY2 0x4C5D6E7F + +#define DBGMCU_IDCODE_REGISTER 0x5C001000 +#define FLASH_BANK0_ADDRESS 0x08000000 +#define FLASH_BANK1_ADDRESS 0x08100000 +#define FLASH_REG_BASE_B0 0x52002000 +#define FLASH_REG_BASE_B1 0x52002100 +#define FLASH_SIZE_ADDRESS 0x1FF1E880 +#define FLASH_BLOCK_SIZE 32 + +struct stm32h7x_rev { + uint16_t rev; + const char *str; +}; + +struct stm32x_options { + uint8_t RDP; + uint32_t protection; /* bank1 WRP */ + uint32_t protection2; /* bank2 WRP */ + uint8_t user_options; + uint8_t user2_options; + uint8_t user3_options; + uint8_t independent_watchdog_selection; +}; + +struct stm32h7x_part_info { + uint16_t id; + const char *device_str; + const struct stm32h7x_rev *revs; + size_t num_revs; + unsigned int page_size; + unsigned int pages_per_sector; + uint16_t max_flash_size_kb; + uint8_t has_dual_bank; + uint16_t first_bank_size_kb; /* Used when has_dual_bank is true */ + uint32_t flash_base; /* Flash controller registers location */ + uint32_t fsize_base; /* Location of FSIZE register */ +}; + +struct stm32h7x_flash_bank { + int probed; + uint32_t idcode; + uint32_t user_bank_size; + uint32_t flash_base; /* Address of flash reg controller */ + struct stm32x_options option_bytes; + const struct stm32h7x_part_info *part_info; +}; + +static const struct stm32h7x_rev stm32_450_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, +}; + +static const struct stm32h7x_part_info stm32h7x_parts[] = { + { + .id = 0x450, + .revs = stm32_450_revs, + .num_revs = ARRAY_SIZE(stm32_450_revs), + .device_str = "STM32H7xx 2M", + .page_size = 128, /* 128 KB */ + .max_flash_size_kb = 2048, + .first_bank_size_kb = 1024, + .has_dual_bank = 1, + .flash_base = FLASH_REG_BASE_B0, + .fsize_base = FLASH_SIZE_ADDRESS, + }, +}; + +static int stm32x_unlock_reg(struct flash_bank *bank); +static int stm32x_lock_reg(struct flash_bank *bank); +static int stm32x_probe(struct flash_bank *bank); + +/* flash bank stm32x 0 0 */ + +FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) +{ + struct stm32h7x_flash_bank *stm32x_info; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank)); + bank->driver_priv = stm32x_info; + + stm32x_info->probed = 0; + stm32x_info->user_bank_size = bank->size; + + return ERROR_OK; +} + +static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + return reg + stm32x_info->flash_base; +} + +static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) +{ + struct target *target = bank->target; + return target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_SR), status); +} + +static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + uint32_t status; + int retval; + + /* wait for busy to clear */ + for (;;) { + retval = stm32x_get_flash_status(bank, &status); + if (retval != ERROR_OK) { + LOG_INFO("wait_status_busy, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base); + return retval; + } + + if ((status & FLASH_BSY) == 0) + break; + + if (timeout-- <= 0) { + LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + return ERROR_FAIL; + } + alive_sleep(1); + } + + if (status & FLASH_WRPERR) { + LOG_INFO("wait_status_busy, WRPERR : error : remote address 0x%x", stm32x_info->flash_base); + retval = ERROR_FAIL; + } + + /* Clear error + EOP flags but report errors */ + if (status & FLASH_ERROR) { + /* If this operation fails, we ignore it and report the original retval */ + target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status); + } + return retval; +} + +static int stm32x_unlock_reg(struct flash_bank *bank) +{ + uint32_t ctrl; + struct target *target = bank->target; + + /* first check if not already unlocked + * otherwise writing on FLASH_KEYR will fail + */ + int retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & FLASH_LOCK) == 0) + return ERROR_OK; + + /* unlock flash registers for bank */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_LOCK) { + LOG_ERROR("flash not unlocked STM32_FLASH_CRx: %" PRIx32, ctrl); + return ERROR_TARGET_FAILURE; + } + return ERROR_OK; +} + +static int stm32x_unlock_option_reg(struct flash_bank *bank) +{ + uint32_t ctrl; + struct target *target = bank->target; + + int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & OPT_LOCK) == 0) + return ERROR_OK; + + /* unlock option registers */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY2); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & OPT_LOCK) { + LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: %" PRIx32, ctrl); + return ERROR_TARGET_FAILURE; + } + + return ERROR_OK; +} + +static int stm32x_lock_reg(struct flash_bank *bank) +{ + struct target *target = bank->target; + + /* Lock bank reg */ + int retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_read_options(struct flash_bank *bank) +{ + uint32_t optiondata; + struct stm32h7x_flash_bank *stm32x_info = NULL; + struct target *target = bank->target; + + stm32x_info = bank->driver_priv; + + /* read current option bytes */ + int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + + /* decode option data */ + stm32x_info->option_bytes.user_options = optiondata & 0xfc; + stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; + stm32x_info->option_bytes.user2_options = (optiondata >> 16) & 0xff; + stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0x83; + + if (optiondata & IWDG1_HW) + stm32x_info->option_bytes.independent_watchdog_selection = 1; + else + stm32x_info->option_bytes.independent_watchdog_selection = 0; + + if (stm32x_info->option_bytes.RDP != 0xAA) + LOG_INFO("Device Security Bit Set"); + + /* read current WPSN option bytes */ + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + stm32x_info->option_bytes.protection = optiondata & 0xff; + + /* read current WPSN2 option bytes */ + retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + stm32x_info->option_bytes.protection2 = optiondata & 0xff; + + return ERROR_OK; +} + +static int stm32x_write_options(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = NULL; + struct target *target = bank->target; + uint32_t optiondata; + + stm32x_info = bank->driver_priv; + + int retval = stm32x_unlock_option_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* rebuild option data */ + optiondata = stm32x_info->option_bytes.user_options; + optiondata |= (stm32x_info->option_bytes.RDP << 8); + optiondata |= (stm32x_info->option_bytes.user2_options & 0xff) << 16; + optiondata |= (stm32x_info->option_bytes.user3_options & 0x83) << 24; + + if (stm32x_info->option_bytes.independent_watchdog_selection) + optiondata |= IWDG1_HW; + else + optiondata &= ~IWDG1_HW; + + /* program options */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = stm32x_info->option_bytes.protection & 0xff; + /* Program protection WPSNPRG */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = stm32x_info->option_bytes.protection2 & 0xff; + /* Program protection WPSNPRG2 */ + retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = 0x40000000; + /* Remove OPT error flag before programming */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCCR, optiondata); + if (retval != ERROR_OK) + return retval; + + /* start programming cycle */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START); + if (retval != ERROR_OK) + return retval; + + /* wait for completion */ + int timeout = FLASH_ERASE_TIMEOUT; + for (;;) { + uint32_t status; + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status); + if (retval != ERROR_OK) { + LOG_INFO("stm32x_write_options: wait_status_busy : error"); + return retval; + } + if ((status & FLASH_BSY) == 0) + break; + + if (timeout-- <= 0) { + LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + return ERROR_FAIL; + } + alive_sleep(1); + } + + /* relock option registers */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_protect_check(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + /* read 'write protection' settings */ + int retval = stm32x_read_options(bank); + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read option bytes"); + return retval; + } + + for (int i = 0; i < bank->num_sectors; i++) { + if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { + if (stm32x_info->option_bytes.protection & (1 << i)) + bank->sectors[i].is_protected = 0; + else + bank->sectors[i].is_protected = 1; + } else { + if (stm32x_info->option_bytes.protection2 & (1 << i)) + bank->sectors[i].is_protected = 0; + else + bank->sectors[i].is_protected = 1; + } + } + return ERROR_OK; +} + +static int stm32x_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + int retval; + + assert(first < bank->num_sectors); + assert(last < bank->num_sectors); + + if (bank->target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* + Sector Erase + To erase a sector, follow the procedure below: + 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the + FLASH_SR register + 2. Set the SER bit and select the sector + you wish to erase (SNB) in the FLASH_CR register + 3. Set the STRT bit in the FLASH_CR register + 4. Wait for the BSY bit to be cleared + */ + for (int i = first; i <= last; i++) { + LOG_DEBUG("erase sector %d", i); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64); + if (retval != ERROR_OK) { + LOG_ERROR("Error erase sector %d", i); + return retval; + } + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64 | FLASH_START); + if (retval != ERROR_OK) { + LOG_ERROR("Error erase sector %d", i); + return retval; + } + retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + + if (retval != ERROR_OK) { + LOG_ERROR("erase time-out error sector %d", i); + return retval; + } + bank->sectors[i].is_erased = 1; + } + + retval = stm32x_lock_reg(bank); + if (retval != ERROR_OK) { + LOG_ERROR("error during the lock of flash"); + return retval; + } + + return ERROR_OK; +} + +static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + /* read protection settings */ + int retval = stm32x_read_options(bank); + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read option bytes"); + return retval; + } + + for (int i = first; i <= last; i++) { + if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { + if (set) + stm32x_info->option_bytes.protection &= ~(1 << i); + else + stm32x_info->option_bytes.protection |= (1 << i); + } else { + if (set) + stm32x_info->option_bytes.protection2 &= ~(1 << i); + else + stm32x_info->option_bytes.protection2 |= (1 << i); + } + } + + LOG_INFO("stm32x_protect, option_bytes written WRP1 0x%x , WRP2 0x%x", + (stm32x_info->option_bytes.protection & 0xff), (stm32x_info->option_bytes.protection2 & 0xff)); + + retval = stm32x_write_options(bank); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + /* + * If the size of the data part of the buffer is not a multiple of FLASH_BLOCK_SIZE, we get + * "corrupted fifo read" pointer in target_run_flash_async_algorithm() + */ + uint32_t data_size = 512 * FLASH_BLOCK_SIZE; /* 16384 */ + uint32_t buffer_size = 8 + data_size; + struct working_area *write_algorithm; + struct working_area *source; + uint32_t address = bank->base + offset; + struct reg_param reg_params[5]; + struct armv7m_algorithm armv7m_info; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int retval = ERROR_OK; + + /* see contrib/loaders/flash/smt32h7x.S for src */ + static const uint8_t stm32x_flash_write_code[] = { + /* : */ + 0x45, 0x68, /* ldr r5, [r0, #4] */ + /* : */ + 0x06, 0x68, /* ldr r6, [r0, #0] */ + 0x26, 0xb3, /* cbz r6, */ + 0x76, 0x1b, /* subs r6, r6, r5 */ + 0x42, 0xbf, /* ittt mi */ + 0x76, 0x18, /* addmi r6, r6, r1 */ + 0x36, 0x1a, /* submi r6, r6, r0 */ + 0x08, 0x3e, /* submi r6, #8 */ + 0x20, 0x2e, /* cmp r6, #32 */ + 0xf6, 0xd3, /* bcc.n */ + 0x4f, 0xf0, 0x32, 0x06, /* mov.w r6, #STM32_PROG */ + 0xe6, 0x60, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ + 0x4f, 0xf0, 0x08, 0x07, /* mov.w r7, #8 */ + /* : */ + 0x55, 0xf8, 0x04, 0x6b, /* ldr.w r6, [r5], #4 */ + 0x42, 0xf8, 0x04, 0x6b, /* str.w r6, [r2], #4 */ + 0xbf, 0xf3, 0x4f, 0x8f, /* dsb sy */ + 0x8d, 0x42, /* cmp r5, r1 */ + 0x28, 0xbf, /* it cs */ + 0x00, 0xf1, 0x08, 0x05, /* addcs.w r5, r0, #8 */ + 0x01, 0x3f, /* subs r7, #1 */ + 0xf3, 0xd1, /* bne.n */ + /* : */ + 0x26, 0x69, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ + 0x16, 0xf0, 0x01, 0x0f, /* tst.w r6, #STM32_SR_BUSY_MASK */ + 0xfb, 0xd1, /* bne.n */ + 0x05, 0x4f, /* ldr r7, [pc, #20] ; () */ + 0x3e, 0x42, /* tst r6, r7 */ + 0x03, 0xd1, /* bne.n */ + 0x45, 0x60, /* str r5, [r0, #4] */ + 0x01, 0x3b, /* subs r3, #1 */ + 0xdb, 0xd1, /* bne.n */ + 0x01, 0xe0, /* b.n */ + /* : */ + 0x00, 0x27, /* movs r7, #0 */ + 0x47, 0x60, /* str r7, [r0, #4] */ + /* : */ + 0x30, 0x46, /* mov r0, r6 */ + 0x00, 0xbe, /* bkpt 0x0000 */ + /* : */ + 0x00, 0x00, 0xee, 0x03 /* .word 0x03ee0000 ; (STM32_SR_ERROR_MASK) */ + }; + + if (target_alloc_working_area(target, sizeof(stm32x_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; + } + + retval = target_write_buffer(target, write_algorithm->address, + sizeof(stm32x_flash_write_code), + stm32x_flash_write_code); + if (retval != ERROR_OK) + return retval; + + /* memory buffer */ + while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + data_size /= 2; + buffer_size = 8 + data_size; + if (data_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; + } + } + + LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%x", buffer_size); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (word-256 bits) */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash reg base */ + + buf_set_u32(reg_params[0].value, 0, 32, source->address); + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + buf_set_u32(reg_params[2].value, 0, 32, address); + buf_set_u32(reg_params[3].value, 0, 32, count); + buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->flash_base); + + retval = target_run_flash_async_algorithm(target, + buffer, + count, + FLASH_BLOCK_SIZE, + 0, NULL, + 5, reg_params, + source->address, source->size, + write_algorithm->address, 0, + &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_INFO("error executing stm32h7x flash write algorithm"); + + uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32); + + if (flash_sr & FLASH_WRPERR) + LOG_ERROR("flash memory write protected"); + + if ((flash_sr & FLASH_ERROR) != 0) { + LOG_ERROR("flash write failed, FLASH_SR = %08" PRIx32, flash_sr); + /* Clear error + EOP flags but report errors */ + target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), flash_sr); + retval = ERROR_FAIL; + } + } + + 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]); + return retval; +} + +static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + uint32_t address = bank->base + offset; + int retval, retval2; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset % FLASH_BLOCK_SIZE) { + LOG_WARNING("offset 0x%" PRIx32 " breaks required 32-byte alignment", offset); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + uint32_t blocks_remaining = count / FLASH_BLOCK_SIZE; + uint32_t bytes_remaining = count % FLASH_BLOCK_SIZE; + + /* multiple words (32-bytes) to be programmed in block */ + if (blocks_remaining) { + retval = stm32x_write_block(bank, buffer, offset, blocks_remaining); + if (retval != ERROR_OK) { + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* if block write failed (no sufficient working area), + * we use normal (slow) dword accesses */ + LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); + } + } else { + buffer += blocks_remaining * FLASH_BLOCK_SIZE; + address += blocks_remaining * FLASH_BLOCK_SIZE; + blocks_remaining = 0; + } + if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) + goto flash_lock; + } + + /* + Standard programming + The Flash memory programming sequence is as follows: + 1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the + FLASH_SR register. + 2. Set the PG bit in the FLASH_CR register + 3. 8 x Word access (or Force Write FW) + 4. Wait for the BSY bit to be cleared + */ + while (blocks_remaining > 0) { + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + if (retval != ERROR_OK) + goto flash_lock; + + retval = target_write_buffer(target, address, FLASH_BLOCK_SIZE, buffer); + if (retval != ERROR_OK) + goto flash_lock; + + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto flash_lock; + + buffer += FLASH_BLOCK_SIZE; + address += FLASH_BLOCK_SIZE; + blocks_remaining--; + } + + if (bytes_remaining) { + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + if (retval != ERROR_OK) + goto flash_lock; + + retval = target_write_buffer(target, address, bytes_remaining, buffer); + if (retval != ERROR_OK) + goto flash_lock; + + /* Force Write buffer of FLASH_BLOCK_SIZE = 32 bytes */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64 | FLASH_FW); + if (retval != ERROR_OK) + goto flash_lock; + + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto flash_lock; + } + +flash_lock: + retval2 = stm32x_lock_reg(bank); + if (retval2 != ERROR_OK) + LOG_ERROR("error during the lock of flash"); + + if (retval == ERROR_OK) + retval = retval2; + + return retval; +} + +static void setup_sector(struct flash_bank *bank, int start, int num, int size) +{ + for (int i = start; i < (start + num) ; i++) { + assert(i < bank->num_sectors); + bank->sectors[i].offset = bank->size; + bank->sectors[i].size = size; + bank->size += bank->sectors[i].size; + } +} + +static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) +{ + /* read stm32 device id register */ + int retval = target_read_u32(bank->target, DBGMCU_IDCODE_REGISTER, id); + if (retval != ERROR_OK) + return retval; + return ERROR_OK; +} + +static int stm32x_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int i; + uint16_t flash_size_in_kb; + uint32_t device_id; + uint32_t base_address = FLASH_BANK0_ADDRESS; + uint32_t second_bank_base; + + stm32x_info->probed = 0; + stm32x_info->part_info = NULL; + + int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("device id = 0x%08" PRIx32 "", stm32x_info->idcode); + + device_id = stm32x_info->idcode & 0xfff; + + for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7x_parts); n++) { + if (device_id == stm32h7x_parts[n].id) + stm32x_info->part_info = &stm32h7x_parts[n]; + } + if (!stm32x_info->part_info) { + LOG_WARNING("Cannot identify target as a STM32H7xx family."); + return ERROR_FAIL; + } else { + LOG_INFO("Device: %s", stm32x_info->part_info->device_str); + } + + /* update the address of controller from data base */ + stm32x_info->flash_base = stm32x_info->part_info->flash_base; + + /* get flash size from target */ + retval = target_read_u16(target, stm32x_info->part_info->fsize_base, &flash_size_in_kb); + if (retval != ERROR_OK) { + /* read error when device has invalid value, set max flash size */ + flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + } else + LOG_INFO("flash size probed value %d", flash_size_in_kb); + + /* Lower flash size devices are single bank */ + if (stm32x_info->part_info->has_dual_bank && (flash_size_in_kb > stm32x_info->part_info->first_bank_size_kb)) { + /* Use the configured base address to determine if this is the first or second flash bank. + * Verify that the base address is reasonably correct and determine the flash bank size + */ + second_bank_base = base_address + stm32x_info->part_info->first_bank_size_kb * 1024; + if (bank->base == second_bank_base) { + /* This is the second bank */ + base_address = second_bank_base; + flash_size_in_kb = flash_size_in_kb - stm32x_info->part_info->first_bank_size_kb; + /* bank1 also uses a register offset */ + stm32x_info->flash_base = FLASH_REG_BASE_B1; + } else if (bank->base == base_address) { + /* This is the first bank */ + flash_size_in_kb = stm32x_info->part_info->first_bank_size_kb; + } else { + LOG_WARNING("STM32H flash bank base address config is incorrect." + " 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, + bank->base, base_address, second_bank_base); + return ERROR_FAIL; + } + LOG_INFO("STM32H flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32, + bank->bank_number, flash_size_in_kb, base_address); + } else { + LOG_INFO("STM32H flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address); + } + + /* if the user sets the size manually then ignore the probed value + * this allows us to work around devices that have an invalid flash size register value */ + if (stm32x_info->user_bank_size) { + LOG_INFO("ignoring flash probed value, using configured bank size"); + flash_size_in_kb = stm32x_info->user_bank_size / 1024; + } else if (flash_size_in_kb == 0xffff) { + /* die flash size */ + flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + } + + /* did we assign flash size? */ + assert(flash_size_in_kb != 0xffff); + + /* calculate numbers of pages */ + int num_pages = flash_size_in_kb / stm32x_info->part_info->page_size; + + /* check that calculation result makes sense */ + assert(num_pages > 0); + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + bank->base = base_address; + bank->num_sectors = num_pages; + bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); + if (bank->sectors == NULL) { + LOG_ERROR("failed to allocate bank sectors"); + return ERROR_FAIL; + } + bank->size = 0; + + /* fixed memory */ + setup_sector(bank, 0, num_pages, stm32x_info->part_info->page_size * 1024); + + for (i = 0; i < num_pages; i++) { + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + stm32x_info->probed = 1; + return ERROR_OK; +} + +static int stm32x_auto_probe(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + if (stm32x_info->probed) + return ERROR_OK; + + return stm32x_probe(bank); +} + +/* This method must return a string displaying information about the bank */ +static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + const struct stm32h7x_part_info *info = stm32x_info->part_info; + + if (!stm32x_info->probed) { + int retval = stm32x_probe(bank); + if (retval != ERROR_OK) { + snprintf(buf, buf_size, "Unable to find bank information."); + return retval; + } + } + + if (info) { + const char *rev_str = NULL; + uint16_t rev_id = stm32x_info->idcode >> 16; + + for (unsigned int i = 0; i < info->num_revs; i++) + if (rev_id == info->revs[i].rev) + rev_str = info->revs[i].str; + + if (rev_str != NULL) { + snprintf(buf, buf_size, "%s - Rev: %s", + stm32x_info->part_info->device_str, rev_str); + } else { + snprintf(buf, buf_size, + "%s - Rev: unknown (0x%04x)", + stm32x_info->part_info->device_str, rev_id); + } + } else { + snprintf(buf, buf_size, "Cannot identify target as a STM32H7x"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_lock_command) +{ + struct target *target = NULL; + struct stm32h7x_flash_bank *stm32x_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; + + stm32x_info = bank->driver_priv; + target = bank->target; + + /* if we have a dual flash bank device then + * we need to perform option byte lock on bank0 only */ + if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { + LOG_ERROR("Option Byte Lock Operation must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (stm32x_read_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to read options", + bank->driver->name); + return ERROR_OK; + } + /* set readout protection */ + stm32x_info->option_bytes.RDP = 0; + + if (stm32x_write_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to lock device", + bank->driver->name); + return ERROR_OK; + } + command_print(CMD_CTX, "%s locked", bank->driver->name); + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_unlock_command) +{ + struct target *target = NULL; + struct stm32h7x_flash_bank *stm32x_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; + + stm32x_info = bank->driver_priv; + target = bank->target; + + /* if we have a dual flash bank device then + * we need to perform option byte unlock on bank0 only */ + if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { + LOG_ERROR("Option Byte Unlock Operation must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (stm32x_read_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to read options", bank->driver->name); + return ERROR_OK; + } + + /* clear readout protection option byte + * this will also force a device unlock if set */ + stm32x_info->option_bytes.RDP = 0xAA; + + if (stm32x_write_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); + return ERROR_OK; + } + command_print(CMD_CTX, "%s unlocked.\n", bank->driver->name); + + return ERROR_OK; +} + +static int stm32x_mass_erase(struct flash_bank *bank) +{ + int retval; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* mass erase flash memory bank */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER_CMD | FLASH_PSIZE_64); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_BER_CMD | FLASH_PSIZE_64 | FLASH_START); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_wait_status_busy(bank, 30000); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_lock_reg(bank); + if (retval != ERROR_OK) { + LOG_ERROR("error during the lock of flash"); + return retval; + } + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_mass_erase_command) +{ + int i; + + if (CMD_ARGC < 1) { + command_print(CMD_CTX, "stm32h7x mass_erase "); + 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; + + retval = stm32x_mass_erase(bank); + if (retval == ERROR_OK) { + /* set all sectors as erased */ + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = 1; + + command_print(CMD_CTX, "stm32h7x mass erase complete"); + } else { + command_print(CMD_CTX, "stm32h7x mass erase failed"); + } + + return retval; +} + +static const struct command_registration stm32x_exec_command_handlers[] = { + { + .name = "lock", + .handler = stm32x_handle_lock_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Lock entire flash device.", + }, + { + .name = "unlock", + .handler = stm32x_handle_unlock_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Unlock entire protected flash device.", + }, + { + .name = "mass_erase", + .handler = stm32x_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Erase entire flash device.", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration stm32x_command_handlers[] = { + { + .name = "stm32h7x", + .mode = COMMAND_ANY, + .help = "stm32h7x flash command group", + .usage = "", + .chain = stm32x_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver stm32h7x_flash = { + .name = "stm32h7x", + .commands = stm32x_command_handlers, + .flash_bank_command = stm32x_flash_bank_command, + .erase = stm32x_erase, + .protect = stm32x_protect, + .write = stm32x_write, + .read = default_flash_read, + .probe = stm32x_probe, + .auto_probe = stm32x_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = stm32x_protect_check, + .info = stm32x_get_info, +}; From 6090a5b158ad212a54510f061226ca58155b51fe Mon Sep 17 00:00:00 2001 From: Alexandre Torgue Date: Mon, 13 Nov 2017 17:00:58 +0100 Subject: [PATCH 44/54] Add STM32H7 config files Add 2 target files: -stm32h7x.cfg -stm32h7x_dual_bank.cfg Add 2 config files for: -STM32H743zi-nucleo bord -STM32H743i and STM32H753i eval boards. Change-Id: I2aae2c5acff4f3ff8e1bf232fda5a11a87f71703 Signed-off-by: Alexandre TORGUE Reviewed-on: http://openocd.zylin.com/4182 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/st_nucleo_h743zi.cfg | 10 ++++ tcl/board/stm32h7x3i_eval.cfg | 13 +++++ tcl/target/stm32h7x.cfg | 93 +++++++++++++++++++++++++++++++ tcl/target/stm32h7x_dual_bank.cfg | 7 +++ 4 files changed, 123 insertions(+) create mode 100644 tcl/board/st_nucleo_h743zi.cfg create mode 100644 tcl/board/stm32h7x3i_eval.cfg create mode 100644 tcl/target/stm32h7x.cfg create mode 100644 tcl/target/stm32h7x_dual_bank.cfg diff --git a/tcl/board/st_nucleo_h743zi.cfg b/tcl/board/st_nucleo_h743zi.cfg new file mode 100644 index 000000000..baedeb6d4 --- /dev/null +++ b/tcl/board/st_nucleo_h743zi.cfg @@ -0,0 +1,10 @@ +# This is an ST NUCLEO-H743ZI board with single STM32H743ZI chip. +# http://www.st.com/en/evaluation-tools/nucleo-h743zi.html + +source [find interface/stlink-v2-1.cfg] + +transport select hla_swd + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only diff --git a/tcl/board/stm32h7x3i_eval.cfg b/tcl/board/stm32h7x3i_eval.cfg new file mode 100644 index 000000000..2949ded32 --- /dev/null +++ b/tcl/board/stm32h7x3i_eval.cfg @@ -0,0 +1,13 @@ +# STM32H7[4|5]3I-EVAL: this is for the H7 eval boards. +# This is an ST EVAL-H743XI board with single STM32H743XI chip. +# http://www.st.com/en/evaluation-tools/stm32h743i-eval.html +# This is an ST EVAL-H753XI board with single STM32H753XI chip. +# http://www.st.com/en/evaluation-tools/stm32h753i-eval.html + +source [find interface/stlink-v2-1.cfg] + +transport select hla_swd + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg new file mode 100644 index 000000000..02dbed4a8 --- /dev/null +++ b/tcl/target/stm32h7x.cfg @@ -0,0 +1,93 @@ +# script for stm32h7x family + +# +# stm32h7 devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32h7x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +if {[using_jtag]} { + swj_newdap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32h7x 0x08000000 0 0 0 $_TARGETNAME + +# Clock after reset is HSI at 64 MHz, no need of PLL +adapter_khz 1800 + +adapter_nsrst_delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +# use hardware reset, connect under reset +reset_config srst_only srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event examine-end { + # Enable D3 and D1 DBG clocks + # DBGMCU_CR |= D3DBGCKEN | D1DBGCKEN + mmw 0x5C001004 0x00600000 0 + + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP in D3 & D1 Domains + mmw 0x5C001004 0x00000187 0 + + # Stop watchdog counters during halt + # DBGMCU_APB3FZ1 |= WWDG1 + mmw 0x5C001034 0x00000040 0 + # DBGMCU_APB4FZ1 |= WDGLSD1 + mmw 0x5C001054 0x00040000 0 +} + +$_TARGETNAME configure -event trace-config { + # Set TRACECLKEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0x5C001004 0x00100000 0 +} + +$_TARGETNAME configure -event reset-init { + # Clock after reset is HSI at 64 MHz, no need of PLL + adapter_khz 4000 +} diff --git a/tcl/target/stm32h7x_dual_bank.cfg b/tcl/target/stm32h7x_dual_bank.cfg new file mode 100644 index 000000000..7e342f931 --- /dev/null +++ b/tcl/target/stm32h7x_dual_bank.cfg @@ -0,0 +1,7 @@ +# script for stm32h7x family (dual flash bank) +source [find target/stm32h7x.cfg] + +# STM32H7xxxI 2Mo have a dual bank flash. +# Add the second flash bank. +set _FLASHNAME $_CHIPNAME.flash1 +flash bank $_FLASHNAME stm32h7x 0x08100000 0 0 0 $_TARGETNAME From 020cb12077cb15be1700bf7733178acfb2b26428 Mon Sep 17 00:00:00 2001 From: Ake Rehnman Date: Mon, 6 Nov 2017 19:56:28 +0100 Subject: [PATCH 45/54] stm8 : new target New STM8 target based mostly on mips4k. Target communication through STLINK/SWIM. No flash driver yet but it is still possible to program flash through load_image command. The usual target debug methods are implemented. Change-Id: I7216f231d3ac7c70cae20f1cd8463c2ed864a329 Signed-off-by: Ake Rehnman Reviewed-on: http://openocd.zylin.com/3953 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Paul Fertser --- contrib/loaders/Makefile | 5 +- contrib/loaders/erase_check/Makefile | 17 + .../loaders/erase_check/stm8_erase_check.inc | 5 + .../loaders/erase_check/stm8_erase_check.s | 69 + src/target/Makefile.am | 5 + src/target/stm8.c | 2219 +++++++++++++++++ src/target/stm8.h | 75 + src/target/target.c | 2 + tcl/target/stm8l.cfg | 87 + tcl/target/stm8s.cfg | 84 + 10 files changed, 2567 insertions(+), 1 deletion(-) create mode 100644 contrib/loaders/erase_check/stm8_erase_check.inc create mode 100644 contrib/loaders/erase_check/stm8_erase_check.s create mode 100644 src/target/stm8.c create mode 100644 src/target/stm8.h create mode 100644 tcl/target/stm8l.cfg create mode 100644 tcl/target/stm8s.cfg diff --git a/contrib/loaders/Makefile b/contrib/loaders/Makefile index 31cccb5ff..a9a27706d 100644 --- a/contrib/loaders/Makefile +++ b/contrib/loaders/Makefile @@ -1,6 +1,6 @@ .PHONY: arm clean-arm -all: arm +all: arm stm8 common_dirs = \ checksum \ @@ -32,3 +32,6 @@ clean: clean-arm for d in $(common_dirs); do \ $(MAKE) -C $$d clean; \ done + +stm8: + $(MAKE) -C erase_check stm8 diff --git a/contrib/loaders/erase_check/Makefile b/contrib/loaders/erase_check/Makefile index 01e62dead..427fa0c07 100644 --- a/contrib/loaders/erase_check/Makefile +++ b/contrib/loaders/erase_check/Makefile @@ -6,6 +6,12 @@ ARM_OBJCOPY ?= $(ARM_CROSS_COMPILE)objcopy ARM_AFLAGS = -EL +STM8_CROSS_COMPILE ?= stm8- +STM8_AS ?= $(STM8_CROSS_COMPILE)as +STM8_OBJCOPY ?= $(STM8_CROSS_COMPILE)objcopy + +STM8_AFLAGS = + arm: armv4_5_erase_check.inc armv7m_erase_check.inc armv7m_0_erase_check.inc armv4_5_%.elf: armv4_5_%.s @@ -26,5 +32,16 @@ armv7m_%.bin: armv7m_%.elf armv7m_%.inc: armv7m_%.bin $(BIN2C) < $< > $@ +stm8: stm8_erase_check.inc + +stm8_%.elf: stm8_%.s + $(STM8_AS) $(STM8_AFLAGS) $< -o $@ + +stm8_%.bin: stm8_%.elf + $(STM8_OBJCOPY) -Obinary $< $@ + +stm8_%.inc: stm8_%.bin + $(BIN2C) < $< > $@ + clean: -rm -f *.elf *.bin *.inc diff --git a/contrib/loaders/erase_check/stm8_erase_check.inc b/contrib/loaders/erase_check/stm8_erase_check.inc new file mode 100644 index 000000000..66b4ec7f5 --- /dev/null +++ b/contrib/loaders/erase_check/stm8_erase_check.inc @@ -0,0 +1,5 @@ +/* Autogenerated with ../../../src/helper/bin2char.sh */ +0x00,0x80,0x00,0x00,0x80,0x00,0x96,0xcf,0x00,0x22,0x1e,0x01,0x16,0x04,0xa6,0xff, +0x90,0x5d,0x26,0x04,0x0d,0x03,0x27,0x17,0x90,0x5d,0x26,0x02,0x0a,0x03,0x90,0x5a, +0x92,0xbc,0x00,0x00,0xa1,0xff,0x26,0x07,0x5c,0x26,0xe5,0x0c,0x00,0x20,0xe1,0x1f, +0x01,0x17,0x04,0x8b, diff --git a/contrib/loaders/erase_check/stm8_erase_check.s b/contrib/loaders/erase_check/stm8_erase_check.s new file mode 100644 index 000000000..62694006b --- /dev/null +++ b/contrib/loaders/erase_check/stm8_erase_check.s @@ -0,0 +1,69 @@ +/* + Copyright (C) 2017 Ake Rehnman + ake.rehnman(at)gmail.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 3 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, see . +*/ +;; +;; erase check memory code +;; + .org 0x0 +;; start address + start_addr: .byte 0x00 + .word 0x8000 +;; byte count + byte_cnt: .byte 0x00 + .word 0x8000 +; +; SP must point to start_addr on entry +; first relocate start_addr to the location +; we are running at +start: + ldw X,SP + ldw .cont+2,X + ldw X,(start_addr+1,SP) ;start addr + ldw Y,(byte_cnt+1,SP) ;count + ld A,#0xff +; +; if count == 0 return +.L1: + tnzw Y + jrne .decrcnt ;continue if low word != 0 + tnz (byte_cnt,SP) ;high byte + jreq .exit ;goto exit +; +; decrement count (byte_cnt) +.decrcnt: + tnzw Y ;low word count + jrne .decr1 + dec (byte_cnt,SP) ;high byte +.decr1: + decw Y; decr low word +; +; first check if [start_addr] is 0xff +.cont: + ldf A, [start_addr.e] + cp A,#0xff + jrne .exit ;exit if not 0xff +; +; increment start_addr (addr) + incw X + jrne .L1 + inc (start_addr,SP) ;increment high byte + jra .L1 +; +.exit: + ldw (start_addr+1,SP),X ;start addr + ldw (byte_cnt+1,SP),Y ;count + break diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 597070c4b..d2aab0a5e 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -19,6 +19,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(AVR32_SRC) \ $(MIPS32_SRC) \ $(NDS32_SRC) \ + $(STM8_SRC) \ $(INTEL_IA32_SRC) \ %D%/avrt.c \ %D%/dsp563xx.c \ @@ -124,6 +125,9 @@ NDS32_SRC = \ %D%/nds32_v3m.c \ %D%/nds32_aice.c +STM8_SRC = \ + %D%/stm8.c + INTEL_IA32_SRC = \ %D%/quark_x10xx.c \ %D%/quark_d20xx.c \ @@ -205,6 +209,7 @@ INTEL_IA32_SRC = \ %D%/nds32_v3.h \ %D%/nds32_v3m.h \ %D%/nds32_aice.h \ + %D%/stm8.h \ %D%/lakemont.h \ %D%/x86_32_common.h \ %D%/arm_cti.h diff --git a/src/target/stm8.c b/src/target/stm8.c new file mode 100644 index 000000000..262497b0d --- /dev/null +++ b/src/target/stm8.c @@ -0,0 +1,2219 @@ +/* + OpenOCD STM8 target driver + Copyright (C) 2017 Ake Rehnman + ake.rehnman(at)gmail.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 3 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, see . +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "target.h" +#include "target_type.h" +#include "hello.h" +#include "jtag/jtag.h" +#include "jtag/hla/hla_transport.h" +#include "jtag/hla/hla_interface.h" +#include "jtag/hla/hla_layout.h" +#include "register.h" +#include "breakpoints.h" +#include "algorithm.h" +#include "stm8.h" + +static struct reg_cache *stm8_build_reg_cache(struct target *target); +static int stm8_read_core_reg(struct target *target, unsigned int num); +static int stm8_write_core_reg(struct target *target, unsigned int num); +static int stm8_save_context(struct target *target); +static void stm8_enable_breakpoints(struct target *target); +static int stm8_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static int stm8_set_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static void stm8_enable_watchpoints(struct target *target); +static int stm8_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint); + +static const struct { + unsigned id; + const char *name; + const uint8_t bits; + enum reg_type type; + const char *group; + const char *feature; + int flag; +} stm8_regs[] = { + { 0, "pc", 32, REG_TYPE_UINT32, "general", "org.gnu.gdb.stm8.core", 0 }, + { 1, "a", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, + { 2, "x", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, + { 3, "y", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, + { 4, "sp", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, + { 5, "cc", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, +}; + +#define STM8_NUM_REGS ARRAY_SIZE(stm8_regs) +#define STM8_PC 0 +#define STM8_A 1 +#define STM8_X 2 +#define STM8_Y 3 +#define STM8_SP 4 +#define STM8_CC 5 + +#define CC_I0 0x8 +#define CC_I1 0x20 + +#define DM_REGS 0x7f00 +#define DM_REG_A 0x7f00 +#define DM_REG_PC 0x7f01 +#define DM_REG_X 0x7f04 +#define DM_REG_Y 0x7f06 +#define DM_REG_SP 0x7f08 +#define DM_REG_CC 0x7f0a + +#define DM_BKR1E 0x7f90 +#define DM_BKR2E 0x7f93 +#define DM_CR1 0x7f96 +#define DM_CR2 0x7f97 +#define DM_CSR1 0x7f98 +#define DM_CSR2 0x7f99 + +#define STE 0x40 +#define STF 0x20 +#define RST 0x10 +#define BRW 0x08 +#define BK2F 0x04 +#define BK1F 0x02 + +#define SWBRK 0x20 +#define SWBKF 0x10 +#define STALL 0x08 +#define FLUSH 0x01 + +#define FLASH_CR1_STM8S 0x505A +#define FLASH_CR2_STM8S 0x505B +#define FLASH_NCR2_STM8S 0x505C +#define FLASH_IAPSR_STM8S 0x505F +#define FLASH_PUKR_STM8S 0x5062 +#define FLASH_DUKR_STM8S 0x5064 + +#define FLASH_CR1_STM8L 0x5050 +#define FLASH_CR2_STM8L 0x5051 +#define FLASH_NCR2_STM8L 0 +#define FLASH_PUKR_STM8L 0x5052 +#define FLASH_DUKR_STM8L 0x5053 +#define FLASH_IAPSR_STM8L 0x5054 + +/* FLASH_IAPSR */ +#define HVOFF 0x40 +#define DUL 0x08 +#define EOP 0x04 +#define PUL 0x02 +#define WR_PG_DIS 0x01 + +/* FLASH_CR2 */ +#define OPT 0x80 +#define WPRG 0x40 +#define ERASE 0x20 +#define FPRG 0x10 +#define PRG 0x01 + +/* SWIM_CSR */ +#define SAFE_MASK 0x80 +#define NO_ACCESS 0x40 +#define SWIM_DM 0x20 +#define HS 0x10 +#define OSCOFF 0x08 +#define SWIM_RST 0x04 +#define HSIT 0x02 +#define PRI 0x01 + +#define SWIM_CSR 0x7f80 + +#define STM8_BREAK 0x8B + +enum mem_type { + RAM, + FLASH, + EEPROM, + OPTION +}; + +struct stm8_algorithm { + int common_magic; +}; + +struct stm8_core_reg { + uint32_t num; + struct target *target; + struct stm8_common *stm8_common; +}; + +enum hw_break_type { + /* break on execute */ + HWBRK_EXEC, + /* break on read */ + HWBRK_RD, + /* break on write */ + HWBRK_WR, + /* break on read, write and execute */ + HWBRK_ACC +}; + +struct stm8_comparator { + bool used; + uint32_t bp_value; + uint32_t reg_address; + enum hw_break_type type; +}; + +static inline struct hl_interface_s *target_to_adapter(struct target *target) +{ + return target->tap->priv; +} + +static int stm8_adapter_read_memory(struct target *target, + uint32_t addr, int size, int count, void *buf) +{ + int ret; + struct hl_interface_s *adapter = target_to_adapter(target); + + ret = adapter->layout->api->read_mem(adapter->handle, + addr, size, count, buf); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_adapter_write_memory(struct target *target, + uint32_t addr, int size, int count, const void *buf) +{ + int ret; + struct hl_interface_s *adapter = target_to_adapter(target); + + ret = adapter->layout->api->write_mem(adapter->handle, + addr, size, count, buf); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_write_u8(struct target *target, + uint32_t addr, uint8_t val) +{ + int ret; + uint8_t buf[1]; + struct hl_interface_s *adapter = target_to_adapter(target); + + buf[0] = val; + ret = adapter->layout->api->write_mem(adapter->handle, addr, 1, 1, buf); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_read_u8(struct target *target, + uint32_t addr, uint8_t *val) +{ + int ret; + struct hl_interface_s *adapter = target_to_adapter(target); + + ret = adapter->layout->api->read_mem(adapter->handle, addr, 1, 1, val); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_set_speed(struct target *target, int speed) +{ + struct hl_interface_s *adapter = target_to_adapter(target); + adapter->layout->api->speed(adapter->handle, speed, 0); + return ERROR_OK; +} + +/* + Disables interrupts. + If interrupts are enabled they are masked and the cc register + is saved. + + Enables interrupts. + Enable interrupts is actually restoring I1 I0 state from previous + call with enable == 0. Note that if stepping and breaking on a sim + instruction will NOT work since the interrupt flags are restored on + debug_entry. We don't have any way for the debugger to exclusively + disable the interrupts +*/ +static int stm8_enable_interrupts(struct target *target, int enable) +{ + struct stm8_common *stm8 = target_to_stm8(target); + uint8_t cc; + + if (enable) { + if (!stm8->cc_valid) + return ERROR_OK; /* cc was not stashed */ + /* fetch current cc */ + stm8_read_u8(target, DM_REG_CC, &cc); + /* clear I1 I0 */ + cc &= ~(CC_I0 + CC_I1); + /* restore I1 & I0 from stash*/ + cc |= (stm8->cc & (CC_I0+CC_I1)); + /* update current cc */ + stm8_write_u8(target, DM_REG_CC, cc); + stm8->cc_valid = false; + } else { + stm8_read_u8(target, DM_REG_CC, &cc); + if ((cc & CC_I0) && (cc & CC_I1)) + return ERROR_OK; /* interrupts already masked */ + /* stash cc */ + stm8->cc = cc; + stm8->cc_valid = true; + /* mask interrupts (disable) */ + cc |= (CC_I0 + CC_I1); + stm8_write_u8(target, DM_REG_CC, cc); + } + + return ERROR_OK; +} + +static int stm8_set_hwbreak(struct target *target, + struct stm8_comparator comparator_list[]) +{ + uint8_t buf[3]; + int i, ret; + + /* Refer to Table 4 in UM0470 */ + uint8_t bc = 0x5; + uint8_t bir = 0; + uint8_t biw = 0; + + uint32_t data; + uint32_t addr; + + if (!comparator_list[0].used) { + comparator_list[0].type = HWBRK_EXEC; + comparator_list[0].bp_value = -1; + } + + if (!comparator_list[1].used) { + comparator_list[1].type = HWBRK_EXEC; + comparator_list[1].bp_value = -1; + } + + if ((comparator_list[0].type == HWBRK_EXEC) + && (comparator_list[1].type == HWBRK_EXEC)) { + comparator_list[0].reg_address = 0; + comparator_list[1].reg_address = 1; + } + + if ((comparator_list[0].type == HWBRK_EXEC) + && (comparator_list[1].type != HWBRK_EXEC)) { + comparator_list[0].reg_address = 0; + comparator_list[1].reg_address = 1; + switch (comparator_list[1].type) { + case HWBRK_RD: + bir = 1; + break; + case HWBRK_WR: + biw = 1; + break; + default: + bir = 1; + biw = 1; + break; + } + } + + if ((comparator_list[1].type == HWBRK_EXEC) + && (comparator_list[0].type != HWBRK_EXEC)) { + comparator_list[0].reg_address = 1; + comparator_list[1].reg_address = 0; + switch (comparator_list[0].type) { + case HWBRK_RD: + bir = 1; + break; + case HWBRK_WR: + biw = 1; + break; + default: + bir = 1; + biw = 1; + break; + } + } + + if ((comparator_list[0].type != HWBRK_EXEC) + && (comparator_list[1].type != HWBRK_EXEC)) { + if ((comparator_list[0].type != comparator_list[1].type)) { + LOG_ERROR("data hw breakpoints must be of same type"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + for (i = 0; i < 2; i++) { + data = comparator_list[i].bp_value; + addr = comparator_list[i].reg_address; + + buf[0] = data >> 16; + buf[1] = data >> 8; + buf[2] = data; + + if (addr == 0) { + ret = stm8_adapter_write_memory(target, DM_BKR1E, 1, 3, buf); + LOG_DEBUG("DM_BKR1E=%" PRIx32, data); + } else if (addr == 1) { + ret = stm8_adapter_write_memory(target, DM_BKR2E, 1, 3, buf); + LOG_DEBUG("DM_BKR2E=%" PRIx32, data); + } else { + LOG_DEBUG("addr=%" PRIu32, addr); + return ERROR_FAIL; + } + + if (ret != ERROR_OK) + return ret; + + ret = stm8_write_u8(target, DM_CR1, + (bc << 3) + (bir << 2) + (biw << 1)); + LOG_DEBUG("DM_CR1=%" PRIx8, buf[0]); + if (ret != ERROR_OK) + return ret; + + } + return ERROR_OK; +} + +/* read DM control and status regs */ +static int stm8_read_dm_csrx(struct target *target, uint8_t *csr1, + uint8_t *csr2) +{ + int ret; + uint8_t buf[2]; + + ret = stm8_adapter_read_memory(target, DM_CSR1, 1, sizeof(buf), buf); + if (ret != ERROR_OK) + return ret; + if (csr1) + *csr1 = buf[0]; + if (csr2) + *csr2 = buf[1]; + return ERROR_OK; +} + +/* set or clear the single step flag in DM */ +static int stm8_config_step(struct target *target, int enable) +{ + int ret; + uint8_t csr1, csr2; + + ret = stm8_read_dm_csrx(target, &csr1, &csr2); + if (ret != ERROR_OK) + return ret; + if (enable) + csr1 |= STE; + else + csr1 &= ~STE; + + ret = stm8_write_u8(target, DM_CSR1, csr1); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +/* set the stall flag in DM */ +static int stm8_debug_stall(struct target *target) +{ + int ret; + uint8_t csr1, csr2; + + ret = stm8_read_dm_csrx(target, &csr1, &csr2); + if (ret != ERROR_OK) + return ret; + csr2 |= STALL; + ret = stm8_write_u8(target, DM_CSR2, csr2); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_configure_break_unit(struct target *target) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (stm8->bp_scanned) + return ERROR_OK; + + stm8->num_hw_bpoints = 2; + stm8->num_hw_bpoints_avail = stm8->num_hw_bpoints; + + stm8->hw_break_list = calloc(stm8->num_hw_bpoints, + sizeof(struct stm8_comparator)); + + stm8->hw_break_list[0].reg_address = 0; + stm8->hw_break_list[1].reg_address = 1; + + LOG_DEBUG("hw breakpoints: numinst %i numdata %i", stm8->num_hw_bpoints, + stm8->num_hw_bpoints); + + stm8->bp_scanned = true; + + return ERROR_OK; +} + +static int stm8_examine_debug_reason(struct target *target) +{ + int retval; + uint8_t csr1, csr2; + + retval = stm8_read_dm_csrx(target, &csr1, &csr2); + LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); + + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) { + + if (retval != ERROR_OK) + return retval; + + if (csr1 & RST) + /* halted on reset */ + target->debug_reason = DBG_REASON_UNDEFINED; + + if (csr1 & (BK1F+BK2F)) + /* we have halted on a breakpoint (or wp)*/ + target->debug_reason = DBG_REASON_BREAKPOINT; + + if (csr2 & SWBKF) + /* we have halted on a breakpoint */ + target->debug_reason = DBG_REASON_BREAKPOINT; + + } + + return ERROR_OK; +} + +static int stm8_debug_entry(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + /* restore interrupts */ + stm8_enable_interrupts(target, 1); + + stm8_save_context(target); + + /* make sure stepping disabled STE bit in CSR1 cleared */ + stm8_config_step(target, 0); + + /* attempt to find halt reason */ + stm8_examine_debug_reason(target); + + LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", + buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32), + target_state_name(target)); + + return ERROR_OK; +} + +/* clear stall flag in DM and flush instruction pipe */ +static int stm8_exit_debug(struct target *target) +{ + int ret; + uint8_t csr1, csr2; + + ret = stm8_read_dm_csrx(target, &csr1, &csr2); + if (ret != ERROR_OK) + return ret; + csr2 |= FLUSH; + ret = stm8_write_u8(target, DM_CSR2, csr2); + if (ret != ERROR_OK) + return ret; + + csr2 &= ~STALL; + csr2 |= SWBRK; + ret = stm8_write_u8(target, DM_CSR2, csr2); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_read_regs(struct target *target, uint32_t regs[]) +{ + int ret; + uint8_t buf[11]; + + ret = stm8_adapter_read_memory(target, DM_REGS, 1, sizeof(buf), buf); + if (ret != ERROR_OK) + return ret; + + regs[0] = be_to_h_u24(buf+DM_REG_PC-DM_REGS); + regs[1] = buf[DM_REG_A-DM_REGS]; + regs[2] = be_to_h_u16(buf+DM_REG_X-DM_REGS); + regs[3] = be_to_h_u16(buf+DM_REG_Y-DM_REGS); + regs[4] = be_to_h_u16(buf+DM_REG_SP-DM_REGS); + regs[5] = buf[DM_REG_CC-DM_REGS]; + + return ERROR_OK; +} + +static int stm8_write_regs(struct target *target, uint32_t regs[]) +{ + int ret; + uint8_t buf[11]; + + h_u24_to_be(buf+DM_REG_PC-DM_REGS, regs[0]); + buf[DM_REG_A-DM_REGS] = regs[1]; + h_u16_to_be(buf+DM_REG_X-DM_REGS, regs[2]); + h_u16_to_be(buf+DM_REG_Y-DM_REGS, regs[3]); + h_u16_to_be(buf+DM_REG_SP-DM_REGS, regs[4]); + buf[DM_REG_CC-DM_REGS] = regs[5]; + + ret = stm8_adapter_write_memory(target, DM_REGS, 1, sizeof(buf), buf); + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +static int stm8_get_core_reg(struct reg *reg) +{ + int retval; + struct stm8_core_reg *stm8_reg = reg->arch_info; + struct target *target = stm8_reg->target; + struct stm8_common *stm8_target = target_to_stm8(target); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = stm8_target->read_core_reg(target, stm8_reg->num); + + return retval; +} + +static int stm8_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct stm8_core_reg *stm8_reg = reg->arch_info; + struct target *target = stm8_reg->target; + uint32_t value = buf_get_u32(buf, 0, reg->size); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = true; + reg->valid = true; + + return ERROR_OK; +} + +static int stm8_save_context(struct target *target) +{ + unsigned int i; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + /* read core registers */ + stm8_read_regs(target, stm8->core_regs); + + for (i = 0; i < STM8_NUM_REGS; i++) { + if (!stm8->core_cache->reg_list[i].valid) + stm8->read_core_reg(target, i); + } + + return ERROR_OK; +} + +static int stm8_restore_context(struct target *target) +{ + unsigned int i; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + for (i = 0; i < STM8_NUM_REGS; i++) { + if (stm8->core_cache->reg_list[i].dirty) + stm8->write_core_reg(target, i); + } + + /* write core regs */ + stm8_write_regs(target, stm8->core_regs); + + return ERROR_OK; +} + +static int stm8_unlock_flash(struct target *target) +{ + uint8_t data[1]; + + struct stm8_common *stm8 = target_to_stm8(target); + + /* check if flash is unlocked */ + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & PUL) { + /* unlock flash */ + stm8_write_u8(target, stm8->flash_pukr, 0x56); + stm8_write_u8(target, stm8->flash_pukr, 0xae); + } + + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & PUL) + return ERROR_FAIL; + return ERROR_OK; +} + +static int stm8_unlock_eeprom(struct target *target) +{ + uint8_t data[1]; + + struct stm8_common *stm8 = target_to_stm8(target); + + /* check if eeprom is unlocked */ + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & DUL) { + /* unlock eeprom */ + stm8_write_u8(target, stm8->flash_dukr, 0xae); + stm8_write_u8(target, stm8->flash_dukr, 0x56); + } + + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & DUL) + return ERROR_FAIL; + return ERROR_OK; +} + +static int stm8_write_flash(struct target *target, enum mem_type type, + uint32_t address, + uint32_t size, uint32_t count, uint32_t blocksize_param, + const uint8_t *buffer) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + uint8_t iapsr; + uint8_t opt = 0; + unsigned int i; + uint32_t blocksize = 0; + uint32_t bytecnt; + int res; + + switch (type) { + case (FLASH): + stm8_unlock_flash(target); + break; + case (EEPROM): + stm8_unlock_eeprom(target); + break; + case (OPTION): + stm8_unlock_eeprom(target); + opt = OPT; + break; + default: + LOG_ERROR("BUG: wrong mem_type %d", type); + assert(0); + } + + if (size == 2) { + /* we don't support short writes */ + count = count * 2; + size = 1; + } + + bytecnt = count * size; + + while (bytecnt) { + if ((bytecnt >= blocksize_param) && ((address & (blocksize_param-1)) == 0)) { + if (stm8->flash_cr2) + stm8_write_u8(target, stm8->flash_cr2, PRG + opt); + if (stm8->flash_ncr2) + stm8_write_u8(target, stm8->flash_ncr2, ~(PRG + opt)); + blocksize = blocksize_param; + } else + if ((bytecnt >= 4) && ((address & 0x3) == 0)) { + if (stm8->flash_cr2) + stm8_write_u8(target, stm8->flash_cr2, WPRG + opt); + if (stm8->flash_ncr2) + stm8_write_u8(target, stm8->flash_ncr2, ~(WPRG + opt)); + blocksize = 4; + } else + if (blocksize != 1) { + if (stm8->flash_cr2) + stm8_write_u8(target, stm8->flash_cr2, opt); + if (stm8->flash_ncr2) + stm8_write_u8(target, stm8->flash_ncr2, ~opt); + blocksize = 1; + } + + res = stm8_adapter_write_memory(target, address, 1, blocksize, buffer); + if (res != ERROR_OK) + return res; + address += blocksize; + buffer += blocksize; + bytecnt -= blocksize; + + /* lets hang here until end of program (EOP) */ + for (i = 0; i < 16; i++) { + stm8_read_u8(target, stm8->flash_iapsr, &iapsr); + if (iapsr & EOP) + break; + else + usleep(1000); + } + if (i == 16) + return ERROR_FAIL; + } + + /* disable write access */ + res = stm8_write_u8(target, stm8->flash_iapsr, 0x0); + + if (res != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int stm8_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, + const uint8_t *buffer) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR + ", size: 0x%8.8" PRIx32 + ", count: 0x%8.8" PRIx32, + address, size, count); + + if (target->state != TARGET_HALTED) + LOG_WARNING("target not halted"); + + int retval; + + if ((address >= stm8->flashstart) && (address <= stm8->flashend)) + retval = stm8_write_flash(target, FLASH, address, size, count, + stm8->blocksize, buffer); + else if ((address >= stm8->eepromstart) && (address <= stm8->eepromend)) + retval = stm8_write_flash(target, EEPROM, address, size, count, + stm8->blocksize, buffer); + else if ((address >= stm8->optionstart) && (address <= stm8->optionend)) + retval = stm8_write_flash(target, OPTION, address, size, count, 0, buffer); + else + retval = stm8_adapter_write_memory(target, address, size, count, + buffer); + + if (retval != ERROR_OK) + return ERROR_TARGET_FAILURE; + + return retval; +} + +static int stm8_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR + ", size: 0x%8.8" PRIx32 + ", count: 0x%8.8" PRIx32, + address, size, count); + + if (target->state != TARGET_HALTED) + LOG_WARNING("target not halted"); + + int retval; + retval = stm8_adapter_read_memory(target, address, size, count, buffer); + + if (retval != ERROR_OK) + return ERROR_TARGET_FAILURE; + + return retval; +} + +static int stm8_init(struct command_context *cmd_ctx, struct target *target) +{ + stm8_build_reg_cache(target); + + return ERROR_OK; +} + +static int stm8_poll(struct target *target) +{ + int retval = ERROR_OK; + uint8_t csr1, csr2; + +#ifdef LOG_STM8 + LOG_DEBUG("target->state=%d", target->state); +#endif + + /* read dm_csrx control regs */ + retval = stm8_read_dm_csrx(target, &csr1, &csr2); + if (retval != ERROR_OK) { + LOG_DEBUG("stm8_read_dm_csrx failed retval=%d", retval); + /* + We return ERROR_OK here even if we didn't get an answer. + openocd will call target_wait_state until we get target state TARGET_HALTED + */ + return ERROR_OK; + } + + /* check for processor halted */ + if (csr2 & STALL) { + if (target->state != TARGET_HALTED) { + if (target->state == TARGET_UNKNOWN) + LOG_DEBUG("DM_CSR2_STALL already set during server startup."); + + retval = stm8_debug_entry(target); + if (retval != ERROR_OK) { + LOG_DEBUG("stm8_debug_entry failed retval=%d", retval); + return ERROR_TARGET_FAILURE; + } + + if (target->state == TARGET_DEBUG_RUNNING) { + target->state = TARGET_HALTED; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } else { + target->state = TARGET_HALTED; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + } + } else + target->state = TARGET_RUNNING; +#ifdef LOG_STM8 + LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); +#endif + return ERROR_OK; +} + +static int stm8_halt(struct target *target) +{ + LOG_DEBUG("target->state: %s", target_state_name(target)); + + if (target->state == TARGET_HALTED) { + LOG_DEBUG("target was already halted"); + return ERROR_OK; + } + + if (target->state == TARGET_UNKNOWN) + LOG_WARNING("target was in unknown state when halt was requested"); + + if (target->state == TARGET_RESET) { + /* we came here in a reset_halt or reset_init sequence + * debug entry was already prepared in stm8_assert_reset() + */ + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; + } + + + /* break processor */ + stm8_debug_stall(target); + + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static int stm8_reset_assert(struct target *target) +{ + int res = ERROR_OK; + struct hl_interface_s *adapter = target_to_adapter(target); + struct stm8_common *stm8 = target_to_stm8(target); + bool use_srst_fallback = true; + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_HAS_SRST) { + jtag_add_reset(0, 1); + res = adapter->layout->api->assert_srst(adapter->handle, 0); + + if (res == ERROR_OK) + /* hardware srst supported */ + use_srst_fallback = false; + else if (res != ERROR_COMMAND_NOTFOUND) + /* some other failure */ + return res; + } + + if (use_srst_fallback) { + LOG_DEBUG("Hardware srst not supported, falling back to swim reset"); + res = adapter->layout->api->reset(adapter->handle); + if (res != ERROR_OK) + return res; + } + + /* registers are now invalid */ + register_cache_invalidate(stm8->core_cache); + + target->state = TARGET_RESET; + target->debug_reason = DBG_REASON_NOTHALTED; + + if (target->reset_halt) { + res = target_halt(target); + if (res != ERROR_OK) + return res; + } + + return ERROR_OK; +} + +static int stm8_reset_deassert(struct target *target) +{ + int res; + struct hl_interface_s *adapter = target_to_adapter(target); + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_HAS_SRST) { + res = adapter->layout->api->assert_srst(adapter->handle, 1); + if ((res != ERROR_OK) && (res != ERROR_COMMAND_NOTFOUND)) + return res; + } + + /* virtual deassert reset, we need it for the internal + * jtag state machine + */ + jtag_add_reset(0, 0); + + /* The cpu should now be stalled. If halt was requested + let poll detect the stall */ + if (target->reset_halt) + return ERROR_OK; + + /* Instead of going thrugh saving context, polling and + then resuming target again just clear stall and proceed. */ + target->state = TARGET_RUNNING; + return stm8_exit_debug(target); +} + +/* stm8_single_step_core() is only used for stepping over breakpoints + from stm8_resume() */ +static int stm8_single_step_core(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + /* configure single step mode */ + stm8_config_step(target, 1); + + /* disable interrupts while stepping */ + if (!stm8->enable_step_irq) + stm8_enable_interrupts(target, 0); + + /* exit debug mode */ + stm8_exit_debug(target); + + stm8_debug_entry(target); + + return ERROR_OK; +} + +static int stm8_resume(struct target *target, int current, + target_addr_t address, int handle_breakpoints, + int debug_execution) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct breakpoint *breakpoint = NULL; + uint32_t resume_pc; + + LOG_DEBUG("%d " TARGET_ADDR_FMT " %d %d", current, address, + handle_breakpoints, debug_execution); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) { + target_free_all_working_areas(target); + stm8_enable_breakpoints(target); + stm8_enable_watchpoints(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + stm8_set_hwbreak(target, comparator_list); + } + + /* current = 1: continue on current pc, + otherwise continue at
*/ + if (!current) { + buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, + 0, 32, address); + stm8->core_cache->reg_list[STM8_PC].dirty = true; + stm8->core_cache->reg_list[STM8_PC].valid = true; + } + + if (!current) + resume_pc = address; + else + resume_pc = buf_get_u32( + stm8->core_cache->reg_list[STM8_PC].value, + 0, 32); + + stm8_restore_context(target); + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + /* Single step past breakpoint at current address */ + breakpoint = breakpoint_find(target, resume_pc); + if (breakpoint) { + LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT, + breakpoint->address); + stm8_unset_breakpoint(target, breakpoint); + stm8_single_step_core(target); + stm8_set_breakpoint(target, breakpoint); + } + } + + /* disable interrupts if we are debugging */ + if (debug_execution) + stm8_enable_interrupts(target, 0); + + /* exit debug mode */ + stm8_exit_debug(target); + target->debug_reason = DBG_REASON_NOTHALTED; + + /* registers are now invalid */ + register_cache_invalidate(stm8->core_cache); + + if (!debug_execution) { + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + } else { + target->state = TARGET_DEBUG_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); + LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); + } + + return ERROR_OK; +} + +static int stm8_init_flash_regs(bool enable_stm8l, struct stm8_common *stm8) +{ + stm8->enable_stm8l = enable_stm8l; + + if (stm8->enable_stm8l) { + stm8->flash_cr2 = FLASH_CR2_STM8L; + stm8->flash_ncr2 = FLASH_NCR2_STM8L; + stm8->flash_iapsr = FLASH_IAPSR_STM8L; + stm8->flash_dukr = FLASH_DUKR_STM8L; + stm8->flash_pukr = FLASH_PUKR_STM8L; + } else { + stm8->flash_cr2 = FLASH_CR2_STM8S; + stm8->flash_ncr2 = FLASH_NCR2_STM8S; + stm8->flash_iapsr = FLASH_IAPSR_STM8S; + stm8->flash_dukr = FLASH_DUKR_STM8S; + stm8->flash_pukr = FLASH_PUKR_STM8S; + } + return ERROR_OK; +} + +static int stm8_init_arch_info(struct target *target, + struct stm8_common *stm8, struct jtag_tap *tap) +{ + target->endianness = TARGET_BIG_ENDIAN; + target->arch_info = stm8; + stm8->common_magic = STM8_COMMON_MAGIC; + stm8->fast_data_area = NULL; + stm8->blocksize = 0x80; + stm8->flashstart = 0x8000; + stm8->flashend = 0xffff; + stm8->eepromstart = 0x4000; + stm8->eepromend = 0x43ff; + stm8->optionstart = 0x4800; + stm8->optionend = 0x487F; + + /* has breakpoint/watchpoint unit been scanned */ + stm8->bp_scanned = false; + stm8->hw_break_list = NULL; + + stm8->read_core_reg = stm8_read_core_reg; + stm8->write_core_reg = stm8_write_core_reg; + + stm8_init_flash_regs(0, stm8); + + return ERROR_OK; +} + +static int stm8_target_create(struct target *target, + Jim_Interp *interp) +{ + + struct stm8_common *stm8 = calloc(1, sizeof(struct stm8_common)); + + stm8_init_arch_info(target, stm8, target->tap); + stm8_configure_break_unit(target); + + return ERROR_OK; +} + +static int stm8_read_core_reg(struct target *target, unsigned int num) +{ + uint32_t reg_value; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (num >= STM8_NUM_REGS) + return ERROR_COMMAND_SYNTAX_ERROR; + + reg_value = stm8->core_regs[num]; + LOG_DEBUG("read core reg %i value 0x%" PRIx32 "", num , reg_value); + buf_set_u32(stm8->core_cache->reg_list[num].value, 0, 32, reg_value); + stm8->core_cache->reg_list[num].valid = true; + stm8->core_cache->reg_list[num].dirty = false; + + return ERROR_OK; +} + +static int stm8_write_core_reg(struct target *target, unsigned int num) +{ + uint32_t reg_value; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (num >= STM8_NUM_REGS) + return ERROR_COMMAND_SYNTAX_ERROR; + + reg_value = buf_get_u32(stm8->core_cache->reg_list[num].value, 0, 32); + stm8->core_regs[num] = reg_value; + LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value); + stm8->core_cache->reg_list[num].valid = true; + stm8->core_cache->reg_list[num].dirty = false; + + return ERROR_OK; +} + +static int stm8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + unsigned int i; + + *reg_list_size = STM8_NUM_REGS; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < STM8_NUM_REGS; i++) + (*reg_list)[i] = &stm8->core_cache->reg_list[i]; + + return ERROR_OK; +} + +static const struct reg_arch_type stm8_reg_type = { + .get = stm8_get_core_reg, + .set = stm8_set_core_reg, +}; + +static struct reg_cache *stm8_build_reg_cache(struct target *target) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + int num_regs = STM8_NUM_REGS; + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); + struct stm8_core_reg *arch_info = malloc( + sizeof(struct stm8_core_reg) * num_regs); + struct reg_feature *feature; + int i; + + /* Build the process context cache */ + cache->name = "stm8 registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = num_regs; + (*cache_p) = cache; + stm8->core_cache = cache; + + for (i = 0; i < num_regs; i++) { + arch_info[i].num = stm8_regs[i].id; + arch_info[i].target = target; + arch_info[i].stm8_common = stm8; + + reg_list[i].name = stm8_regs[i].name; + reg_list[i].size = stm8_regs[i].bits; + + reg_list[i].value = calloc(1, 4); + reg_list[i].valid = false; + reg_list[i].type = &stm8_reg_type; + reg_list[i].arch_info = &arch_info[i]; + + reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list[i].reg_data_type) + reg_list[i].reg_data_type->type = stm8_regs[i].type; + else { + LOG_ERROR("unable to allocate reg type list"); + return NULL; + } + + reg_list[i].dirty = false; + reg_list[i].group = stm8_regs[i].group; + reg_list[i].number = stm8_regs[i].id; + reg_list[i].exist = true; + reg_list[i].caller_save = true; /* gdb defaults to true */ + + feature = calloc(1, sizeof(struct reg_feature)); + if (feature) { + feature->name = stm8_regs[i].feature; + reg_list[i].feature = feature; + } else + LOG_ERROR("unable to allocate feature list"); + } + + return cache; +} + +static void stm8_free_reg_cache(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct reg_cache *cache; + struct reg *reg; + unsigned int i; + + cache = stm8->core_cache; + + if (!cache) + return; + + for (i = 0; i < cache->num_regs; i++) { + reg = &cache->reg_list[i]; + + free(reg->feature); + free(reg->reg_data_type); + free(reg->value); + } + + free(cache->reg_list[0].arch_info); + free(cache->reg_list); + free(cache); + + stm8->core_cache = NULL; +} + +static void stm8_deinit(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + free(stm8->hw_break_list); + + stm8_free_reg_cache(target); + + free(stm8); +} + +static int stm8_arch_state(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + debug_reason_name(target), + buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); + + return ERROR_OK; +} + +static int stm8_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ + LOG_DEBUG("%" PRIx32 " " TARGET_ADDR_FMT " %" PRIx32, + current, address, handle_breakpoints); + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct breakpoint *breakpoint = NULL; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* current = 1: continue on current pc, otherwise continue at
*/ + if (!current) { + buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32, address); + stm8->core_cache->reg_list[STM8_PC].dirty = true; + stm8->core_cache->reg_list[STM8_PC].valid = true; + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + breakpoint = breakpoint_find(target, + buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); + if (breakpoint) + stm8_unset_breakpoint(target, breakpoint); + } + + /* restore context */ + stm8_restore_context(target); + + /* configure single step mode */ + stm8_config_step(target, 1); + + target->debug_reason = DBG_REASON_SINGLESTEP; + + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + + /* disable interrupts while stepping */ + if (!stm8->enable_step_irq) + stm8_enable_interrupts(target, 0); + + /* exit debug mode */ + stm8_exit_debug(target); + + /* registers are now invalid */ + register_cache_invalidate(stm8->core_cache); + + LOG_DEBUG("target stepped "); + stm8_debug_entry(target); + + if (breakpoint) + stm8_set_breakpoint(target, breakpoint); + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +static void stm8_enable_breakpoints(struct target *target) +{ + struct breakpoint *breakpoint = target->breakpoints; + + /* set any pending breakpoints */ + while (breakpoint) { + if (breakpoint->set == 0) + stm8_set_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } +} + +static int stm8_set_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + int retval; + + if (breakpoint->set) { + LOG_WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) { + int bp_num = 0; + + while (comparator_list[bp_num].used && (bp_num < stm8->num_hw_bpoints)) + bp_num++; + if (bp_num >= stm8->num_hw_bpoints) { + LOG_ERROR("Can not find free breakpoint register (bpid: %" PRIu32 ")", + breakpoint->unique_id); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + breakpoint->set = bp_num + 1; + comparator_list[bp_num].used = true; + comparator_list[bp_num].bp_value = breakpoint->address; + comparator_list[bp_num].type = HWBRK_EXEC; + + retval = stm8_set_hwbreak(target, comparator_list); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", + breakpoint->unique_id, + bp_num, comparator_list[bp_num].bp_value); + } else if (breakpoint->type == BKPT_SOFT) { + LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + if (breakpoint->length == 1) { + uint8_t verify = 0x55; + + retval = target_read_u8(target, breakpoint->address, + breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + retval = target_write_u8(target, breakpoint->address, STM8_BREAK); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u8(target, breakpoint->address, &verify); + if (retval != ERROR_OK) + return retval; + if (verify != STM8_BREAK) { + LOG_ERROR("Unable to set breakpoint at address " TARGET_ADDR_FMT + " - check that memory is read/writable", + breakpoint->address); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } else { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + breakpoint->set = 1; /* Any nice value but 0 */ + } + + return ERROR_OK; +} + +static int stm8_add_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + struct stm8_common *stm8 = target_to_stm8(target); + int ret; + + if (breakpoint->type == BKPT_HARD) { + if (stm8->num_hw_bpoints_avail < 1) { + LOG_INFO("no hardware breakpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + ret = stm8_set_breakpoint(target, breakpoint); + if (ret != ERROR_OK) + return ret; + + stm8->num_hw_bpoints_avail--; + return ERROR_OK; + } + + ret = stm8_set_breakpoint(target, breakpoint); + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +static int stm8_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + int retval; + + if (!breakpoint->set) { + LOG_WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) { + int bp_num = breakpoint->set - 1; + if ((bp_num < 0) || (bp_num >= stm8->num_hw_bpoints)) { + LOG_DEBUG("Invalid comparator number in breakpoint (bpid: %" PRIu32 ")", + breakpoint->unique_id); + return ERROR_OK; + } + LOG_DEBUG("bpid: %" PRIu32 " - releasing hw: %d", + breakpoint->unique_id, + bp_num); + comparator_list[bp_num].used = false; + retval = stm8_set_hwbreak(target, comparator_list); + if (retval != ERROR_OK) + return retval; + } else { + /* restore original instruction (kept in target endianness) */ + LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + if (breakpoint->length == 1) { + uint8_t current_instr; + + /* check that user program has not + modified breakpoint instruction */ + retval = target_read_memory(target, breakpoint->address, 1, 1, + (uint8_t *)¤t_instr); + if (retval != ERROR_OK) + return retval; + + if (current_instr == STM8_BREAK) { + retval = target_write_memory(target, breakpoint->address, 1, 1, + breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } + } else + return ERROR_FAIL; + } + breakpoint->set = 0; + + return ERROR_OK; +} + +static int stm8_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (breakpoint->set) + stm8_unset_breakpoint(target, breakpoint); + + if (breakpoint->type == BKPT_HARD) + stm8->num_hw_bpoints_avail++; + + return ERROR_OK; +} + +static int stm8_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + int wp_num = 0; + int ret; + + if (watchpoint->set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + while (comparator_list[wp_num].used && (wp_num < stm8->num_hw_bpoints)) + wp_num++; + if (wp_num >= stm8->num_hw_bpoints) { + LOG_ERROR("Can not find free hw breakpoint"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (watchpoint->length != 1) { + LOG_ERROR("Only watchpoints of length 1 are supported"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + enum hw_break_type enable = 0; + + switch (watchpoint->rw) { + case WPT_READ: + enable = HWBRK_RD; + break; + case WPT_WRITE: + enable = HWBRK_WR; + break; + case WPT_ACCESS: + enable = HWBRK_ACC; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + } + + comparator_list[wp_num].used = true; + comparator_list[wp_num].bp_value = watchpoint->address; + comparator_list[wp_num].type = enable; + + ret = stm8_set_hwbreak(target, comparator_list); + if (ret != ERROR_OK) { + comparator_list[wp_num].used = false; + return ret; + } + + watchpoint->set = wp_num + 1; + + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", + wp_num, + comparator_list[wp_num].bp_value); + + return ERROR_OK; +} + +static int stm8_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int ret; + struct stm8_common *stm8 = target_to_stm8(target); + + if (stm8->num_hw_bpoints_avail < 1) { + LOG_INFO("no hardware watchpoints available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + ret = stm8_set_watchpoint(target, watchpoint); + if (ret != ERROR_OK) + return ret; + + stm8->num_hw_bpoints_avail--; + return ERROR_OK; +} + +static void stm8_enable_watchpoints(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + + /* set any pending watchpoints */ + while (watchpoint) { + if (watchpoint->set == 0) + stm8_set_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } +} + +static int stm8_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + + if (!watchpoint->set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wp_num = watchpoint->set - 1; + if ((wp_num < 0) || (wp_num >= stm8->num_hw_bpoints)) { + LOG_DEBUG("Invalid hw comparator number in watchpoint"); + return ERROR_OK; + } + comparator_list[wp_num].used = false; + watchpoint->set = 0; + + stm8_set_hwbreak(target, comparator_list); + + return ERROR_OK; +} + +static int stm8_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + stm8_unset_watchpoint(target, watchpoint); + + stm8->num_hw_bpoints_avail++; + + return ERROR_OK; +} + +static int stm8_examine(struct target *target) +{ + int retval; + uint8_t csr1, csr2; + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct hl_interface_s *adapter = target_to_adapter(target); + + if (!target_was_examined(target)) { + if (!stm8->swim_configured) { + /* set SWIM_CSR = 0xa0 (enable mem access & mask reset) */ + LOG_DEBUG("writing A0 to SWIM_CSR (SAFE_MASK + SWIM_DM)"); + retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM); + if (retval != ERROR_OK) + return retval; + /* set high speed */ + LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS)"); + retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM + HS); + if (retval != ERROR_OK) + return retval; + retval = stm8_set_speed(target, 1); + if (retval == ERROR_OK) + stm8->swim_configured = true; + /* + Now is the time to deassert reset if connect_under_reset. + Releasing reset line will cause the option bytes to load. + The core will still be stalled. + */ + if (adapter->param.connect_under_reset) + stm8_reset_deassert(target); + } else { + LOG_INFO("trying to reconnect"); + + retval = adapter->layout->api->state(adapter->handle); + if (retval != ERROR_OK) { + LOG_ERROR("reconnect failed"); + return ERROR_FAIL; + } + + /* read dm_csrx control regs */ + retval = stm8_read_dm_csrx(target, &csr1, &csr2); + if (retval != ERROR_OK) { + LOG_ERROR("state query failed"); + return ERROR_FAIL; + } + } + + target_set_examined(target); + + return ERROR_OK; + } + + return ERROR_OK; +} + +/** Checks whether a memory region is erased. */ +static int stm8_blank_check_memory(struct target *target, + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) +{ + struct working_area *erase_check_algorithm; + struct reg_param reg_params[2]; + struct mem_param mem_params[2]; + struct stm8_algorithm stm8_info; + + static const uint8_t stm8_erase_check_code[] = { +#include "../../contrib/loaders/erase_check/stm8_erase_check.inc" + }; + + if (erased_value != 0xff) { + LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for STM8", + erased_value); + return ERROR_FAIL; + } + + /* make sure we have a working area */ + if (target_alloc_working_area(target, sizeof(stm8_erase_check_code), + &erase_check_algorithm) != ERROR_OK) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + target_write_buffer(target, erase_check_algorithm->address, + sizeof(stm8_erase_check_code), stm8_erase_check_code); + + stm8_info.common_magic = STM8_COMMON_MAGIC; + + init_mem_param(&mem_params[0], 0x0, 3, PARAM_OUT); + buf_set_u32(mem_params[0].value, 0, 24, address); + + init_mem_param(&mem_params[1], 0x3, 3, PARAM_OUT); + buf_set_u32(mem_params[1].value, 0, 24, count); + + init_reg_param(®_params[0], "a", 32, PARAM_IN_OUT); + buf_set_u32(reg_params[0].value, 0, 32, erased_value); + + init_reg_param(®_params[1], "sp", 32, PARAM_OUT); + buf_set_u32(reg_params[1].value, 0, 32, erase_check_algorithm->address); + + int retval = target_run_algorithm(target, 2, mem_params, 2, reg_params, + erase_check_algorithm->address + 6, + erase_check_algorithm->address + (sizeof(stm8_erase_check_code) - 1), + 10000, &stm8_info); + + if (retval == ERROR_OK) + *blank = (*(reg_params[0].value) == 0xff); + + destroy_mem_param(&mem_params[0]); + destroy_mem_param(&mem_params[1]); + destroy_reg_param(®_params[0]); + + target_free_working_area(target, erase_check_algorithm); + + return retval; +} + +static int stm8_checksum_memory(struct target *target, target_addr_t address, + uint32_t count, uint32_t *checksum) +{ + /* let image_calculate_checksum() take care of business */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; +} + +/* run to exit point. return error if exit point was not reached. */ +static int stm8_run_and_wait(struct target *target, uint32_t entry_point, + int timeout_ms, uint32_t exit_point, struct stm8_common *stm8) +{ + uint32_t pc; + int retval; + /* This code relies on the target specific resume() and + poll()->debug_entry() sequence to write register values to the + processor and the read them back */ + retval = target_resume(target, 0, entry_point, 0, 1); + if (retval != ERROR_OK) + return retval; + + retval = target_wait_state(target, TARGET_HALTED, timeout_ms); + /* If the target fails to halt due to the breakpoint, force a halt */ + if (retval != ERROR_OK || target->state != TARGET_HALTED) { + retval = target_halt(target); + if (retval != ERROR_OK) + return retval; + retval = target_wait_state(target, TARGET_HALTED, 500); + if (retval != ERROR_OK) + return retval; + return ERROR_TARGET_TIMEOUT; + } + + pc = buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32); + if (exit_point && (pc != exit_point)) { + LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); + return ERROR_TARGET_TIMEOUT; + } + + return ERROR_OK; +} + +static int stm8_run_algorithm(struct target *target, int num_mem_params, + struct mem_param *mem_params, int num_reg_params, + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + uint32_t context[STM8_NUM_REGS]; + int retval = ERROR_OK; + + LOG_DEBUG("Running algorithm"); + + /* NOTE: stm8_run_algorithm requires that each + algorithm uses a software breakpoint + at the exit point */ + + if (stm8->common_magic != STM8_COMMON_MAGIC) { + LOG_ERROR("current target isn't a STM8 target"); + return ERROR_TARGET_INVALID; + } + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* refresh core register cache */ + for (unsigned int i = 0; i < STM8_NUM_REGS; i++) { + if (!stm8->core_cache->reg_list[i].valid) + stm8->read_core_reg(target, i); + context[i] = buf_get_u32(stm8->core_cache->reg_list[i].value, 0, 32); + } + + for (int i = 0; i < num_mem_params; i++) { + retval = target_write_buffer(target, mem_params[i].address, + mem_params[i].size, mem_params[i].value); + if (retval != ERROR_OK) + return retval; + } + + for (int i = 0; i < num_reg_params; i++) { + struct reg *reg = register_get_by_name(stm8->core_cache, + reg_params[i].reg_name, 0); + + if (!reg) { + LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (reg_params[i].size != 32) { + LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + stm8_set_core_reg(reg, reg_params[i].value); + } + + retval = stm8_run_and_wait(target, entry_point, + timeout_ms, exit_point, stm8); + + if (retval != ERROR_OK) + return retval; + + for (int i = 0; i < num_mem_params; i++) { + if (mem_params[i].direction != PARAM_OUT) { + retval = target_read_buffer(target, mem_params[i].address, + mem_params[i].size, mem_params[i].value); + if (retval != ERROR_OK) + return retval; + } + } + + for (int i = 0; i < num_reg_params; i++) { + if (reg_params[i].direction != PARAM_OUT) { + struct reg *reg = register_get_by_name(stm8->core_cache, + reg_params[i].reg_name, 0); + if (!reg) { + LOG_ERROR("BUG: register '%s' not found", + reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (reg_params[i].size != 32) { + LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + buf_set_u32(reg_params[i].value, + 0, 32, buf_get_u32(reg->value, 0, 32)); + } + } + + /* restore everything we saved before */ + for (unsigned int i = 0; i < STM8_NUM_REGS; i++) { + uint32_t regvalue; + regvalue = buf_get_u32(stm8->core_cache->reg_list[i].value, 0, 32); + if (regvalue != context[i]) { + LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, + stm8->core_cache->reg_list[i].name, context[i]); + buf_set_u32(stm8->core_cache->reg_list[i].value, + 0, 32, context[i]); + stm8->core_cache->reg_list[i].valid = true; + stm8->core_cache->reg_list[i].dirty = true; + } + } + + return ERROR_OK; +} + +int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) +{ + struct stm8_common *stm8 = target_to_stm8(target); + jim_wide w; + int e; + const char *arg; + + arg = Jim_GetString(goi->argv[0], NULL); + if (!strcmp(arg, "-blocksize")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-blocksize ?bytes? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->blocksize = w; + LOG_DEBUG("blocksize=%8.8x", stm8->blocksize); + return JIM_OK; + } + if (!strcmp(arg, "-flashstart")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-flashstart ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->flashstart = w; + LOG_DEBUG("flashstart=%8.8x", stm8->flashstart); + return JIM_OK; + } + if (!strcmp(arg, "-flashend")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-flashend ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->flashend = w; + LOG_DEBUG("flashend=%8.8x", stm8->flashend); + return JIM_OK; + } + if (!strcmp(arg, "-eepromstart")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-eepromstart ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->eepromstart = w; + LOG_DEBUG("eepromstart=%8.8x", stm8->eepromstart); + return JIM_OK; + } + if (!strcmp(arg, "-eepromend")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-eepromend ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->eepromend = w; + LOG_DEBUG("eepromend=%8.8x", stm8->eepromend); + return JIM_OK; + } + if (!strcmp(arg, "-optionstart")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-optionstart ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->optionstart = w; + LOG_DEBUG("optionstart=%8.8x", stm8->optionstart); + return JIM_OK; + } + if (!strcmp(arg, "-optionend")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-optionend ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->optionend = w; + LOG_DEBUG("optionend=%8.8x", stm8->optionend); + return JIM_OK; + } + if (!strcmp(arg, "-enable_step_irq")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + stm8->enable_step_irq = true; + LOG_DEBUG("enable_step_irq=%8.8x", stm8->enable_step_irq); + return JIM_OK; + } + if (!strcmp(arg, "-enable_stm8l")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + stm8->enable_stm8l = true; + LOG_DEBUG("enable_stm8l=%8.8x", stm8->enable_stm8l); + stm8_init_flash_regs(stm8->enable_stm8l, stm8); + return JIM_OK; + } + return JIM_CONTINUE; +} + +COMMAND_HANDLER(stm8_handle_enable_step_irq_command) +{ + const char *msg; + struct target *target = get_current_target(CMD_CTX); + struct stm8_common *stm8 = target_to_stm8(target); + bool enable = stm8->enable_step_irq; + + if (CMD_ARGC > 0) { + COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); + stm8->enable_step_irq = enable; + } + msg = stm8->enable_step_irq ? "enabled" : "disabled"; + command_print(CMD_CTX, "enable_step_irq = %s", msg); + return ERROR_OK; +} + +COMMAND_HANDLER(stm8_handle_enable_stm8l_command) +{ + const char *msg; + struct target *target = get_current_target(CMD_CTX); + struct stm8_common *stm8 = target_to_stm8(target); + bool enable = stm8->enable_stm8l; + + if (CMD_ARGC > 0) { + COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); + stm8->enable_stm8l = enable; + } + msg = stm8->enable_stm8l ? "enabled" : "disabled"; + command_print(CMD_CTX, "enable_stm8l = %s", msg); + stm8_init_flash_regs(stm8->enable_stm8l, stm8); + return ERROR_OK; +} + +static const struct command_registration stm8_exec_command_handlers[] = { + { + .name = "enable_step_irq", + .handler = stm8_handle_enable_step_irq_command, + .mode = COMMAND_ANY, + .help = "Enable/disable irq handling during step", + .usage = "[1/0]", + }, + { + .name = "enable_stm8l", + .handler = stm8_handle_enable_stm8l_command, + .mode = COMMAND_ANY, + .help = "Enable/disable STM8L flash programming", + .usage = "[1/0]", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration stm8_command_handlers[] = { + { + .name = "stm8", + .mode = COMMAND_ANY, + .help = "stm8 command group", + .usage = "", + .chain = stm8_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct target_type stm8_target = { + .name = "stm8", + + .poll = stm8_poll, + .arch_state = stm8_arch_state, + + .halt = stm8_halt, + .resume = stm8_resume, + .step = stm8_step, + + .assert_reset = stm8_reset_assert, + .deassert_reset = stm8_reset_deassert, + + .get_gdb_reg_list = stm8_get_gdb_reg_list, + + .read_memory = stm8_read_memory, + .write_memory = stm8_write_memory, + .checksum_memory = stm8_checksum_memory, + .blank_check_memory = stm8_blank_check_memory, + + .run_algorithm = stm8_run_algorithm, + + .add_breakpoint = stm8_add_breakpoint, + .remove_breakpoint = stm8_remove_breakpoint, + .add_watchpoint = stm8_add_watchpoint, + .remove_watchpoint = stm8_remove_watchpoint, + + .commands = stm8_command_handlers, + .target_create = stm8_target_create, + .init_target = stm8_init, + .examine = stm8_examine, + + .deinit_target = stm8_deinit, + .target_jim_configure = stm8_jim_configure, +}; diff --git a/src/target/stm8.h b/src/target/stm8.h new file mode 100644 index 000000000..39fac3e32 --- /dev/null +++ b/src/target/stm8.h @@ -0,0 +1,75 @@ +/* + OpenOCD STM8 target driver + Copyright (C) 2017 Ake Rehnman + ake.rehnman(at)gmail.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 3 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, see . +*/ + +#ifndef OPENOCD_TARGET_STM8_H +#define OPENOCD_TARGET_STM8_H + +struct target; + +#define STM8_COMMON_MAGIC 0x53544D38 +#define STM8_NUM_CORE_REGS 6 + +struct stm8_common { + uint32_t common_magic; + void *arch_info; + struct reg_cache *core_cache; + uint32_t core_regs[STM8_NUM_CORE_REGS]; + + /* working area for fastdata access */ + struct working_area *fast_data_area; + + bool swim_configured; + bool bp_scanned; + uint8_t num_hw_bpoints; + uint8_t num_hw_bpoints_avail; + struct stm8_comparator *hw_break_list; + uint32_t blocksize; + uint32_t flashstart; + uint32_t flashend; + uint32_t eepromstart; + uint32_t eepromend; + uint32_t optionstart; + uint32_t optionend; + bool enable_step_irq; + + bool enable_stm8l; + uint32_t flash_cr2; + uint32_t flash_ncr2; + uint32_t flash_iapsr; + uint32_t flash_dukr; + uint32_t flash_pukr; + + /* cc value used for interrupt flags restore */ + uint32_t cc; + bool cc_valid; + + /* register cache to processor synchronization */ + int (*read_core_reg)(struct target *target, unsigned int num); + int (*write_core_reg)(struct target *target, unsigned int num); +}; + +static inline struct stm8_common * +target_to_stm8(struct target *target) +{ + return target->arch_info; +} + +const struct command_registration stm8_command_handlers[]; + +#endif /* OPENOCD_TARGET_STM8_H */ diff --git a/src/target/target.c b/src/target/target.c index 36318d88e..dcb672506 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -105,6 +105,7 @@ extern struct target_type nds32_v3m_target; extern struct target_type or1k_target; extern struct target_type quark_x10xx_target; extern struct target_type quark_d20xx_target; +extern struct target_type stm8_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -136,6 +137,7 @@ static struct target_type *target_types[] = { &or1k_target, &quark_x10xx_target, &quark_d20xx_target, + &stm8_target, #if BUILD_TARGET64 &aarch64_target, #endif diff --git a/tcl/target/stm8l.cfg b/tcl/target/stm8l.cfg new file mode 100644 index 000000000..5cc99e191 --- /dev/null +++ b/tcl/target/stm8l.cfg @@ -0,0 +1,87 @@ +# script for stm8l family + +# +# stm8 devices support SWIM transports only. +# + +transport select stlink_swim + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm8l +} + +# Work-area is a space in RAM used for flash programming +# By default use 1kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x400 +} + +if { [info exists FLASHSTART] } { + set _FLASHSTART $FLASHSTART +} else { + set _FLASHSTART 0x8000 +} + +if { [info exists FLASHEND] } { + set _FLASHEND $FLASHEND +} else { + set _FLASHEND 0xffff +} + +if { [info exists EEPROMSTART] } { + set _EEPROMSTART $EEPROMSTART +} else { + set _EEPROMSTART 0x4000 +} + +if { [info exists EEPROMEND] } { + set _EEPROMEND $EEPROMEND +} else { + set _EEPROMEND 0x43ff +} + +if { [info exists OPTIONSTART] } { + set _OPTIONSTART $OPTIONSTART +} else { + set _OPTIONSTART 0x4800 +} + +if { [info exists OPTIONEND] } { + set _OPTIONEND $OPTIONEND +} else { + set _OPTIONEND 0x487f +} + +if { [info exists BLOCKSIZE] } { + set _BLOCKSIZE $BLOCKSIZE +} else { + set _BLOCKSIZE 0x80 +} + +hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu + +$_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 +$_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND +$_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE + +# Uncomment this line to enable interrupts while instruction step +#$_TARGETNAME configure -enable_step_irq + +# Set stm8l type +$_TARGETNAME configure -enable_stm8l + +# The khz rate does not apply here, only slow <0> and fast <1> +adapter_khz 1 + +reset_config srst_only + +#uncomment this line to connect under reset +#reset_config srst_nogate connect_assert_srst diff --git a/tcl/target/stm8s.cfg b/tcl/target/stm8s.cfg new file mode 100644 index 000000000..d55e61b08 --- /dev/null +++ b/tcl/target/stm8s.cfg @@ -0,0 +1,84 @@ +# script for stm8s family + +# +# stm8 devices support SWIM transports only. +# + +transport select stlink_swim + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm8s +} + +# Work-area is a space in RAM used for flash programming +# By default use 1kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x400 +} + +if { [info exists FLASHSTART] } { + set _FLASHSTART $FLASHSTART +} else { + set _FLASHSTART 0x8000 +} + +if { [info exists FLASHEND] } { + set _FLASHEND $FLASHEND +} else { + set _FLASHEND 0xffff +} + +if { [info exists EEPROMSTART] } { + set _EEPROMSTART $EEPROMSTART +} else { + set _EEPROMSTART 0x4000 +} + +if { [info exists EEPROMEND] } { + set _EEPROMEND $EEPROMEND +} else { + set _EEPROMEND 0x43ff +} + +if { [info exists OPTIONSTART] } { + set _OPTIONSTART $OPTIONSTART +} else { + set _OPTIONSTART 0x4800 +} + +if { [info exists OPTIONEND] } { + set _OPTIONEND $OPTIONEND +} else { + set _OPTIONEND 0x487f +} + +if { [info exists BLOCKSIZE] } { + set _BLOCKSIZE $BLOCKSIZE +} else { + set _BLOCKSIZE 0x80 +} + +hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu + +$_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 +$_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND +$_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE + +# Uncomment this line to enable interrupts while instruction step +#$_TARGETNAME configure -enable_step_irq + +# The khz rate does not apply here, only slow <0> and fast <1> +adapter_khz 1 + +reset_config srst_only + +# uncomment this line to connect under reset +#reset_config srst_nogate connect_assert_srst From 9021210428c87bd8db943c0d88a682077aedb533 Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Wed, 6 Dec 2017 22:04:49 +0000 Subject: [PATCH 46/54] docs: add missing stm32 flash driver documentation Change-Id: I433780646e6fdfd0c2527b4a68025946ccb79d8b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/4307 Tested-by: jenkins Reviewed-by: Reviewed-by: Antonio Borneo --- doc/openocd.texi | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 2719c2d97..ac491b144 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5952,6 +5952,12 @@ Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn +@deffn Command {stm32f1x mass_erase} num +Mass erases the entire stm32f1x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + @deffn Command {stm32f1x options_read} num Read and display the stm32 option bytes written by the @command{stm32f1x options_write} command. @@ -5970,6 +5976,10 @@ include internal flash and use ARM Cortex-M3/M4/M7 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. +@example +flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME +@end example + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @@ -5990,6 +6000,12 @@ Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn +@deffn Command {stm32f2x mass_erase} num +Mass erases the entire stm32f2x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + @deffn Command {stm32f2x options_read} num Reads and displays user options and (where implemented) boot_addr0, boot_addr1, optcr2. The @var{num} parameter is a value shown by @command{flash banks}. @@ -6015,6 +6031,10 @@ include internal flash and use ARM Cortex-M7 core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. +@example +flash bank $_FLASHNAME stm32h7x 0 0 0 0 $_TARGETNAME +@end example + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @@ -6034,6 +6054,12 @@ The @var{num} parameter is a value shown by @command{flash banks}. Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn + +@deffn Command {stm32h7x mass_erase} num +Mass erases the entire stm32h7x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn @end deffn @deffn {Flash Driver} stm32lx @@ -6042,6 +6068,10 @@ include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. +@example +flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME +@end example + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. If you use 0 as the bank base address, it tells the @@ -6062,6 +6092,43 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn +@deffn {Flash Driver} stm32l4x +All members of the STM32L4 microcontroller families from ST Microelectronics +include internal flash and use ARM Cortex-M4 cores. +The driver automatically recognizes a number of these chips using +the chip identification register, and autoconfigures itself. + +@example +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +@end example + +Note that some devices have been found that have a flash size register that contains +an invalid value, to workaround this issue you can override the probed value used by +the flash driver. + +@example +flash bank $_FLASHNAME stm32l4x 0x08000000 0x40000 0 0 $_TARGETNAME +@end example + +Some stm32l4x-specific commands are defined: + +@deffn Command {stm32l4x lock} num +Locks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32l4x unlock} num +Unlocks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32l4x mass_erase} num +Mass erases the entire stm32l4x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn +@end deffn + @deffn {Flash Driver} str7x All members of the STR7 microcontroller family from ST Microelectronics include internal flash and use ARM7TDMI cores. From eb26a884e0ff0fb6568aeda65fe21eec1e5b6557 Mon Sep 17 00:00:00 2001 From: elmot Date: Thu, 7 Dec 2017 10:08:28 +0200 Subject: [PATCH 47/54] config: stm32l01x and stm32l02x chips support New low-end chips have only 2k of RAM, workarea size adjusted Change-Id: Ibfccd73fef9e6dabffc87d901736c5626ce411fe Signed-off-by: Ilia Motornyi Reviewed-on: http://openocd.zylin.com/4308 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Andreas Fritiofson --- tcl/target/stm32l0.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/target/stm32l0.cfg b/tcl/target/stm32l0.cfg index 245213b42..417b282d3 100644 --- a/tcl/target/stm32l0.cfg +++ b/tcl/target/stm32l0.cfg @@ -15,11 +15,11 @@ if { [info exists CHIPNAME] } { set _ENDIAN little # Work-area is a space in RAM used for flash programming -# By default use 8kB (max ram on smallest part) +# By default use 2kB (max ram on smallest part) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x2000 + set _WORKAREASIZE 0x800 } # JTAG speed should be <= F_CPU/6. From 31c58c139d85c35cc8ebce4196edb2c5eb157c7a Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Thu, 26 Jan 2017 23:41:40 +0300 Subject: [PATCH 48/54] jtag: drivers: stlink: handle all versions with single config Extend HLA interface to allow multiple VID/PID pairs and use it to autodetect the connected stlink version. Change-Id: I35cd895b2260e23cf0e8fcb1fc11a78c2b99c69b Signed-off-by: Paul Fertser Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/3961 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver --- doc/openocd.texi | 4 ++-- src/jtag/drivers/stlink_usb.c | 28 +++++++++++++--------------- src/jtag/drivers/ti_icdi_usb.c | 8 ++++++-- src/jtag/hla/hla_interface.c | 26 +++++++++++++++++++------- src/jtag/hla/hla_interface.h | 10 ++++++---- tcl/board/st_nucleo_f0.cfg | 2 +- tcl/board/st_nucleo_f103rb.cfg | 2 +- tcl/board/st_nucleo_f3.cfg | 2 +- tcl/board/st_nucleo_f4.cfg | 2 +- tcl/board/st_nucleo_l1.cfg | 2 +- tcl/board/st_nucleo_l476rg.cfg | 2 +- tcl/board/stm320518_eval_stlink.cfg | 2 +- tcl/board/stm3220g_eval_stlink.cfg | 2 +- tcl/board/stm3241g_eval_stlink.cfg | 2 +- tcl/board/stm32429i_eval_stlink.cfg | 2 +- tcl/board/stm32439i_eval_stlink.cfg | 2 +- tcl/board/stm32f0discovery.cfg | 2 +- tcl/board/stm32f3discovery.cfg | 2 +- tcl/board/stm32f429disc1.cfg | 2 +- tcl/board/stm32f429discovery.cfg | 2 +- tcl/board/stm32f469discovery.cfg | 2 +- tcl/board/stm32f4discovery.cfg | 2 +- tcl/board/stm32f7discovery.cfg | 2 +- tcl/board/stm32l0discovery.cfg | 2 +- tcl/board/stm32l4discovery.cfg | 2 +- tcl/board/stm32ldiscovery.cfg | 2 +- tcl/board/stm32vldiscovery.cfg | 2 +- tcl/interface/stlink-v1.cfg | 11 ++--------- tcl/interface/stlink-v2-1.cfg | 18 ++---------------- tcl/interface/stlink-v2.cfg | 18 ++---------------- tcl/interface/stlink.cfg | 17 +++++++++++++++++ 31 files changed, 91 insertions(+), 93 deletions(-) create mode 100644 tcl/interface/stlink.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index ac491b144..7de0db8b7 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2948,8 +2948,8 @@ Specifies the serial number of the adapter. Specifies the adapter layout to use. @end deffn -@deffn {Config Command} {hla_vid_pid} vid pid -The vendor ID and product ID of the device. +@deffn {Config Command} {hla_vid_pid} [vid pid]+ +Pairs of vendor IDs and product IDs of the device. @end deffn @deffn {Command} {hla_command} command diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 0bdcd316b..64868ea9e 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1650,13 +1650,11 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) h->transport = param->transport; - const uint16_t vids[] = { param->vid, 0 }; - const uint16_t pids[] = { param->pid, 0 }; - const char *serial = param->serial; - - LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", - param->transport, param->vid, param->pid, - param->serial ? param->serial : ""); + for (unsigned i = 0; param->vid[i]; i++) { + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", + param->transport, param->vid[i], param->pid[i], + param->serial ? param->serial : ""); + } /* On certain host USB configurations(e.g. MacBook Air) @@ -1668,7 +1666,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) in order to become operational. */ do { - if (jtag_libusb_open(vids, pids, serial, &h->fd) != ERROR_OK) { + if (jtag_libusb_open(param->vid, param->pid, param->serial, &h->fd) != ERROR_OK) { LOG_ERROR("open failed"); goto error_open; } @@ -1683,8 +1681,14 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) /* RX EP is common for all versions */ h->rx_ep = STLINK_RX_EP; + uint16_t pid; + if (jtag_libusb_get_pid(jtag_libusb_get_device(h->fd), &pid) != ERROR_OK) { + LOG_DEBUG("libusb_get_pid failed"); + goto error_open; + } + /* wrap version for first read */ - switch (param->pid) { + switch (pid) { case STLINK_V1_PID: h->version.stlink = 1; h->tx_ep = STLINK_TX_EP; @@ -1736,12 +1740,6 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) } } while (1); - /* compare usb vid/pid */ - if ((param->vid != h->vid) || (param->pid != h->pid)) - LOG_INFO("vid/pid are not identical: 0x%04X/0x%04X 0x%04X/0x%04X", - param->vid, param->pid, - h->vid, h->pid); - /* check if mode is supported */ err = ERROR_OK; diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 171ac66c4..f316c8256 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -688,14 +688,18 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) } LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport, - param->vid, param->pid); + param->vid[0], param->pid[0]); + + /* TODO: convert libusb_ calls to jtag_libusb_ */ + if (param->vid[1]) + LOG_WARNING("Bad configuration: 'hla_vid_pid' command does not accept more than one VID PID pair on ti-icdi!"); if (libusb_init(&h->usb_ctx) != 0) { LOG_ERROR("libusb init failed"); goto error_open; } - h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid, param->pid); + h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid[0], param->pid[0]); if (!h->usb_dev) { LOG_ERROR("open failed"); goto error_open; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 9217631b0..62a8f5947 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -35,7 +35,7 @@ #include -static struct hl_interface_s hl_if = { {0, 0, 0, 0, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; +static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; int hl_interface_open(enum hl_transports tr) { @@ -264,15 +264,27 @@ COMMAND_HANDLER(hl_interface_handle_layout_command) COMMAND_HANDLER(hl_interface_handle_vid_pid_command) { - LOG_DEBUG("hl_interface_handle_vid_pid_command"); - - if (CMD_ARGC != 2) { - LOG_WARNING("ignoring extra IDs in hl_vid_pid (maximum is 1 pair)"); + if (CMD_ARGC > HLA_MAX_USB_IDS * 2) { + LOG_WARNING("ignoring extra IDs in hla_vid_pid " + "(maximum is %d pairs)", HLA_MAX_USB_IDS); + CMD_ARGC = HLA_MAX_USB_IDS * 2; + } + if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { + LOG_WARNING("incomplete hla_vid_pid configuration directive"); return ERROR_COMMAND_SYNTAX_ERROR; } - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], hl_if.param.vid); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], hl_if.param.pid); + unsigned i; + for (i = 0; i < CMD_ARGC; i += 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], hl_if.param.vid[i / 2]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], hl_if.param.pid[i / 2]); + } + + /* + * Explicitly terminate, in case there are multiple instances of + * hla_vid_pid. + */ + hl_if.param.vid[i / 2] = hl_if.param.pid[i / 2] = 0; return ERROR_OK; } diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index 0992d1cad..262025e98 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -29,15 +29,17 @@ enum e_hl_transports; /** */ extern const char *hl_transports[]; +#define HLA_MAX_USB_IDS 8 + struct hl_interface_param_s { /** */ const char *device_desc; /** */ const char *serial; - /** */ - uint16_t vid; - /** */ - uint16_t pid; + /** List of recognised VIDs */ + uint16_t vid[HLA_MAX_USB_IDS + 1]; + /** List of recognised PIDs */ + uint16_t pid[HLA_MAX_USB_IDS + 1]; /** */ unsigned api; /** */ diff --git a/tcl/board/st_nucleo_f0.cfg b/tcl/board/st_nucleo_f0.cfg index e9fda19a6..e6a03bba8 100644 --- a/tcl/board/st_nucleo_f0.cfg +++ b/tcl/board/st_nucleo_f0.cfg @@ -6,7 +6,7 @@ # STM32F091RC # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260944 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_f103rb.cfg b/tcl/board/st_nucleo_f103rb.cfg index 71a92f704..e1990dcf4 100644 --- a/tcl/board/st_nucleo_f103rb.cfg +++ b/tcl/board/st_nucleo_f103rb.cfg @@ -1,7 +1,7 @@ # This is an ST NUCLEO F103RB board with a single STM32F103RBT6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259875 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_f3.cfg b/tcl/board/st_nucleo_f3.cfg index 9dffdcbbd..fec612b39 100644 --- a/tcl/board/st_nucleo_f3.cfg +++ b/tcl/board/st_nucleo_f3.cfg @@ -1,7 +1,7 @@ # This is an ST NUCLEO F334R8 board with a single STM32F334R8T6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260004 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_f4.cfg b/tcl/board/st_nucleo_f4.cfg index b5a78c1c0..11f6f8778 100644 --- a/tcl/board/st_nucleo_f4.cfg +++ b/tcl/board/st_nucleo_f4.cfg @@ -4,7 +4,7 @@ # STM32F411RET6 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260320 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_l1.cfg b/tcl/board/st_nucleo_l1.cfg index 56e275627..d97eb7c17 100644 --- a/tcl/board/st_nucleo_l1.cfg +++ b/tcl/board/st_nucleo_l1.cfg @@ -1,7 +1,7 @@ # This is an ST NUCLEO L152RE board with a single STM32L152RET6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260002 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_l476rg.cfg b/tcl/board/st_nucleo_l476rg.cfg index 2baa34e76..4426c3bc9 100644 --- a/tcl/board/st_nucleo_l476rg.cfg +++ b/tcl/board/st_nucleo_l476rg.cfg @@ -1,7 +1,7 @@ # This is a ST NUCLEO L476RG board with a single STM32L476RGT6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF261636 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm320518_eval_stlink.cfg b/tcl/board/stm320518_eval_stlink.cfg index ce074cbf2..a7fef0765 100644 --- a/tcl/board/stm320518_eval_stlink.cfg +++ b/tcl/board/stm320518_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm3220g_eval_stlink.cfg b/tcl/board/stm3220g_eval_stlink.cfg index 43a4df986..b58e42fe5 100644 --- a/tcl/board/stm3220g_eval_stlink.cfg +++ b/tcl/board/stm3220g_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm3241g_eval_stlink.cfg b/tcl/board/stm3241g_eval_stlink.cfg index 9c7ad5d95..b1c54a2c6 100644 --- a/tcl/board/stm3241g_eval_stlink.cfg +++ b/tcl/board/stm3241g_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32429i_eval_stlink.cfg b/tcl/board/stm32429i_eval_stlink.cfg index 2b51cea67..010d37198 100644 --- a/tcl/board/stm32429i_eval_stlink.cfg +++ b/tcl/board/stm32429i_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32439i_eval_stlink.cfg b/tcl/board/stm32439i_eval_stlink.cfg index 5995fb1d2..b722ce67c 100644 --- a/tcl/board/stm32439i_eval_stlink.cfg +++ b/tcl/board/stm32439i_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f0discovery.cfg b/tcl/board/stm32f0discovery.cfg index bae9a69ba..e2b5e3844 100644 --- a/tcl/board/stm32f0discovery.cfg +++ b/tcl/board/stm32f0discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32F0 discovery board with a single STM32F051R8T6 chip. # http://www.st.com/internet/evalboard/product/253215.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f3discovery.cfg b/tcl/board/stm32f3discovery.cfg index 5a17b4c99..9bb62f5f2 100644 --- a/tcl/board/stm32f3discovery.cfg +++ b/tcl/board/stm32f3discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32F3 discovery board with a single STM32F303VCT6 chip. # http://www.st.com/internet/evalboard/product/254044.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f429disc1.cfg b/tcl/board/stm32f429disc1.cfg index 9d3cdd757..c0bcebae4 100644 --- a/tcl/board/stm32f429disc1.cfg +++ b/tcl/board/stm32f429disc1.cfg @@ -3,7 +3,7 @@ # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f429discovery.cfg b/tcl/board/stm32f429discovery.cfg index e06d2a51c..7aef09d4f 100644 --- a/tcl/board/stm32f429discovery.cfg +++ b/tcl/board/stm32f429discovery.cfg @@ -3,7 +3,7 @@ # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f469discovery.cfg b/tcl/board/stm32f469discovery.cfg index 63b13638a..a9559a756 100644 --- a/tcl/board/stm32f469discovery.cfg +++ b/tcl/board/stm32f469discovery.cfg @@ -3,7 +3,7 @@ # http://www.st.com/web/catalog/tools/FM116/CL1620/SC959/SS1532/LN1848/PF262395 # -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f4discovery.cfg b/tcl/board/stm32f4discovery.cfg index 963e0f959..60b7f42b5 100644 --- a/tcl/board/stm32f4discovery.cfg +++ b/tcl/board/stm32f4discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32F4 discovery board with a single STM32F407VGT6 chip. # http://www.st.com/internet/evalboard/product/252419.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f7discovery.cfg b/tcl/board/stm32f7discovery.cfg index 085340f30..7d1bc9665 100755 --- a/tcl/board/stm32f7discovery.cfg +++ b/tcl/board/stm32f7discovery.cfg @@ -2,7 +2,7 @@ # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF261641 # This is for using the onboard STLINK/V2-1 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32l0discovery.cfg b/tcl/board/stm32l0discovery.cfg index a03506224..aabbf8170 100644 --- a/tcl/board/stm32l0discovery.cfg +++ b/tcl/board/stm32l0discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32L053 discovery board with a single STM32L053 chip. # http://www.st.com/web/en/catalog/tools/PF260319 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32l4discovery.cfg b/tcl/board/stm32l4discovery.cfg index eb1933116..8b79841ed 100644 --- a/tcl/board/stm32l4discovery.cfg +++ b/tcl/board/stm32l4discovery.cfg @@ -4,7 +4,7 @@ # an stlink-v2-1 interface. # This is for STM32L4 boards that are connected via stlink-v2-1. -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32ldiscovery.cfg b/tcl/board/stm32ldiscovery.cfg index 8678d290b..3e397cba4 100644 --- a/tcl/board/stm32ldiscovery.cfg +++ b/tcl/board/stm32ldiscovery.cfg @@ -1,7 +1,7 @@ # This is an STM32L discovery board with a single STM32L152RBT6 chip. # http://www.st.com/internet/evalboard/product/250990.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32vldiscovery.cfg b/tcl/board/stm32vldiscovery.cfg index 970b5101e..60805b32c 100644 --- a/tcl/board/stm32vldiscovery.cfg +++ b/tcl/board/stm32vldiscovery.cfg @@ -1,7 +1,7 @@ # This is an STM32VL discovery board with a single STM32F100RB chip. # http://www.st.com/internet/evalboard/product/250863.jsp -source [find interface/stlink-v1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/interface/stlink-v1.cfg b/tcl/interface/stlink-v1.cfg index 13f207dc6..000422725 100644 --- a/tcl/interface/stlink-v1.cfg +++ b/tcl/interface/stlink-v1.cfg @@ -1,9 +1,2 @@ -# -# STMicroelectronics ST-LINK/V1 in-circuit debugger/programmer -# - -interface hla -hla_layout stlink -hla_device_desc "ST-LINK/V1" -hla_vid_pid 0x0483 0x3744 - +echo "WARNING: interface/stlink-v1.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink-v2-1.cfg b/tcl/interface/stlink-v2-1.cfg index 093e80177..62f37dc33 100644 --- a/tcl/interface/stlink-v2-1.cfg +++ b/tcl/interface/stlink-v2-1.cfg @@ -1,16 +1,2 @@ -# -# STMicroelectronics ST-LINK/V2-1 in-circuit debugger/programmer -# - -interface hla -hla_layout stlink -hla_device_desc "ST-LINK/V2-1" -hla_vid_pid 0x0483 0x374b - -# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 -# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 -# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial -# number reset issues. -# eg. -#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" - +echo "WARNING: interface/stlink-v2-1.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink-v2.cfg b/tcl/interface/stlink-v2.cfg index ae545a118..070e46958 100644 --- a/tcl/interface/stlink-v2.cfg +++ b/tcl/interface/stlink-v2.cfg @@ -1,16 +1,2 @@ -# -# STMicroelectronics ST-LINK/V2 in-circuit debugger/programmer -# - -interface hla -hla_layout stlink -hla_device_desc "ST-LINK/V2" -hla_vid_pid 0x0483 0x3748 - -# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 -# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 -# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial -# number reset issues. -# eg. -#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" - +echo "WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg new file mode 100644 index 000000000..d747d8533 --- /dev/null +++ b/tcl/interface/stlink.cfg @@ -0,0 +1,17 @@ +# +# STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1 in-circuit +# debugger/programmer +# + +interface hla +hla_layout stlink +hla_device_desc "ST-LINK" +hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b + +# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 +# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 +# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial +# number reset issues. +# eg. +#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" + From 04227634896ebe6a600d647508b6c934791662b7 Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Thu, 7 Dec 2017 12:30:35 +0000 Subject: [PATCH 49/54] doc: improve stm32 flash driver documentation also remove legacy footnote as it adds no value. Change-Id: I3892acf244bd8fba6f844a5d82a66004e193a395 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/4309 Tested-by: jenkins Reviewed-by: Karl Palsson --- doc/openocd.texi | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 7de0db8b7..574834404 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5888,9 +5888,6 @@ All members of the Stellaris LM3Sxxx, LM4x and Tiva C microcontroller families from Texas Instruments include internal flash. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. -@footnote{Currently there is a @command{stellaris mass_erase} command. -That seems pointless since the same effect can be had using the -standard @command{flash erase_address} command.} @example flash bank $_FLASHNAME stellaris 0 0 0 0 $_TARGETNAME @@ -5936,11 +5933,7 @@ as per the following example. flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME @end example -Some stm32f1x-specific commands -@footnote{Currently there is a @command{stm32f1x mass_erase} command. -That seems pointless since the same effect can be had using the -standard @command{flash erase_address} command.} -are defined: +Some stm32f1x-specific commands are defined: @deffn Command {stm32f1x lock} num Locks the entire stm32 device. @@ -5953,8 +5946,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x mass_erase} num -Mass erases the entire stm32f1x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32f1x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -6001,8 +5993,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f2x mass_erase} num -Mass erases the entire stm32f2x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32f2x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -6056,8 +6047,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32h7x mass_erase} num -Mass erases the entire stm32h7x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn @@ -6084,6 +6074,16 @@ flash bank $_FLASHNAME stm32lx 0x08000000 0x20000 0 0 $_TARGETNAME Some stm32lx-specific commands are defined: +@deffn Command {stm32lx lock} num +Locks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32lx unlock} num +Unlocks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + @deffn Command {stm32lx mass_erase} num Mass erases the entire stm32lx device (all flash banks and EEPROM data). This is the only way to unlock a protected flash (unless RDP @@ -6123,8 +6123,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32l4x mass_erase} num -Mass erases the entire stm32l4x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn From 90a6245eecd82c95112c09700cfebcf2403d0478 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 26 Oct 2017 18:00:33 +0200 Subject: [PATCH 50/54] flash/nor/stm32f2x: fix protection block size for F767 in dual bank mode A protection block comprises two adjacent sectors in dual bank mode. As there are 64 and 128kB sectors joined in blocks 2 and 8, block size should be computed as a sum of sector sizes. Change-Id: Ie915df8cf7ca232c4565d7e0c514c8933e71fdfe Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4271 Tested-by: jenkins Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver --- src/flash/nor/stm32f2x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 65cb212b6..8127f1334 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1047,7 +1047,8 @@ static int stm32x_probe(struct flash_bank *bank) if (device_id == 0x451) { for (i = 0; i < num_prot_blocks; i++) { bank->prot_blocks[i].offset = bank->sectors[i << 1].offset; - bank->prot_blocks[i].size = bank->sectors[i << 1].size << 1; + bank->prot_blocks[i].size = bank->sectors[i << 1].size + + bank->sectors[(i << 1) + 1].size; } } } else { From 3f6ab8e6a6f80f4a6486c688793daad866d21863 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 23 Nov 2017 14:47:37 +0100 Subject: [PATCH 51/54] flash/nor/stm32f2x: fix erase on STM32F413/423 Theese devices do not have a gap in sector numbering. The driver translates sectors numbers 12 13... to 16 17... as used on dual bank flash devices. Therefore erase of sector 12 and above fails with error 'stm32x device protected' on F413/423. Drop sector number translation for devices without has_large_mem flag. Change-Id: I65531c0dfe02e2fd0f3d68f0615e0926e9901391 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4299 Tested-by: jenkins Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver --- src/flash/nor/stm32f2x.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 8127f1334..b0992b404 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -143,9 +143,8 @@ #define FLASH_PSIZE_16 (1 << 8) #define FLASH_PSIZE_32 (2 << 8) #define FLASH_PSIZE_64 (3 << 8) -/* The sector number encoding is not straight binary for dual bank flash. - * Warning: evaluates the argument multiple times */ -#define FLASH_SNB(a) ((((a) >= 12) ? 0x10 | ((a) - 12) : (a)) << 3) +/* The sector number encoding is not straight binary for dual bank flash. */ +#define FLASH_SNB(a) ((a) << 3) #define FLASH_LOCK (1 << 31) /* FLASH_SR register bits */ @@ -489,6 +488,7 @@ static int stm32x_protect_check(struct flash_bank *bank) static int stm32x_erase(struct flash_bank *bank, int first, int last) { + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; int i; @@ -516,8 +516,14 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) */ for (i = first; i <= last; i++) { + int snb; + if (stm32x_info->has_large_mem && i >= 12) + snb = (i - 12) | 0x10; + else + snb = i; + retval = target_write_u32(target, - stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(i) | FLASH_STRT); + stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(snb) | FLASH_STRT); if (retval != ERROR_OK) return retval; From 19f8f58c0d4d9ee618969254a368e4396657b946 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 31 Oct 2017 12:32:22 +0100 Subject: [PATCH 52/54] target: remove unused event definitions Events reset-halt-pre, reset-halt-post, reset-wait-pre and reset-wait-post are not used anywhere. Change-Id: I9a0f94875b102d9b08f6c2fd9d73a9f05f8e8e79 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4285 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- doc/openocd.texi | 12 ------------ src/target/target.c | 4 ---- src/target/target.h | 4 ---- 3 files changed, 20 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 574834404..ebd03c4cb 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4503,12 +4503,6 @@ and (if the target is using it) after SRST has been released on the scan chain. @item @b{reset-end} @* Issued as the final step in @command{reset} processing. -@ignore -@item @b{reset-halt-post} -@* Currently not used -@item @b{reset-halt-pre} -@* Currently not used -@end ignore @item @b{reset-init} @* Used by @b{reset init} command for board-specific initialization. This event fires after @emph{reset-deassert-post}. @@ -4525,12 +4519,6 @@ before @command{reset_init} is called. This is the most robust place to use @command{jtag_rclk} or @command{adapter_khz} to switch to a low JTAG clock rate, when reset disables PLLs needed to use a fast clock. -@ignore -@item @b{reset-wait-pos} -@* Currently not used -@item @b{reset-wait-pre} -@* Currently not used -@end ignore @item @b{resume-start} @* Before any target is resumed @item @b{resume-end} diff --git a/src/target/target.c b/src/target/target.c index dcb672506..a9907b0c3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -204,10 +204,6 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_RESET_ASSERT_POST, .name = "reset-assert-post" }, { .value = TARGET_EVENT_RESET_DEASSERT_PRE, .name = "reset-deassert-pre" }, { .value = TARGET_EVENT_RESET_DEASSERT_POST, .name = "reset-deassert-post" }, - { .value = TARGET_EVENT_RESET_HALT_PRE, .name = "reset-halt-pre" }, - { .value = TARGET_EVENT_RESET_HALT_POST, .name = "reset-halt-post" }, - { .value = TARGET_EVENT_RESET_WAIT_PRE, .name = "reset-wait-pre" }, - { .value = TARGET_EVENT_RESET_WAIT_POST, .name = "reset-wait-post" }, { .value = TARGET_EVENT_RESET_INIT, .name = "reset-init" }, { .value = TARGET_EVENT_RESET_END, .name = "reset-end" }, diff --git a/src/target/target.h b/src/target/target.h index 53f9e2614..0096cae10 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -253,10 +253,6 @@ enum target_event { TARGET_EVENT_RESET_ASSERT_POST, TARGET_EVENT_RESET_DEASSERT_PRE, TARGET_EVENT_RESET_DEASSERT_POST, - TARGET_EVENT_RESET_HALT_PRE, - TARGET_EVENT_RESET_HALT_POST, - TARGET_EVENT_RESET_WAIT_PRE, - TARGET_EVENT_RESET_WAIT_POST, TARGET_EVENT_RESET_INIT, TARGET_EVENT_RESET_END, From 84d68579eb55c1b4aba4fddc11b33ae746f84d23 Mon Sep 17 00:00:00 2001 From: Jiri Kastner Date: Sat, 16 Dec 2017 22:17:52 +0100 Subject: [PATCH 53/54] configs for Marvell Armada 3700 Change-Id: I367f39c9bc9e58380d6d5b500d5368d5173d96bd Signed-off-by: Jiri Kastner Signed-off-by: Forest Crossman Reviewed-on: http://openocd.zylin.com/4302 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/target/marvell/88f3710.cfg | 5 +++ tcl/target/marvell/88f3720.cfg | 5 +++ tcl/target/marvell/88f37x0.cfg | 68 ++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 tcl/target/marvell/88f3710.cfg create mode 100644 tcl/target/marvell/88f3720.cfg create mode 100644 tcl/target/marvell/88f37x0.cfg diff --git a/tcl/target/marvell/88f3710.cfg b/tcl/target/marvell/88f3710.cfg new file mode 100644 index 000000000..6e35f293d --- /dev/null +++ b/tcl/target/marvell/88f3710.cfg @@ -0,0 +1,5 @@ +# Marvell Armada 3710 + +set CORES 1 + +source [find target/marvell/88f37x0.cfg] diff --git a/tcl/target/marvell/88f3720.cfg b/tcl/target/marvell/88f3720.cfg new file mode 100644 index 000000000..799d614ba --- /dev/null +++ b/tcl/target/marvell/88f3720.cfg @@ -0,0 +1,5 @@ +# Marvell Armada 3720 + +set CORES 2 + +source [find target/marvell/88f37x0.cfg] diff --git a/tcl/target/marvell/88f37x0.cfg b/tcl/target/marvell/88f37x0.cfg new file mode 100644 index 000000000..dba7da21e --- /dev/null +++ b/tcl/target/marvell/88f37x0.cfg @@ -0,0 +1,68 @@ +# Main file for Marvell Armada 3700 series targets +# +# !!!!!! +# +# This file should not be included directly. Instead, please include +# either marvell/88f3710.cfg or marvell/88f3720.cfg, which set the needed +# variables to the appropriate values. +# +# !!!!!! + +# Armada 3700 supports both JTAG and SWD transports. +source [find target/swj-dp.tcl] + +if { [info exists CORES] } { + set _cores $CORES +} else { + error "CORES not set. Please do not include marvell/88f37x0.cfg directly, but the specific chip configuration file (marvell/88f3710.cfg, marvell/88f3720.cfg, etc.)." +} + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME [format a37%s0 $_cores] +} + +set _ctis {0x80820000 0x80920000} + +# +# Main DAP +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +# declare the one JTAG tap to access the DAP +swj_newdap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable + +# declare the main application cores +set _TARGETNAME $_CHIPNAME.cpu +set _smp_command "" + +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + + set _command "target create ${_TARGETNAME}$_core aarch64 \ + -chain-position $_CHIPNAME.dap -coreid $_core \ + -ctibase [lindex $_ctis $_core]" + + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command ${_TARGETNAME}$_core" + } else { + # uncomment when "hawt" rtos is merged + # set _command "$_command -rtos hawt" + set _smp_command "target smp ${_TARGETNAME}$_core" + } + + eval $_command +} + +eval $_smp_command + +# declare the auxiliary Cortex-M3 core on AP #3 +target create ${_TARGETNAME}.m3 cortex_m -chain-position $_CHIPNAME.dap -ap-num 3 -defer-examine + +targets ${_TARGETNAME}0 From 1c2e3d41de30c5e47d3fc8eda3de0a0a8229895a Mon Sep 17 00:00:00 2001 From: Jiri Kastner Date: Sat, 16 Dec 2017 22:21:14 +0100 Subject: [PATCH 54/54] config for ESPRESSObin from Globalscale Tech. Inc. Change-Id: I77f536a9d2e901ebcef0a7dd0f205e5332b1d382 Signed-off-by: Jiri Kastner Reviewed-on: http://openocd.zylin.com/4303 Tested-by: jenkins Reviewed-by: Forest Crossman Reviewed-by: Tomas Vanek --- tcl/board/gti/espressobin.cfg | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tcl/board/gti/espressobin.cfg diff --git a/tcl/board/gti/espressobin.cfg b/tcl/board/gti/espressobin.cfg new file mode 100644 index 000000000..20d0452fd --- /dev/null +++ b/tcl/board/gti/espressobin.cfg @@ -0,0 +1,7 @@ +# config for ESPRESSObin from +# Globalscale Technologies Inc. + +# srst is isolated through missing resistor +reset_config trst_only + +source [find target/marvell/88f3720.cfg]