interface: define TMS sequence command
authorDavid Brownell <dbrownell@users.sourceforge.net>
Sat, 27 Feb 2010 08:12:38 +0000 (00:12 -0800)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Sat, 27 Feb 2010 08:12:38 +0000 (00:12 -0800)
For support of SWD we need to be able to clock out special bit
sequences over TMS or SWDIO.  Create this as a generic operation,
not yet called by anything, which is split as usual into:

 - upper level abstraction ... here, jtag_add_tms_seq();
 - midlayer implementation logic hooking that to the lowlevel code;
 - lowlevel minidriver operation ... here, interface_add_tms_seq();
 - message type for request queue, here JTAG_TMS.

This is done slightly differently than other operations: there's a flag
saying whether the interface driver supports this request.  (In fact a
flag *word* so upper layers can learn about other capabilities too ...
for example, supporting SWD operations.)

That approach (flag) lets this method *eventually* be used to eliminate
pathmove() and statemove() support from most adapter drivers, by moving
all that logic into the mid-layer and increasing uniformity between the
various drivers.  (Which will in turn reduce subtle bugginess.)

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
src/jtag/commands.h
src/jtag/core.c
src/jtag/drivers/driver.c
src/jtag/interface.h
src/jtag/jtag.h
src/jtag/minidriver.h
src/jtag/minidummy/minidummy.c
src/jtag/zy1000/zy1000.c

index b10b545369e28643345fbc8bd7dfef4d44959258..692eee430fbf8c101a99f35ecc8f425ec9aba847 100644 (file)
@@ -98,19 +98,39 @@ struct sleep_command {
        uint32_t us;
 };
 
+/**
+ * Encapsulates a series of bits to be clocked out, affecting state
+ * and mode of the interface.
+ *
+ * In JTAG mode these are clocked out on TMS, using TCK.  They may be
+ * used for link resets, transitioning between JTAG and SWD modes, or
+ * to implement JTAG state machine transitions (implementing pathmove
+ * or statemove operations).
+ *
+ * In SWD mode these are clocked out on SWDIO, using SWCLK, and are
+ * used for link resets and transitioning between SWD and JTAG modes.
+ */
+struct tms_command {
+       /** How many bits should be clocked out. */
+       unsigned        num_bits;
+       /** The bits to clock out; the LSB is bit 0 of bits[0].  */
+       const uint8_t           *bits;
+};
+
 /**
  * Defines a container type that hold a pointer to a JTAG command
  * structure of any defined type.
  */
 union jtag_command_container {
-       struct scan_command*         scan;
-       struct statemove_command*    statemove;
-       struct pathmove_command*     pathmove;
-       struct runtest_command*      runtest;
-       struct stableclocks_command* stableclocks;
-       struct reset_command*        reset;
-       struct end_state_command*    end_state;
-       struct sleep_command* sleep;
+       struct scan_command             *scan;
+       struct statemove_command        *statemove;
+       struct pathmove_command         *pathmove;
+       struct runtest_command          *runtest;
+       struct stableclocks_command     *stableclocks;
+       struct reset_command            *reset;
+       struct end_state_command        *end_state;
+       struct sleep_command            *sleep;
+       struct tms_command              *tms;
 };
 
 /**
@@ -124,7 +144,8 @@ enum jtag_command_type {
        JTAG_RESET        = 4,
        JTAG_PATHMOVE     = 6,
        JTAG_SLEEP        = 7,
-       JTAG_STABLECLOCKS = 8
+       JTAG_STABLECLOCKS = 8,
+       JTAG_TMS          = 9,
 };
 
 struct jtag_command {
index 4f517c098e0e354659b150ad1e7dce1f327a7ef8..7f417b737ce4cc7a0c101c7f7d6b4ddb2f61e705 100644 (file)
@@ -488,6 +488,35 @@ void jtag_add_tlr(void)
        jtag_notify_event(JTAG_TRST_ASSERTED);
 }
 
+/**
+ * If supported by the underlying adapter, this clocks a raw bit sequence
+ * onto TMS for switching betwen JTAG and SWD modes.
+ *
+ * DO NOT use this to bypass the integrity checks and logging provided
+ * by the jtag_add_pathmove() and jtag_add_statemove() calls.
+ *
+ * @param nbits How many bits to clock out.
+ * @param seq The bit sequence.  The LSB is bit 0 of seq[0].
+ * @param state The JTAG tap state to record on completion.  Use
+ *     TAP_INVALID to represent being in in SWD mode.
+ *
+ * @todo Update naming conventions to stop assuming everything is JTAG.
+ */
+int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state)
+{
+       int retval;
+
+       if (!(jtag->supported & DEBUG_CAP_TMS_SEQ))
+               return ERROR_JTAG_NOT_IMPLEMENTED;
+
+       jtag_checks();
+       cmd_queue_cur_state = state;
+
+       retval = interface_add_tms_seq(nbits, seq);
+       jtag_set_error(retval);
+       return retval;
+}
+
 void jtag_add_pathmove(int num_states, const tap_state_t *path)
 {
        tap_state_t cur_state = cmd_queue_cur_state;
index 45c5d10afa8b4730cf78f83d8513620139b64f26..14efe965e7aad3037b12ac2a88b3809dcf0d4d06 100644 (file)
@@ -388,6 +388,31 @@ int interface_jtag_add_tlr(void)
        return ERROR_OK;
 }
 
