+ }
+}
+
+static int bitbang_swd_switch_seq(enum swd_special_seq seq)
+{
+ LOG_DEBUG("bitbang_swd_switch_seq");
+
+ switch (seq) {
+ case LINE_RESET:
+ LOG_DEBUG("SWD line reset");
+ bitbang_swd_exchange(false, (uint8_t *)swd_seq_line_reset, 0, swd_seq_line_reset_len);
+ break;
+ case JTAG_TO_SWD:
+ LOG_DEBUG("JTAG-to-SWD");
+ bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len);
+ break;
+ case JTAG_TO_DORMANT:
+ LOG_DEBUG("JTAG-to-DORMANT");
+ bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len);
+ break;
+ case SWD_TO_JTAG:
+ LOG_DEBUG("SWD-to-JTAG");
+ bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len);
+ break;
+ case SWD_TO_DORMANT:
+ LOG_DEBUG("SWD-to-DORMANT");
+ bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len);
+ break;
+ case DORMANT_TO_SWD:
+ LOG_DEBUG("DORMANT-to-SWD");
+ bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len);
+ break;
+ case DORMANT_TO_JTAG:
+ LOG_DEBUG("DORMANT-to-JTAG");
+ bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len);
+ break;
+ default:
+ LOG_ERROR("Sequence %d not supported", seq);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static void swd_clear_sticky_errors(void)
+{
+ bitbang_swd_write_reg(swd_cmd(false, false, DP_ABORT),
+ STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
+}
+
+static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
+{
+ LOG_DEBUG("bitbang_swd_read_reg");
+ assert(cmd & SWD_CMD_RNW);
+
+ if (queued_retval != ERROR_OK) {
+ LOG_DEBUG("Skip bitbang_swd_read_reg because queued_retval=%d", queued_retval);
+ return;
+ }
+
+ for (;;) {
+ uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
+
+ cmd |= SWD_CMD_START | SWD_CMD_PARK;
+ bitbang_swd_exchange(false, &cmd, 0, 8);
+
+ bitbang_interface->swdio_drive(false);
+ bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 32 + 1 + 1);
+ bitbang_interface->swdio_drive(true);
+
+ int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3);
+ uint32_t data = buf_get_u32(trn_ack_data_parity_trn, 1 + 3, 32);
+ int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1);
+
+ 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("Wrong parity detected");
+ queued_retval = ERROR_FAIL;
+ return;
+ }
+ if (value)
+ *value = data;
+ if (cmd & SWD_CMD_APNDP)
+ bitbang_swd_exchange(true, NULL, 0, ap_delay_clk);
+ return;
+ case SWD_ACK_WAIT:
+ LOG_DEBUG("SWD_ACK_WAIT");
+ swd_clear_sticky_errors();
+ break;
+ 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;
+ }
+ }
+}