diff --git a/doc/openocd.texi b/doc/openocd.texi index e7d0c67c5..6ad19e1e8 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2578,10 +2578,11 @@ For example adapter definitions, see the configuration files shipped in the @end deffn @deffn {Interface Driver} {ft232r} -This driver is implementing synchronous bitbang mode of an FTDI FT232R -USB UART bridge IC. +This driver is implementing synchronous bitbang mode of an FTDI FT232R, +FT230X, FT231X and similar USB UART bridge ICs by reusing RS232 signals as GPIO. +It currently doesn't support using CBUS pins as GPIO. -List of connections (pin numbers for SSOP): +List of connections (default physical pin numbers for FT232R in 28-pin SSOP package): @itemize @minus @item RXD(5) - TDI @item TXD(1) - TCK @@ -2591,6 +2592,27 @@ List of connections (pin numbers for SSOP): @item DCD(10) - SRST @end itemize +User can change default pinout by supplying configuration +commands with GPIO numbers or RS232 signal names. +GPIO numbers correspond to bit numbers in FTDI GPIO register. +They differ from physical pin numbers. +For details see actual FTDI chip datasheets. +Every JTAG line must be configured to unique GPIO number +different than any other JTAG line, even those lines +that are sometimes not used like TRST or SRST. + +FT232R +@itemize @minus +@item bit 7 - RI +@item bit 6 - DCD +@item bit 5 - DSR +@item bit 4 - DTR +@item bit 3 - CTS +@item bit 2 - RTS +@item bit 1 - RXD +@item bit 0 - TXD +@end itemize + These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @@ -2605,6 +2627,47 @@ vendor provides unique IDs and more than one adapter is connected to the host. If not specified, serial numbers are not considered. @end deffn +@deffn {Config Command} {ft232r_jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo} +Set four JTAG GPIO numbers at once. +If not specified, default 0 3 1 2 or TXD CTS RXD RTS is used. +@end deffn + +@deffn {Config Command} {ft232r_tck_num} @var{tck} +Set TCK GPIO number. If not specified, default 0 or TXD is used. +@end deffn + +@deffn {Config Command} {ft232r_tms_num} @var{tms} +Set TMS GPIO number. If not specified, default 3 or CTS is used. +@end deffn + +@deffn {Config Command} {ft232r_tdi_num} @var{tdi} +Set TDI GPIO number. If not specified, default 1 or RXD is used. +@end deffn + +@deffn {Config Command} {ft232r_tdo_num} @var{tdo} +Set TDO GPIO number. If not specified, default 2 or RTS is used. +@end deffn + +@deffn {Config Command} {ft232r_trst_num} @var{trst} +Set TRST GPIO number. If not specified, default 4 or DTR is used. +@end deffn + +@deffn {Config Command} {ft232r_srst_num} @var{srst} +Set SRST GPIO number. If not specified, default 6 or DCD is used. +@end deffn + +@deffn {Config Command} {ft232r_restore_serial} @var{word} +Restore serial port after JTAG. This USB bitmode control word +(16-bit) will be sent before quit. Lower byte should +set GPIO direction register to a "sane" state: +0x15 for TXD RTS DTR as outputs (1), others as inputs (0). Higher +byte is usually 0 to disable bitbang mode. +When kernel driver reattaches, serial port should continue to work. +Value 0xFFFF disables sending control word and serial port, +then kernel driver will not reattach. +If not specified, default 0xFFFF is used. +@end deffn + @end deffn @deffn {Interface Driver} {remote_bitbang} diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index fc3d75f43..e16bcdcbf 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -39,24 +39,9 @@ #include /* - * Bit 7 (0x80, pin 6, RI ): unused. - * Bit 6 (0x40, pin 10,DCD): /SYSRST output. - * Bit 5 (0x20, pin 9, DSR): unused. - * Bit 4 (0x10, pin 2, DTR): /TRST output. - * Bit 3 (0x08, pin 11,CTS): TMS output. - * Bit 2 (0x04, pin 3, RTS): TDO input. - * Bit 1 (0x02, pin 5, RXD): TDI output. - * Bit 0 (0x01, pin 1, TXD): TCK output. - * * Sync bit bang mode is implemented as described in FTDI Application * Note AN232R-01: "Bit Bang Modes for the FT232R and FT245R". */ -#define TCK (1 << 0) -#define TDI (1 << 1) -#define READ_TDO (1 << 2) -#define TMS (1 << 3) -#define NTRST (1 << 4) -#define NSYSRST (1 << 6) /* * USB endpoints. @@ -81,7 +66,7 @@ #define SIO_WRITE_EEPROM 0x91 #define SIO_ERASE_EEPROM 0x92 -#define FT232R_BUF_SIZE 4000 +#define FT232R_BUF_SIZE_EXTRA 4096 static char *ft232r_serial_desc; static uint16_t ft232r_vid = 0x0403; /* FTDI */ @@ -91,6 +76,33 @@ static jtag_libusb_device_handle *adapter; static uint8_t *ft232r_output; static size_t ft232r_output_len; +/** + * FT232R GPIO bit number to RS232 name + */ +#define FT232R_BIT_COUNT 8 +static char *ft232r_bit_name_array[FT232R_BIT_COUNT] = { + "TXD", /* 0: pin 1 TCK output */ + "RXD", /* 1: pin 5 TDI output */ + "RTS", /* 2: pin 3 TDO input */ + "CTS", /* 3: pin 11 TMS output */ + "DTR", /* 4: pin 2 /TRST output */ + "DSR", /* 5: pin 9 unused */ + "DCD", /* 6: pin 10 /SYSRST output */ + "RI" /* 7: pin 6 unused */ +}; + +static int tck_gpio; /* initialized to 0 by default */ +static int tdi_gpio = 1; +static int tdo_gpio = 2; +static int tms_gpio = 3; +static int ntrst_gpio = 4; +static int nsysrst_gpio = 6; +static size_t ft232r_buf_size = FT232R_BUF_SIZE_EXTRA; +/** 0xFFFF disables restore by default, after exit serial port will not work. + * 0x15 sets TXD RTS DTR as outputs, after exit serial port will continue to work. + */ +static uint16_t ft232r_restore_bitmode = 0xFFFF; + /** * Perform sync bitbang output/input transaction. * Before call, an array ft232r_output[] should be filled with data to send. @@ -160,20 +172,35 @@ static int ft232r_send_recv(void) return ERROR_OK; } +void ft232r_increase_buf_size(size_t new_buf_size) +{ + uint8_t *new_buf_ptr; + if (new_buf_size >= ft232r_buf_size) { + new_buf_size += FT232R_BUF_SIZE_EXTRA; + new_buf_ptr = realloc(ft232r_output, new_buf_size); + if (new_buf_ptr != NULL) { + ft232r_output = new_buf_ptr; + ft232r_buf_size = new_buf_size; + } + } +} + /** * Add one TCK/TMS/TDI sample to send buffer. */ static void ft232r_write(int tck, int tms, int tdi) { - unsigned out_value = NTRST | NSYSRST; + unsigned out_value = (1<= FT232R_BUF_SIZE) { + ft232r_increase_buf_size(ft232r_output_len); + + if (ft232r_output_len >= ft232r_buf_size) { /* FIXME: should we just execute queue here? */ LOG_ERROR("ft232r_write: buffer overflow"); return; @@ -187,20 +214,22 @@ static void ft232r_write(int tck, int tms, int tdi) */ static void ft232r_reset(int trst, int srst) { - unsigned out_value = NTRST | NSYSRST; + unsigned out_value = (1<= FT232R_BUF_SIZE) { + ft232r_increase_buf_size(ft232r_output_len); + + if (ft232r_output_len >= ft232r_buf_size) { /* FIXME: should we just execute queue here? */ LOG_ERROR("ft232r_write: buffer overflow"); return; @@ -236,7 +265,10 @@ static int ft232r_init(void) return ERROR_JTAG_INIT_FAILED; } - libusb_detach_kernel_driver(adapter, 0); + if (ft232r_restore_bitmode == 0xFFFF) /* serial port will not be restored after jtag: */ + libusb_detach_kernel_driver(adapter, 0); + else /* serial port will be restored after jtag: */ + libusb_set_auto_detach_kernel_driver(adapter, 1); /* 1: DONT_DETACH_SIO_MODULE */ if (jtag_libusb_claim_interface(adapter, 0)) { LOG_ERROR("unable to claim interface"); @@ -254,7 +286,7 @@ static int ft232r_init(void) /* Sync bit bang mode. */ if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_SET_BITMODE, TCK | TDI | TMS | NTRST | NSYSRST | 0x400, + SIO_SET_BITMODE, (1<= 0 && bit < FT232R_BIT_COUNT) + return ft232r_bit_name_array[bit]; + return "?"; +} + +static int ft232r_bit_name_to_number(const char *name) +{ + int i; + if (name[0] >= '0' && name[0] <= '9' && name[1] == '\0') { + i = atoi(name); + if (i >= 0 && i < FT232R_BIT_COUNT) + return i; + } + for (i = 0; i < FT232R_BIT_COUNT; i++) + if (strcasecmp(name, ft232r_bit_name_array[i]) == 0) + return i; + return -1; +} + COMMAND_HANDLER(ft232r_handle_serial_desc_command) { if (CMD_ARGC == 1) @@ -357,6 +423,145 @@ COMMAND_HANDLER(ft232r_handle_vid_pid_command) return ERROR_OK; } +COMMAND_HANDLER(ft232r_handle_jtag_nums_command) +{ + if (CMD_ARGC == 4) { + tck_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); + tms_gpio = ft232r_bit_name_to_number(CMD_ARGV[1]); + tdi_gpio = ft232r_bit_name_to_number(CMD_ARGV[2]); + tdo_gpio = ft232r_bit_name_to_number(CMD_ARGV[3]); + } else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (tck_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + if (tms_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + if (tdi_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + if (tdo_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R nums: TCK = %d %s, TMS = %d %s, TDI = %d %s, TDO = %d %s", + tck_gpio, ft232r_bit_number_to_name(tck_gpio), + tms_gpio, ft232r_bit_number_to_name(tms_gpio), + tdi_gpio, ft232r_bit_number_to_name(tdi_gpio), + tdo_gpio, ft232r_bit_number_to_name(tdo_gpio)); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_tck_num_command) +{ + if (CMD_ARGC == 1) + tck_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); + else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (tck_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R num: TCK = %d %s", tck_gpio, ft232r_bit_number_to_name(tck_gpio)); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_tms_num_command) +{ + if (CMD_ARGC == 1) + tms_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); + else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (tms_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R num: TMS = %d %s", tms_gpio, ft232r_bit_number_to_name(tms_gpio)); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_tdo_num_command) +{ + if (CMD_ARGC == 1) + tdo_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); + else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (tdo_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R num: TDO = %d %s", tdo_gpio, ft232r_bit_number_to_name(tdo_gpio)); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_tdi_num_command) +{ + if (CMD_ARGC == 1) + tdi_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); + else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (tdi_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R num: TDI = %d %s", tdi_gpio, ft232r_bit_number_to_name(tdi_gpio)); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_trst_num_command) +{ + if (CMD_ARGC == 1) + ntrst_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); + else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (ntrst_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R num: TRST = %d %s", ntrst_gpio, ft232r_bit_number_to_name(ntrst_gpio)); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_srst_num_command) +{ + if (CMD_ARGC == 1) + nsysrst_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); + else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (nsysrst_gpio < 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R num: SRST = %d %s", nsysrst_gpio, ft232r_bit_number_to_name(nsysrst_gpio)); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_restore_serial_command) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_restore_bitmode); + else if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD_CTX, + "FT232R restore serial: 0x%04X (%s)", + ft232r_restore_bitmode, ft232r_restore_bitmode == 0xFFFF ? "disabled" : "enabled"); + + return ERROR_OK; +} + static const struct command_registration ft232r_command_handlers[] = { { .name = "ft232r_serial_desc", @@ -372,6 +577,62 @@ static const struct command_registration ft232r_command_handlers[] = { .help = "USB VID and PID of the adapter", .usage = "vid pid", }, + { + .name = "ft232r_jtag_nums", + .handler = ft232r_handle_jtag_nums_command, + .mode = COMMAND_CONFIG, + .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", + .usage = "<0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI>", + }, + { + .name = "ft232r_tck_num", + .handler = ft232r_handle_tck_num_command, + .mode = COMMAND_CONFIG, + .help = "gpio number for tck.", + .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", + }, + { + .name = "ft232r_tms_num", + .handler = ft232r_handle_tms_num_command, + .mode = COMMAND_CONFIG, + .help = "gpio number for tms.", + .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", + }, + { + .name = "ft232r_tdo_num", + .handler = ft232r_handle_tdo_num_command, + .mode = COMMAND_CONFIG, + .help = "gpio number for tdo.", + .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", + }, + { + .name = "ft232r_tdi_num", + .handler = ft232r_handle_tdi_num_command, + .mode = COMMAND_CONFIG, + .help = "gpio number for tdi.", + .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", + }, + { + .name = "ft232r_srst_num", + .handler = ft232r_handle_srst_num_command, + .mode = COMMAND_CONFIG, + .help = "gpio number for srst.", + .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", + }, + { + .name = "ft232r_trst_num", + .handler = ft232r_handle_trst_num_command, + .mode = COMMAND_CONFIG, + .help = "gpio number for trst.", + .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", + }, + { + .name = "ft232r_restore_serial", + .handler = ft232r_handle_restore_serial_command, + .mode = COMMAND_CONFIG, + .help = "bitmode control word that restores serial port.", + .usage = "bitmode_control_word", + }, COMMAND_REGISTRATION_DONE }; @@ -553,7 +814,7 @@ static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int int bcval = 1 << (bit_cnt % 8); int val = ft232r_output[bit0_index + bit_cnt*2 + 1]; - if (val & READ_TDO) + if (val & (1<