]> git.sur5r.net Git - openocd/blobdiff - src/jtag/drivers/ftdi.c
Remove FSF address from GPL notices
[openocd] / src / jtag / drivers / ftdi.c
index 292a44107417075a74c646a231c88cb00e9bb96a..8f47468b7e2d1f815b3f5336d71861629f68ffad 100644 (file)
@@ -13,9 +13,7 @@
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
-*   along with this program; if not, write to the                         *
-*   Free Software Foundation, Inc.,                                       *
-*   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+*   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/
 
 /**
 #include "mpsse.h"
 
 #define JTAG_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
+#define JTAG_MODE_ALT (LSB_FIRST | NEG_EDGE_IN | NEG_EDGE_OUT)
 #define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
 
 static char *ftdi_device_desc;
 static char *ftdi_serial;
+static char *ftdi_location;
 static uint8_t ftdi_channel;
+static uint8_t ftdi_jtag_mode = JTAG_MODE;
 
 static bool swd_mode;
 
@@ -127,10 +128,8 @@ static uint16_t output;
 static uint16_t direction;
 static uint16_t jtag_output_init;
 static uint16_t jtag_direction_init;
-static uint16_t swd_output_init;
-static uint16_t swd_direction_init;
 
-static int ftdi_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
+static int ftdi_swd_switch_seq(enum swd_special_seq seq);
 
 static struct signal *find_signal_by_name(const char *name)
 {
@@ -246,7 +245,7 @@ static void move_to_state(tap_state_t goal_state)
                0,
                tms_count,
                false,
-               JTAG_MODE);
+               ftdi_jtag_mode);
 }
 
 static int ftdi_speed(int speed)
@@ -259,6 +258,9 @@ static int ftdi_speed(int speed)
                return retval;
        }
 
+       if (!swd_mode && speed >= 10000000 && ftdi_jtag_mode != JTAG_MODE_ALT)
+               LOG_INFO("ftdi: if you experience problems at higher adapter clocks, try "
+                        "the command \"ftdi_tdo_sample_edge falling\"");
        return ERROR_OK;
 }
 
@@ -306,7 +308,7 @@ static void ftdi_execute_runtest(struct jtag_command *cmd)
        while (i > 0) {
                /* there are no state transitions in this code, so omit state tracking */
                unsigned this_len = i > 7 ? 7 : i;
-               mpsse_clock_tms_cs_out(mpsse_ctx, &zero, 0, this_len, false, JTAG_MODE);
+               mpsse_clock_tms_cs_out(mpsse_ctx, &zero, 0, this_len, false, ftdi_jtag_mode);
                i -= this_len;
        }
 
@@ -346,7 +348,7 @@ static void ftdi_execute_tms(struct jtag_command *cmd)
                0,
                cmd->cmd.tms->num_bits,
                false,
-               JTAG_MODE);
+               ftdi_jtag_mode);
 }
 
 static void ftdi_execute_pathmove(struct jtag_command *cmd)
@@ -393,7 +395,7 @@ static void ftdi_execute_pathmove(struct jtag_command *cmd)
                                        0,
                                        bit_count,
                                        false,
-                                       JTAG_MODE);
+                                       ftdi_jtag_mode);
                        bit_count = 0;
                }
        }
@@ -448,7 +450,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                field->in_value,
                                0,
                                field->num_bits - 1,
-                               JTAG_MODE);
+                               ftdi_jtag_mode);
                        uint8_t last_bit = 0;
                        if (field->out_value)
                                bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1);
@@ -460,14 +462,14 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                        field->num_bits - 1,
                                        1,
                                        last_bit,
-                                       JTAG_MODE);
+                                       ftdi_jtag_mode);
                        tap_set_state(tap_state_transition(tap_get_state(), 1));
                        mpsse_clock_tms_cs_out(mpsse_ctx,
                                        &tms_bits,
                                        1,
                                        1,
                                        last_bit,
-                                       JTAG_MODE);
+                                       ftdi_jtag_mode);
                        tap_set_state(tap_state_transition(tap_get_state(), 0));
                } else
                        mpsse_clock_data(mpsse_ctx,
@@ -476,7 +478,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
                                field->in_value,
                                0,
                                field->num_bits,
-                               JTAG_MODE);
+                               ftdi_jtag_mode);
        }
 
        if (tap_get_state() != tap_get_end_state())
@@ -503,7 +505,8 @@ static void ftdi_execute_reset(struct jtag_command *cmd)
                        ftdi_set_signal(trst, '0');
                else
                        LOG_ERROR("Can't assert TRST: nTRST signal is not defined");
