jtag/drivers/cmsis-dap: Restructure commands
[openocd.git] / src / jtag / drivers / cmsis_dap.c
index 10e6638627def00d9f9050fe9a8ca56c9bd30bf1..52e4fadeb90748bb4c36dd4e584142e38bbd9f3e 100644 (file)
@@ -160,6 +160,11 @@ static bool swd_mode;
 #define CMD_DAP_TFER_BLOCK        0x06
 #define CMD_DAP_TFER_ABORT        0x07
 
+/* DAP_TransferBlock increases the sum of command/response sizes
+ * (due to 16-bit Transfer Count) if used in a small packet.
+ * Prevent using it until we have at least r/w operations. */
+#define CMD_DAP_TFER_BLOCK_MIN_OPS 4
+
 /* DAP Status Code */
 #define DAP_OK                    0
 #define DAP_ERROR                 0xFF
@@ -756,8 +761,9 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
        dap->write_count = 0;
        dap->read_count = 0;
 
-       LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %u",
-                         block->transfer_count, dap->pending_fifo_put_idx);
+       LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %u%s",
+                                block->transfer_count, dap->pending_fifo_put_idx,
+                                cmsis_dap_handle->swd_cmds_differ ? "" : ", same swd ops");
 
        if (queued_retval != ERROR_OK) {
                LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
@@ -767,10 +773,21 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
        if (block->transfer_count == 0)
                goto skip;
 
-       command[0] = CMD_DAP_TFER;
+       bool block_cmd = !cmsis_dap_handle->swd_cmds_differ
+                                        && block->transfer_count >= CMD_DAP_TFER_BLOCK_MIN_OPS;
+       block->command = block_cmd ? CMD_DAP_TFER_BLOCK : CMD_DAP_TFER;
+
+       command[0] = block->command;
        command[1] = 0x00;      /* DAP Index */
-       command[2] = block->transfer_count;
-       size_t idx = 3;
+
+       unsigned int idx;
+       if (block_cmd) {
+               h_u16_to_le(&command[2], block->transfer_count);
+               idx = 4;        /* The first transfer will store the common DAP register */
+       } else {
+               command[2] = block->transfer_count;
+               idx = 3;
+       }
 
        for (unsigned int i = 0; i < block->transfer_count; i++) {
                struct pending_transfer_result *transfer = &(block->transfers[i]);
@@ -801,7 +818,9 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
                        data &= ~CORUNDETECT;
                }
 
-               command[idx++] = (cmd >> 1) & 0x0f;
+               if (!block_cmd || i == 0)
+                       command[idx++] = (cmd >> 1) & 0x0f;
+
                if (!(cmd & SWD_CMD_RNW)) {
                        h_u32_to_le(&command[idx], data);
                        idx += 4;
@@ -846,20 +865,28 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
        }
 
        uint8_t *resp = dap->response;
-       if (resp[0] != CMD_DAP_TFER) {
+       if (resp[0] != block->command) {
                LOG_ERROR("CMSIS-DAP command mismatch. Expected 0x%x received 0x%" PRIx8,
-                       CMD_DAP_TFER, resp[0]);
+                       block->command, resp[0]);
                queued_retval = ERROR_FAIL;
                goto skip;
        }
 
-       unsigned int transfer_count = resp[1];
-       uint8_t ack = resp[2] & 0x07;
-       if (resp[2] & 0x08) {
+       unsigned int transfer_count;
+       unsigned int idx;
+       if (block->command == CMD_DAP_TFER_BLOCK) {
+               transfer_count = le_to_h_u16(&resp[1]);
+               idx = 3;
+       } else {
+               transfer_count = resp[1];
+               idx = 2;
+       }
+       if (resp[idx] & 0x08) {
                LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", transfer_count);
                queued_retval = ERROR_FAIL;
                goto skip;
        }
+       uint8_t ack = resp[idx++] & 0x07;
        if (ack != SWD_ACK_OK) {
                LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count,
                          ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
@@ -874,7 +901,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
 
        LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %u timeout %i",
                 transfer_count, dap->pending_fifo_get_idx, timeout_ms);
-       unsigned int idx = 3;
+
        for (unsigned int i = 0; i < transfer_count; i++) {
                struct pending_transfer_result *transfer = &(block->transfers[i]);
                if (transfer->cmd & SWD_CMD_RNW) {
@@ -923,19 +950,30 @@ static int cmsis_dap_swd_run_queue(void)
 }
 
 static unsigned int cmsis_dap_tfer_cmd_size(unsigned int write_count,
-                                                                                       unsigned int read_count)
+                                                       unsigned int read_count, bool block_tfer)
 {
-       unsigned int size = 3;                  /* header */
-       size += write_count * (1 + 4);  /* DAP register + data */
-       size += read_count;                             /* DAP register */
+       unsigned int size;
+       if (block_tfer) {
+               size = 5;                                               /* DAP_TransferBlock header */
+               size += write_count * 4;                /* data */
+       } else {
+               size = 3;                                               /* DAP_Transfer header */
+               size += write_count * (1 + 4);  /* DAP register + data */
+               size += read_count;                             /* DAP register */
+       }
        return size;
 }
 
 static unsigned int cmsis_dap_tfer_resp_size(unsigned int write_count,
-                                                                                        unsigned int read_count)
+                                                       unsigned int read_count, bool block_tfer)
 {
-       unsigned int size = 3;                  /* header */
-       size += read_count * 4;                 /* data */
+       unsigned int size;
+       if (block_tfer)
+               size = 4;                                               /* DAP_TransferBlock response header */
+       else
+               size = 3;                                               /* DAP_Transfer response header */
+
+       size += read_count * 4;                         /* data */
        return size;
 }
 
@@ -947,19 +985,30 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
 
        unsigned int write_count = cmsis_dap_handle->write_count;
        unsigned int read_count = cmsis_dap_handle->read_count;
+       bool block_cmd;
+       if (write_count + read_count < CMD_DAP_TFER_BLOCK_MIN_OPS)
+               block_cmd = false;
+       else
+               block_cmd = !cmsis_dap_handle->swd_cmds_differ
+                                       && cmd == cmsis_dap_handle->common_swd_cmd;
+
        if (cmd & SWD_CMD_RNW)
                read_count++;
        else
                write_count++;
 
-       unsigned int cmd_size = cmsis_dap_tfer_cmd_size(write_count, read_count);
-       unsigned int resp_size = cmsis_dap_tfer_resp_size(write_count, read_count);
+       unsigned int cmd_size = cmsis_dap_tfer_cmd_size(write_count, read_count,
+                                                                                                       block_cmd);
+       unsigned int resp_size = cmsis_dap_tfer_resp_size(write_count, read_count,
+                                                                                                       block_cmd);
+       unsigned int max_transfer_count = block_cmd ? 65535 : 255;
 
        /* Does the DAP Transfer command and the expected response fit into one packet?
         * Run the queue also before a targetsel - it cannot be queued */
        if (cmd_size > tfer_max_command_size
                        || resp_size > tfer_max_response_size
-                       || targetsel_cmd) {
+                       || targetsel_cmd
+                       || write_count + read_count > max_transfer_count) {
                if (cmsis_dap_handle->pending_fifo_block_count)
                        cmsis_dap_swd_read_process(cmsis_dap_handle, 0);
 
@@ -984,6 +1033,13 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
        struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]);
        transfer->data = data;
        transfer->cmd = cmd;