+int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq)
+{
+       struct jtag_command *cmd;
+
+       cmd = cmd_queue_alloc(sizeof(struct jtag_command));
+       if (cmd == NULL)
+               return ERROR_FAIL;
+
+       cmd->type = JTAG_TMS;
+       cmd->cmd.tms = cmd_queue_alloc(sizeof(*cmd->cmd.tms));
+       if (!cmd->cmd.tms)
+               return ERROR_FAIL;
+
+       /* copy the bits; our caller doesn't guarantee they'll persist */
+       cmd->cmd.tms->num_bits = num_bits;
+       cmd->cmd.tms->bits = buf_cpy(seq,
+                       cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits);
+       if (!cmd->cmd.tms->bits)
+               return ERROR_FAIL;
+
+       jtag_queue_command(cmd);
+
+       return ERROR_OK;
+}
+
 int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
 {
        /* allocate memory for a new list member */
index a264d69f274ba61c61fdad96ec2471952421b24a..0d474049e4860f1f22dc3c2230f431bb91460e71 100644 (file)
@@ -184,10 +184,28 @@ static inline tap_state_t jtag_debug_state_machine(const void *tms_buf,
 }
 #endif // _DEBUG_JTAG_IO_
 
+/**
+ * Represents a driver for a debugging interface.
+ *
+ * @todo Rename; perhaps "debug_driver".  This isn't an interface,
+ * it's a driver!  Also, not all drivers support JTAG.
+ *
+ * @todo We need a per-instance structure too, and changes to pass
+ * that structure to the driver.  Instances can for example be in
+ * either SWD or JTAG modes.  This will help remove globals, and
+ * eventually to cope with systems which have more than one such
+ * debugging interface.
+ */
 struct jtag_interface {
        /// The name of the JTAG interface driver.
        char* name;
 
+       /**
+        * Bit vector listing capabilities exposed by this driver.
+        */
+       unsigned supported;
+#define DEBUG_CAP_TMS_SEQ      (1 << 0)
+
        /**
         * Execute queued commands.
         * @returns ERROR_OK on success, or an error code on failure.
index 055575407a273c4a8581c49900143a5ae0a5e347..7e5dc102b794cb2d48f3549f1f5c44b616bbc4df 100644 (file)
@@ -575,6 +575,8 @@ tap_state_t jtag_get_end_state(void);
 
 void jtag_add_sleep(uint32_t us);
 
+int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state t);
+
 /**
  * Function jtag_add_clocks
  * first checks that the state in which the clocks are to be issued is
@@ -693,7 +695,7 @@ int jtag_error_clear(void);
 /**
  * Return true if it's safe for a background polling task to access the
  * JTAG scan chain.  Polling may be explicitly disallowed, and is also
- * unsafe while nTRST is active or the JTAG clock is gated off.,
+ * unsafe while nTRST is active or the JTAG clock is gated off.
  */
 bool is_jtag_poll_safe(void);
 
index 2109c75f69ff4deee0ef87982d99687765ecb2af..5caec58b137112cf21e1c9e9d35c74b5ee5a9f5b 100644 (file)
@@ -67,6 +67,8 @@ int interface_jtag_add_tlr(void);
 int interface_jtag_add_pathmove(int num_states, const tap_state_t* path);
 int interface_jtag_add_runtest(int num_cycles, tap_state_t endstate);
 
+int interface_add_tms_seq(unsigned num_bits, const uint8_t *bits);
+
 /**
  * This drives the actual srst and trst pins. srst will always be 0
  * if jtag_reset_config & RESET_SRST_PULLS_TRST != 0 and ditto for
index 9c608cdbb460af9a292ac25b8eb39ef8035c6038..6410c2d2beafad132fc70e413c5f1a0e1d3e1d63 100644 (file)
@@ -147,6 +147,13 @@ int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
        return ERROR_OK;
 }
 
+int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq)
+{
+       /* synchronously do the operation here */
+
+       return ERROR_OK;
+}
+
 void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, uint8_t *buffer, int little, int count)
 {
        int i;
index d920c30b29ca95aee3d7cecd917dd7cb1deef6a3..e21104c7f45c1a8fdd2d679f51e3283f39bf892f 100644 (file)
@@ -804,7 +804,16 @@ int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
        return ERROR_OK;
 }
 
-
+int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq)
+{
+       /* FIXME just implement this, like pathmove but without
+        * JTAG-specific state transition checking.  Then update
+        * zy1000_interface to report that it's supported.
+        *
+        * Eventually interface_jtag_add_pathmove() could vanish.
+        */
+       return ERROR_JTAG_NOT_IMPLEMENTED;
+}
 
 void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, uint8_t *buffer, int little, int count)
 {