X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fcmsis_dap_usb.c;h=9e723b51d103ffe8c62bdd67166ac0b421fd972b;hp=a07064be5d904e80fcfdf2c9d17906de087d8b27;hb=06589d2de48556f5216e3e671e656f4fd9069b43;hpb=e3ccae3ed72b47e353fc97d11318a580dadcb7d9 diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index a07064be5d..9e723b51d1 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -118,6 +118,13 @@ static bool swd_mode; * Bit 7: nRESET */ +#define SWJ_PIN_TCK (1<<0) +#define SWJ_PIN_TMS (1<<1) +#define SWJ_PIN_TDI (1<<2) +#define SWJ_PIN_TDO (1<<3) +#define SWJ_PIN_TRST (1<<5) +#define SWJ_PIN_SRST (1<<7) + /* CMSIS-DAP SWD Commands */ #define CMD_DAP_SWD_CONFIGURE 0x13 @@ -199,6 +206,8 @@ static uint8_t queued_seq_buf[1024]; /* TODO: make dynamic / move into cmsis obj static int queued_retval; +static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST; + static struct cmsis_dap *cmsis_dap_handle; static int cmsis_dap_usb_open(void) @@ -309,9 +318,11 @@ static int cmsis_dap_usb_open(void) int packet_size = PACKET_SIZE; /* atmel cmsis-dap uses 512 byte reports */ + /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained + * board */ /* TODO: HID report descriptor should be parsed instead of * hardcoding a match by VID */ - if (target_vid == 0x03eb) + if (target_vid == 0x03eb && target_pid != 0x2145) packet_size = 512 + 1; cmsis_dap_handle->packet_buffer = malloc(packet_size); @@ -587,7 +598,7 @@ static int cmsis_dap_swd_run_queue(void) { uint8_t *buffer = cmsis_dap_handle->packet_buffer; - LOG_DEBUG("Executing %d queued transactions", pending_transfer_count); + LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); @@ -607,7 +618,7 @@ static int cmsis_dap_swd_run_queue(void) uint8_t cmd = pending_transfers[i].cmd; uint32_t data = pending_transfers[i].data; - LOG_DEBUG("%s %s reg %x %"PRIx32, + LOG_DEBUG_IO("%s %s reg %x %"PRIx32, cmd & SWD_CMD_APnDP ? "AP" : "DP", cmd & SWD_CMD_RnW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); @@ -665,7 +676,7 @@ static int cmsis_dap_swd_run_queue(void) uint32_t tmp = data; idx += 4; - LOG_DEBUG("Read result: %"PRIx32, data); + LOG_DEBUG_IO("Read result: %"PRIx32, data); /* Imitate posted AP reads */ if ((pending_transfers[i].cmd & SWD_CMD_APnDP) || @@ -718,6 +729,20 @@ static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del cmsis_dap_swd_queue_cmd(cmd, value, 0); } +static int cmsis_dap_get_serial_info(void) +{ + uint8_t *data; + + int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data); + if (retval != ERROR_OK) + return retval; + + if (data[0]) /* strlen */ + LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]); + + return ERROR_OK; +} + static int cmsis_dap_get_version_info(void) { uint8_t *data; @@ -764,12 +789,12 @@ static int cmsis_dap_get_status(void) if (retval == ERROR_OK) { LOG_INFO("SWCLK/TCK = %d SWDIO/TMS = %d TDI = %d TDO = %d nTRST = %d nRESET = %d", - (d & (0x01 << 0)) ? 1 : 0, /* Bit 0: SWCLK/TCK */ - (d & (0x01 << 1)) ? 1 : 0, /* Bit 1: SWDIO/TMS */ - (d & (0x01 << 2)) ? 1 : 0, /* Bit 2: TDI */ - (d & (0x01 << 3)) ? 1 : 0, /* Bit 3: TDO */ - (d & (0x01 << 5)) ? 1 : 0, /* Bit 5: nTRST */ - (d & (0x01 << 7)) ? 1 : 0); /* Bit 7: nRESET */ + (d & SWJ_PIN_TCK) ? 1 : 0, + (d & SWJ_PIN_TMS) ? 1 : 0, + (d & SWJ_PIN_TDI) ? 1 : 0, + (d & SWJ_PIN_TDO) ? 1 : 0, + (d & SWJ_PIN_TRST) ? 1 : 0, + (d & SWJ_PIN_SRST) ? 1 : 0); } return retval; @@ -781,15 +806,20 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) unsigned int s_len; int retval; - /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */ - cmsis_dap_cmd_DAP_Disconnect(); + if ((output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) == (SWJ_PIN_SRST | SWJ_PIN_TRST)) { + /* Following workaround deasserts reset on most adapters. + * Do not reconnect if a reset line is active! + * Reconnecting would break connecting under reset. */ - /* When we are reconnecting, DAP_Connect needs to be rerun, at - * least on Keil ULINK-ME */ - retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ? - CONNECT_SWD : CONNECT_JTAG); - if (retval != ERROR_OK) - return retval; + /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */ + cmsis_dap_cmd_DAP_Disconnect(); + + /* When we are reconnecting, DAP_Connect needs to be rerun, at + * least on Keil ULINK-ME */ + retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD); + if (retval != ERROR_OK) + return retval; + } switch (seq) { case LINE_RESET: @@ -812,24 +842,19 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) return ERROR_FAIL; } - return cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s); + retval = cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s); + if (retval != ERROR_OK) + return retval; + + /* Atmel EDBG needs renew clock setting after SWJ_Sequence + * otherwise default frequency is used */ + return cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz()); } static int cmsis_dap_swd_open(void) { int retval; - if (cmsis_dap_handle == NULL) { - /* SWD init */ - retval = cmsis_dap_usb_open(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_caps_info(); - if (retval != ERROR_OK) - return retval; - } - if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) { LOG_ERROR("CMSIS-DAP: SWD not supported"); return ERROR_JTAG_DEVICE_ERROR; @@ -850,23 +875,27 @@ static int cmsis_dap_init(void) int retval; uint8_t *data; - if (swd_mode) { - retval = cmsis_dap_swd_open(); - if (retval != ERROR_OK) - return retval; - } + retval = cmsis_dap_usb_open(); + if (retval != ERROR_OK) + return retval; - if (cmsis_dap_handle == NULL) { + retval = cmsis_dap_get_caps_info(); + if (retval != ERROR_OK) + return retval; - /* JTAG init */ - retval = cmsis_dap_usb_open(); - if (retval != ERROR_OK) - return retval; + retval = cmsis_dap_get_version_info(); + if (retval != ERROR_OK) + return retval; - retval = cmsis_dap_get_caps_info(); + retval = cmsis_dap_get_serial_info(); + if (retval != ERROR_OK) + return retval; + + if (swd_mode) { + retval = cmsis_dap_swd_open(); if (retval != ERROR_OK) return retval; - + } else { /* Connect in JTAG mode */ if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { LOG_ERROR("CMSIS-DAP: JTAG not supported"); @@ -880,10 +909,6 @@ static int cmsis_dap_init(void) LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); } - retval = cmsis_dap_get_version_info(); - if (retval != ERROR_OK) - return retval; - /* INFO_ID_PKT_SZ - short */ retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data); if (retval != ERROR_OK) @@ -941,14 +966,17 @@ static int cmsis_dap_init(void) * up to 64 times. This must be changed to 0 if sticky * overrun detection is enabled. */ retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0); - if (retval != ERROR_OK) - return ERROR_FAIL; - /* Data Phase (bit 2) must be set to 1 if sticky overrun - * detection is enabled */ - retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ if (retval != ERROR_OK) return ERROR_FAIL; + if (swd_mode) { + /* Data Phase (bit 2) must be set to 1 if sticky overrun + * detection is enabled */ + retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ + if (retval != ERROR_OK) + return ERROR_FAIL; + } + retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */ if (retval != ERROR_OK) return ERROR_FAIL; @@ -990,8 +1018,17 @@ static int cmsis_dap_quit(void) static void cmsis_dap_execute_reset(struct jtag_command *cmd) { - int retval = cmsis_dap_cmd_DAP_SWJ_Pins(cmd->cmd.reset->srst ? 0 : (1 << 7), \ - (1 << 7), 0, NULL); + /* Set both TRST and SRST even if they're not enabled as + * there's no way to tristate them */ + + output_pins = 0; + if (!cmd->cmd.reset->srst) + output_pins |= SWJ_PIN_SRST; + if (!cmd->cmd.reset->trst) + output_pins |= SWJ_PIN_TRST; + + int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins, + SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL); if (retval != ERROR_OK) LOG_ERROR("CMSIS-DAP: Interface reset failed"); } @@ -1423,6 +1460,12 @@ static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd) cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles); } +static void cmsis_dap_execute_tms(struct jtag_command *cmd) +{ + DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); + cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); +} + /* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE, * JTAG_RUNTEST, JTAG_STABLECLOCKS? */ static void cmsis_dap_execute_command(struct jtag_command *cmd) @@ -1453,6 +1496,8 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd) cmsis_dap_execute_stableclocks(cmd); break; case JTAG_TMS: + cmsis_dap_execute_tms(cmd); + break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); exit(-1); @@ -1475,13 +1520,11 @@ static int cmsis_dap_execute_queue(void) static int cmsis_dap_speed(int speed) { - if (speed > DAP_MAX_CLOCK) { - LOG_INFO("reduce speed request: %dkHz to %dkHz maximum", speed, DAP_MAX_CLOCK); - speed = DAP_MAX_CLOCK; - } + if (speed > DAP_MAX_CLOCK) + LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed); if (speed == 0) { - LOG_INFO("RTCK not supported"); + LOG_ERROR("RTCK not supported. Set nonzero adapter_khz."); return ERROR_JTAG_NOT_IMPLEMENTED; } @@ -1617,6 +1660,7 @@ static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; struct jtag_interface cmsis_dap_interface = { .name = "cmsis-dap", + .supported = DEBUG_CAP_TMS_SEQ, .commands = cmsis_dap_command_handlers, .swd = &cmsis_dap_swd_driver, .transports = cmsis_dap_transport,