diff --git a/jtag/ChangeLog b/jtag/ChangeLog index 8105be0d..4e55b263 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -1,3 +1,8 @@ +2008-02-04 Arnim Laeuger + + * src/tap/cable/ft2232.c (ft2232_flush): rework flush implementation to benefit from + queued deferred transfers + 2008-02-04 Kolja Waschk * configure.ac, src/tap/parport/xpcu_common.c, src/tap/parport_xpcu_pp.c, diff --git a/jtag/src/tap/cable/ft2232.c b/jtag/src/tap/cable/ft2232.c index 54d321fb..ab2c3576 100644 --- a/jtag/src/tap/cable/ft2232.c +++ b/jtag/src/tap/cable/ft2232.c @@ -25,12 +25,14 @@ */ #include +#include #include "sysdep.h" -#include "cable.h" -#include "parport.h" -#include "chain.h" +#include +#include +#include +#include #include "generic.h" @@ -41,10 +43,6 @@ returned data in time -> deadlock */ #define MAXCHUNK (4 * 64) -/* Enable caching of last TDO to speed up things a bit. - Should be left define'd unless comm/sync problems occur. */ -#define LAST_TDO_CACHE - /* Maximum TCK frequency of FT2232 */ #define FT2232_MAX_TCK_FREQ 6000000 @@ -91,15 +89,27 @@ #define BITMASK_ARMUSBOCD_nOE (1 << BIT_ARMUSBOCD_nOE) -#ifdef LAST_TDO_CACHE -/* global variables to save last TDO value - this acts as a cache to prevent multiple "Read Data Bits Low" transfer - over USB for ft2232_get_tdo */ -static unsigned int last_tdo_valid; -static unsigned int last_tdo; -#endif +struct reg_desc { + struct reg_desc *next; + char *in; + char *out; + int len; +}; + +typedef struct reg_desc reg_desc_t; + +typedef struct { + uint32_t mpsse_frequency; + /* variables to save last TDO value + this acts as a cache to prevent multiple "Read Data Bits Low" transfer + over USB for ft2232_get_tdo */ + unsigned int last_tdo_valid; + unsigned int last_tdo; + + int total_length; + reg_desc_t *transfer_chain; +} params_t; -static uint32_t mpsse_frequency; static void @@ -107,12 +117,13 @@ update_frequency( cable_t *cable ) { parport_t *p = cable->port; uint32_t new_frequency = cable_get_frequency( cable ); + params_t *params = (params_t *)cable->params; if (!new_frequency || new_frequency > FT2232_MAX_TCK_FREQ) new_frequency = FT2232_MAX_TCK_FREQ; /* update ft2232 frequency if cable setting changed */ - if (new_frequency != mpsse_frequency) { + if (new_frequency != params->mpsse_frequency) { uint32_t div; div = FT2232_MAX_TCK_FREQ / new_frequency; @@ -132,7 +143,7 @@ update_frequency( cable_t *cable ) parport_set_control( p, 1 ); // flush parport_set_control( p, 0 ); // noflush - mpsse_frequency = FT2232_MAX_TCK_FREQ / (div + 1); + params->mpsse_frequency = FT2232_MAX_TCK_FREQ / (div + 1); } } @@ -141,6 +152,7 @@ static int ft2232_generic_init( cable_t *cable ) { parport_t *p = cable->port; + params_t *params = (params_t *)cable->params; if (parport_open( p )) return -1; @@ -160,11 +172,9 @@ ft2232_generic_init( cable_t *cable ) parport_set_control( p, 1 ); // flush parport_set_control( p, 0 ); // noflush - mpsse_frequency = FT2232_MAX_TCK_FREQ; + params->mpsse_frequency = FT2232_MAX_TCK_FREQ; -#ifdef LAST_TDO_CACHE - last_tdo_valid = 0; -#endif + params->last_tdo_valid = 0; return 0; } @@ -173,6 +183,7 @@ static int ft2232_jtagkey_init( cable_t *cable ) { parport_t *p = cable->port; + params_t *params = (params_t *)cable->params; if (parport_open( p )) return -1; @@ -197,11 +208,9 @@ ft2232_jtagkey_init( cable_t *cable ) parport_set_control( p, 1 ); // flush parport_set_control( p, 0 ); // noflush - mpsse_frequency = FT2232_MAX_TCK_FREQ; + params->mpsse_frequency = FT2232_MAX_TCK_FREQ; -#ifdef LAST_TDO_CACHE - last_tdo_valid = 0; -#endif + params->last_tdo_valid = 0; return 0; } @@ -210,6 +219,7 @@ static int ft2232_armusbocd_init( cable_t *cable ) { parport_t *p = cable->port; + params_t *params = (params_t *)cable->params; if (parport_open( p )) return -1; @@ -234,11 +244,9 @@ ft2232_armusbocd_init( cable_t *cable ) parport_set_control( p, 1 ); // flush parport_set_control( p, 0 ); // noflush - mpsse_frequency = FT2232_MAX_TCK_FREQ; + params->mpsse_frequency = FT2232_MAX_TCK_FREQ; -#ifdef LAST_TDO_CACHE - last_tdo_valid = 0; -#endif + params->last_tdo_valid = 0; return 0; } @@ -309,6 +317,7 @@ static void ft2232_clock_defer( cable_t *cable, int defer, int tms, int tdi, int n ) { parport_t *p = cable->port; + params_t *params = (params_t *)cable->params; tms = tms ? 0x7f : 0; tdi = tdi ? 1 << 7 : 0; @@ -333,9 +342,7 @@ ft2232_clock_defer( cable_t *cable, int defer, int tms, int tdi, int n ) parport_set_control( p, 1 ); // flush parport_set_control( p, 0 ); // noflush -#ifdef LAST_TDO_CACHE - last_tdo_valid = 0; -#endif + params->last_tdo_valid = 0; } } @@ -358,14 +365,13 @@ static int ft2232_get_tdo_finish( cable_t *cable ) { parport_t *p = cable->port; + params_t *params = (params_t *)cable->params; int value; value = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0; -#ifdef LAST_TDO_CACHE - last_tdo = value; - last_tdo_valid = 1; -#endif + params->last_tdo = value; + params->last_tdo_valid = 1; return value; } @@ -391,6 +397,7 @@ static int ft2232_transfer( cable_t *cable, int len, char *in, char *out ) { parport_t *p = cable->port; + params_t *params = (params_t *)cable->params; int in_offset = 0; int out_offset = 0; int bitwise_len; @@ -486,20 +493,17 @@ ft2232_transfer( cable_t *cable, int len, char *in, char *out ) } } -#ifdef LAST_TDO_CACHE if (out) { /* Read Data Bits Low Byte to get current TDO, Do this only if we'll read out data nonetheless */ parport_set_data( p, GET_BITS_LOW ); } -#endif parport_set_control( p, 1 ); // flush parport_set_control( p, 0 ); // noflush -#ifdef LAST_TDO_CACHE - /* invalidate TDO cache */ - last_tdo_valid = 0; -#endif + + /* invalidate TDO cache */ + params->last_tdo_valid = 0; if (out) { @@ -536,57 +540,55 @@ ft2232_transfer( cable_t *cable, int len, char *in, char *out ) } } -#ifdef LAST_TDO_CACHE if (out) { /* gather current TDO */ - last_tdo = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0; - last_tdo_valid = 1; + params->last_tdo = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0; + params->last_tdo_valid = 1; } -#endif } return 0; } +#undef VERBOSE + static void ft2232_flush( cable_t *cable ) { + params_t *params = (params_t *)cable->params; + while (cable->todo.num_items > 0) { int i, j, n, to_send = 0, to_rec = 0; -#ifdef LAST_TDO_CACHE - int last_tdo_valid_schedule = last_tdo_valid; - int last_tdo_valid_finish = last_tdo_valid; -#endif + int last_tdo_valid_schedule = params->last_tdo_valid; + int last_tdo_valid_finish = params->last_tdo_valid; - for ( j = i = cable->todo.next_item, n = 0; to_send < 64 && n < cable->todo.num_items; n++) { + for (j = i = cable->todo.next_item, n = 0; to_rec < 64 && n < cable->todo.num_items; n++) { if (cable->todo.data[i].action == CABLE_TRANSFER) break; switch (cable->todo.data[i].action) { case CABLE_CLOCK: +#ifdef VERBOSE + puts("clock_defer"); +#endif ft2232_clock_defer( cable, 1, cable->todo.data[i].arg.clock.tms, cable->todo.data[i].arg.clock.tdi, cable->todo.data[i].arg.clock.n ); to_send += 3; -#ifdef LAST_TDO_CACHE last_tdo_valid_schedule = 0; -#endif break; case CABLE_GET_TDO: -#ifdef LAST_TDO_CACHE if (!last_tdo_valid_schedule) { -#else - { +#ifdef VERBOSE + puts("get_tdo_schedule"); #endif ft2232_get_tdo_schedule( cable ); to_send += 1; to_rec += 1; -#ifdef LAST_TDO_CACHE last_tdo_valid_schedule = 1; -#endif } break; @@ -595,35 +597,29 @@ ft2232_flush( cable_t *cable ) } i++; - if (i >= cable->todo.max_items) i=0; + if (i >= cable->todo.max_items) + i = 0; } - if(to_rec > 0) - { + if (to_rec > 0) { parport_set_control( cable->port, 1 ); // flush parport_set_control( cable->port, 0 ); } - while (j!=i) { + while (j != i) { switch (cable->todo.data[j].action) { case CABLE_CLOCK: -#ifdef LAST_TDO_CACHE last_tdo_valid_finish = 0; -#endif break; case CABLE_GET_TDO: { int tdo; int m; -#ifdef LAST_TDO_CACHE if (last_tdo_valid_finish) - tdo = last_tdo; + tdo = params->last_tdo; else tdo = ft2232_get_tdo_finish( cable ); last_tdo_valid_finish = 1; -#else - tdo = ft2232_get_tdo_finish( cable ); -#endif m = cable_add_queue_item( cable, &(cable->done) ); cable->done.data[m].action = CABLE_GET_TDO; cable->done.data[m].arg.value.tdo = tdo; @@ -641,39 +637,168 @@ ft2232_flush( cable_t *cable ) } j++; - if (j >= cable->todo.max_items) j=0; - cable->todo.num_items --; + if (j >= cable->todo.max_items) + j = 0; + cable->todo.num_items--; } while (cable->todo.num_items > 0 && cable->todo.data[i].action == CABLE_TRANSFER) { - int r = ft2232_transfer( cable, - cable->todo.data[i].arg.transfer.len, - cable->todo.data[i].arg.transfer.in, - cable->todo.data[i].arg.transfer.out); - - free( cable->todo.data[i].arg.transfer.in ); - if (cable->todo.data[i].arg.transfer.out != NULL) { - int m = cable_add_queue_item( cable, &(cable->done) ); - if (m < 0) - printf("out of memory!!\n"); - cable->done.data[m].action = CABLE_TRANSFER; - cable->done.data[m].arg.xferred.len = cable->todo.data[i].arg.transfer.len; - cable->done.data[m].arg.xferred.res = r; - cable->done.data[m].arg.xferred.out = cable->todo.data[i].arg.transfer.out; - + reg_desc_t *new_reg = (reg_desc_t *)malloc( sizeof(reg_desc_t) ); + reg_desc_t *r; + + if (!new_reg) { + printf( _("out of memory!\n") ); + break; } + new_reg->next = NULL; + new_reg->in = cable->todo.data[i].arg.transfer.in; + new_reg->out = cable->todo.data[i].arg.transfer.out; + new_reg->len = cable->todo.data[i].arg.transfer.len; + params->total_length += cable->todo.data[i].arg.transfer.len; + + if (params->transfer_chain) { + r = params->transfer_chain; + while (r->next) + r = r->next; + r->next = new_reg; + } else + params->transfer_chain = new_reg; + i++; if (i >= cable->todo.max_items) i = 0; cable->todo.num_items--; } + /* build combined in- and out-strams */ + if (params->transfer_chain) { + reg_desc_t *reg = params->transfer_chain; + char *full_in = (char *)malloc( params->total_length ); + char *full_out = (char *)malloc( params->total_length ); + char *idx; + int do_out = 0; + int r; + + if (full_in && full_out) { + /* combine all in-streams */ + full_in[0] = '\0'; + idx = full_in; + while (reg) { + reg_desc_t *t = reg; + memcpy( idx, reg->in, reg->len ); + idx += reg->len; + if (reg->out) + do_out = 1; + reg = reg->next; + free( t ); + } + + /* and perform the transfer */ +#ifdef VERBOSE + printf( "transfer %d %s\n", cable->todo.data[i].arg.transfer.len, + cable->todo.data[i].arg.transfer.out ? "out" : "" ); +#endif + r = ft2232_transfer( cable, + params->total_length, + full_in, + do_out ? full_out : NULL ); + params->transfer_chain = NULL; + params->total_length = 0; + + /* copy the result of the combined transfer to the done queue */ + idx = full_out; + while (j != i) { + free( cable->todo.data[j].arg.transfer.in ); + + if (cable->todo.data[j].arg.transfer.out != NULL) { + int m = cable_add_queue_item( cable, &(cable->done) ); + if (m < 0) + printf("out of memory!\n"); + + memcpy( cable->todo.data[j].arg.transfer.out, idx, + cable->todo.data[j].arg.transfer.len ); + + cable->done.data[m].action = CABLE_TRANSFER; + cable->done.data[m].arg.xferred.len = cable->todo.data[j].arg.transfer.len; + cable->done.data[m].arg.xferred.res = r; + cable->done.data[m].arg.xferred.out = cable->todo.data[j].arg.transfer.out; + } + idx += cable->todo.data[j].arg.transfer.len; + + j++; + if (j >= cable->todo.max_items) + j = 0; + } + + } else + printf( _("out of memory!\n") ); + + if (full_in) + free( full_in ); + if (full_out); + free( full_out ); + } + cable->todo.next_item = i; } } -void +static int +ft2232_connect( char *params[], cable_t *cable ) +{ + params_t *cable_params = (params_t *)malloc( sizeof(params_t) ); + parport_t *port; + int i; + + if ( cmd_params( params ) < 3 ) { + printf( _("not enough arguments!\n") ); + return 1; + } + + /* search parport driver list */ + for (i = 0; parport_drivers[i]; i++) + if (strcasecmp( params[1], parport_drivers[i]->type ) == 0) + break; + if (!parport_drivers[i]) { + printf( _("Unknown port driver: %s\n"), params[1] ); + return 2; + } + + /* set up parport driver */ + port = parport_drivers[i]->connect( (const char **) ¶ms[2], + cmd_params( params ) - 2 ); + + if (port == NULL) { + printf( _("Error: Cable connection failed!\n") ); + return 3; + } + + if (!cable_params) { + free( cable ); + return 4; + } + + cable_params->last_tdo_valid = 0; + cable_params->total_length = 0; + cable_params->transfer_chain = NULL; + + cable->port = port; + cable->params = cable_params; + cable->chain = NULL; + + return 0; +} + +static void +ft2232_cable_free( cable_t *cable ) +{ + cable->port->driver->parport_free( cable->port ); + free( cable->params ); + free( cable ); +} + +static void ft2232_usbcable_help( const char *cablename ) { printf( _( @@ -689,9 +814,9 @@ ft2232_usbcable_help( const char *cablename ) cable_driver_t ft2232_cable_driver = { "FT2232", N_("Generic FTDI FT2232 Cable"), - generic_connect, + ft2232_connect, generic_disconnect, - generic_cable_free, + ft2232_cable_free, ft2232_generic_init, ft2232_generic_done, ft2232_clock, @@ -706,9 +831,9 @@ cable_driver_t ft2232_cable_driver = { cable_driver_t ft2232_armusbocd_cable_driver = { "ARM-USB-OCD", N_("Olimex ARM-USB-OCD (FT2232) Cable"), - generic_connect, + ft2232_connect, generic_disconnect, - generic_cable_free, + ft2232_cable_free, ft2232_armusbocd_init, ft2232_armusbocd_done, ft2232_clock, @@ -716,7 +841,6 @@ cable_driver_t ft2232_armusbocd_cable_driver = { ft2232_transfer, ft2232_set_trst, generic_get_trst, -// generic_flush_using_transfer, ft2232_flush, ft2232_usbcable_help }; @@ -724,9 +848,9 @@ cable_driver_t ft2232_armusbocd_cable_driver = { cable_driver_t ft2232_jtagkey_cable_driver = { "JTAGkey", N_("Amontec JTAGkey (FT2232) Cable"), - generic_connect, + ft2232_connect, generic_disconnect, - generic_cable_free, + ft2232_cable_free, ft2232_jtagkey_init, ft2232_jtagkey_done, ft2232_clock,