Skip to content

Commit

Permalink
target/adiv5_swdp: cleanup SWD switching sequences
Browse files Browse the repository at this point in the history
  • Loading branch information
perigoso committed Jul 18, 2023
1 parent 8f5dc03 commit 90f0094
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 25 deletions.
19 changes: 19 additions & 0 deletions src/target/adiv5.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@
#define ADIV5_DP_RDBUFF ADIV5_DP_REG(0xcU)
#define ADIV5_DP_TARGETSEL ADIV5_DP_REG(0xcU)

/* ADIv5 SWD/JTAG Select Sequence */
#define ADIV5_SWD_TO_JTAG_SELECT_SEQUENCE 0xe73cU /* 16 bits, LSB (MSB: 0x3ce7) */
#define ADIV5_JTAG_TO_SWD_SELECT_SEQUENCE 0xe79eU /* 16 bits, LSB (MSB: 0x79e7) */

/*
* ADIv5 Selection Alert sequence
* This sequence is sent MSB first and can be represented as either:
* - 0x49cf9046 a9b4a161 97f5bbc7 45703d98 transmitted MSB first
* - 0x19bc0ea2 e3ddafe9 86852d95 6209f392 transmitted LSB first
*/
#define ADIV5_SELECTION_ALERT_SEQUENCE_0 0x6209f392U /* 32 bits, LSB */
#define ADIV5_SELECTION_ALERT_SEQUENCE_1 0x86852d95U /* 32 bits, LSB */
#define ADIV5_SELECTION_ALERT_SEQUENCE_2 0xe3ddafe9U /* 32 bits, LSB */
#define ADIV5_SELECTION_ALERT_SEQUENCE_3 0x19bc0ea2U /* 32 bits, LSB */

/* ADIv5 Dormant state activation codes */
#define ADIV5_ACTIVATION_CODE_ARM_SWD_DP 0x1aU /* 8bits, LSB (MSB: 0x58) */
#define ADIV5_ACTIVATION_CODE_ARM_JTAG_DP 0x0aU /* 8bits, LSB (MSB: 0x50) */

/* DP DPIDR */
#define ADIV5_DP_DPIDR_REVISION_OFFSET 28U
#define ADIV5_DP_DPIDR_REVISION_MASK (0xfU << ADIV5_DP_DPIDR_VERSION_OFFSET)
Expand Down
89 changes: 64 additions & 25 deletions src/target/adiv5_swd.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,65 @@ uint8_t make_packet_request(uint8_t RnW, uint16_t addr)

/* Provide bare DP access functions without timeout and exception */

static void swd_line_reset(void)
static void swd_line_reset(const bool idle)
{
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0x0fffffffU, 32U);
/*
* A line reset is achieved by holding the SWDIOTMS HIGH for at least 50 SWCLKTCK cycles, followed by at least two idle cycles
* note: some targes require 51 HIGH cycles and/or 3/4 idle cycles
* for robustness, we use 60 HIGH cycles and 4 idle cycles
*/
swd_proc.seq_out(0xffffffffU, 32U); /* 32 cycles HIGH */
swd_proc.seq_out(0x0fffffffU, idle ? 32U : 28U); /* 28 cycles HIGH + 4 idle cycles if idle is requested */
}

/* Switch out of dormant state into SWD */
static void dormant_state_to_swd_sequence()
{
/*
* ARM Debug Interface Architecture Specification, ADIv5.0 to ADIv5.2. ARM IHI 0031C
* §5.3.4 Switching out of Dormant state
*/

DEBUG_INFO("Switching out of dormant state into SWD\n");

/* Send at least 8 SWCLKTCK cycles with SWDIOTMS HIGH */
swd_line_reset(false);
/* Send the 128-bit Selection Alert sequence on SWDIOTMS */
swd_proc.seq_out(ADIV5_SELECTION_ALERT_SEQUENCE_0, 32U);
swd_proc.seq_out(ADIV5_SELECTION_ALERT_SEQUENCE_1, 32U);
swd_proc.seq_out(ADIV5_SELECTION_ALERT_SEQUENCE_2, 32U);
swd_proc.seq_out(ADIV5_SELECTION_ALERT_SEQUENCE_3, 32U);
/* Send 4 SWCLKTCK cycles with SWDIOTMS LOW */
/* Send the required activation code sequence on SWDIOTMS */
/* We combine the last two actions in a single seq_out as an optimization */
swd_proc.seq_out(ADIV5_ACTIVATION_CODE_ARM_SWD_DP << 4U, 8U + 4U);

/*
* The target is in the protocol error state after selecting SWD
* Ensure the interface is in a known state by performing a line reset
*/
swd_line_reset(true);
}