-       } else if (trst && cmd->cmd.reset->trst == 0) {
+       } else if (trst && jtag_get_reset_config() & RESET_HAS_TRST &&
+                       cmd->cmd.reset->trst == 0) {
                if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
                        ftdi_set_signal(trst, 'z');
                else
@@ -516,7 +519,8 @@ static void ftdi_execute_reset(struct jtag_command *cmd)
                        ftdi_set_signal(srst, '0');
                else
                        LOG_ERROR("Can't assert SRST: nSRST signal is not defined");
-       } else if (srst && cmd->cmd.reset->srst == 0) {
+       } else if (srst && jtag_get_reset_config() & RESET_HAS_SRST &&
+                       cmd->cmd.reset->srst == 0) {
                if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
                        ftdi_set_signal(srst, '1');
                else
@@ -553,7 +557,7 @@ static void ftdi_execute_stableclocks(struct jtag_command *cmd)
        while (num_cycles > 0) {
                /* there are no state transitions in this code, so omit state tracking */
                unsigned this_len = num_cycles > 7 ? 7 : num_cycles;
-               mpsse_clock_tms_cs_out(mpsse_ctx, &tms, 0, this_len, false, JTAG_MODE);
+               mpsse_clock_tms_cs_out(mpsse_ctx, &tms, 0, this_len, false, ftdi_jtag_mode);
                num_cycles -= this_len;
        }
 
@@ -626,7 +630,7 @@ static int ftdi_initialize(void)
 
        for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) {
                mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc,
-                               ftdi_serial, ftdi_channel);
+                               ftdi_serial, ftdi_location, ftdi_channel);
                if (mpsse_ctx)
                        break;
        }
@@ -634,21 +638,26 @@ static int ftdi_initialize(void)
        if (!mpsse_ctx)
                return ERROR_JTAG_INIT_FAILED;
 
-       output = swd_mode ? swd_output_init : jtag_output_init;
-       direction = swd_mode ? swd_direction_init : jtag_direction_init;
+       output = jtag_output_init;
+       direction = jtag_direction_init;
+
+       if (swd_mode) {
+               struct signal *sig = find_signal_by_name("SWD_EN");
+               if (!sig) {
+                       LOG_ERROR("SWD mode is active but SWD_EN signal is not defined");
+                       return ERROR_JTAG_INIT_FAILED;
+               }
+               /* A dummy SWD_EN would have zero mask */
+               if (sig->data_mask)
+                       ftdi_set_signal(sig, '1');
+       }
 
        mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff);
        mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8);
 
        mpsse_loopback_config(mpsse_ctx, false);
 
-       /* Set a low default */
-       freq = mpsse_set_frequency(mpsse_ctx, 1000);
-
-       if (swd_mode)
-               ftdi_swd_switch_seq(NULL, JTAG_TO_SWD);
-       else
-               ftdi_swd_switch_seq(NULL, SWD_TO_JTAG);
+       freq = mpsse_set_frequency(mpsse_ctx, jtag_get_speed_khz() * 1000);
 
        return mpsse_flush(mpsse_ctx);
 }
@@ -657,6 +666,8 @@ static int ftdi_quit(void)
 {
        mpsse_close(mpsse_ctx);
 
+       free(swd_cmd_queue);
+
        return ERROR_OK;
 }
 
@@ -686,6 +697,21 @@ COMMAND_HANDLER(ftdi_handle_serial_command)
        return ERROR_OK;
 }
 
