2021-03-10 14:12:31 +01:00
/** library for Serial Wire Debug (SWD) communication
* @ file
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
* @ date 2018 - 2021
* @ note peripherals used : timer @ ref swd_timer , GPIO @ ref swd_gpio
* @ implements " ARM Debug Interface Architecture Specification ADIv6.0 " ( ARM IHI 0074 A )
* @ note this library implements DP architecture version 3 ( DPv3 ) , but only DPv1 feature could be tested .
* @ implements The physical layer ( electrical characteristic and timing ) is described in " ARM DSTREAM System and Interface Design Reference Guide " ( ARM DUI0499K )
*/
/** @remark{
* This library implements DP architecture version 3 ( DPv3 ) , but only DPv1 feature could be tested .
*
* See B2 .1 .1 DP architecture versions summary for more details about the versions :
* - DPv0 is only available using JTAG ( e . g . does not support SWD ) .
* - DPv1 introduces SWD ( with protocol version 1 ) .
* - DPv2 adds multi - drop support ( with protocol version 2 ) .
* - DPv3 add register for 64 - bit support .
*
* I couldn ' t find any hardware supporting SWD protocol version 2 to test DPv2 and DPv3 features , in particular dormant state and target select .
* According to https : //developer.arm.com/docs/103489514/latest/does-the-cortex-m3-or-cortex-m4-processor-that-i-have-licensed-support-multi-drop-serial-wire-debug, although it is a property of the debug standard (e.g. CoreSight block) rather than core, no Cortex-M3 or Cortex-M4 seem to support DPv2/SWDv2.
* }
*/
# pragma once
/** Debug Port (DP) register address
* @ implements ARM IHI 0074 A B2 .1 .2 DP architecture version 3 ( DPv3 ) address map
*/
enum swd_a_dp_e {
SWD_A_DP_DPIDR = 0x0 , /**< Debug Port Identification Register (DP: v1, access: RO) */
SWD_A_DP_DPIDR1 = 0x0 , /**< Debug Port Identification Register 1 (DP: v3, access: RO) */
SWD_A_DP_BASEPTR0 = 0x0 , /**< Base Pointer 0 (DP: v3, access: RO) */
SWD_A_DP_BASEPTR1 = 0x0 , /**< Base Pointer 1 (DP: v3, access: RO) */
SWD_A_DP_ABORT = 0x0 , /**< AP Abort register (DP: v0, access: WO) */
SWD_A_DP_CTRL_STAT = 0x4 , /**< Control/Status register (DP: v0, access: RW) */
SWD_A_DP_DLCR = 0x4 , /**< Data Link Control Register (DP: v1, access: RW) */
SWD_A_DP_TARGETID = 0x4 , /**< Target Identification register (DP: v2, access: RO) */
SWD_A_DP_DLPIDR = 0x4 , /**< Data Link Protocol Identification Register (DP: v2, access: RO) */
SWD_A_DP_EVENTSTAT = 0x4 , /**< Event Status register (DP: v0, access: RO) */
SWD_A_DP_SELECT1 = 0x4 , /**< AP Select register 1 (DP: v3, access: WO) */
SWD_A_DP_SELECT = 0x8 , /**< AP Select register (DP: v0, access: WO) */
SWD_A_DP_RESEND = 0x8 , /**< Read Resend register (DP: v1, access: RO) */
SWD_A_DP_RDBUFF = 0xc , /**< Read Buffer register (DP: v0, access: RO) */
SWD_A_DP_TARGETSEL = 0xc , /**< Target Selection register (DP: v2, access: WO) */
} ;
/** Access Port (AP) MEM-AP register address
* @ implements ARM IHI 0074 A C2 .5 MEM - AP Programmers ’ Model
* @ note only the registers addressable with A [ 3 : 2 ] are included
*/
enum swd_a_ap_memap_e {
SWD_A_AP_MEMAP_CSW = 0x0 , /**< Control/Status Word register (access: RW) */
SWD_A_AP_MEMAP_TAR = 0x4 , /**< Transfer Address Register (access: RW) */
SWD_A_AP_MEMAP_TAR_EXT = 0x8 , /**< Transfer Address Register, large physical address extension (access: RW) */
SWD_A_AP_MEMAP_DRW = 0xc , /**< Data Read/Write register (access: RW) */
} ;
/** Access Port (AP) JTAG-AP register address
* @ implements ARM IHI 0074 A C3 .4 JTAG - AP programmers ’ model
* @ note only the registers addressable with A [ 3 : 2 ] are included
*/
enum swd_a_ap_jtagap_e {
SWD_A_AP_JTAGAP_CSW = 0x0 , /**< Control/Status Word register (access: RW) */
SWD_A_AP_JTAGAP_PSEL = 0x4 , /**< Port Select register (access: RW) */
SWD_A_AP_JTAGAP_PSTA = 0x8 , /**< Port Status Register (access: RW) */
} ;
2021-03-15 12:30:39 +01:00
/** ACK acknowledge response
2021-03-10 14:12:31 +01:00
* @ implements ARM IHI 0074 A B4 .2 SWD protocol operation
*/
enum swd_ack_e {
SWD_ACK_OK = 0x1 , /**< Successful operation */
SWD_ACK_WAIT = 0x2 , /**< Wait for response */
SWD_ACK_FAULT = 0x4 , /**< Fault */
2021-03-15 12:30:39 +01:00
SWD_ACK_NOREPLY = 0x7 , /**< Error (pulled-up line not driven) */
2021-03-10 14:12:31 +01:00
} ;
/** Activation codes
* @ implements ARM IHI 0074 A B5 .3 .4 Leaving dormant state
*/
enum swd_activation_code_e {
SWD_ACTIVATION_CODE_JTAG , /**< JTAG-Serial */
SWD_ACTIVATION_CODE_SWDP , /**< ARM CoreSight SW-DP */
SWD_ACTIVATION_CODE_JTAGDP , /**< ARM CoreSight JTAG-DP */
} ;
/** setup SWD peripheral
2021-03-22 11:52:58 +01:00
* @ param [ in ] freq clock frequency , in Hz
* @ note above 50 kHz the communication still works , but the clock is not periodic anymore
2021-03-10 14:12:31 +01:00
*/
void swd_setup ( uint32_t freq ) ;
2021-03-16 12:15:49 +01:00
/** release peripherals used for SWD communication
2021-03-10 14:12:31 +01:00
*/
void swd_release ( void ) ;
2021-03-12 13:10:59 +01:00
/** release used pins */
void swd_release_pins ( void ) ;
2021-03-10 18:26:13 +01:00
/** set SWCLK and SWDIO pins
* @ param [ in ] swclk_port port for SWCLK pin
* @ param [ in ] swclk_pin pin for SWCLK pin
* @ param [ in ] swclk_port port for SWDIO pin
* @ param [ in ] swclk_pin pin for SWDIO pin
* @ return true if operation succeeded , false if pin is unknown
*/
bool swd_set_pins ( uint32_t swclk_port , uint32_t swclk_pin , uint32_t swdio_port , uint32_t swdio_pin ) ;
2021-03-10 14:12:31 +01:00
/* DPv1/SWDv1 operations */
/** send line reset sequence to put target in reset state
* @ implements ARM IHI 0074 A B4 .3 .3 Connection and line reset sequence
* @ note this does not include the tailing idle cycles
*/
void swd_line_reset ( void ) ;
/** send JTAG to SWD sequence to switch the target SWJ-DP from JTAG to SWD
* @ note a line reset must be perform just before
* @ implements ARM IHI 0074 A B5 .2 .2 Switching from JTAG to SWD operation
*/
void swd_jtag_to_swd ( void ) ;
/** send SWD to JTAG sequence to switch the target SWJ-DP from SWD to JTAG
* @ note a line reset must be perform just before
* @ implements ARM IHI 0074 A B5 .2 .3 Switching from SWD to JTAG operation
*/
void swd_swd_to_jtag ( void ) ;
/** send idle cycles
* @ param [ in ] nb number idle cycles to send
* @ note at least two idle cycles a required after a line reset and before a packet request
* @ implements ARM IHI 0074 A B4 .1 .4 Idle cycles
*/
void swd_idle_cycles ( uint8_t nb ) ;
/** send packet request
* @ param [ in ] apndp true to access the Access Port ( AP ) or false to access the Debug Port ( DP ) access register
* @ param [ in ] a address field for the DP or AP register Address ( complete address , not just bits 3 : 2 )
* @ param [ in ] rnw true for read access , false for write access
* @ implements ARM IHI 0074 A B4 .2 SWD protocol operation
*/
void swd_packet_request ( bool apndp , uint8_t a , bool rnw ) ;
/** insert turnaround cycle
* @ param [ in ] nb number idle for the turnaround ( by default 1 , else set in DLCR . TURNROUND )
* @ note used to switch between reading and writing on the data signal
* @ implements ARM IHI 0074 A B4 .1 .3 Line turnaround
*/
void swd_turnaround ( uint8_t nb ) ;
/** read acknowledge response (ACK)
* @ return ACK
* @ implements ARM IHI 0074 A B4 .2 SWD protocol operation
*/
enum swd_ack_e swd_acknowledge_response ( void ) ;
/** write data
* @ param [ in ] wdata data to write
* @ implements ARM IHI 0074 A B4 .2 SWD protocol operation
*/
void swd_write ( uint32_t wdata ) ;
/** read data
* @ param [ out ] rdata read data
* @ return if parity check passed
* @ implements ARM IHI 0074 A B4 .2 SWD protocol operation
*/
bool swd_read ( uint32_t * rdata ) ;
/* DPv2/SWDv2 operations */
/** send JTAG to dormant state (DS) sequence
* @ note the preceding line reset does not seem mandatory , but recommended
* @ implements ARM IHI 0074 A B5 .3 .2 Switching from JTAG to dormant state
* @ remark it is not mentioned what happens if the TAP is in SWD state ( probably nothing )
*/
void swd_jtag_to_ds ( void ) ;
/** send SWD to dormant state (DS) sequence
* @ note no preceding line reset is requires
* @ implements ARM IHI 0074 A B5 .3 .3 Switching from SWD to dormant state
* @ remark it is not mentioned what happens if the TAP is in JTAG state ( probably nothing )
*/
void swd_swd_to_ds ( void ) ;
/** send selection code and activation alert to leave dormant state and go into JTAG or SWD mode
* @ param [ in ] activation_code activation code to select protocol ( JTAG , or SWD )
* @ implements ARM IHI 0074 A B5 .3 .3 Switching from SWD to dormant state
* @ remark it is not mentioned what happens if the TAP is in any other state
*/
void swd_selection_alert ( enum swd_activation_code_e activation_code ) ;
/** perform SWD transaction (one sequence of bits read or write)
* @ param [ in ] output bits to write ( LSb first )
* @ param [ in ] bit_count number of bits to read / write
* @ param [ in ] write true for write transaction , false for read transaction
* @ return the bits read
* @ note this should only be used for unimplemented operations
*/
uint64_t swd_transaction ( uint64_t output , uint8_t bit_count , bool write ) ;
/** get manufacturer name corresponding to the designer id
* @ param [ in ] bank bank number ( first 4 bits of the DESIGNER value )
* @ param [ in ] id JEP106 id ( last 7 bits of the DESIGNER value )
* @ return manufacturer name
* @ implements JEDEC JEP106
* @ note from the OpenOCD project
* @ date 2015
* @ copyright Andreas Fritiofson < andreas . fritiofson @ gmail . com >
*/
const char * swd_jep106_manufacturer ( uint8_t bank , uint8_t id ) ;
/** get DAP name corresponding to the DPIDR part number
2021-03-16 12:15:35 +01:00
* @ param [ in ] designer DESIGNER value ( bits 1 - 11 in DPIDR / IDCODE )
* @ param [ in ] partno PARTNO part number bits 12 - 27 in DPIDR / IDCODE )
2021-03-10 14:12:31 +01:00
* @ return DAP name
*/
2021-03-16 12:15:35 +01:00
const char * swd_dpidr_partno ( uint16_t designer , uint16_t partno ) ;
2021-03-10 14:12:31 +01:00