summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2008-03-10 14:07:28 +0000
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2008-03-10 14:07:28 +0000
commite6dac739cffdecc0c65254eb7b3f2942cfff0f68 (patch)
tree1f991f0dea21966de4845a93843ce196197022e2 /src
parent0424155dfc29ab8e3b5e4b7f36f9164df7b5b740 (diff)
downloadopenocd+libswd-e6dac739cffdecc0c65254eb7b3f2942cfff0f68.tar.gz
openocd+libswd-e6dac739cffdecc0c65254eb7b3f2942cfff0f68.tar.bz2
openocd+libswd-e6dac739cffdecc0c65254eb7b3f2942cfff0f68.tar.xz
openocd+libswd-e6dac739cffdecc0c65254eb7b3f2942cfff0f68.zip
- the jtag chain is examined and validated after GDB & telnet servers
are up and running. The examination and validation is actually "optional" from the point of view of GDB + telnet servers. Multiple targets should work fine with this. - jtag_speed is dropped(divisor is increased), if jtag examination and validation fails. - the chain is validated 10x to catch the worst jtag_speed offences - added LOG_SILENT that can be used to shut up log. Feeble ersatz for try+catch. - GDB register packets are now always replied in order to make sure that GDB connect works. If the target is not halted, then these packets contain dummy values. git-svn-id: svn://svn.berlios.de/openocd/trunk@483 b42882b7-edfa-0310-969c-e2dbd0fdcd60
Diffstat (limited to 'src')
-rw-r--r--src/jtag/Makefile.am2
-rw-r--r--src/jtag/jtag.c112
-rw-r--r--src/target/arm11.c6
-rw-r--r--src/target/armv4_5.c6
-rw-r--r--src/target/armv7m.c6
-rw-r--r--src/target/target.h10
6 files changed, 105 insertions, 37 deletions
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am
index a35e3f3f..04e50ffd 100644
--- a/src/jtag/Makefile.am
+++ b/src/jtag/Makefile.am
@@ -9,7 +9,7 @@ else
FTD2XXINC =
endif
-INCLUDES = -I$(top_srcdir)/src/helper $(FTD2XXINC) $(all_includes)
+INCLUDES = -I$(top_srcdir)/src/helper $(FTD2XXINC) $(all_includes) -I$(top_srcdir)/src/target
METASOURCES = AUTO
noinst_LIBRARIES = libjtag.a
diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c
index 430a6ff8..48cd0595 100644
--- a/src/jtag/jtag.c
+++ b/src/jtag/jtag.c
@@ -28,6 +28,7 @@
#include "command.h"
#include "log.h"
#include "interpreter.h"
+#include "target.h"
#include "stdlib.h"
#include "string.h"
@@ -1327,11 +1328,10 @@ void jtag_sleep(u32 us)
/* Try to examine chain layout according to IEEE 1149.1 §12
*/
-int jtag_examine_chain()
+int jtag_examine_chain(u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4] )
{
jtag_device_t *device = jtag_devices;
scan_field_t field;
- u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
int i;
int bit_count;
int device_count = 0;
@@ -1533,9 +1533,36 @@ int jtag_interface_init(struct command_context_s *cmd_ctx)
return ERROR_OK;
}
+extern int jtag_init_chain(struct command_context_s *cmd_ctx);
+
+static int jtag_sense_handler(void *priv)
+{
+ struct command_context_s *cmd_ctx;
+ cmd_ctx=(struct command_context_s *)priv;
+
+ static int scan_complete = 0;
+ if (!scan_complete)
+ {
+ if (jtag_init_chain(cmd_ctx)==ERROR_OK)
+ {
+ scan_complete = 1;
+ }
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
+/* OpenOCD will start telnet/gdb servers before the JTAG chain has
+ * been enumerated. This is to allow e.g. GDB init script to
+ * run monitor commands to initialize the target so jtag_init_chain()
+ * will succeed.
+ *
+ * A timer callback is added where sensing is retried once every second
+ * until it succeeds.
+ */
int jtag_init(struct command_context_s *cmd_ctx)
{
- int validate_tries = 0;
jtag_device_t *device;
DEBUG("-");
@@ -1556,24 +1583,76 @@ int jtag_init(struct command_context_s *cmd_ctx)
jtag_add_statemove(TAP_TLR);
jtag_execute_queue();
+ target_register_timer_callback(jtag_sense_handler, 1000, 1, cmd_ctx);
+
+ return ERROR_OK;
+ }
+
+static int jtag_test_chain(u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4])
+{
+ jtag_add_statemove(TAP_TLR);
+ jtag_execute_queue();
+
/* examine chain first, as this could discover the real chain layout */
- if (jtag_examine_chain() != ERROR_OK)
+ if (jtag_examine_chain(idcode_buffer)!=ERROR_OK)
{
- ERROR("trying to validate configured JTAG chain anyway...");
+ WARNING("trying to validate configured JTAG chain anyway...");
}
- while (jtag_validate_chain() != ERROR_OK)
- {
- validate_tries++;
- if (validate_tries > 5)
+ return jtag_validate_chain();
+}
+
+/* Unless we can do this successfully 10 times, we're not
+ * satisfied with the quality of the JTAG communication.
+ *
+ * Since we're continously repeating this operation, be a bit
+ * wary of filling the log with megabytes of data.
+ *
+ * Keep increasing the jtag_divisor until we've got a solid
+ * result.
+ */
+int jtag_init_chain(struct command_context_s *cmd_ctx)
+{
+ int i, j;
+ int retval;
+ for (i=jtag_speed; i<64; i++)
+ {
+ u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
+ jtag_speed=i;
+ if ((retval=jtag->speed(jtag_speed))!=ERROR_OK)
+ continue;
+ for (j=0; j<10; j++)
{
- ERROR("Could not validate JTAG chain, exit");
- return ERROR_JTAG_INVALID_INTERFACE;
+ u8 idcode_current[JTAG_MAX_CHAIN_SIZE * 4];
+ enum log_levels save_log_level=debug_level;
+ /* avoid spamming log */
+ debug_level=LOG_SILENT;
+ retval=jtag_test_chain(idcode_current);
+ if (retval==ERROR_OK)
+ {
+ if (j==0)
+ {
+ memcpy(idcode_buffer, idcode_current, sizeof(idcode_buffer));
+ } else
+ {
+ retval=(memcmp(idcode_buffer, idcode_current, sizeof(idcode_buffer))==0)?ERROR_OK:ERROR_JTAG_INIT_FAILED;
+ }
+ }
+ debug_level = save_log_level;
+ if (retval!=ERROR_OK)
+ {
+ break;
+ }
}
- usleep(10000);
+ if (retval==ERROR_OK)
+ {
+ /* Print out result */
+ INFO("Succeeded jtag chain test jtag_speed=%d", jtag_speed);
+ return jtag_test_chain(idcode_buffer);
+ }
+ DEBUG("Failed jtag chain test, dropping clock rate. Trying jtag_speed=%d\n", i+1);
}
-
- return ERROR_OK;
+ return retval;
}
int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
@@ -1778,12 +1857,11 @@ int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char
if (argc > 0)
{
+ jtag_speed = strtoul(args[0], NULL, 0);
/* this command can be called during CONFIG,
* in which case jtag isn't initialized */
if (jtag)
- jtag->speed(strtoul(args[0], NULL, 0));
- else
- jtag_speed = strtoul(args[0], NULL, 0);
+ jtag->speed(jtag_speed);
}
return ERROR_OK;
diff --git a/src/target/arm11.c b/src/target/arm11.c
index a197945f..890b836b 100644
--- a/src/target/arm11.c
+++ b/src/target/arm11.c
@@ -1040,12 +1040,6 @@ int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], i
arm11_common_t * arm11 = target->arch_info;
- if (target->state != TARGET_HALTED)
- {
- WARNING("target was not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
*reg_list_size = ARM11_GDB_REGISTER_COUNT;
*reg_list = malloc(sizeof(reg_t*) * ARM11_GDB_REGISTER_COUNT);
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index 82e65c78..ff5f4735 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -474,12 +474,6 @@ int armv4_5_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list
armv4_5_common_t *armv4_5 = target->arch_info;
int i;
- if (target->state != TARGET_HALTED)
- {
- ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
*reg_list_size = 26;
*reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
diff --git a/src/target/armv7m.c b/src/target/armv7m.c
index 6ee5903a..f1f0ac96 100644
--- a/src/target/armv7m.c
+++ b/src/target/armv7m.c
@@ -321,12 +321,6 @@ int armv7m_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_
armv7m_common_t *armv7m = target->arch_info;
int i;
- if (target->state != TARGET_HALTED)
- {
- ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
*reg_list_size = 26;
*reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
diff --git a/src/target/target.h b/src/target/target.h
index 8d70e77e..e0286650 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -127,7 +127,15 @@ typedef struct target_type_s
int (*soft_reset_halt)(struct target_s *target);
int (*prepare_reset_halt)(struct target_s *target);
- /* target register access for gdb */
+ /* target register access for gdb.
+ *
+ * Danger! this function will succeed even if the target is running
+ * and return a register list with dummy values.
+ *
+ * The reason is that GDB connection will fail without a valid register
+ * list, however it is after GDB is connected that monitor commands can
+ * be run to properly initialize the target
+ */
int (*get_gdb_reg_list)(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size);
/* target memory access