+}
+
+/************************* SWD related stuff **********/
+
+static int buspirate_swd_init(void)
+{
+ LOG_INFO("Buspirate SWD mode enabled");
+ swd_mode = true;
+
+ return ERROR_OK;
+}
+
+static int buspirate_swd_switch_seq(enum swd_special_seq seq)
+{
+ const uint8_t *sequence;
+ int sequence_len;
+ uint32_t no_bytes, sequence_offset;
+
+ switch (seq) {
+ case LINE_RESET:
+ LOG_DEBUG("SWD line reset");
+ sequence = swd_seq_line_reset;
+ sequence_len = DIV_ROUND_UP(swd_seq_line_reset_len, 8);
+ break;
+ case JTAG_TO_SWD:
+ LOG_DEBUG("JTAG-to-SWD");
+ sequence = swd_seq_jtag_to_swd;
+ sequence_len = DIV_ROUND_UP(swd_seq_jtag_to_swd_len, 8);
+ break;
+ case SWD_TO_JTAG:
+ LOG_DEBUG("SWD-to-JTAG");
+ sequence = swd_seq_swd_to_jtag;
+ sequence_len = DIV_ROUND_UP(swd_seq_swd_to_jtag_len, 8);
+ break;
+ default:
+ LOG_ERROR("Sequence %d not supported", seq);
+ return ERROR_FAIL;
+ }
+
+ no_bytes = sequence_len;
+ sequence_offset = 0;
+
+ while (no_bytes) {
+ uint8_t tmp[17];
+ uint32_t to_send;
+
+ to_send = no_bytes > 16 ? 16 : no_bytes;
+
+ tmp[0] = 0x10 + ((to_send - 1) & 0x0F);
+ memcpy(tmp + 1, &sequence[sequence_offset], to_send);
+
+ buspirate_serial_write(buspirate_fd, tmp, to_send + 1);
+ buspirate_serial_read(buspirate_fd, tmp, to_send + 1);
+
+ no_bytes -= to_send;
+ sequence_offset += to_send;
+ }
+
+ return ERROR_OK;
+}
+
+static uint8_t buspirate_swd_write_header(uint8_t cmd)
+{
+ uint8_t tmp[8];
+ int to_send;
+
+ tmp[0] = 0x10; /* bus pirate: send 1 byte */
+ tmp[1] = cmd; /* swd cmd */
+ tmp[2] = 0x07; /* ack __x */
+ tmp[3] = 0x07; /* ack _x_ */
+ tmp[4] = 0x07; /* ack x__ */
+ tmp[5] = 0x07; /* write mode trn_1 */
+ tmp[6] = 0x07; /* write mode trn_2 */
+
+ to_send = ((cmd & SWD_CMD_RNW) == 0) ? 7 : 5;
+ buspirate_serial_write(buspirate_fd, tmp, to_send);
+
+ /* read ack */
+ buspirate_serial_read(buspirate_fd, tmp, 2); /* drop pirate command ret vals */
+ buspirate_serial_read(buspirate_fd, tmp, to_send - 2); /* ack bits */
+
+ return tmp[2] << 2 | tmp[1] << 1 | tmp[0];
+}
+
+static void buspirate_swd_idle_clocks(uint32_t no_bits)
+{
+ uint32_t no_bytes;
+ uint8_t tmp[20];
+
+ no_bytes = (no_bits + 7) / 8;
+ memset(tmp + 1, 0x00, sizeof(tmp) - 1);
+
+ /* unfortunately bus pirate misbehaves when clocks are sent in parts
+ * so we need to limit at 128 clock cycles
+ */
+ if (no_bytes > 16)
+ no_bytes = 16;
+
+ while (no_bytes) {
+ uint8_t to_send = no_bytes > 16 ? 16 : no_bytes;
+ tmp[0] = 0x10 + ((to_send - 1) & 0x0F);
+
+ buspirate_serial_write(buspirate_fd, tmp, to_send + 1);
+ buspirate_serial_read(buspirate_fd, tmp, to_send + 1);
+
+ no_bytes -= to_send;
+ }
+}
+
+static void buspirate_swd_clear_sticky_errors(void)
+{
+ buspirate_swd_write_reg(swd_cmd(false, false, DP_ABORT),
+ STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
+}
+
+static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
+{
+ uint8_t tmp[16];
+
+ LOG_DEBUG("buspirate_swd_read_reg");
+ assert(cmd & SWD_CMD_RNW);
+
+ if (queued_retval != ERROR_OK) {
+ LOG_DEBUG("Skip buspirate_swd_read_reg because queued_retval=%d", queued_retval);
+ return;
+ }
+
+ cmd |= SWD_CMD_START | SWD_CMD_PARK;
+ uint8_t ack = buspirate_swd_write_header(cmd);
+
+ /* do a read transaction */
+ tmp[0] = 0x06; /* 4 data bytes */
+ tmp[1] = 0x06;
+ tmp[2] = 0x06;
+ tmp[3] = 0x06;
+ tmp[4] = 0x07; /* parity bit */
+ tmp[5] = 0x21; /* 2 turnaround clocks */
+
+ buspirate_serial_write(buspirate_fd, tmp, 6);
+ buspirate_serial_read(buspirate_fd, tmp, 6);
+
+ /* store the data and parity */
+ uint32_t data = (uint8_t) tmp[0];
+ data |= (uint8_t) tmp[1] << 8;
+ data |= (uint8_t) tmp[2] << 16;
+ data |= (uint8_t) tmp[3] << 24;
+ int parity = tmp[4] ? 0x01 : 0x00;
+
+ LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
+ ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
+ cmd & SWD_CMD_APNDP ? "AP" : "DP",
+ cmd & SWD_CMD_RNW ? "read" : "write",
+ (cmd & SWD_CMD_A32) >> 1,
+ data);
+
+ switch (ack) {
+ case SWD_ACK_OK:
+ if (parity != parity_u32(data)) {
+ LOG_DEBUG("Read data parity mismatch %x %x", parity, parity_u32(data));
+ queued_retval = ERROR_FAIL;
+ return;
+ }
+ if (value)
+ *value = data;
+ if (cmd & SWD_CMD_APNDP)
+ buspirate_swd_idle_clocks(ap_delay_clk);
+ return;
+ case SWD_ACK_WAIT:
+ LOG_DEBUG("SWD_ACK_WAIT");
+ buspirate_swd_clear_sticky_errors();
+ return;
+ case SWD_ACK_FAULT:
+ LOG_DEBUG("SWD_ACK_FAULT");
+ queued_retval = ack;
+ return;
+ default:
+ LOG_DEBUG("No valid acknowledge: ack=%d", ack);
+ queued_retval = ack;
+ return;