+       if (block->transfer_count == 0) {
+               cmsis_dap_handle->swd_cmds_differ = false;
+               cmsis_dap_handle->common_swd_cmd = cmd;
+       } else if (cmd != cmsis_dap_handle->common_swd_cmd) {
+               cmsis_dap_handle->swd_cmds_differ = true;
+       }
+
        if (cmd & SWD_CMD_RNW) {
                /* Queue a read transaction */
                transfer->buffer = dst;
@@ -1104,7 +1160,9 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
        unsigned int s_len;
        int retval;
 
-       if ((output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) == (SWJ_PIN_SRST | SWJ_PIN_TRST)) {
+       if (seq != LINE_RESET &&
+                       (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. */
@@ -2050,12 +2108,12 @@ COMMAND_HANDLER(cmsis_dap_handle_cmd_command)
 COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command)
 {
        if (CMD_ARGC > MAX_USB_IDS * 2) {
-               LOG_WARNING("ignoring extra IDs in cmsis_dap_vid_pid "
+               LOG_WARNING("ignoring extra IDs in cmsis-dap vid_pid "
                        "(maximum is %d pairs)", MAX_USB_IDS);
                CMD_ARGC = MAX_USB_IDS * 2;
        }
        if (CMD_ARGC < 2 || (CMD_ARGC & 1)) {
-               LOG_WARNING("incomplete cmsis_dap_vid_pid configuration directive");
+               LOG_WARNING("incomplete cmsis-dap vid_pid configuration directive");
                if (CMD_ARGC < 2)
                        return ERROR_COMMAND_SYNTAX_ERROR;
                /* remove the incomplete trailing id */
@@ -2090,10 +2148,10 @@ COMMAND_HANDLER(cmsis_dap_handle_backend_command)
                                }
                        }
 
-                       LOG_ERROR("invalid backend argument to cmsis_dap_backend <backend>");
+                       LOG_ERROR("invalid backend argument to cmsis-dap backend <backend>");
                }
        } else {
-               LOG_ERROR("expected exactly one argument to cmsis_dap_backend <backend>");
+               LOG_ERROR("expected exactly one argument to cmsis-dap backend <backend>");
        }
 
        return ERROR_OK;
@@ -2114,27 +2172,15 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = {
                .usage = "",
                .help = "issue cmsis-dap command",
        },
-       COMMAND_REGISTRATION_DONE
-};
-
-
-static const struct command_registration cmsis_dap_command_handlers[] = {
-       {
-               .name = "cmsis-dap",
-               .mode = COMMAND_ANY,
-               .help = "perform CMSIS-DAP management",
-               .usage = "<cmd>",
-               .chain = cmsis_dap_subcommand_handlers,
-       },
        {
-               .name = "cmsis_dap_vid_pid",
+               .name = "vid_pid",
                .handler = &cmsis_dap_handle_vid_pid_command,
                .mode = COMMAND_CONFIG,
                .help = "the vendor ID and product ID of the CMSIS-DAP device",
                .usage = "(vid pid)*",
        },
        {
-               .name = "cmsis_dap_backend",
+               .name = "backend",
                .handler = &cmsis_dap_handle_backend_command,
                .mode = COMMAND_CONFIG,
                .help = "set the communication backend to use (USB bulk or HID).",
@@ -2142,7 +2188,7 @@ static const struct command_registration cmsis_dap_command_handlers[] = {
        },
 #if BUILD_CMSIS_DAP_USB
        {
-               .name = "cmsis_dap_usb",
+               .name = "usb",
                .chain = cmsis_dap_usb_subcommand_handlers,
                .mode = COMMAND_ANY,
                .help = "USB bulk backend-specific commands",
@@ -2152,6 +2198,18 @@ static const struct command_registration cmsis_dap_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
+
+static const struct command_registration cmsis_dap_command_handlers[] = {
+       {
+               .name = "cmsis-dap",
+               .mode = COMMAND_ANY,
+               .help = "perform CMSIS-DAP management",
+               .usage = "<cmd>",
+               .chain = cmsis_dap_subcommand_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
 static const struct swd_driver cmsis_dap_swd_driver = {
        .init = cmsis_dap_swd_init,
        .switch_seq = cmsis_dap_swd_switch_seq,

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)