X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fftdi.c;h=e7f3c3dcea292bbc1eaf7464ecb38cbe43af5d93;hp=3f74f1cae202c7c8bbb5e9b7fc3bdb017f489274;hb=4db695c66c9240232a0c7a4af494657ea0e18da5;hpb=414e4eb40e9a5decfaa2a5aef9ceac9768b7740b
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index 3f74f1cae2..e7f3c3dcea 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -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 . *
***************************************************************************/
/**
@@ -55,11 +53,11 @@
*
* This code uses information contained in the MPSSE specification which was
* found here:
- * http://www.ftdichip.com/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf
+ * https://www.ftdichip.com/Support/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf
* Hereafter this is called the "MPSSE Spec".
*
- * The datasheet for the ftdichip.com's FT2232D part is here:
- * http://www.ftdichip.com/Documents/DataSheets/DS_FT2232D.pdf
+ * The datasheet for the ftdichip.com's FT2232H part is here:
+ * https://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT2232H.pdf
*
* Also note the issue with code 0x4b (clock data to TMS) noted in
* http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html
@@ -71,6 +69,7 @@
#endif
/* project specific includes */
+#include
#include
#include
#include
@@ -91,7 +90,6 @@
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;
@@ -107,8 +105,10 @@ static struct mpsse_ctx *mpsse_ctx;
struct signal {
const char *name;
uint16_t data_mask;
+ uint16_t input_mask;
uint16_t oe_mask;
bool invert_data;
+ bool invert_input;
bool invert_oe;
struct signal *next;
};
@@ -213,6 +213,32 @@ static int ftdi_set_signal(const struct signal *s, char value)
return ERROR_OK;
}
+static int ftdi_get_signal(const struct signal *s, uint16_t * value_out)
+{
+ uint8_t data_low = 0;
+ uint8_t data_high = 0;
+
+ if (s->input_mask == 0) {
+ LOG_ERROR("interface doesn't provide signal '%s'", s->name);
+ return ERROR_FAIL;
+ }
+
+ if (s->input_mask & 0xff)
+ mpsse_read_data_bits_low_byte(mpsse_ctx, &data_low);
+ if (s->input_mask >> 8)
+ mpsse_read_data_bits_high_byte(mpsse_ctx, &data_high);
+
+ mpsse_flush(mpsse_ctx);
+
+ *value_out = (((uint16_t)data_high) << 8) | data_low;
+
+ if (s->invert_input)
+ *value_out = ~(*value_out);
+
+ *value_out &= s->input_mask;
+
+ return ERROR_OK;
+}
/**
* Function move_to_state
@@ -413,11 +439,11 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
while (cmd->cmd.scan->num_fields > 0
&& cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) {
cmd->cmd.scan->num_fields--;
- LOG_DEBUG("discarding trailing empty field");
+ DEBUG_JTAG_IO("discarding trailing empty field");
}
if (cmd->cmd.scan->num_fields == 0) {
- LOG_DEBUG("empty scan, doing nothing");
+ DEBUG_JTAG_IO("empty scan, doing nothing");
return;
}
@@ -632,7 +658,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_location, ftdi_channel);
+ ftdi_serial, jtag_usb_get_location(), ftdi_channel);
if (mpsse_ctx)
break;
}
@@ -668,6 +694,17 @@ static int ftdi_quit(void)
{
mpsse_close(mpsse_ctx);
+ struct signal *sig = signals;
+ while (sig) {
+ struct signal *next = sig->next;
+ free((void *)sig->name);
+ free(sig);
+ sig = next;
+ }
+
+ free(ftdi_device_desc);
+ free(ftdi_serial);
+
free(swd_cmd_queue);
return ERROR_OK;
@@ -699,21 +736,6 @@ 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)
@@ -742,6 +764,8 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
bool invert_data = false;
uint16_t data_mask = 0;
+ bool invert_input = false;
+ uint16_t input_mask = 0;
bool invert_oe = false;
uint16_t oe_mask = 0;
for (unsigned i = 1; i < CMD_ARGC; i += 2) {
@@ -751,6 +775,12 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
} else if (strcmp("-ndata", CMD_ARGV[i]) == 0) {
invert_data = true;
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], data_mask);
+ } else if (strcmp("-input", CMD_ARGV[i]) == 0) {
+ invert_input = false;
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], input_mask);
+ } else if (strcmp("-ninput", CMD_ARGV[i]) == 0) {
+ invert_input = true;
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], input_mask);
} else if (strcmp("-oe", CMD_ARGV[i]) == 0) {
invert_oe = false;
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask);
@@ -759,15 +789,19 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask);
} else if (!strcmp("-alias", CMD_ARGV[i]) ||
!strcmp("-nalias", CMD_ARGV[i])) {
- if (!strcmp("-nalias", CMD_ARGV[i]))
+ if (!strcmp("-nalias", CMD_ARGV[i])) {
invert_data = true;
+ invert_input = true;
+ }
struct signal *sig = find_signal_by_name(CMD_ARGV[i + 1]);
if (!sig) {
LOG_ERROR("signal %s is not defined", CMD_ARGV[i + 1]);
return ERROR_FAIL;
}
data_mask = sig->data_mask;
+ input_mask = sig->input_mask;
oe_mask = sig->oe_mask;
+ invert_input ^= sig->invert_input;
invert_oe = sig->invert_oe;
invert_data ^= sig->invert_data;
} else {
@@ -787,6 +821,8 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
sig->invert_data = invert_data;
sig->data_mask = data_mask;
+ sig->invert_input = invert_input;
+ sig->input_mask = input_mask;
sig->invert_oe = invert_oe;
sig->oe_mask = oe_mask;
@@ -815,6 +851,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;
@@ -823,6 +860,28 @@ COMMAND_HANDLER(ftdi_handle_set_signal_command)
return mpsse_flush(mpsse_ctx);
}
+COMMAND_HANDLER(ftdi_handle_get_signal_command)
+{
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct signal *sig;
+ uint16_t sig_data = 0;
+ sig = find_signal_by_name(CMD_ARGV[0]);
+ if (!sig) {
+ LOG_ERROR("interface configuration doesn't define signal '%s'", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ int ret = ftdi_get_signal(sig, &sig_data);
+ if (ret != ERROR_OK)
+ return ret;
+
+ LOG_USER("Signal %s = %#06x", sig->name, sig_data);
+
+ return ERROR_OK;
+}
+
COMMAND_HANDLER(ftdi_handle_vid_pid_command)
{
if (CMD_ARGC > MAX_USB_IDS * 2) {
@@ -891,15 +950,6 @@ 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 = ":port[,port]...",
- },
-#endif
{
.name = "ftdi_channel",
.handler = &ftdi_handle_channel_command,
@@ -930,6 +980,13 @@ static const struct command_registration ftdi_command_handlers[] = {
.help = "control a layout-specific signal",
.usage = "name (1|0|z)",
},
+ {
+ .name = "ftdi_get_signal",
+ .handler = &ftdi_handle_get_signal_command,
+ .mode = COMMAND_EXEC,
+ .help = "read the value of a layout-specific signal",
+ .usage = "name",
+ },
{
.name = "ftdi_vid_pid",
.handler = &ftdi_handle_vid_pid_command,
@@ -994,8 +1051,19 @@ static int ftdi_swd_init(void)
static void ftdi_swd_swdio_en(bool enable)
{
struct signal *oe = find_signal_by_name("SWDIO_OE");
- if (oe)
- ftdi_set_signal(oe, enable ? '1' : '0');
+ if (oe) {
+ if (oe->data_mask)
+ ftdi_set_signal(oe, enable ? '1' : '0');
+ else {
+ /* Sets TDI/DO pin to input during rx when both pins are connected
+ to SWDIO */
+ if (enable)
+ direction |= jtag_direction_init & 0x0002U;
+ else
+ direction &= ~0x0002U;
+ mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff);
+ }
+ }
}
/**
@@ -1005,12 +1073,12 @@ static void ftdi_swd_swdio_en(bool enable)
*/
static int ftdi_swd_run_queue(void)
{
- LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length);
+ LOG_DEBUG_IO("Executing %zu queued transactions", swd_cmd_queue_length);
int retval;
struct signal *led = find_signal_by_name("LED");
if (queued_retval != ERROR_OK) {
- LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
+ LOG_DEBUG_IO("Skipping due to previous errors: %d", queued_retval);
goto skip;
}
@@ -1031,7 +1099,7 @@ static int ftdi_swd_run_queue(void)
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);
- LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
+ LOG_DEBUG_IO("%s %s %s reg %X = %08"PRIx32,
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
swd_cmd_queue[i].cmd & SWD_CMD_APnDP ? "AP" : "DP",
swd_cmd_queue[i].cmd & SWD_CMD_RnW ? "read" : "write",
@@ -1148,14 +1216,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: