2009-03-08 15:14:18 +00:00
/***************************************************************************
* Copyright ( C ) 2009 by Dimitar Dimitrov < dinuxbg @ gmail . com > *
* based on Dominic Rath ' s and Benedikt Sauter ' s usbprog . c *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* 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 . , *
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2009-12-03 12:14:31 +00:00
# include <jtag/interface.h>
2009-12-03 12:14:30 +00:00
# include <jtag/commands.h>
2009-03-08 15:14:18 +00:00
# include <usb.h>
2009-11-19 20:06:05 +00:00
# include "usb_common.h"
2009-03-08 15:14:18 +00:00
# define USB_VID 0x15ba
# define USB_PID 0x001e
# define ARMJTAGEW_EPT_BULK_OUT 0x01u
# define ARMJTAGEW_EPT_BULK_IN 0x82u
# define ARMJTAGEW_USB_TIMEOUT 2000
# define ARMJTAGEW_IN_BUFFER_SIZE (4*1024)
# define ARMJTAGEW_OUT_BUFFER_SIZE (4*1024)
/* USB command request codes. */
# define CMD_GET_VERSION 0x00
# define CMD_SELECT_DPIMPL 0x10
# define CMD_SET_TCK_FREQUENCY 0x11
# define CMD_GET_TCK_FREQUENCY 0x12
# define CMD_MEASURE_MAX_TCK_FREQ 0x15
# define CMD_MEASURE_RTCK_RESPONSE 0x16
# define CMD_TAP_SHIFT 0x17
# define CMD_SET_TAPHW_STATE 0x20
# define CMD_GET_TAPHW_STATE 0x21
# define CMD_TGPWR_SETUP 0x22
/* Global USB buffers */
2009-06-18 07:07:12 +00:00
static uint8_t usb_in_buffer [ ARMJTAGEW_IN_BUFFER_SIZE ] ;
static uint8_t usb_out_buffer [ ARMJTAGEW_OUT_BUFFER_SIZE ] ;
2009-03-08 15:14:18 +00:00
/* Queue command functions */
2009-04-21 05:29:23 +00:00
static void armjtagew_end_state ( tap_state_t state ) ;
static void armjtagew_state_move ( void ) ;
static void armjtagew_path_move ( int num_states , tap_state_t * path ) ;
static void armjtagew_runtest ( int num_cycles ) ;
2009-11-13 13:30:28 +00:00
static void armjtagew_scan ( bool ir_scan , enum scan_type type , uint8_t * buffer , int scan_size , struct scan_command * command ) ;
2009-04-21 05:29:23 +00:00
static void armjtagew_reset ( int trst , int srst ) ;
2009-06-18 07:07:12 +00:00
//static void armjtagew_simple_command(uint8_t command);
2009-04-21 05:29:23 +00:00
static int armjtagew_get_status ( void ) ;
2009-03-08 15:14:18 +00:00
/* tap buffer functions */
2009-04-21 05:29:23 +00:00
static void armjtagew_tap_init ( void ) ;
static int armjtagew_tap_execute ( void ) ;
static void armjtagew_tap_ensure_space ( int scans , int bits ) ;
static void armjtagew_tap_append_step ( int tms , int tdi ) ;
2009-11-13 13:30:28 +00:00
static void armjtagew_tap_append_scan ( int length , uint8_t * buffer , struct scan_command * command ) ;
2009-03-08 15:14:18 +00:00
/* ARM-JTAG-EW lowlevel functions */
2009-11-13 12:33:32 +00:00
struct armjtagew {
2009-03-08 15:14:18 +00:00
struct usb_dev_handle * usb_handle ;
2009-11-13 12:33:32 +00:00
} ;
2009-03-08 15:14:18 +00:00
2009-11-13 12:33:32 +00:00
static struct armjtagew * armjtagew_usb_open ( void ) ;
static void armjtagew_usb_close ( struct armjtagew * armjtagew ) ;
static int armjtagew_usb_message ( struct armjtagew * armjtagew , int out_length , int in_length ) ;
static int armjtagew_usb_write ( struct armjtagew * armjtagew , int out_length ) ;
static int armjtagew_usb_read ( struct armjtagew * armjtagew , int exp_in_length ) ;
2009-03-08 15:14:18 +00:00
/* helper functions */
2009-04-21 05:29:23 +00:00
static int armjtagew_get_version_info ( void ) ;
2009-03-08 15:14:18 +00:00
# ifdef _DEBUG_USB_COMMS_
2009-06-18 07:07:12 +00:00
static void armjtagew_debug_buffer ( uint8_t * buffer , int length ) ;
2009-03-08 15:14:18 +00:00
# endif
2009-11-13 12:33:32 +00:00
static struct armjtagew * armjtagew_handle ;
2009-03-08 15:14:18 +00:00
/***************************************************************************/
/* External interface implementation */
2009-04-21 05:29:23 +00:00
static int armjtagew_execute_queue ( void )
2009-03-08 15:14:18 +00:00
{
2009-11-13 14:15:31 +00:00
struct jtag_command * cmd = jtag_command_queue ;
2009-03-08 15:14:18 +00:00
int scan_size ;
enum scan_type type ;
2009-06-18 07:07:12 +00:00
uint8_t * buffer ;
2009-03-08 15:14:18 +00:00
while ( cmd ! = NULL )
{
switch ( cmd - > type )
{
case JTAG_RUNTEST :
2009-06-23 22:46:23 +00:00
DEBUG_JTAG_IO ( " runtest %i cycles, end in %i " , cmd - > cmd . runtest - > num_cycles , \
2009-03-08 15:14:18 +00:00
cmd - > cmd . runtest - > end_state ) ;
2009-06-02 07:21:44 +00:00
armjtagew_end_state ( cmd - > cmd . runtest - > end_state ) ;
2009-03-08 15:14:18 +00:00
armjtagew_runtest ( cmd - > cmd . runtest - > num_cycles ) ;
break ;
2010-06-05 09:30:49 +00:00
case JTAG_TLR_RESET :
2009-03-08 15:14:18 +00:00
DEBUG_JTAG_IO ( " statemove end in %i " , cmd - > cmd . statemove - > end_state ) ;
2009-06-02 07:21:44 +00:00
armjtagew_end_state ( cmd - > cmd . statemove - > end_state ) ;
2009-03-08 15:14:18 +00:00
armjtagew_state_move ( ) ;
break ;
case JTAG_PATHMOVE :
DEBUG_JTAG_IO ( " pathmove: %i states, end in %i " , \
cmd - > cmd . pathmove - > num_states , \
cmd - > cmd . pathmove - > path [ cmd - > cmd . pathmove - > num_states - 1 ] ) ;
armjtagew_path_move ( cmd - > cmd . pathmove - > num_states , cmd - > cmd . pathmove - > path ) ;
break ;
case JTAG_SCAN :
DEBUG_JTAG_IO ( " scan end in %i " , cmd - > cmd . scan - > end_state ) ;
2009-06-02 07:21:44 +00:00
armjtagew_end_state ( cmd - > cmd . scan - > end_state ) ;
2009-03-08 15:14:18 +00:00
scan_size = jtag_build_buffer ( cmd - > cmd . scan , & buffer ) ;
DEBUG_JTAG_IO ( " scan input, length = %d " , scan_size ) ;
# ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer ( buffer , ( scan_size + 7 ) / 8 ) ;
# endif
type = jtag_scan_type ( cmd - > cmd . scan ) ;
armjtagew_scan ( cmd - > cmd . scan - > ir_scan , type , buffer , scan_size , cmd - > cmd . scan ) ;
break ;
case JTAG_RESET :
DEBUG_JTAG_IO ( " reset trst: %i srst %i " , cmd - > cmd . reset - > trst , cmd - > cmd . reset - > srst ) ;
armjtagew_tap_execute ( ) ;
if ( cmd - > cmd . reset - > trst = = 1 )
{
tap_set_state ( TAP_RESET ) ;
}
armjtagew_reset ( cmd - > cmd . reset - > trst , cmd - > cmd . reset - > srst ) ;
break ;
case JTAG_SLEEP :
DEBUG_JTAG_IO ( " sleep %i " , cmd - > cmd . sleep - > us ) ;
armjtagew_tap_execute ( ) ;
jtag_sleep ( cmd - > cmd . sleep - > us ) ;
break ;
default :
LOG_ERROR ( " BUG: unknown JTAG command type encountered " ) ;
exit ( - 1 ) ;
}
cmd = cmd - > next ;
}
return armjtagew_tap_execute ( ) ;
}
/* Sets speed in kHz. */
2009-04-21 05:29:23 +00:00
static int armjtagew_speed ( int speed )
2009-03-08 15:14:18 +00:00
{
int result ;
int speed_real ;
usb_out_buffer [ 0 ] = CMD_SET_TCK_FREQUENCY ;
2011-09-16 19:08:10 +00:00
buf_set_u32 ( usb_out_buffer + 1 , 0 , 32 , speed * 1000 ) ;
2009-03-08 15:14:18 +00:00
2011-09-16 19:06:02 +00:00
result = armjtagew_usb_message ( armjtagew_handle , 5 , 4 ) ;
2009-03-08 15:14:18 +00:00
if ( result < 0 )
{
LOG_ERROR ( " ARM-JTAG-EW setting speed failed (%d) " , result ) ;
return ERROR_JTAG_DEVICE_ERROR ;
}
usb_out_buffer [ 0 ] = CMD_GET_TCK_FREQUENCY ;
2009-11-13 12:33:32 +00:00
result = armjtagew_usb_message ( armjtagew_handle , 1 , 4 ) ;
2011-09-16 19:08:10 +00:00
speed_real = ( int ) buf_get_u32 ( usb_in_buffer , 0 , 32 ) / 1000 ;
2009-06-23 22:35:09 +00:00
if ( result < 0 )
2009-03-08 15:14:18 +00:00
{
LOG_ERROR ( " ARM-JTAG-EW getting speed failed (%d) " , result ) ;
return ERROR_JTAG_DEVICE_ERROR ;
2009-06-04 00:56:41 +00:00
}
2009-03-08 15:14:18 +00:00
else
{
2011-09-16 19:14:39 +00:00
LOG_INFO ( " Requested speed %dkHz, emulator reported %dkHz. " , speed , speed_real ) ;
2009-03-08 15:14:18 +00:00
}
return ERROR_OK ;
}
2009-04-21 05:29:23 +00:00
static int armjtagew_khz ( int khz , int * jtag_speed )
2009-03-08 15:14:18 +00:00
{
* jtag_speed = khz ;
return ERROR_OK ;
}
2011-09-16 19:10:23 +00:00
static int armjtagew_speed_div ( int speed , int * khz )
{
* khz = speed ;
return ERROR_OK ;
}
2009-04-21 05:29:23 +00:00
static int armjtagew_init ( void )
2009-03-08 15:14:18 +00:00
{
int check_cnt ;
2009-11-13 12:33:32 +00:00
armjtagew_handle = armjtagew_usb_open ( ) ;
2009-03-08 15:14:18 +00:00
2009-11-13 12:33:32 +00:00
if ( armjtagew_handle = = 0 )
2009-03-08 15:14:18 +00:00
{
LOG_ERROR ( " Cannot find ARM-JTAG-EW Interface! Please check connection and permissions. " ) ;
return ERROR_JTAG_INIT_FAILED ;
}
check_cnt = 0 ;
while ( check_cnt < 3 )
{
if ( armjtagew_get_version_info ( ) = = ERROR_OK )
{
/* attempt to get status */
armjtagew_get_status ( ) ;
break ;
}
check_cnt + + ;
}
if ( check_cnt = = 3 )
{
LOG_INFO ( " ARM-JTAG-EW initial read failed, don't worry " ) ;
}
2011-09-16 19:13:39 +00:00
// Initial JTAG speed (for reset and initialization): 32 kHz
armjtagew_speed ( 32 ) ;
2009-03-08 15:14:18 +00:00
LOG_INFO ( " ARM-JTAG-EW JTAG Interface ready " ) ;
armjtagew_reset ( 0 , 0 ) ;
armjtagew_tap_init ( ) ;
return ERROR_OK ;
}
2009-04-21 05:29:23 +00:00
static int armjtagew_quit ( void )
2009-03-08 15:14:18 +00:00
{
2009-11-13 12:33:32 +00:00
armjtagew_usb_close ( armjtagew_handle ) ;
2009-03-08 15:14:18 +00:00
return ERROR_OK ;
}
/***************************************************************************/
/* Queue command implementations */
2009-04-21 05:29:23 +00:00
static void armjtagew_end_state ( tap_state_t state )
2009-03-08 15:14:18 +00:00
{
if ( tap_is_state_stable ( state ) )
{
tap_set_end_state ( state ) ;
}
else
{
LOG_ERROR ( " BUG: %i is not a valid end state " , state ) ;
exit ( - 1 ) ;
}
}
/* Goes to the end state. */
2009-04-21 05:29:23 +00:00
static void armjtagew_state_move ( void )
2009-03-08 15:14:18 +00:00
{
int i ;
int tms = 0 ;
2009-06-18 07:07:12 +00:00
uint8_t tms_scan = tap_get_tms_path ( tap_get_state ( ) , tap_get_end_state ( ) ) ;
2009-05-18 20:25:19 +00:00
int tms_count = tap_get_tms_path_len ( tap_get_state ( ) , tap_get_end_state ( ) ) ;
2009-03-08 15:14:18 +00:00
2009-05-18 20:25:19 +00:00
for ( i = 0 ; i < tms_count ; i + + )
2009-03-08 15:14:18 +00:00
{
tms = ( tms_scan > > i ) & 1 ;
armjtagew_tap_append_step ( tms , 0 ) ;
}
tap_set_state ( tap_get_end_state ( ) ) ;
}
2009-04-21 05:29:23 +00:00
static void armjtagew_path_move ( int num_states , tap_state_t * path )
2009-03-08 15:14:18 +00:00
{
int i ;
for ( i = 0 ; i < num_states ; i + + )
{
/*
2009-06-04 00:56:41 +00:00
* TODO : The ARM - JTAG - EW hardware delays TDI with 3 TCK cycles when in RTCK mode .
2009-03-08 15:14:18 +00:00
* Either handle that here , or update the documentation with examples
* how to fix that in the configuration files .
*/
if ( path [ i ] = = tap_state_transition ( tap_get_state ( ) , false ) )
{
armjtagew_tap_append_step ( 0 , 0 ) ;
}
else if ( path [ i ] = = tap_state_transition ( tap_get_state ( ) , true ) )
{
armjtagew_tap_append_step ( 1 , 0 ) ;
}
else
{
LOG_ERROR ( " BUG: %s -> %s isn't a valid TAP transition " , tap_state_name ( tap_get_state ( ) ) , tap_state_name ( path [ i ] ) ) ;
exit ( - 1 ) ;
}
tap_set_state ( path [ i ] ) ;
}
tap_set_end_state ( tap_get_state ( ) ) ;
}
2009-04-21 05:29:23 +00:00
static void armjtagew_runtest ( int num_cycles )
2009-03-08 15:14:18 +00:00
{
int i ;
tap_state_t saved_end_state = tap_get_end_state ( ) ;
/* only do a state_move when we're not already in IDLE */
if ( tap_get_state ( ) ! = TAP_IDLE )
{
armjtagew_end_state ( TAP_IDLE ) ;
armjtagew_state_move ( ) ;
}
/* execute num_cycles */
for ( i = 0 ; i < num_cycles ; i + + )
{
armjtagew_tap_append_step ( 0 , 0 ) ;
}
/* finish in end_state */
armjtagew_end_state ( saved_end_state ) ;
if ( tap_get_state ( ) ! = tap_get_end_state ( ) )
{
armjtagew_state_move ( ) ;
}
}
2009-11-13 13:30:28 +00:00
static void armjtagew_scan ( bool ir_scan , enum scan_type type , uint8_t * buffer , int scan_size , struct scan_command * command )
2009-03-08 15:14:18 +00:00
{
tap_state_t saved_end_state ;
armjtagew_tap_ensure_space ( 1 , scan_size + 8 ) ;
saved_end_state = tap_get_end_state ( ) ;
/* Move to appropriate scan state */
armjtagew_end_state ( ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT ) ;
armjtagew_state_move ( ) ;
armjtagew_end_state ( saved_end_state ) ;
/* Scan */
armjtagew_tap_append_scan ( scan_size , buffer , command ) ;
/* We are in Exit1, go to Pause */
armjtagew_tap_append_step ( 0 , 0 ) ;
tap_set_state ( ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE ) ;
if ( tap_get_state ( ) ! = tap_get_end_state ( ) )
{
armjtagew_state_move ( ) ;
}
}
2009-04-21 05:29:23 +00:00
static void armjtagew_reset ( int trst , int srst )
2009-03-08 15:14:18 +00:00
{
2009-06-23 22:41:13 +00:00
const uint8_t trst_mask = ( 1u < < 5 ) ;
const uint8_t srst_mask = ( 1u < < 6 ) ;
2009-06-18 07:07:12 +00:00
uint8_t val = 0 ;
uint8_t outp_en = 0 ;
uint8_t change_mask = 0 ;
2009-03-08 15:14:18 +00:00
int result ;
LOG_DEBUG ( " trst: %i, srst: %i " , trst , srst ) ;
if ( srst = = 0 )
{
val | = srst_mask ;
outp_en & = ~ srst_mask ; /* tristate */
change_mask | = srst_mask ;
}
else if ( srst = = 1 )
{
val & = ~ srst_mask ;
outp_en | = srst_mask ;
change_mask | = srst_mask ;
}
if ( trst = = 0 )
{
val | = trst_mask ;
outp_en & = ~ trst_mask ; /* tristate */
change_mask | = trst_mask ;
}
else if ( trst = = 1 )
{
val & = ~ trst_mask ;
outp_en | = trst_mask ;
change_mask | = trst_mask ;
}
usb_out_buffer [ 0 ] = CMD_SET_TAPHW_STATE ;
usb_out_buffer [ 1 ] = val ;
usb_out_buffer [ 2 ] = outp_en ;
usb_out_buffer [ 3 ] = change_mask ;
2009-11-13 12:33:32 +00:00
result = armjtagew_usb_write ( armjtagew_handle , 4 ) ;
2009-03-08 15:14:18 +00:00
if ( result ! = 4 )
{
LOG_ERROR ( " ARM-JTAG-EW TRST/SRST pin set failed failed (%d) " , result ) ;
}
}
2009-04-21 05:29:23 +00:00
static int armjtagew_get_status ( void )
2009-03-08 15:14:18 +00:00
{
int result ;
usb_out_buffer [ 0 ] = CMD_GET_TAPHW_STATE ;
2009-11-13 12:33:32 +00:00
result = armjtagew_usb_message ( armjtagew_handle , 1 , 12 ) ;
2009-03-08 15:14:18 +00:00
if ( result = = 0 )
{
unsigned int u_tg = buf_get_u32 ( usb_in_buffer , 0 , 16 ) ;
2011-01-06 02:54:12 +00:00
LOG_INFO ( " U_tg = %d mV, U_aux = %d mV, U_tgpwr = %d mV, I_tgpwr = %d mA, D1 = %d, Target power %s %s " ,
2009-06-19 23:15:58 +00:00
( int ) ( buf_get_u32 ( usb_in_buffer + 0 , 0 , 16 ) ) ,
( int ) ( buf_get_u32 ( usb_in_buffer + 2 , 0 , 16 ) ) ,
( int ) ( buf_get_u32 ( usb_in_buffer + 4 , 0 , 16 ) ) ,
( int ) ( buf_get_u32 ( usb_in_buffer + 6 , 0 , 16 ) ) ,
2009-06-23 22:50:08 +00:00
usb_in_buffer [ 9 ] ,
usb_in_buffer [ 11 ] ? " OVERCURRENT " : " OK " ,
2009-06-19 23:15:58 +00:00
usb_in_buffer [ 10 ] ? " enabled " : " disabled " ) ;
2009-03-08 15:14:18 +00:00
if ( u_tg < 1500 )
{
2011-01-05 19:24:54 +00:00
LOG_ERROR ( " Vref too low. Check Target Power " ) ;
2009-03-08 15:14:18 +00:00
}
}
else
{
2011-01-05 19:24:54 +00:00
LOG_ERROR ( " ARM-JTAG-EW command CMD_GET_TAPHW_STATE failed (%d) " , result ) ;
2009-03-08 15:14:18 +00:00
}
return ERROR_OK ;
}
2009-04-21 05:29:23 +00:00
static int armjtagew_get_version_info ( void )
2009-03-08 15:14:18 +00:00
{
int result ;
char sn [ 16 ] ;
char auxinfo [ 257 ] ;
/* query hardware version */
usb_out_buffer [ 0 ] = CMD_GET_VERSION ;
2009-11-13 12:33:32 +00:00
result = armjtagew_usb_message ( armjtagew_handle , 1 , 4 + 15 + 256 ) ;
2009-03-08 15:14:18 +00:00
2009-06-04 00:56:41 +00:00
if ( result ! = 0 )
2009-03-08 15:14:18 +00:00
{
2011-01-05 19:24:54 +00:00
LOG_ERROR ( " ARM-JTAG-EW command CMD_GET_VERSION failed (%d) " , result ) ;
2009-03-08 15:14:18 +00:00
return ERROR_JTAG_DEVICE_ERROR ;
}
2009-06-23 22:44:17 +00:00
memcpy ( sn , usb_in_buffer + 4 , 15 ) ;
2009-03-08 15:14:18 +00:00
sn [ 15 ] = ' \0 ' ;
2009-06-23 22:44:17 +00:00
memcpy ( auxinfo , usb_in_buffer + 4 + 15 , 256 ) ;
2009-03-08 15:14:18 +00:00
auxinfo [ 256 ] = ' \0 ' ;
LOG_INFO ( " ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s " , \
usb_in_buffer [ 1 ] , usb_in_buffer [ 0 ] , \
isgraph ( usb_in_buffer [ 2 ] ) ? usb_in_buffer [ 2 ] : ' X ' , \
sn , auxinfo ) ;
2011-09-16 19:12:47 +00:00
if ( 1 ! = usb_in_buffer [ 1 ] | | 6 ! = usb_in_buffer [ 0 ] )
{
LOG_WARNING ( " ARM-JTAG-EW firmware version %d.%d is untested with this version of OpenOCD. You might experience unexpected behavior. " , usb_in_buffer [ 1 ] , usb_in_buffer [ 0 ] ) ;
}
2009-03-08 15:14:18 +00:00
return ERROR_OK ;
}
2009-11-15 17:12:44 +00:00
COMMAND_HANDLER ( armjtagew_handle_armjtagew_info_command )
2009-03-08 15:14:18 +00:00
{
if ( armjtagew_get_version_info ( ) = = ERROR_OK )
{
/* attempt to get status */
armjtagew_get_status ( ) ;
}
return ERROR_OK ;
}
2009-11-21 03:56:02 +00:00
static const struct command_registration armjtagew_command_handlers [ ] = {
{
. name = " armjtagew_info " ,
. handler = & armjtagew_handle_armjtagew_info_command ,
. mode = COMMAND_EXEC ,
. help = " query armjtagew info " ,
} ,
COMMAND_REGISTRATION_DONE
} ;
2009-11-21 18:20:56 +00:00
struct jtag_interface armjtagew_interface = {
2010-01-03 21:07:18 +00:00
. name = " arm-jtag-ew " ,
. commands = armjtagew_command_handlers ,
2011-09-16 19:11:40 +00:00
. transports = jtag_only ,
2010-01-03 21:07:18 +00:00
. execute_queue = armjtagew_execute_queue ,
. speed = armjtagew_speed ,
2011-09-16 19:10:23 +00:00
. speed_div = armjtagew_speed_div ,
2010-01-03 21:07:18 +00:00
. khz = armjtagew_khz ,
. init = armjtagew_init ,
. quit = armjtagew_quit ,
} ;
2009-11-21 18:20:56 +00:00
2009-03-08 15:14:18 +00:00
/***************************************************************************/
/* ARM-JTAG-EW tap functions */
/* 2048 is the max value we can use here */
# define ARMJTAGEW_TAP_BUFFER_SIZE 2048
static int tap_length ;
2009-06-18 07:07:12 +00:00
static uint8_t tms_buffer [ ARMJTAGEW_TAP_BUFFER_SIZE ] ;
static uint8_t tdi_buffer [ ARMJTAGEW_TAP_BUFFER_SIZE ] ;
static uint8_t tdo_buffer [ ARMJTAGEW_TAP_BUFFER_SIZE ] ;
2009-03-08 15:14:18 +00:00
2009-11-13 12:50:26 +00:00
struct pending_scan_result {
2009-03-08 15:14:18 +00:00
int first ; /* First bit position in tdo_buffer to read */
int length ; /* Number of bits to read */
2009-11-13 13:30:28 +00:00
struct scan_command * command ; /* Corresponding scan command */
2009-06-18 07:07:12 +00:00
uint8_t * buffer ;
2009-11-13 12:50:26 +00:00
} ;
2009-03-08 15:14:18 +00:00
# define MAX_PENDING_SCAN_RESULTS 256
static int pending_scan_results_length ;
2009-11-13 12:50:26 +00:00
static struct pending_scan_result pending_scan_results_buffer [ MAX_PENDING_SCAN_RESULTS ] ;
2009-03-08 15:14:18 +00:00
static int last_tms ;
2009-04-21 05:29:23 +00:00
static void armjtagew_tap_init ( void )
2009-03-08 15:14:18 +00:00
{
tap_length = 0 ;
pending_scan_results_length = 0 ;
}
2009-04-21 05:29:23 +00:00
static void armjtagew_tap_ensure_space ( int scans , int bits )
2009-03-08 15:14:18 +00:00
{
int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length ;
int available_bits = ARMJTAGEW_TAP_BUFFER_SIZE * 8 - tap_length ;
if ( scans > available_scans | | bits > available_bits )
{
armjtagew_tap_execute ( ) ;
}
}
2009-04-21 05:29:23 +00:00
static void armjtagew_tap_append_step ( int tms , int tdi )
2009-03-08 15:14:18 +00:00
{
last_tms = tms ;
2010-06-19 09:12:12 +00:00
int index_local = tap_length / 8 ;
2009-03-08 15:14:18 +00:00
2010-06-19 09:12:12 +00:00
if ( index_local < ARMJTAGEW_TAP_BUFFER_SIZE )
2009-03-08 15:14:18 +00:00
{
int bit_index = tap_length % 8 ;
2009-06-18 07:07:12 +00:00
uint8_t bit = 1 < < bit_index ;
2009-03-08 15:14:18 +00:00
if ( tms )
{
2010-06-19 09:12:12 +00:00
tms_buffer [ index_local ] | = bit ;
2009-03-08 15:14:18 +00:00
}
else
{
2010-06-19 09:12:12 +00:00
tms_buffer [ index_local ] & = ~ bit ;
2009-03-08 15:14:18 +00:00
}
if ( tdi )
{
2010-06-19 09:12:12 +00:00
tdi_buffer [ index_local ] | = bit ;
2009-03-08 15:14:18 +00:00
}
else
{
2010-06-19 09:12:12 +00:00
tdi_buffer [ index_local ] & = ~ bit ;
2009-03-08 15:14:18 +00:00
}
tap_length + + ;
}
else
{
LOG_ERROR ( " armjtagew_tap_append_step, overflow " ) ;
}
}
2009-11-13 13:30:28 +00:00
void armjtagew_tap_append_scan ( int length , uint8_t * buffer , struct scan_command * command )
2009-03-08 15:14:18 +00:00
{
2009-11-13 12:50:26 +00:00
struct pending_scan_result * pending_scan_result = & pending_scan_results_buffer [ pending_scan_results_length ] ;
2009-03-08 15:14:18 +00:00
int i ;
pending_scan_result - > first = tap_length ;
pending_scan_result - > length = length ;
pending_scan_result - > command = command ;
pending_scan_result - > buffer = buffer ;
for ( i = 0 ; i < length ; i + + )
{
armjtagew_tap_append_step ( ( i < length - 1 ? 0 : 1 ) , ( buffer [ i / 8 ] > > ( i % 8 ) ) & 1 ) ;
}
pending_scan_results_length + + ;
}
/* Pad and send a tap sequence to the device, and receive the answer.
* For the purpose of padding we assume that we are in idle or pause state . */
2009-04-21 05:29:23 +00:00
static int armjtagew_tap_execute ( void )
2009-03-08 15:14:18 +00:00
{
int byte_length ;
int tms_offset ;
int tdi_offset ;
int i ;
int result ;
if ( tap_length > 0 )
{
/* Pad last byte so that tap_length is divisible by 8 */
while ( tap_length % 8 ! = 0 )
{
/* More of the last TMS value keeps us in the same state,
* analogous to free - running JTAG interfaces . */
armjtagew_tap_append_step ( last_tms , 0 ) ;
}
byte_length = tap_length / 8 ;
usb_out_buffer [ 0 ] = CMD_TAP_SHIFT ;
2009-06-23 22:44:17 +00:00
buf_set_u32 ( usb_out_buffer + 1 , 0 , 16 , byte_length ) ;
2009-03-08 15:14:18 +00:00
tms_offset = 3 ;
for ( i = 0 ; i < byte_length ; i + + )
{
usb_out_buffer [ tms_offset + i ] = flip_u32 ( tms_buffer [ i ] , 8 ) ;
}
tdi_offset = tms_offset + byte_length ;
for ( i = 0 ; i < byte_length ; i + + )
{
usb_out_buffer [ tdi_offset + i ] = flip_u32 ( tdi_buffer [ i ] , 8 ) ;
}
2009-11-13 12:33:32 +00:00
result = armjtagew_usb_message ( armjtagew_handle , 3 + 2 * byte_length , byte_length + 4 ) ;
2009-03-08 15:14:18 +00:00
if ( result = = 0 )
{
2010-06-17 18:30:23 +00:00
int stat_local ;
2009-03-08 15:14:18 +00:00
2010-06-17 18:30:23 +00:00
stat_local = ( int ) buf_get_u32 ( usb_in_buffer + byte_length , 0 , 32 ) ;
if ( stat_local ) {
LOG_ERROR ( " armjtagew_tap_execute, emulator returned error code %d for a CMD_TAP_SHIFT command " , stat_local ) ;
2009-03-08 15:14:18 +00:00
return ERROR_JTAG_QUEUE_FAILED ;
}
for ( i = 0 ; i < byte_length ; i + + )
{
tdo_buffer [ i ] = flip_u32 ( usb_in_buffer [ i ] , 8 ) ;
}
for ( i = 0 ; i < pending_scan_results_length ; i + + )
{
2009-11-13 12:50:26 +00:00
struct pending_scan_result * pending_scan_result = & pending_scan_results_buffer [ i ] ;
2009-06-18 07:07:12 +00:00
uint8_t * buffer = pending_scan_result - > buffer ;
2009-03-08 15:14:18 +00:00
int length = pending_scan_result - > length ;
int first = pending_scan_result - > first ;
2009-11-13 13:30:28 +00:00
struct scan_command * command = pending_scan_result - > command ;
2009-03-08 15:14:18 +00:00
/* Copy to buffer */
buf_set_buf ( tdo_buffer , first , buffer , 0 , length ) ;
DEBUG_JTAG_IO ( " pending scan result, length = %d " , length ) ;
# ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer ( buffer , byte_length ) ;
# endif
if ( jtag_read_buffer ( buffer , command ) ! = ERROR_OK )
{
armjtagew_tap_init ( ) ;
return ERROR_JTAG_QUEUE_FAILED ;
}
if ( pending_scan_result - > buffer ! = NULL )
{
free ( pending_scan_result - > buffer ) ;
}
}
}
else
{
LOG_ERROR ( " armjtagew_tap_execute, wrong result %d, expected %d " , result , byte_length ) ;
return ERROR_JTAG_QUEUE_FAILED ;
}
armjtagew_tap_init ( ) ;
}
return ERROR_OK ;
}
/*****************************************************************************/
/* JLink USB low-level functions */
2009-11-13 12:33:32 +00:00
static struct armjtagew * armjtagew_usb_open ( )
2009-03-08 15:14:18 +00:00
{
usb_init ( ) ;
2009-11-19 20:06:05 +00:00
const uint16_t vids [ ] = { USB_VID , 0 } ;
const uint16_t pids [ ] = { USB_PID , 0 } ;
struct usb_dev_handle * dev ;
if ( jtag_usb_open ( vids , pids , & dev ) ! = ERROR_OK )
return NULL ;
2009-03-08 15:14:18 +00:00
2009-11-19 20:06:05 +00:00
struct armjtagew * result = malloc ( sizeof ( struct armjtagew ) ) ;
result - > usb_handle = dev ;
2009-03-08 15:14:18 +00:00
#if 0
2009-11-19 20:06:05 +00:00
/* usb_set_configuration required under win32 */
usb_set_configuration ( dev , dev - > config [ 0 ] . bConfigurationValue ) ;
2009-03-08 15:14:18 +00:00
# endif
2009-11-19 20:06:05 +00:00
usb_claim_interface ( dev , 0 ) ;
2009-03-08 15:14:18 +00:00
#if 0
2009-11-19 20:06:05 +00:00
/*
* This makes problems under Mac OS X . And is not needed
* under Windows . Hopefully this will not break a linux build
*/
usb_set_altinterface ( dev , 0 ) ;
2009-03-08 15:14:18 +00:00
# endif
2009-11-19 20:06:05 +00:00
return result ;
2009-03-08 15:14:18 +00:00
}
2009-11-13 12:33:32 +00:00
static void armjtagew_usb_close ( struct armjtagew * armjtagew )
2009-03-08 15:14:18 +00:00
{
2009-11-13 12:33:32 +00:00
usb_close ( armjtagew - > usb_handle ) ;
free ( armjtagew ) ;
2009-03-08 15:14:18 +00:00
}
/* Send a message and receive the reply. */
2009-11-13 12:33:32 +00:00
static int armjtagew_usb_message ( struct armjtagew * armjtagew , int out_length , int in_length )
2009-03-08 15:14:18 +00:00
{
int result ;
2009-11-13 12:33:32 +00:00
result = armjtagew_usb_write ( armjtagew , out_length ) ;
2009-03-08 15:14:18 +00:00
if ( result = = out_length )
{
2009-11-13 12:33:32 +00:00
result = armjtagew_usb_read ( armjtagew , in_length ) ;
2009-06-04 00:56:41 +00:00
if ( result ! = in_length )
2009-03-08 15:14:18 +00:00
{
LOG_ERROR ( " usb_bulk_read failed (requested=%d, result=%d) " , in_length , result ) ;
return - 1 ;
}
}
else
{
LOG_ERROR ( " usb_bulk_write failed (requested=%d, result=%d) " , out_length , result ) ;
return - 1 ;
}
return 0 ;
}
/* Write data from out_buffer to USB. */
2009-11-13 12:33:32 +00:00
static int armjtagew_usb_write ( struct armjtagew * armjtagew , int out_length )
2009-03-08 15:14:18 +00:00
{
int result ;
if ( out_length > ARMJTAGEW_OUT_BUFFER_SIZE )
{
2009-11-13 12:33:32 +00:00
LOG_ERROR ( " armjtagew_write illegal out_length=%d (max=%d) " , out_length , ARMJTAGEW_OUT_BUFFER_SIZE ) ;
2009-03-08 15:14:18 +00:00
return - 1 ;
}
2009-11-13 12:33:32 +00:00
result = usb_bulk_write ( armjtagew - > usb_handle , ARMJTAGEW_EPT_BULK_OUT , \
2009-03-08 15:14:18 +00:00
( char * ) usb_out_buffer , out_length , ARMJTAGEW_USB_TIMEOUT ) ;
DEBUG_JTAG_IO ( " armjtagew_usb_write, out_length = %d, result = %d " , out_length , result ) ;
# ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer ( usb_out_buffer , out_length ) ;
# endif
return result ;
}
/* Read data from USB into in_buffer. */
2009-11-13 12:33:32 +00:00
static int armjtagew_usb_read ( struct armjtagew * armjtagew , int exp_in_length )
2009-03-08 15:14:18 +00:00
{
2009-11-13 12:33:32 +00:00
int result = usb_bulk_read ( armjtagew - > usb_handle , ARMJTAGEW_EPT_BULK_IN , \
2009-03-08 15:14:18 +00:00
( char * ) usb_in_buffer , exp_in_length , ARMJTAGEW_USB_TIMEOUT ) ;
DEBUG_JTAG_IO ( " armjtagew_usb_read, result = %d " , result ) ;
# ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer ( usb_in_buffer , result ) ;
# endif
return result ;
}
# ifdef _DEBUG_USB_COMMS_
# define BYTES_PER_LINE 16
2009-06-18 07:07:12 +00:00
static void armjtagew_debug_buffer ( uint8_t * buffer , int length )
2009-03-08 15:14:18 +00:00
{
char line [ 81 ] ;
char s [ 4 ] ;
int i ;
int j ;
for ( i = 0 ; i < length ; i + = BYTES_PER_LINE )
{
snprintf ( line , 5 , " %04x " , i ) ;
for ( j = i ; j < i + BYTES_PER_LINE & & j < length ; j + + )
{
snprintf ( s , 4 , " %02x " , buffer [ j ] ) ;
strcat ( line , s ) ;
}
2009-04-21 05:33:47 +00:00
LOG_DEBUG ( " %s " , line ) ;
2011-09-16 19:15:19 +00:00
// Prevent GDB timeout (writing to log might take some time)
keep_alive ( ) ;
2009-03-08 15:14:18 +00:00
}
}
# endif