2022-06-26 23:06:45 +00:00
/* SPDX-License-Identifier: GPL-2.0-or-later */
2016-01-30 05:23:49 +00:00
/***************************************************************************
* Copyright ( C ) 2007 by Juergen Stuber < juergen @ jstuber . net > *
* based on Dominic Rath ' s and Benedikt Sauter ' s usbprog . c *
* *
* Copyright ( C ) 2008 by Spencer Oliver *
* spen @ spen - soft . co . uk *
* *
* Copyright ( C ) 2011 by Jean - Christophe PLAGNIOL - VIILARD *
* plagnioj @ jcrosoft . com *
* *
* Copyright ( C ) 2015 by Marc Schink *
* openocd - dev @ marcschink . de *
* *
* Copyright ( C ) 2015 by Paul Fertser *
* fercerpav @ gmail . com *
* *
* Copyright ( C ) 2015 - 2017 by Forest Crossman *
* cyrozap @ gmail . com *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <stdint.h>
# include <hidapi.h>
# include <jtag/interface.h>
# include <jtag/swd.h>
# include <jtag/commands.h>
2020-02-05 15:07:48 +00:00
# include "libusb_helper.h"
2016-01-30 05:23:49 +00:00
# define VID 0x04b4
# define PID 0xf139
# define BULK_EP_IN 1
# define BULK_EP_OUT 2
# define CONTROL_TYPE_READ 0x01
# define CONTROL_TYPE_WRITE 0x02
# define CONTROL_COMMAND_PROGRAM 0x07
# define CONTROL_MODE_POLL_PROGRAMMER_STATUS 0x01
# define CONTROL_MODE_RESET_TARGET 0x04
# define CONTROL_MODE_SET_PROGRAMMER_PROTOCOL 0x40
# define CONTROL_MODE_SYNCHRONIZE_TRANSFER 0x41
# define CONTROL_MODE_ACQUIRE_SWD_TARGET 0x42
# define CONTROL_MODE_SEND_SWD_SEQUENCE 0x43
# define PROTOCOL_JTAG 0x00
# define PROTOCOL_SWD 0x01
# define DEVICE_PSOC4 0x00
# define DEVICE_PSOC3 0x01
# define DEVICE_UNKNOWN 0x02
# define DEVICE_PSOC5 0x03
# define ACQUIRE_MODE_RESET 0x00
# define ACQUIRE_MODE_POWER_CYCLE 0x01
# define SEQUENCE_LINE_RESET 0x00
# define SEQUENCE_JTAG_TO_SWD 0x01
# define PROGRAMMER_NOK_NACK 0x00
# define PROGRAMMER_OK_ACK 0x01
# define HID_TYPE_WRITE 0x00
# define HID_TYPE_READ 0x01
# define HID_TYPE_START 0x02
# define HID_COMMAND_POWER 0x80
# define HID_COMMAND_VERSION 0x81
# define HID_COMMAND_RESET 0x82
# define HID_COMMAND_CONFIGURE 0x8f
# define HID_COMMAND_BOOTLOADER 0xa0
2022-08-02 07:16:21 +00:00
/* 512 bytes seemed to work reliably.
* It works with both full queue of mostly reads or mostly writes .
*
* Unfortunately the commit 88f 429 ead019fd6df96ec15f0d897385f3cef0d0
* 5321 : target / cortex_m : faster reading of all CPU registers
* revealed a serious Kitprog firmware problem :
* If the queue contains more than 63 transactions in the repeated pattern
* one write , two reads , the firmware fails badly .
* Sending 64 transactions makes the adapter to loose the connection with the
* device . Sending 65 or more transactions causes the adapter to stop
* receiving USB HID commands , next kitprog_hid_command ( ) stops in hid_write ( ) .
*
* The problem was detected with KitProg v2 .12 and v2 .16 .
* We can guess the problem is something like a buffer or stack overflow .
*
* Use shorter buffer as a workaround . 300 bytes ( = 60 transactions ) works .
*/
# define SWD_MAX_BUFFER_LENGTH 300
2016-01-30 05:23:49 +00:00
struct kitprog {
hid_device * hid_handle ;
2020-02-05 14:50:31 +00:00
struct libusb_device_handle * usb_handle ;
2016-01-30 05:23:49 +00:00
uint16_t packet_size ;
uint16_t packet_index ;
uint8_t * packet_buffer ;
char * serial ;
uint8_t hardware_version ;
uint8_t minor_version ;
uint8_t major_version ;
uint16_t millivolts ;
bool supports_jtag_to_swd ;
} ;
struct pending_transfer_result {
uint8_t cmd ;
uint32_t data ;
void * buffer ;
} ;
static bool kitprog_init_acquire_psoc ;
static int pending_transfer_count , pending_queue_len ;
static struct pending_transfer_result * pending_transfers ;
static int queued_retval ;
static struct kitprog * kitprog_handle ;
static int kitprog_usb_open ( void ) ;
static void kitprog_usb_close ( void ) ;
static int kitprog_hid_command ( uint8_t * command , size_t command_length ,
uint8_t * data , size_t data_length ) ;
static int kitprog_get_version ( void ) ;
static int kitprog_get_millivolts ( void ) ;
static int kitprog_get_info ( void ) ;
static int kitprog_set_protocol ( uint8_t protocol ) ;
static int kitprog_get_status ( void ) ;
static int kitprog_set_unknown ( void ) ;
static int kitprog_acquire_psoc ( uint8_t psoc_type , uint8_t acquire_mode ,
uint8_t max_attempts ) ;
static int kitprog_reset_target ( void ) ;
static int kitprog_swd_sync ( void ) ;
static int kitprog_swd_seq ( uint8_t seq_type ) ;
static int kitprog_generic_acquire ( void ) ;
static int kitprog_swd_run_queue ( void ) ;
static void kitprog_swd_queue_cmd ( uint8_t cmd , uint32_t * dst , uint32_t data ) ;
static int kitprog_swd_switch_seq ( enum swd_special_seq seq ) ;
static inline int mm_to_version ( uint8_t major , uint8_t minor )
{
return ( major < < 8 ) | minor ;
}
static int kitprog_init ( void )
{
int retval ;
kitprog_handle = malloc ( sizeof ( struct kitprog ) ) ;
2021-07-03 16:51:20 +00:00
if ( ! kitprog_handle ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to allocate memory " ) ;
return ERROR_FAIL ;
}
if ( kitprog_usb_open ( ) ! = ERROR_OK ) {
LOG_ERROR ( " Can't find a KitProg device! Please check device connections and permissions. " ) ;
return ERROR_JTAG_INIT_FAILED ;
}
/* Get the current KitProg version and target voltage */
if ( kitprog_get_info ( ) ! = ERROR_OK )
return ERROR_FAIL ;
/* Compatibility check */
kitprog_handle - > supports_jtag_to_swd = true ;
int kitprog_version = mm_to_version ( kitprog_handle - > major_version , kitprog_handle - > minor_version ) ;
if ( kitprog_version < mm_to_version ( 2 , 14 ) ) {
LOG_WARNING ( " KitProg firmware versions below v2.14 do not support sending JTAG to SWD sequences. These sequences will be substituted with SWD line resets. " ) ;
kitprog_handle - > supports_jtag_to_swd = false ;
}
/* I have no idea what this does */
if ( kitprog_set_unknown ( ) ! = ERROR_OK )
return ERROR_FAIL ;
/* SWD won't work unless we do this */
if ( kitprog_swd_sync ( ) ! = ERROR_OK )
return ERROR_FAIL ;
/* Set the protocol to SWD */
if ( kitprog_set_protocol ( PROTOCOL_SWD ) ! = ERROR_OK )
return ERROR_FAIL ;
/* Reset the SWD bus */
if ( kitprog_swd_seq ( SEQUENCE_LINE_RESET ) ! = ERROR_OK )
return ERROR_FAIL ;
if ( kitprog_init_acquire_psoc ) {
/* Try to acquire any device that will respond */
retval = kitprog_generic_acquire ( ) ;
if ( retval ! = ERROR_OK ) {
LOG_ERROR ( " No PSoC devices found " ) ;
return retval ;
}
}
/* Allocate packet buffers and queues */
kitprog_handle - > packet_size = SWD_MAX_BUFFER_LENGTH ;
kitprog_handle - > packet_buffer = malloc ( SWD_MAX_BUFFER_LENGTH ) ;
2021-07-03 16:51:20 +00:00
if ( ! kitprog_handle - > packet_buffer ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to allocate memory for the packet buffer " ) ;
return ERROR_FAIL ;
}
pending_queue_len = SWD_MAX_BUFFER_LENGTH / 5 ;
pending_transfers = malloc ( pending_queue_len * sizeof ( * pending_transfers ) ) ;
2021-07-03 16:51:20 +00:00
if ( ! pending_transfers ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to allocate memory for the SWD transfer queue " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_quit ( void )
{
kitprog_usb_close ( ) ;
2020-08-17 08:05:11 +00:00
free ( kitprog_handle - > packet_buffer ) ;
free ( kitprog_handle - > serial ) ;
free ( kitprog_handle ) ;
free ( pending_transfers ) ;
2016-01-30 05:23:49 +00:00
return ERROR_OK ;
}
/*************** kitprog usb functions *********************/
static int kitprog_get_usb_serial ( void )
{
int retval ;
const uint8_t str_index = 128 ; /* This seems to be a constant */
char desc_string [ 256 + 1 ] ; /* Max size of string descriptor */
retval = libusb_get_string_descriptor_ascii ( kitprog_handle - > usb_handle ,
str_index , ( unsigned char * ) desc_string , sizeof ( desc_string ) - 1 ) ;
if ( retval < 0 ) {
LOG_ERROR ( " libusb_get_string_descriptor_ascii() failed with %d " , retval ) ;
return ERROR_FAIL ;
}
/* Null terminate descriptor string */
desc_string [ retval ] = ' \0 ' ;
/* Allocate memory for the serial number */
kitprog_handle - > serial = calloc ( retval + 1 , sizeof ( char ) ) ;
2021-07-03 16:51:20 +00:00
if ( ! kitprog_handle - > serial ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to allocate memory for the serial number " ) ;
return ERROR_FAIL ;
}
/* Store the serial number */
strncpy ( kitprog_handle - > serial , desc_string , retval + 1 ) ;
return ERROR_OK ;
}
static int kitprog_usb_open ( void )
{
const uint16_t vids [ ] = { VID , 0 } ;
const uint16_t pids [ ] = { PID , 0 } ;
2021-10-19 11:09:25 +00:00
if ( jtag_libusb_open ( vids , pids , & kitprog_handle - > usb_handle , NULL ) ! = ERROR_OK ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to open or find the device " ) ;
return ERROR_FAIL ;
}
/* Get the serial number for the device */
if ( kitprog_get_usb_serial ( ) ! = ERROR_OK )
LOG_WARNING ( " Failed to get KitProg serial number " ) ;
/* Convert the ASCII serial number into a (wchar_t *) */
size_t len = strlen ( kitprog_handle - > serial ) ;
wchar_t * hid_serial = calloc ( len + 1 , sizeof ( wchar_t ) ) ;
2021-07-03 16:51:20 +00:00
if ( ! hid_serial ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to allocate memory for the serial number " ) ;
return ERROR_FAIL ;
}
if ( mbstowcs ( hid_serial , kitprog_handle - > serial , len + 1 ) = = ( size_t ) - 1 ) {
free ( hid_serial ) ;
LOG_ERROR ( " Failed to convert serial number " ) ;
return ERROR_FAIL ;
}
/* Use HID for the KitBridge interface */
kitprog_handle - > hid_handle = hid_open ( VID , PID , hid_serial ) ;
free ( hid_serial ) ;
2021-07-03 16:51:20 +00:00
if ( ! kitprog_handle - > hid_handle ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to open KitBridge (HID) interface " ) ;
return ERROR_FAIL ;
}
/* Claim the KitProg Programmer (bulk transfer) interface */
2020-02-05 14:50:31 +00:00
if ( libusb_claim_interface ( kitprog_handle - > usb_handle , 1 ) ! = ERROR_OK ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Failed to claim KitProg Programmer (bulk transfer) interface " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static void kitprog_usb_close ( void )
{
2021-07-03 16:51:20 +00:00
if ( kitprog_handle - > hid_handle ) {
2016-01-30 05:23:49 +00:00
hid_close ( kitprog_handle - > hid_handle ) ;
hid_exit ( ) ;
}
jtag_libusb_close ( kitprog_handle - > usb_handle ) ;
}
/*************** kitprog lowlevel functions *********************/
static int kitprog_hid_command ( uint8_t * command , size_t command_length ,
uint8_t * data , size_t data_length )
{
int ret ;
ret = hid_write ( kitprog_handle - > hid_handle , command , command_length ) ;
if ( ret < 0 ) {
LOG_DEBUG ( " HID write returned %i " , ret ) ;
return ERROR_FAIL ;
}
2022-08-01 21:16:47 +00:00
ret = hid_read_timeout ( kitprog_handle - > hid_handle ,
data , data_length , LIBUSB_TIMEOUT_MS ) ;
if ( ret = = 0 ) {
LOG_ERROR ( " HID read timed out " ) ;
return ERROR_TIMEOUT_REACHED ;
} else if ( ret < 0 ) {
LOG_ERROR ( " HID read error %ls " , hid_error ( kitprog_handle - > hid_handle ) ) ;
2016-01-30 05:23:49 +00:00
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_get_version ( void )
{
int ret ;
unsigned char command [ 3 ] = { HID_TYPE_START | HID_TYPE_WRITE , 0x00 , HID_COMMAND_VERSION } ;
unsigned char data [ 64 ] ;
2019-05-05 22:35:52 +00:00
ret = kitprog_hid_command ( command , sizeof ( command ) , data , sizeof ( data ) ) ;
2016-01-30 05:23:49 +00:00
if ( ret ! = ERROR_OK )
return ret ;
kitprog_handle - > hardware_version = data [ 1 ] ;
kitprog_handle - > minor_version = data [ 2 ] ;
kitprog_handle - > major_version = data [ 3 ] ;
return ERROR_OK ;
}
static int kitprog_get_millivolts ( void )
{
int ret ;
unsigned char command [ 3 ] = { HID_TYPE_START | HID_TYPE_READ , 0x00 , HID_COMMAND_POWER } ;
unsigned char data [ 64 ] ;
2019-05-05 22:35:52 +00:00
ret = kitprog_hid_command ( command , sizeof ( command ) , data , sizeof ( data ) ) ;
2016-01-30 05:23:49 +00:00
if ( ret ! = ERROR_OK )
return ret ;
kitprog_handle - > millivolts = ( data [ 4 ] < < 8 ) | data [ 3 ] ;
return ERROR_OK ;
}
static int kitprog_get_info ( void )
{
/* Get the device version information */
if ( kitprog_get_version ( ) = = ERROR_OK ) {
LOG_INFO ( " KitProg v%u.%02u " ,
kitprog_handle - > major_version , kitprog_handle - > minor_version ) ;
LOG_INFO ( " Hardware version: %u " ,
kitprog_handle - > hardware_version ) ;
} else {
LOG_ERROR ( " Failed to get KitProg version " ) ;
return ERROR_FAIL ;
}
/* Get the current reported target voltage */
if ( kitprog_get_millivolts ( ) = = ERROR_OK ) {
LOG_INFO ( " VTARG = %u.%03u V " ,
kitprog_handle - > millivolts / 1000 , kitprog_handle - > millivolts % 1000 ) ;
} else {
LOG_ERROR ( " Failed to get target voltage " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_set_protocol ( uint8_t protocol )
{
int transferred ;
char status = PROGRAMMER_NOK_NACK ;
transferred = jtag_libusb_control_transfer ( kitprog_handle - > usb_handle ,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE ,
CONTROL_TYPE_WRITE ,
( CONTROL_MODE_SET_PROGRAMMER_PROTOCOL < < 8 ) | CONTROL_COMMAND_PROGRAM ,
protocol , & status , 1 , 0 ) ;
if ( transferred = = 0 ) {
LOG_DEBUG ( " Zero bytes transferred " ) ;
return ERROR_FAIL ;
}
if ( status ! = PROGRAMMER_OK_ACK ) {
LOG_DEBUG ( " Programmer did not respond OK " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_get_status ( void )
{
int transferred = 0 ;
char status = PROGRAMMER_NOK_NACK ;
/* Try a maximum of three times */
for ( int i = 0 ; ( i < 3 ) & & ( transferred = = 0 ) ; i + + ) {
transferred = jtag_libusb_control_transfer ( kitprog_handle - > usb_handle ,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE ,
CONTROL_TYPE_READ ,
( CONTROL_MODE_POLL_PROGRAMMER_STATUS < < 8 ) | CONTROL_COMMAND_PROGRAM ,
0 , & status , 1 , 0 ) ;
jtag_sleep ( 1000 ) ;
}
if ( transferred = = 0 ) {
LOG_DEBUG ( " Zero bytes transferred " ) ;
return ERROR_FAIL ;
}
if ( status ! = PROGRAMMER_OK_ACK ) {
LOG_DEBUG ( " Programmer did not respond OK " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_set_unknown ( void )
{
int transferred ;
char status = PROGRAMMER_NOK_NACK ;
transferred = jtag_libusb_control_transfer ( kitprog_handle - > usb_handle ,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE ,
CONTROL_TYPE_WRITE ,
( 0x03 < < 8 ) | 0x04 ,
0 , & status , 1 , 0 ) ;
if ( transferred = = 0 ) {
LOG_DEBUG ( " Zero bytes transferred " ) ;
return ERROR_FAIL ;
}
if ( status ! = PROGRAMMER_OK_ACK ) {
LOG_DEBUG ( " Programmer did not respond OK " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_acquire_psoc ( uint8_t psoc_type , uint8_t acquire_mode ,
uint8_t max_attempts )
{
int transferred ;
char status = PROGRAMMER_NOK_NACK ;
transferred = jtag_libusb_control_transfer ( kitprog_handle - > usb_handle ,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE ,
CONTROL_TYPE_WRITE ,
( CONTROL_MODE_ACQUIRE_SWD_TARGET < < 8 ) | CONTROL_COMMAND_PROGRAM ,
( max_attempts < < 8 ) | ( acquire_mode < < 4 ) | psoc_type , & status , 1 , 0 ) ;
if ( transferred = = 0 ) {
LOG_DEBUG ( " Zero bytes transferred " ) ;
return ERROR_FAIL ;
}
if ( status ! = PROGRAMMER_OK_ACK ) {
LOG_DEBUG ( " Programmer did not respond OK " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_reset_target ( void )
{
int transferred ;
char status = PROGRAMMER_NOK_NACK ;
transferred = jtag_libusb_control_transfer ( kitprog_handle - > usb_handle ,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE ,
CONTROL_TYPE_WRITE ,
( CONTROL_MODE_RESET_TARGET < < 8 ) | CONTROL_COMMAND_PROGRAM ,
0 , & status , 1 , 0 ) ;
if ( transferred = = 0 ) {
LOG_DEBUG ( " Zero bytes transferred " ) ;
return ERROR_FAIL ;
}
if ( status ! = PROGRAMMER_OK_ACK ) {
LOG_DEBUG ( " Programmer did not respond OK " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_swd_sync ( void )
{
int transferred ;
char status = PROGRAMMER_NOK_NACK ;
transferred = jtag_libusb_control_transfer ( kitprog_handle - > usb_handle ,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE ,
CONTROL_TYPE_WRITE ,
( CONTROL_MODE_SYNCHRONIZE_TRANSFER < < 8 ) | CONTROL_COMMAND_PROGRAM ,
0 , & status , 1 , 0 ) ;
if ( transferred = = 0 ) {
LOG_DEBUG ( " Zero bytes transferred " ) ;
return ERROR_FAIL ;
}
if ( status ! = PROGRAMMER_OK_ACK ) {
LOG_DEBUG ( " Programmer did not respond OK " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_swd_seq ( uint8_t seq_type )
{
int transferred ;
char status = PROGRAMMER_NOK_NACK ;
transferred = jtag_libusb_control_transfer ( kitprog_handle - > usb_handle ,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE ,
CONTROL_TYPE_WRITE ,
( CONTROL_MODE_SEND_SWD_SEQUENCE < < 8 ) | CONTROL_COMMAND_PROGRAM ,
seq_type , & status , 1 , 0 ) ;
if ( transferred = = 0 ) {
LOG_DEBUG ( " Zero bytes transferred " ) ;
return ERROR_FAIL ;
}
if ( status ! = PROGRAMMER_OK_ACK ) {
LOG_DEBUG ( " Programmer did not respond OK " ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_generic_acquire ( void )
{
const uint8_t devices [ ] = { DEVICE_PSOC4 , DEVICE_PSOC3 , DEVICE_PSOC5 } ;
int retval ;
int acquire_count = 0 ;
/* Due to the way the SWD port is shared between the Test Controller (TC)
* and the Cortex - M3 DAP on the PSoC 5L P , the TC is the default SWD target
* after power is applied . To access the DAP , the PSoC 5L P requires at least
* one acquisition sequence to be run ( which switches the SWD mux from the
* TC to the DAP ) . However , after the mux is switched , the Cortex - M3 will be
* held in reset until a series of registers are written to ( see section 5.2
* of the PSoC 5L P Device Programming Specifications for details ) .
*
* Instead of writing the registers in this function , we just do what the
* Cypress tools do and run the acquisition sequence a second time . This
* will take the Cortex - M3 out of reset and enable debugging .
*/
for ( int i = 0 ; i < 2 ; i + + ) {
2019-05-05 22:35:52 +00:00
for ( uint8_t j = 0 ; j < sizeof ( devices ) & & acquire_count = = i ; j + + ) {
2016-01-30 05:23:49 +00:00
retval = kitprog_acquire_psoc ( devices [ j ] , ACQUIRE_MODE_RESET , 3 ) ;
if ( retval ! = ERROR_OK ) {
2020-07-12 21:40:41 +00:00
LOG_DEBUG ( " Acquisition function failed for device 0x%02x. " , devices [ j ] ) ;
2016-01-30 05:23:49 +00:00
return retval ;
}
if ( kitprog_get_status ( ) = = ERROR_OK )
acquire_count + + ;
}
jtag_sleep ( 10 ) ;
}
if ( acquire_count < 2 )
return ERROR_FAIL ;
return ERROR_OK ;
}
/*************** swd wrapper functions *********************/
static int kitprog_swd_init ( void )
{
return ERROR_OK ;
}
static void kitprog_swd_write_reg ( uint8_t cmd , uint32_t value , uint32_t ap_delay_clk )
{
2021-06-06 15:20:10 +00:00
assert ( ! ( cmd & SWD_CMD_RNW ) ) ;
2016-01-30 05:23:49 +00:00
kitprog_swd_queue_cmd ( cmd , NULL , value ) ;
}
static void kitprog_swd_read_reg ( uint8_t cmd , uint32_t * value , uint32_t ap_delay_clk )
{
2021-06-06 15:20:10 +00:00
assert ( cmd & SWD_CMD_RNW ) ;
2016-01-30 05:23:49 +00:00
kitprog_swd_queue_cmd ( cmd , value , 0 ) ;
}
/*************** swd lowlevel functions ********************/
static int kitprog_swd_switch_seq ( enum swd_special_seq seq )
{
switch ( seq ) {
case JTAG_TO_SWD :
if ( kitprog_handle - > supports_jtag_to_swd ) {
LOG_DEBUG ( " JTAG to SWD " ) ;
if ( kitprog_swd_seq ( SEQUENCE_JTAG_TO_SWD ) ! = ERROR_OK )
return ERROR_FAIL ;
break ;
} else {
LOG_DEBUG ( " JTAG to SWD not supported " ) ;
/* Fall through to fix target reset issue */
}
2017-06-29 21:48:19 +00:00
/* fallthrough */
2016-01-30 05:23:49 +00:00
case LINE_RESET :
LOG_DEBUG ( " SWD line reset " ) ;
if ( kitprog_swd_seq ( SEQUENCE_LINE_RESET ) ! = ERROR_OK )
return ERROR_FAIL ;
break ;
default :
LOG_ERROR ( " Sequence %d not supported. " , seq ) ;
return ERROR_FAIL ;
}
return ERROR_OK ;
}
static int kitprog_swd_run_queue ( void )
{
int ret ;
size_t read_count = 0 ;
size_t read_index = 0 ;
size_t write_count = 0 ;
uint8_t * buffer = kitprog_handle - > packet_buffer ;
do {
2018-01-06 04:11:38 +00:00
LOG_DEBUG_IO ( " Executing %d queued transactions " , pending_transfer_count ) ;
2016-01-30 05:23:49 +00:00
if ( queued_retval ! = ERROR_OK ) {
LOG_DEBUG ( " Skipping due to previous errors: %d " , queued_retval ) ;
break ;
}
if ( ! pending_transfer_count )
break ;
for ( int i = 0 ; i < pending_transfer_count ; i + + ) {
uint8_t cmd = pending_transfers [ i ] . cmd ;
uint32_t data = pending_transfers [ i ] . data ;
/* When proper WAIT handling is implemented in the
* common SWD framework , this kludge can be
* removed . However , this might lead to minor
* performance degradation as the adapter wouldn ' t be
* able to automatically retry anything ( because ARM
* has forgotten to implement sticky error flags
* clearing ) . See also comments regarding
* cmsis_dap_cmd_DAP_TFER_Configure ( ) and
* cmsis_dap_cmd_DAP_SWD_Configure ( ) in
* cmsis_dap_init ( ) .
*/
2021-06-06 15:20:10 +00:00
if ( ! ( cmd & SWD_CMD_RNW ) & &
! ( cmd & SWD_CMD_APNDP ) & &
2016-01-30 05:23:49 +00:00
( cmd & SWD_CMD_A32 ) > > 1 = = DP_CTRL_STAT & &
( data & CORUNDETECT ) ) {
LOG_DEBUG ( " refusing to enable sticky overrun detection " ) ;
data & = ~ CORUNDETECT ;
}
2018-01-06 04:11:38 +00:00
LOG_DEBUG_IO ( " %s %s reg %x % " PRIx32 ,
2021-06-06 15:20:10 +00:00
cmd & SWD_CMD_APNDP ? " AP " : " DP " ,
cmd & SWD_CMD_RNW ? " read " : " write " ,
2016-01-30 05:23:49 +00:00
( cmd & SWD_CMD_A32 ) > > 1 , data ) ;
buffer [ write_count + + ] = ( cmd | SWD_CMD_START | SWD_CMD_PARK ) & ~ SWD_CMD_STOP ;
read_count + + ;
2021-06-06 15:20:10 +00:00
if ( ! ( cmd & SWD_CMD_RNW ) ) {
2016-01-30 05:23:49 +00:00
buffer [ write_count + + ] = ( data ) & 0xff ;
buffer [ write_count + + ] = ( data > > 8 ) & 0xff ;
buffer [ write_count + + ] = ( data > > 16 ) & 0xff ;
buffer [ write_count + + ] = ( data > > 24 ) & 0xff ;
} else {
read_count + = 4 ;
}
}
2018-07-05 11:42:14 +00:00
if ( jtag_libusb_bulk_write ( kitprog_handle - > usb_handle ,
BULK_EP_OUT , ( char * ) buffer ,
write_count , 0 , & ret ) ) {
2016-01-30 05:23:49 +00:00
LOG_ERROR ( " Bulk write failed " ) ;
queued_retval = ERROR_FAIL ;
break ;
2018-07-05 11:42:14 +00:00
} else {
queued_retval = ERROR_OK ;
2016-01-30 05:23:49 +00:00
}
2018-02-21 21:19:58 +00:00
/* KitProg firmware does not send a zero length packet
* after the bulk - in transmission of a length divisible by bulk packet
* size ( 64 bytes ) as required by the USB specification .
* Therefore libusb would wait for continuation of transmission .
* Workaround : Limit bulk read size to expected number of bytes
2020-07-12 21:40:41 +00:00
* for problematic transfer sizes . Otherwise use the maximum buffer
2018-02-21 21:19:58 +00:00
* size here because the KitProg sometimes doesn ' t like bulk reads
* of fewer than 62 bytes . ( ? ! ? ! )
2016-01-30 05:23:49 +00:00
*/
2018-02-21 21:19:58 +00:00
size_t read_count_workaround = SWD_MAX_BUFFER_LENGTH ;
if ( read_count % 64 = = 0 )
read_count_workaround = read_count ;
2018-07-05 11:42:14 +00:00
if ( jtag_libusb_bulk_read ( kitprog_handle - > usb_handle ,
2016-01-30 05:23:49 +00:00
BULK_EP_IN | LIBUSB_ENDPOINT_IN , ( char * ) buffer ,
2018-07-05 11:42:14 +00:00
read_count_workaround , 1000 , & ret ) ) {
LOG_ERROR ( " Bulk read failed " ) ;
queued_retval = ERROR_FAIL ;
break ;
} else {
2016-01-30 05:23:49 +00:00
/* Handle garbage data by offsetting the initial read index */
if ( ( unsigned int ) ret > read_count )
read_index = ret - read_count ;
queued_retval = ERROR_OK ;
}
for ( int i = 0 ; i < pending_transfer_count ; i + + ) {
2021-06-06 15:20:10 +00:00
if ( pending_transfers [ i ] . cmd & SWD_CMD_RNW ) {
2016-01-30 05:23:49 +00:00
uint32_t data = le_to_h_u32 ( & buffer [ read_index ] ) ;
2018-01-06 04:11:38 +00:00
LOG_DEBUG_IO ( " Read result: % " PRIx32 , data ) ;
2016-01-30 05:23:49 +00:00
if ( pending_transfers [ i ] . buffer )
* ( uint32_t * ) pending_transfers [ i ] . buffer = data ;
read_index + = 4 ;
}
uint8_t ack = buffer [ read_index ] & 0x07 ;
if ( ack ! = SWD_ACK_OK | | ( buffer [ read_index ] & 0x08 ) ) {
LOG_DEBUG ( " SWD ack not OK: %d %s " , i ,
ack = = SWD_ACK_WAIT ? " WAIT " : ack = = SWD_ACK_FAULT ? " FAULT " : " JUNK " ) ;
queued_retval = ack = = SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL ;
break ;
}
read_index + + ;
}
} while ( 0 ) ;
pending_transfer_count = 0 ;
int retval = queued_retval ;
queued_retval = ERROR_OK ;
return retval ;
}
static void kitprog_swd_queue_cmd ( uint8_t cmd , uint32_t * dst , uint32_t data )
{
if ( pending_transfer_count = = pending_queue_len ) {
/* Not enough room in the queue. Run the queue. */
queued_retval = kitprog_swd_run_queue ( ) ;
}
if ( queued_retval ! = ERROR_OK )
return ;
pending_transfers [ pending_transfer_count ] . data = data ;
pending_transfers [ pending_transfer_count ] . cmd = cmd ;
2021-06-06 15:20:10 +00:00
if ( cmd & SWD_CMD_RNW ) {
2016-01-30 05:23:49 +00:00
/* Queue a read transaction */
pending_transfers [ pending_transfer_count ] . buffer = dst ;
}
pending_transfer_count + + ;
}
/*************** jtag lowlevel functions ********************/
2019-08-31 09:08:16 +00:00
static int kitprog_reset ( int trst , int srst )
2016-01-30 05:23:49 +00:00
{
int retval = ERROR_OK ;
2019-08-31 09:08:16 +00:00
if ( trst = = 1 ) {
LOG_ERROR ( " KitProg: Interface has no TRST " ) ;
return ERROR_FAIL ;
}
if ( srst = = 1 ) {
2016-01-30 05:23:49 +00:00
retval = kitprog_reset_target ( ) ;
/* Since the previous command also disables SWCLK output, we need to send an
* SWD bus reset command to re - enable it . For some reason , running
* kitprog_swd_seq ( ) immediately after kitprog_reset_target ( ) won ' t
* actually fix this . Instead , kitprog_swd_seq ( ) will be run once OpenOCD
* tries to send a JTAG - to - SWD sequence , which should happen during
* swd_check_reconnect ( see the JTAG_TO_SWD case in kitprog_swd_switch_seq ) .
*/
}
if ( retval ! = ERROR_OK )
LOG_ERROR ( " KitProg: Interface reset failed " ) ;
2019-08-31 09:08:16 +00:00
return retval ;
2016-01-30 05:23:49 +00:00
}
COMMAND_HANDLER ( kitprog_handle_info_command )
{
int retval = kitprog_get_info ( ) ;
return retval ;
}
COMMAND_HANDLER ( kitprog_handle_acquire_psoc_command )
{
int retval = kitprog_generic_acquire ( ) ;
return retval ;
}
COMMAND_HANDLER ( kitprog_handle_init_acquire_psoc_command )
{
kitprog_init_acquire_psoc = true ;
return ERROR_OK ;
}
static const struct command_registration kitprog_subcommand_handlers [ ] = {
{
. name = " info " ,
. handler = & kitprog_handle_info_command ,
. mode = COMMAND_EXEC ,
. usage = " " ,
. help = " show KitProg info " ,
} ,
{
. name = " acquire_psoc " ,
. handler = & kitprog_handle_acquire_psoc_command ,
. mode = COMMAND_EXEC ,
. usage = " " ,
. help = " try to acquire a PSoC " ,
} ,
COMMAND_REGISTRATION_DONE
} ;
static const struct command_registration kitprog_command_handlers [ ] = {
{
. name = " kitprog " ,
. mode = COMMAND_ANY ,
. help = " perform KitProg management " ,
. usage = " <cmd> " ,
. chain = kitprog_subcommand_handlers ,
} ,
{
. name = " kitprog_init_acquire_psoc " ,
. handler = & kitprog_handle_init_acquire_psoc_command ,
. mode = COMMAND_CONFIG ,
. help = " try to acquire a PSoC during init " ,
. usage = " " ,
} ,
COMMAND_REGISTRATION_DONE
} ;
static const struct swd_driver kitprog_swd = {
. init = kitprog_swd_init ,
. switch_seq = kitprog_swd_switch_seq ,
. read_reg = kitprog_swd_read_reg ,
. write_reg = kitprog_swd_write_reg ,
. run = kitprog_swd_run_queue ,
} ;
static const char * const kitprog_transports [ ] = { " swd " , NULL } ;
2019-01-22 15:31:18 +00:00
struct adapter_driver kitprog_adapter_driver = {
2016-01-30 05:23:49 +00:00
. name = " kitprog " ,
. transports = kitprog_transports ,
2019-01-22 15:31:18 +00:00
. commands = kitprog_command_handlers ,
2016-01-30 05:23:49 +00:00
. init = kitprog_init ,
2019-08-31 09:08:16 +00:00
. quit = kitprog_quit ,
. reset = kitprog_reset ,
2019-01-22 15:31:18 +00:00
. swd_ops = & kitprog_swd ,
2016-01-30 05:23:49 +00:00
} ;