/* Deprecated JTAG-to-SWD select sequence */
static void jtag_to_swd_sequence()
{
/*
* ARM Debug Interface Architecture Specification, ADIv5.0 to ADIv5.2. ARM IHI 0031C
* §5.2.1 Switching from JTAG to SWD operation
*/

/* ARM deprecates use of these sequences on devices where the dormant state of operation is implemented */
DEBUG_WARN("Deprecated TAG-to-SWD sequence\n");

/* SWD interface must be in reset state */
swd_line_reset(false);

/* Send the 16-bit JTAG-to-SWD select sequence on SWDIOTMS */
swd_proc.seq_out(ADIV5_JTAG_TO_SWD_SELECT_SEQUENCE, 16U);

/* This ensures that if SWJ-DP was already in SWD operation before sending the select sequence, the interface enters reset state */
swd_line_reset(true);
}

bool firmware_dp_low_write(const uint16_t addr, const uint32_t data)
Expand Down Expand Up @@ -106,18 +161,9 @@ uint32_t adiv5_swdp_scan(const uint32_t targetid)
#endif

platform_target_clk_output_enable(true);
/* DORMANT-> SWD sequence*/
swd_proc.seq_out(0xffffffff, 32);
swd_proc.seq_out(0xffffffff, 32);
/* 128 bit selection alert sequence for SW-DP-V2 */
swd_proc.seq_out(0x6209f392, 32);
swd_proc.seq_out(0x86852d95, 32);
swd_proc.seq_out(0xe3ddafe9, 32);
swd_proc.seq_out(0x19bc0ea2, 32);
/* 4 cycle low,
* 0x1a Arm CoreSight SW-DP activation sequence
* 20 bits start of reset another reset sequence*/
swd_proc.seq_out(0x1a0, 12);

/* Switch out of dormant state */
dormant_state_to_swd_sequence();

uint32_t dp_targetid = targetid;

Expand All @@ -137,8 +183,6 @@ uint32_t adiv5_swdp_scan(const uint32_t targetid)
* configured to support.
*/

swd_line_reset();

/* Read DPIDR, if the first read fails, try the JTAG to SWD sequence, if that fails, give up */
uint32_t dpidr = 0;
bool tried_jtag_to_swd = false;
Expand All @@ -149,12 +193,7 @@ uint32_t adiv5_swdp_scan(const uint32_t targetid)
break;

if (!tried_jtag_to_swd) {
DEBUG_WARN("Trying old JTAG to SWD sequence\n");
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0xffffffffU, 32U);
swd_proc.seq_out(0xe79eU, 16U); /* 0b0111100111100111 */

swd_line_reset();
jtag_to_swd_sequence();

dp->fault = 0;

Expand Down Expand Up @@ -246,7 +285,7 @@ void adiv5_swdp_multidrop_scan(adiv5_debug_port_s *target_dp, const uint32_t tar
*/

/* Line reset sequence */
swd_line_reset();
swd_line_reset(true);
target_dp->fault = 0;

/* Select the instance */
Expand Down Expand Up @@ -310,7 +349,7 @@ uint32_t firmware_swdp_error(adiv5_debug_port_s *dp, const bool protocol_recover
* we must then re-select the target to bring the device back
* into the expected state.
*/
swd_line_reset();
swd_line_reset(true);
if (dp->version >= 2U)
firmware_dp_low_write(ADIV5_DP_TARGETSEL, dp->targetsel);
firmware_dp_low_read(ADIV5_DP_DPIDR);
Expand Down

0 comments on commit 90f0094

Please sign in to comment.