+#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
+COMMAND_HANDLER(ftdi_handle_location_command)
+{
+       if (CMD_ARGC == 1) {
+               if (ftdi_location)
+                       free(ftdi_location);
+               ftdi_location = strdup(CMD_ARGV[0]);
+       } else {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       return ERROR_OK;
+}
+#endif
+
 COMMAND_HANDLER(ftdi_handle_channel_command)
 {
        if (CMD_ARGC == 1)
@@ -707,17 +733,6 @@ COMMAND_HANDLER(ftdi_handle_layout_init_command)
        return ERROR_OK;
 }
 
-COMMAND_HANDLER(ftdi_handle_layout_init_swd_command)
-{
-       if (CMD_ARGC != 2)
-               return ERROR_COMMAND_SYNTAX_ERROR;
-
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], swd_output_init);
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], swd_direction_init);
-
-       return ERROR_OK;
-}
-
 COMMAND_HANDLER(ftdi_handle_layout_signal_command)
 {
        if (CMD_ARGC < 1)
@@ -836,6 +851,29 @@ COMMAND_HANDLER(ftdi_handle_vid_pid_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command)
+{
+       Jim_Nvp *n;
+       static const Jim_Nvp nvp_ftdi_jtag_modes[] = {
+               { .name = "rising", .value = JTAG_MODE },
+               { .name = "falling", .value = JTAG_MODE_ALT },
+               { .name = NULL, .value = -1 },
+       };
+
+       if (CMD_ARGC > 0) {
+               n = Jim_Nvp_name2value_simple(nvp_ftdi_jtag_modes, CMD_ARGV[0]);
+               if (n->name == NULL)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               ftdi_jtag_mode = n->value;
+
+       }
+
+       n = Jim_Nvp_value2name_simple(nvp_ftdi_jtag_modes, ftdi_jtag_mode);
+       command_print(CMD_CTX, "ftdi samples TDO on %s edge of TCK", n->name);
+
+       return ERROR_OK;
+}
+
 static const struct command_registration ftdi_command_handlers[] = {
        {
                .name = "ftdi_device_desc",
@@ -851,6 +889,15 @@ static const struct command_registration ftdi_command_handlers[] = {
                .help = "set the serial number of the FTDI device",
                .usage = "serial_string",
        },
+#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
+       {
+               .name = "ftdi_location",
+               .handler = &ftdi_handle_location_command,
+               .mode = COMMAND_CONFIG,
+               .help = "set the USB bus location of the FTDI device",
+               .usage = "<bus>:port[,port]...",
+       },
+#endif
        {
                .name = "ftdi_channel",
                .handler = &ftdi_handle_channel_command,
@@ -863,17 +910,7 @@ static const struct command_registration ftdi_command_handlers[] = {
                .handler = &ftdi_handle_layout_init_command,
                .mode = COMMAND_CONFIG,
                .help = "initialize the FTDI GPIO signals used "
-                       "to control output-enables and reset signals"
-                       "when JTAG mode is selected",
-               .usage = "data direction",
-       },
-       {
-               .name = "ftdi_layout_init_swd",
-               .handler = &ftdi_handle_layout_init_swd_command,
-               .mode = COMMAND_CONFIG,
-               .help = "initialize the FTDI GPIO signals used "
-                       "to control output-enables and reset signals"
-                       "when SWD mode is selected",
+                       "to control output-enables and reset signals",
                .usage = "data direction",
        },
        {
@@ -898,6 +935,15 @@ static const struct command_registration ftdi_command_handlers[] = {
                .help = "the vendor ID and product ID of the FTDI device",
                .usage = "(vid pid)* ",
        },
+       {
+               .name = "ftdi_tdo_sample_edge",
+               .handler = &ftdi_handle_tdo_sample_edge_command,
+               .mode = COMMAND_ANY,
+               .help = "set which TCK clock edge is used for sampling TDO "
+                       "- default is rising-edge (Setting to falling-edge may "
+                       "allow signalling speed increase)",
+               .usage = "(rising|falling)",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -955,7 +1001,7 @@ static void ftdi_swd_swdio_en(bool enable)
  * @param dap
  * @return
  */
-static int ftdi_swd_run_queue(struct adiv5_dap *dap)
+static int ftdi_swd_run_queue(void)
 {
        LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length);
        int retval;
@@ -981,7 +1027,7 @@ static int ftdi_swd_run_queue(struct adiv5_dap *dap)
        }
 
        for (size_t i = 0; i < swd_cmd_queue_length; i++) {
-               int ack = buf_get_u32(&swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3);
+               int ack = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3);
 
                LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
                                ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
@@ -992,7 +1038,7 @@ static int ftdi_swd_run_queue(struct adiv5_dap *dap)
                                                1 + 3 + (swd_cmd_queue[i].cmd & SWD_CMD_RnW ? 0 : 1), 32));
 
                if (ack != SWD_ACK_OK) {
-                       queued_retval = ack;
+                       queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
                        goto skip;
 
                } else if (swd_cmd_queue[i].cmd & SWD_CMD_RnW) {
@@ -1022,13 +1068,13 @@ skip:
        return retval;
 }
 
-static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
+static void ftdi_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk)
 {
        if (swd_cmd_queue_length >= swd_cmd_queue_alloced) {
                /* Not enough room in the queue. Run the queue and increase its size for next time.
                 * Note that it's not possible to avoid running the queue here, because mpsse contains
                 * pointers into the queue which may be invalid after the realloc. */
-               queued_retval = ftdi_swd_run_queue(dap);
+               queued_retval = ftdi_swd_run_queue();
                struct swd_cmd_queue_entry *q = realloc(swd_cmd_queue, swd_cmd_queue_alloced * 2 * sizeof(*swd_cmd_queue));
                if (q != NULL) {
                        swd_cmd_queue = q;
@@ -1071,23 +1117,23 @@ static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst
 
        /* Insert idle cycles after AP accesses to avoid WAIT */
        if (cmd & SWD_CMD_APnDP)
-               mpsse_clock_data_out(mpsse_ctx, NULL, 0, dap->memaccess_tck, SWD_MODE);
+               mpsse_clock_data_out(mpsse_ctx, NULL, 0, ap_delay_clk, SWD_MODE);
 
 }
 
-static void ftdi_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
+static void ftdi_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
 {
        assert(cmd & SWD_CMD_RnW);
-       ftdi_swd_queue_cmd(dap, cmd, value, 0);
+       ftdi_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
 }
 
-static void ftdi_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
+static void ftdi_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
 {
        assert(!(cmd & SWD_CMD_RnW));
-       ftdi_swd_queue_cmd(dap, cmd, NULL, value);
+       ftdi_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
 }
 
-static int_least32_t ftdi_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
+static int_least32_t ftdi_swd_frequency(int_least32_t hz)
 {
        if (hz > 0)
                freq = mpsse_set_frequency(mpsse_ctx, hz);
@@ -1095,7 +1141,7 @@ static int_least32_t ftdi_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
        return freq;
 }
 
-static int ftdi_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
+static int ftdi_swd_switch_seq(enum swd_special_seq seq)
 {
        switch (seq) {
        case LINE_RESET: