From 36df240cea04990e8c18aa0b90bd63374f22dbd3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=98yvind=20Harboe?= Date: Tue, 16 Mar 2010 14:13:03 +0100 Subject: [PATCH] jtag: cut down on usage of unintended modification of global end state MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit jtag_get/set_end_state() is now deprecated. There were lots of places in the code where the end state was unintentionally modified. The big Q is whether there were any places where the intention was to modify the end state. 0.5 is a long way off, so we'll get a fair amount of testing. Signed-off-by: Øyvind Harboe --- src/flash/nor/str9xpec.c | 26 +- src/jtag/core.c | 5 +- src/jtag/jtag.h | 7 +- src/pld/virtex2.c | 12 +- src/target/adi_v5_jtag.c | 6 +- src/target/arm11_dbgtap.c | 2 +- src/target/arm720t.c | 6 +- src/target/arm7_9_common.c | 2 +- src/target/arm7tdmi.c | 12 +- src/target/arm920t.c | 8 +- src/target/arm926ejs.c | 8 +- src/target/arm966e.c | 6 +- src/target/arm9tdmi.c | 16 +- src/target/arm_adi_v5.c.orig | 1981 ++++++++++++++++++++++++++++++++++ src/target/arm_adi_v5.c~ | 1981 ++++++++++++++++++++++++++++++++++ src/target/avrt.c | 5 +- src/target/dsp563xx.c | 6 +- src/target/embeddedice.c | 14 +- src/target/etb.c | 8 +- src/target/etm.c | 6 +- src/target/feroceon.c | 4 +- src/target/mips_ejtag.c | 4 +- src/target/xscale.c | 28 +- src/xsvf/xsvf.c | 8 +- 24 files changed, 4062 insertions(+), 99 deletions(-) create mode 100644 src/target/arm_adi_v5.c.orig create mode 100644 src/target/arm_adi_v5.c~ diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index 35fe806d2e..732226f598 100644 --- a/src/flash/nor/str9xpec.c +++ b/src/flash/nor/str9xpec.c @@ -69,7 +69,7 @@ static uint8_t str9xpec_isc_status(struct jtag_tap *tap) field.in_value = &status; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); LOG_DEBUG("status: 0x%2.2x", status); @@ -156,7 +156,7 @@ static int str9xpec_read_config(struct flash_bank *bank) field.in_value = str9xpec_info->options; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); status = str9xpec_isc_status(tap); @@ -302,7 +302,7 @@ static int str9xpec_blank_check(struct flash_bank *bank, int first, int last) field.out_value = buffer; field.in_value = NULL; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_sleep(40000); /* read blank check result */ @@ -406,7 +406,7 @@ static int str9xpec_erase_area(struct flash_bank *bank, int first, int last) field.out_value = buffer; field.in_value = NULL; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); jtag_add_sleep(10); @@ -466,7 +466,7 @@ static int str9xpec_lock_device(struct flash_bank *bank) field.out_value = NULL; field.in_value = &status; - jtag_add_dr_scan(tap, 1, &field, jtag_get_end_state()); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); } while (!(status & ISC_STATUS_BUSY)); @@ -546,7 +546,7 @@ static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector) field.out_value = §or; field.in_value = NULL; - jtag_add_dr_scan(tap, 1, &field, jtag_get_end_state()); + jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); return ERROR_OK; } @@ -631,7 +631,7 @@ static int str9xpec_write(struct flash_bank *bank, uint8_t *buffer, field.out_value = (buffer + bytes_written); field.in_value = NULL; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); @@ -643,7 +643,7 @@ static int str9xpec_write(struct flash_bank *bank, uint8_t *buffer, field.out_value = NULL; field.in_value = scanbuf; - jtag_add_dr_scan(tap, 1, &field, jtag_get_end_state()); + jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = buf_get_u32(scanbuf, 0, 8); @@ -679,7 +679,7 @@ static int str9xpec_write(struct flash_bank *bank, uint8_t *buffer, field.out_value = last_dword; field.in_value = NULL; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); @@ -691,7 +691,7 @@ static int str9xpec_write(struct flash_bank *bank, uint8_t *buffer, field.out_value = NULL; field.in_value = scanbuf; - jtag_add_dr_scan(tap, 1, &field, jtag_get_end_state()); + jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = buf_get_u32(scanbuf, 0, 8); @@ -744,7 +744,7 @@ COMMAND_HANDLER(str9xpec_handle_part_id_command) field.out_value = NULL; field.in_value = buffer; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); idcode = buf_get_u32(buffer, 0, 32); @@ -860,7 +860,7 @@ static int str9xpec_write_options(struct flash_bank *bank) field.out_value = str9xpec_info->options; field.in_value = NULL; - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); @@ -872,7 +872,7 @@ static int str9xpec_write_options(struct flash_bank *bank) field.out_value = NULL; field.in_value = &status; - jtag_add_dr_scan(tap, 1, &field, jtag_get_end_state()); + jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); } while (!(status & ISC_STATUS_BUSY)); diff --git a/src/jtag/core.c b/src/jtag/core.c index 9792280b20..a09472a76c 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -743,7 +743,8 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) } } -tap_state_t jtag_set_end_state(tap_state_t state) +/* DEPRECATED! store such global state outside JTAG layer */ +void jtag_set_end_state(tap_state_t state) { if ((state == TAP_DRSHIFT)||(state == TAP_IRSHIFT)) { @@ -752,9 +753,9 @@ tap_state_t jtag_set_end_state(tap_state_t state) if (state != TAP_INVALID) cmd_queue_end_state = state; - return cmd_queue_end_state; } +/* DEPRECATED! store such global state outside JTAG layer */ tap_state_t jtag_get_end_state(void) { return cmd_queue_end_state; diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 0bbea5f561..a92c986d11 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -552,15 +552,18 @@ void jtag_add_reset(int req_tlr_or_trst, int srst); /** + * DEPRECATED! store such global state outside JTAG layer + * * Function jtag_set_end_state * * Set a global variable to \a state if \a state != TAP_INVALID. * - * Return the value of the global variable. */ -tap_state_t jtag_set_end_state(tap_state_t state); +void jtag_set_end_state(tap_state_t state); /** + * DEPRECATED! store such global state outside JTAG layer + * * Function jtag_get_end_state * * Return the value of the global variable for end state diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index 976535b4cd..93509dec1c 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -40,7 +40,7 @@ static int virtex2_set_instr(struct jtag_tap *tap, uint32_t new_instr) buf_set_u32(field.out_value, 0, field.num_bits, new_instr); field.in_value = NULL; - jtag_add_ir_scan(tap, &field, jtag_set_end_state(TAP_IDLE)); + jtag_add_ir_scan(tap, &field, TAP_IDLE); free(field.out_value); } @@ -67,7 +67,7 @@ static int virtex2_send_32(struct pld_device *pld_device, virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ - jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); free(values); @@ -96,7 +96,7 @@ static int virtex2_receive_32(struct pld_device *pld_device, { scan_field.in_value = (uint8_t *)words; - jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); jtag_add_callback(virtexflip32, (jtag_callback_data_t)words); @@ -155,18 +155,18 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename) field.num_bits = bit_file.length * 8; field.out_value = bit_file.data; - jtag_add_dr_scan(virtex2_info->tap, 1, &field, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(virtex2_info->tap, 1, &field, TAP_DRPAUSE); jtag_execute_queue(); jtag_add_tlr(); jtag_set_end_state(TAP_IDLE); virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ - jtag_add_runtest(13, jtag_set_end_state(TAP_IDLE)); + jtag_add_runtest(13, TAP_IDLE); virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ - jtag_add_runtest(13, jtag_set_end_state(TAP_IDLE)); + jtag_add_runtest(13, TAP_IDLE); virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ jtag_execute_queue(); diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index eac83b7b82..091b77ab4c 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -107,7 +107,7 @@ int adi_jtag_dp_scan(struct adiv5_dap *swjdp, fields[1].out_value = outvalue; fields[1].in_value = invalue; - jtag_add_dr_scan(jtag_info->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); /* Add specified number of tck clocks after starting memory bus * access, giving the hardware time to complete the access. @@ -119,7 +119,7 @@ int adi_jtag_dp_scan(struct adiv5_dap *swjdp, || ((reg_addr & 0xF0) == AP_REG_BD0)) && (swjdp->memaccess_tck != 0)) jtag_add_runtest(swjdp->memaccess_tck, - jtag_set_end_state(TAP_IDLE)); + TAP_IDLE); return jtag_get_error(); } @@ -341,7 +341,7 @@ static int jtag_idcode_q_read(struct adiv5_dap *dap, fields[0].out_value = NULL; fields[0].in_value = (void *) data; - jtag_add_dr_scan(jtag_info->tap, 1, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE); retval = jtag_get_error(); if (retval != ERROR_OK) return retval; diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 2b7b4e42d6..18bf2555d6 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -482,7 +482,7 @@ int arm11_run_instr_data_to_core(struct arm11_common * arm11, uint32_t opcode, u { Data = *data; - arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(chain5_fields), chain5_fields, jtag_set_end_state(TAP_IDLE)); + arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); diff --git a/src/target/arm720t.c b/src/target/arm720t.c index 79eb79be34..71d4a0172b 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -75,15 +75,15 @@ static int arm720t_scan_cp15(struct target *target, if (in) { fields[1].in_value = (uint8_t *)in; - jtag_add_dr_scan(jtag_info->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback(arm7flip32, (jtag_callback_data_t)in); } else { - jtag_add_dr_scan(jtag_info->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); } if (clock) - jtag_add_runtest(0, jtag_get_end_state()); + jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ if ((retval = jtag_execute_queue()) != ERROR_OK) diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index d1e7a93e10..c6a08cf1bf 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -1750,7 +1750,7 @@ int arm7_9_restart_core(struct target *target) } arm_jtag_set_instr(jtag_info, 0x4, NULL); - jtag_add_runtest(1, jtag_set_end_state(TAP_IDLE)); + jtag_add_runtest(1, TAP_IDLE); return jtag_execute_queue(); } diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index ab8a3e52dc..2d6d68f61a 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -72,7 +72,7 @@ static int arm7tdmi_examine_debug_reason(struct target *target) } arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); - jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE); if ((retval = jtag_execute_queue()) != ERROR_OK) { return retval; @@ -83,7 +83,7 @@ static int arm7tdmi_examine_debug_reason(struct target *target) fields[1].in_value = NULL; fields[1].out_value = databus; - jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE); if (breakpoint & 1) target->debug_reason = DBG_REASON_WATCHPOINT; @@ -147,11 +147,11 @@ static int arm7tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in) fields[1].out_value = NULL; fields[1].in_value = (uint8_t *)in; - jtag_add_dr_scan(jtag_info->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback(arm7flip32, (jtag_callback_data_t)in); - jtag_add_runtest(0, jtag_get_end_state()); + jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ if ((retval = jtag_execute_queue()) != ERROR_OK) @@ -232,11 +232,11 @@ static int arm7tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, fields[1].out_value = NULL; jtag_alloc_in_value32(&fields[1]); - jtag_add_dr_scan(jtag_info->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback4(arm7endianness, (jtag_callback_data_t)in, (jtag_callback_data_t)size, (jtag_callback_data_t)be, (jtag_callback_data_t)fields[1].in_value); - jtag_add_runtest(0, jtag_get_end_state()); + jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { diff --git a/src/target/arm920t.c b/src/target/arm920t.c index a7816fd8c6..68d3997c9a 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -111,11 +111,11 @@ static int arm920t_read_cp15_physical(struct target *target, fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); fields[1].in_value = (uint8_t *)value; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); @@ -162,7 +162,7 @@ static int arm920t_write_cp15_physical(struct target *target, fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); @@ -214,7 +214,7 @@ static int arm920t_execute_cp15(struct target *target, uint32_t cp15_opcode, fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); arm9tdmi_clock_out(jtag_info, arm_opcode, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index f4c47748cd..ea951e5565 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -86,7 +86,7 @@ static int arm926ejs_cp15_read(struct target *target, uint32_t op1, uint32_t op2 fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); long long then = timeval_ms(); @@ -95,7 +95,7 @@ static int arm926ejs_cp15_read(struct target *target, uint32_t op1, uint32_t op2 /* rescan with NOP, to wait for the access to complete */ access = 0; nr_w_buf = 0; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); @@ -175,7 +175,7 @@ static int arm926ejs_cp15_write(struct target *target, uint32_t op1, uint32_t op fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); long long then = timeval_ms(); @@ -184,7 +184,7 @@ static int arm926ejs_cp15_write(struct target *target, uint32_t op1, uint32_t op /* rescan with NOP, to wait for the access to complete */ access = 0; nr_w_buf = 0; - jtag_add_dr_scan(jtag_info->tap, 4, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); if ((retval = jtag_execute_queue()) != ERROR_OK) { return retval; diff --git a/src/target/arm966e.c b/src/target/arm966e.c index 4f4764485a..67678c14de 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -106,11 +106,11 @@ static int arm966e_read_cp15(struct target *target, int reg_addr, uint32_t *valu fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); fields[1].in_value = (uint8_t *)value; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); @@ -158,7 +158,7 @@ int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value) fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index f3935a3a22..f0911880bb 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -107,7 +107,7 @@ int arm9tdmi_examine_debug_reason(struct target *target) } arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); - jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE); if ((retval = jtag_execute_queue()) != ERROR_OK) { return retval; @@ -120,7 +120,7 @@ int arm9tdmi_examine_debug_reason(struct target *target) fields[2].in_value = NULL; fields[2].out_value = instructionbus; - jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE); if (debug_reason & 0x4) if (debug_reason & 0x2) @@ -177,13 +177,13 @@ int arm9tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t instr, if (in) { fields[0].in_value = (uint8_t *)in; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in); } else { - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); } jtag_add_runtest(0, jtag_get_end_state()); @@ -233,11 +233,11 @@ int arm9tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in) fields[2].out_value = NULL; fields[2].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in); - jtag_add_runtest(0, jtag_get_end_state()); + jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { @@ -300,11 +300,11 @@ int arm9tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, fields[2].out_value = NULL; fields[2].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_callback4(arm9endianness, (jtag_callback_data_t)in, (jtag_callback_data_t)size, (jtag_callback_data_t)be, (jtag_callback_data_t)fields[0].in_value); - jtag_add_runtest(0, jtag_get_end_state()); + jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { diff --git a/src/target/arm_adi_v5.c.orig b/src/target/arm_adi_v5.c.orig new file mode 100644 index 0000000000..708e8581fd --- /dev/null +++ b/src/target/arm_adi_v5.c.orig @@ -0,0 +1,1981 @@ +/*************************************************************************** + * Copyright (C) 2006 by Magnus Lundin * + * lundin@mlu.mine.nu * + * * + * Copyright (C) 2008 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * Copyright (C) 2009 by Oyvind Harboe * + * oyvind.harboe@zylin.com * + * * + * Copyright (C) 2009-2010 by David Brownell * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/** + * @file + * This file implements support for the ARM Debug Interface version 5 (ADIv5) + * debugging architecture. Compared with previous versions, this includes + * a low pin-count Serial Wire Debug (SWD) alternative to JTAG for message + * transport, and focusses on memory mapped resources as defined by the + * CoreSight architecture. + * + * A key concept in ADIv5 is the Debug Access Port, or DAP. A DAP has two + * basic components: a Debug Port (DP) transporting messages to and from a + * debugger, and an Access Port (AP) accessing resources. Three types of DP + * are defined. One uses only JTAG for communication, and is called JTAG-DP. + * One uses only SWD for communication, and is called SW-DP. The third can + * use either SWD or JTAG, and is called SWJ-DP. The most common type of AP + * is used to access memory mapped resources and is called a MEM-AP. Also a + * JTAG-AP is also defined, bridging to JTAG resources; those are uncommon. + * + * This programming interface allows DAP pipelined operations through a + * transaction queue. This primarily affects AP operations (such as using + * a MEM-AP to access memory or registers). If the current transaction has + * not finished by the time the next one must begin, and the ORUNDETECT bit + * is set in the DP_CTRL_STAT register, the SSTICKYORUN status is set and + * further AP operations will fail. There are two basic methods to avoid + * such overrun errors. One involves polling for status instead of using + * transaction piplining. The other involves adding delays to ensure the + * AP has enough time to complete one operation before starting the next + * one. (For JTAG these delays are controlled by memaccess_tck.) + */ + +/* + * Relevant specifications from ARM include: + * + * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031A + * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B + * + * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D + * Cortex-M3(tm) TRM, ARM DDI 0337G + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm.h" +#include "arm_adi_v5.h" +#include + + +/* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */ + +/* + uint32_t tar_block_size(uint32_t address) + Return the largest block starting at address that does not cross a tar block size alignment boundary +*/ +static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address) +{ + return (tar_autoincr_block - ((tar_autoincr_block - 1) & address)) >> 2; +} + +/*************************************************************************** + * * +<<<<<<< HEAD:src/target/arm_adi_v5.c +======= + * DPACC and APACC scanchain access through JTAG-DP * + * * +***************************************************************************/ + +/** + * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness + * conversions are performed. See section 4.4.3 of the ADIv5 spec, which + * discusses operations which access these registers. + * + * Note that only one scan is performed. If RnW is set, a separate scan + * will be needed to collect the data which was read; the "invalue" collects + * the posted result of a preceding operation, not the current one. + * + * @param swjdp the DAP + * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access) + * @param reg_addr two significant bits; A[3:2]; for APACC access, the + * SELECT register has more addressing bits. + * @param RnW false iff outvalue will be written to the DP or AP + * @param outvalue points to a 32-bit (little-endian) integer + * @param invalue NULL, or points to a 32-bit (little-endian) integer + * @param ack points to where the three bit JTAG_ACK_* code will be stored + */ +static int adi_jtag_dp_scan(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint8_t *outvalue, uint8_t *invalue, uint8_t *ack) +{ + struct arm_jtag *jtag_info = swjdp->jtag_info; + struct scan_field fields[2]; + uint8_t out_addr_buf; + + jtag_set_end_state(TAP_IDLE); + arm_jtag_set_instr(jtag_info, instr, NULL); + + /* Scan out a read or write operation using some DP or AP register. + * For APACC access with any sticky error flag set, this is discarded. + */ + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].in_value = ack; + + /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not + * complete; data we write is discarded, data we read is unpredictable. + * When overrun detect is active, STICKYORUN is set. + */ + + fields[1].num_bits = 32; + fields[1].out_value = outvalue; + fields[1].in_value = invalue; + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + + /* Add specified number of tck clocks after starting memory bus + * access, giving the hardware time to complete the access. + * They provide more time for the (MEM) AP to complete the read ... + * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec. + */ + if ((instr == JTAG_DP_APACC) + && ((reg_addr == AP_REG_DRW) + || ((reg_addr & 0xF0) == AP_REG_BD0)) + && (swjdp->memaccess_tck != 0)) + jtag_add_runtest(swjdp->memaccess_tck, + TAP_IDLE); + + return jtag_get_error(); +} + +/** + * Scan DPACC or APACC out and in from host ordered uint32_t buffers. + * This is exactly like adi_jtag_dp_scan(), except that endianness + * conversions are performed (so the types of invalue and outvalue + * must be different). + */ +static int adi_jtag_dp_scan_u32(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint32_t outvalue, uint32_t *invalue, uint8_t *ack) +{ + uint8_t out_value_buf[4]; + int retval; + + buf_set_u32(out_value_buf, 0, 32, outvalue); + + retval = adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW, + out_value_buf, (uint8_t *)invalue, ack); + if (retval != ERROR_OK) + return retval; + + if (invalue) + jtag_add_callback(arm_le_to_h_u32, + (jtag_callback_data_t) invalue); + + return retval; +} + +/** + * Utility to write AP registers. + */ +static inline int adi_jtag_ap_write_check(struct adiv5_dap *dap, + uint8_t reg_addr, uint8_t *outvalue) +{ + return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE, + outvalue, NULL, NULL); +} + +static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint32_t outvalue, uint32_t *invalue) +{ + int retval; + + /* Issue the read or write */ + retval = adi_jtag_dp_scan_u32(swjdp, instr, reg_addr, + RnW, outvalue, NULL, NULL); + if (retval != ERROR_OK) + return retval; + + /* For reads, collect posted value; RDBUFF has no other effect. + * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK". + */ + if ((RnW == DPAP_READ) && (invalue != NULL)) + retval = adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC, + DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack); + return retval; +} + +static int jtagdp_transaction_endcheck(struct adiv5_dap *swjdp) +{ + int retval; + uint32_t ctrlstat; + + /* too expensive to call keep_alive() here */ + +#if 0 + /* Danger!!!! BROKEN!!!! */ + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + /* Danger!!!! BROKEN!!!! Why will jtag_execute_queue() fail here???? + R956 introduced the check on return value here and now Michael Schwingen reports + that this code no longer works.... + + https://lists.berlios.de/pipermail/openocd-development/2008-September/003107.html + */ + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + LOG_ERROR("BUG: Why does this fail the first time????"); + } + /* Why??? second time it works??? */ +#endif + + /* Post CTRL/STAT read; discard any previous posted read value + * but collect its ACK status. + */ + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + swjdp->ack = swjdp->ack & 0x7; + + /* common code path avoids calling timeval_ms() */ + if (swjdp->ack != JTAG_ACK_OK_FAULT) + { + long long then = timeval_ms(); + + while (swjdp->ack != JTAG_ACK_OK_FAULT) + { + if (swjdp->ack == JTAG_ACK_WAIT) + { + if ((timeval_ms()-then) > 1000) + { + /* NOTE: this would be a good spot + * to use JTAG_DP_ABORT. + */ + LOG_WARNING("Timeout (1000ms) waiting " + "for ACK=OK/FAULT " + "in JTAG-DP transaction"); + return ERROR_JTAG_DEVICE_ERROR; + } + } + else + { + LOG_WARNING("Invalid ACK %#x " + "in JTAG-DP transaction", + swjdp->ack); + return ERROR_JTAG_DEVICE_ERROR; + } + + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + swjdp->ack = swjdp->ack & 0x7; + } + } + + /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */ + + /* Check for STICKYERR and STICKYORUN */ + if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) + { + LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat); + /* Check power to debug regions */ + if ((ctrlstat & 0xf0000000) != 0xf0000000) + ahbap_debugport_init(swjdp); + else + { + uint32_t mem_ap_csw, mem_ap_tar; + + /* Maybe print information about last intended + * MEM-AP access; but not if autoincrementing. + * *Real* CSW and TAR values are always shown. + */ + if (swjdp->ap_tar_value != (uint32_t) -1) + LOG_DEBUG("MEM-AP Cached values: " + "ap_bank 0x%" PRIx32 + ", ap_csw 0x%" PRIx32 + ", ap_tar 0x%" PRIx32, + swjdp->ap_bank_value, + swjdp->ap_csw_value, + swjdp->ap_tar_value); + + if (ctrlstat & SSTICKYORUN) + LOG_ERROR("JTAG-DP OVERRUN - check clock, " + "memaccess, or reduce jtag speed"); + + if (ctrlstat & SSTICKYERR) + LOG_ERROR("JTAG-DP STICKY ERROR"); + + /* Clear Sticky Error Bits */ + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_WRITE, + swjdp->dp_ctrl_stat | SSTICKYORUN + | SSTICKYERR, NULL); + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + + LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat); + + retval = dap_queue_ap_read(swjdp, + AP_REG_CSW, &mem_ap_csw); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_ap_read(swjdp, + AP_REG_TAR, &mem_ap_tar); + if (retval != ERROR_OK) + return retval; + + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%" + PRIx32, mem_ap_csw, mem_ap_tar); + + } + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/*************************************************************************** + * * +>>>>>>> jtag: cut down on usage of unintended modification of global end state:src/target/arm_adi_v5.c + * DP and MEM-AP register access through APACC and DPACC * + * * +***************************************************************************/ + +/** + * Select one of the APs connected to the specified DAP. The + * selection is implicitly used with future AP transactions. + * This is a NOP if the specified AP is already selected. + * + * @param swjdp The DAP + * @param apsel Number of the AP to (implicitly) use with further + * transactions. This normally identifies a MEM-AP. + */ +void dap_ap_select(struct adiv5_dap *swjdp,uint8_t apsel) +{ + uint32_t select = (apsel << 24) & 0xFF000000; + + if (select != swjdp->apsel) + { + swjdp->apsel = select; + /* Switching AP invalidates cached values. + * Values MUST BE UPDATED BEFORE AP ACCESS. + */ + swjdp->ap_bank_value = -1; + swjdp->ap_csw_value = -1; + swjdp->ap_tar_value = -1; + } +} + +/** + * Queue transactions setting up transfer parameters for the + * currently selected MEM-AP. + * + * Subsequent transfers using registers like AP_REG_DRW or AP_REG_BD2 + * initiate data reads or writes using memory or peripheral addresses. + * If the CSW is configured for it, the TAR may be automatically + * incremented after each transfer. + * + * @todo Rename to reflect it being specifically a MEM-AP function. + * + * @param swjdp The DAP connected to the MEM-AP. + * @param csw MEM-AP Control/Status Word (CSW) register to assign. If this + * matches the cached value, the register is not changed. + * @param tar MEM-AP Transfer Address Register (TAR) to assign. If this + * matches the cached address, the register is not changed. + * + * @return ERROR_OK if the transaction was properly queued, else a fault code. + */ +int dap_setup_accessport(struct adiv5_dap *swjdp, uint32_t csw, uint32_t tar) +{ + int retval; + + csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT; + if (csw != swjdp->ap_csw_value) + { + /* LOG_DEBUG("DAP: Set CSW %x",csw); */ + retval = dap_queue_ap_write(swjdp, AP_REG_CSW, csw); + if (retval != ERROR_OK) + return retval; + swjdp->ap_csw_value = csw; + } + if (tar != swjdp->ap_tar_value) + { + /* LOG_DEBUG("DAP: Set TAR %x",tar); */ + retval = dap_queue_ap_write(swjdp, AP_REG_TAR, tar); + if (retval != ERROR_OK) + return retval; + swjdp->ap_tar_value = tar; + } + /* Disable TAR cache when autoincrementing */ + if (csw & CSW_ADDRINC_MASK) + swjdp->ap_tar_value = -1; + return ERROR_OK; +} + +/** + * Asynchronous (queued) read of a word from memory or a system register. + * + * @param swjdp The DAP connected to the MEM-AP performing the read. + * @param address Address of the 32-bit word to read; it must be + * readable by the currently selected MEM-AP. + * @param value points to where the word will be stored when the + * transaction queue is flushed (assuming no errors). + * + * @return ERROR_OK for success. Otherwise a fault code. + */ +int mem_ap_read_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t *value) +{ + int retval; + + /* Use banked addressing (REG_BDx) to avoid some link traffic + * (updating TAR) when reading several consecutive addresses. + */ + retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, + address & 0xFFFFFFF0); + if (retval != ERROR_OK) + return retval; + + return dap_queue_ap_read(swjdp, AP_REG_BD0 | (address & 0xC), value); +} + +/** + * Synchronous read of a word from memory or a system register. + * As a side effect, this flushes any queued transactions. + * + * @param swjdp The DAP connected to the MEM-AP performing the read. + * @param address Address of the 32-bit word to read; it must be + * readable by the currently selected MEM-AP. + * @param value points to where the result will be stored. + * + * @return ERROR_OK for success; *value holds the result. + * Otherwise a fault code. + */ +int mem_ap_read_atomic_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t *value) +{ + int retval; + + retval = mem_ap_read_u32(swjdp, address, value); + if (retval != ERROR_OK) + return retval; + + return dap_run(swjdp); +} + +/** + * Asynchronous (queued) write of a word to memory or a system register. + * + * @param swjdp The DAP connected to the MEM-AP. + * @param address Address to be written; it must be writable by + * the currently selected MEM-AP. + * @param value Word that will be written to the address when transaction + * queue is flushed (assuming no errors). + * + * @return ERROR_OK for success. Otherwise a fault code. + */ +int mem_ap_write_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t value) +{ + int retval; + + /* Use banked addressing (REG_BDx) to avoid some link traffic + * (updating TAR) when writing several consecutive addresses. + */ + retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, + address & 0xFFFFFFF0); + if (retval != ERROR_OK) + return retval; + + return dap_queue_ap_write(swjdp, AP_REG_BD0 | (address & 0xC), + value); +} + +/** + * Synchronous write of a word to memory or a system register. + * As a side effect, this flushes any queued transactions. + * + * @param swjdp The DAP connected to the MEM-AP. + * @param address Address to be written; it must be writable by + * the currently selected MEM-AP. + * @param value Word that will be written. + * + * @return ERROR_OK for success; the data was written. Otherwise a fault code. + */ +int mem_ap_write_atomic_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t value) +{ + int retval = mem_ap_write_u32(swjdp, address, value); + + if (retval != ERROR_OK) + return retval; + + return dap_run(swjdp); +} + +/***************************************************************************** +* * +* mem_ap_write_buf(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) * +* * +* Write a buffer in target order (little endian) * +* * +*****************************************************************************/ +int mem_ap_write_buf_u32(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) +{ + int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; + uint32_t adr = address; + uint8_t* pBuffer = buffer; + + count >>= 2; + wcount = count; + + /* if we have an unaligned access - reorder data */ + if (adr & 0x3u) + { + for (writecount = 0; writecount < count; writecount++) + { + int i; + uint32_t outvalue; + memcpy(&outvalue, pBuffer, sizeof(uint32_t)); + + for (i = 0; i < 4; i++) + { + *((uint8_t*)pBuffer + (adr & 0x3)) = outvalue; + outvalue >>= 8; + adr++; + } + pBuffer += sizeof(uint32_t); + } + } + + while (wcount > 0) + { + /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + if (wcount < blocksize) + blocksize = wcount; + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + + dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + + for (writecount = 0; writecount < blocksize; writecount++) + { + retval = dap_queue_ap_write(swjdp, AP_REG_DRW, + *(uint32_t *) (buffer + 4 * writecount)); + if (retval != ERROR_OK) + break; + } + + if (dap_run(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address = address + 4 * blocksize; + buffer = buffer + 4 * blocksize; + } + else + { + errorcount++; + } + + if (errorcount > 1) + { + LOG_WARNING("Block write error address 0x%" PRIx32 ", wcount 0x%x", address, wcount); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + return retval; +} + +static int mem_ap_write_buf_packed_u16(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + int wcount, blocksize, writecount, i; + + wcount = count >> 1; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + + if (wcount < blocksize) + blocksize = wcount; + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_PACKED, address); + writecount = blocksize; + + do + { + nbytes = MIN((writecount << 1), 4); + + if (nbytes < 4) + { + if (mem_ap_write_buf_u16(swjdp, buffer, + nbytes, address) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + + address += nbytes >> 1; + } + else + { + uint32_t outvalue; + memcpy(&outvalue, buffer, sizeof(uint32_t)); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer + (address & 0x3)) = outvalue; + outvalue >>= 8; + address++; + } + + memcpy(&outvalue, buffer, sizeof(uint32_t)); + retval = dap_queue_ap_write(swjdp, + AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + /* REVISIT return *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + buffer += nbytes >> 1; + writecount -= nbytes >> 1; + + } while (writecount); + wcount -= blocksize; + } + + return retval; +} + +int mem_ap_write_buf_u16(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_write_buf_packed_u16(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + uint16_t svalue; + memcpy(&svalue, buffer, sizeof(uint16_t)); + uint32_t outvalue = (uint32_t)svalue << 8 * (address & 0x3); + retval = dap_queue_ap_write(swjdp, AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +static int mem_ap_write_buf_packed_u8(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + int wcount, blocksize, writecount, i; + + wcount = count; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + + if (wcount < blocksize) + blocksize = wcount; + + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_PACKED, address); + writecount = blocksize; + + do + { + nbytes = MIN(writecount, 4); + + if (nbytes < 4) + { + if (mem_ap_write_buf_u8(swjdp, buffer, nbytes, address) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + + address += nbytes; + } + else + { + uint32_t outvalue; + memcpy(&outvalue, buffer, sizeof(uint32_t)); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer + (address & 0x3)) = outvalue; + outvalue >>= 8; + address++; + } + + memcpy(&outvalue, buffer, sizeof(uint32_t)); + retval = dap_queue_ap_write(swjdp, + AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + /* REVISIT return *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + buffer += nbytes; + writecount -= nbytes; + + } while (writecount); + wcount -= blocksize; + } + + return retval; +} + +int mem_ap_write_buf_u8(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_write_buf_packed_u8(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + uint32_t outvalue = (uint32_t)*buffer << 8 * (address & 0x3); + retval = dap_queue_ap_write(swjdp, AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + count--; + address++; + buffer++; + } + + return retval; +} + +/* FIXME don't import ... this is a temporary workaround for the + * mem_ap_read_buf_u32() mess, until it's no longer JTAG-specific. + */ +extern int adi_jtag_dp_scan(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint8_t *outvalue, uint8_t *invalue, uint8_t *ack); + +/** + * Synchronously read a block of 32-bit words into a buffer + * @param swjdp The DAP connected to the MEM-AP. + * @param buffer where the words will be stored (in host byte order). + * @param count How many words to read. + * @param address Memory address from which to read words; all the + * words must be readable by the currently selected MEM-AP. + */ +int mem_ap_read_buf_u32(struct adiv5_dap *swjdp, uint8_t *buffer, + int count, uint32_t address) +{ + int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; + uint32_t adr = address; + uint8_t* pBuffer = buffer; + + count >>= 2; + wcount = count; + + while (wcount > 0) + { + /* Adjust to read blocks within boundaries aligned to the + * TAR autoincrement size (at least 2^10). Autoincrement + * mode avoids an extra per-word roundtrip to update TAR. + */ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, + address); + if (wcount < blocksize) + blocksize = wcount; + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + + dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, + address); + + /* FIXME remove these three calls to adi_jtag_dp_scan(), + * so this routine becomes transport-neutral. Be careful + * not to cause performance problems with JTAG; would it + * suffice to loop over dap_queue_ap_read(), or would that + * be slower when JTAG is the chosen transport? + */ + + /* Scan out first read */ + adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW, + DPAP_READ, 0, NULL, NULL); + for (readcount = 0; readcount < blocksize - 1; readcount++) + { + /* Scan out next read; scan in posted value for the + * previous one. Assumes read is acked "OK/FAULT", + * and CTRL_STAT says that meant "OK". + */ + adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW, + DPAP_READ, 0, buffer + 4 * readcount, + &swjdp->ack); + } + + /* Scan in last posted value; RDBUFF has no other effect, + * assuming ack is OK/FAULT and CTRL_STAT says "OK". + */ + adi_jtag_dp_scan(swjdp, JTAG_DP_DPACC, DP_RDBUFF, + DPAP_READ, 0, buffer + 4 * readcount, + &swjdp->ack); + if (dap_run(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address += 4 * blocksize; + buffer += 4 * blocksize; + } + else + { + errorcount++; + } + + if (errorcount > 1) + { + LOG_WARNING("Block read error address 0x%" PRIx32 + ", count 0x%x", address, count); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + /* if we have an unaligned access - reorder data */ + if (adr & 0x3u) + { + for (readcount = 0; readcount < count; readcount++) + { + int i; + uint32_t data; + memcpy(&data, pBuffer, sizeof(uint32_t)); + + for (i = 0; i < 4; i++) + { + *((uint8_t*)pBuffer) = + (data >> 8 * (adr & 0x3)); + pBuffer++; + adr++; + } + } + } + + return retval; +} + +static int mem_ap_read_buf_packed_u16(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + uint32_t invalue; + int retval = ERROR_OK; + int wcount, blocksize, readcount, i; + + wcount = count >> 1; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + if (wcount < blocksize) + blocksize = wcount; + + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_PACKED, address); + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + readcount = blocksize; + + do + { + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + + nbytes = MIN((readcount << 1), 4); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + buffer++; + address++; + } + + readcount -= (nbytes >> 1); + } while (readcount); + wcount -= blocksize; + } + + return retval; +} + +/** + * Synchronously read a block of 16-bit halfwords into a buffer + * @param swjdp The DAP connected to the MEM-AP. + * @param buffer where the halfwords will be stored (in host byte order). + * @param count How many halfwords to read. + * @param address Memory address from which to read words; all the + * words must be readable by the currently selected MEM-AP. + */ +int mem_ap_read_buf_u16(struct adiv5_dap *swjdp, uint8_t *buffer, + int count, uint32_t address) +{ + uint32_t invalue, i; + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_read_buf_packed_u16(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + if (retval != ERROR_OK) + break; + + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + if (address & 0x1) + { + for (i = 0; i < 2; i++) + { + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + buffer++; + address++; + } + } + else + { + uint16_t svalue = (invalue >> 8 * (address & 0x3)); + memcpy(buffer, &svalue, sizeof(uint16_t)); + address += 2; + buffer += 2; + } + count -= 2; + } + + return retval; +} + +/* FIX!!! is this a potential performance bottleneck w.r.t. requiring too many + * roundtrips when jtag_execute_queue() has a large overhead(e.g. for USB)s? + * + * The solution is to arrange for a large out/in scan in this loop and + * and convert data afterwards. + */ +static int mem_ap_read_buf_packed_u8(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + uint32_t invalue; + int retval = ERROR_OK; + int wcount, blocksize, readcount, i; + + wcount = count; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + + if (wcount < blocksize) + blocksize = wcount; + + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_PACKED, address); + readcount = blocksize; + + do + { + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + + nbytes = MIN(readcount, 4); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + buffer++; + address++; + } + + readcount -= nbytes; + } while (readcount); + wcount -= blocksize; + } + + return retval; +} + +/** + * Synchronously read a block of bytes into a buffer + * @param swjdp The DAP connected to the MEM-AP. + * @param buffer where the bytes will be stored. + * @param count How many bytes to read. + * @param address Memory address from which to read data; all the + * data must be readable by the currently selected MEM-AP. + */ +int mem_ap_read_buf_u8(struct adiv5_dap *swjdp, uint8_t *buffer, + int count, uint32_t address) +{ + uint32_t invalue; + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_read_buf_packed_u8(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + count--; + address++; + buffer++; + } + + return retval; +} + +/*--------------------------------------------------------------------------*/ + +<<<<<<< HEAD:src/target/arm_adi_v5.c +======= +static int jtag_idcode_q_read(struct adiv5_dap *dap, + uint8_t *ack, uint32_t *data) +{ + struct arm_jtag *jtag_info = dap->jtag_info; + int retval; + struct scan_field fields[1]; + + jtag_set_end_state(TAP_IDLE); + + /* This is a standard JTAG operation -- no DAP tweakage */ + retval = arm_jtag_set_instr(jtag_info, JTAG_DP_IDCODE, NULL); + if (retval != ERROR_OK) + return retval; + + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].in_value = (void *) data; + + jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE); + retval = jtag_get_error(); + if (retval != ERROR_OK) + return retval; + + jtag_add_callback(arm_le_to_h_u32, + (jtag_callback_data_t) data); + + return retval; +} + +static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data) +{ + return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, + reg, DPAP_READ, 0, data); +} + +static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data) +{ + return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, + reg, DPAP_WRITE, data, NULL); +} + +/** Select the AP register bank matching bits 7:4 of reg. */ +static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg) +{ + uint32_t select = reg & 0x000000F0; + + if (select == dap->ap_bank_value) + return ERROR_OK; + dap->ap_bank_value = select; + + select |= dap->apsel; + + return jtag_dp_q_write(dap, DP_SELECT, select); +} + +static int jtag_ap_q_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data) +{ + int retval = jtag_ap_q_bankselect(dap, reg); + + if (retval != ERROR_OK) + return retval; + + return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_APACC, reg, + DPAP_READ, 0, data); +} + +static int jtag_ap_q_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data) +{ + uint8_t out_value_buf[4]; + + int retval = jtag_ap_q_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; +>>>>>>> jtag: cut down on usage of unintended modification of global end state:src/target/arm_adi_v5.c + +/* FIXME don't import ... just initialize as + * part of DAP transport setup +*/ +extern const struct dap_ops jtag_dp_ops; + +/*--------------------------------------------------------------------------*/ + +/** + * Initialize a DAP. This sets up the power domains, prepares the DP + * for further use, and arranges to use AP #0 for all AP operations + * until dap_ap-select() changes that policy. + * + * @param swjdp The DAP being initialized. + * + * @todo Rename this. We also need an initialization scheme which account + * for SWD transports not just JTAG; that will need to address differences + * in layering. (JTAG is useful without any debug target; but not SWD.) + * And this may not even use an AHB-AP ... e.g. DAP-Lite uses an APB-AP. + */ +int ahbap_debugport_init(struct adiv5_dap *swjdp) +{ + uint32_t idreg, romaddr, dummy; + uint32_t ctrlstat; + int cnt = 0; + int retval; + + LOG_DEBUG(" "); + + /* JTAG-DP or SWJ-DP, in JTAG mode */ + swjdp->ops = &jtag_dp_ops; + + /* Default MEM-AP setup. + * + * REVISIT AP #0 may be an inappropriate default for this. + * Should we probe, or take a hint from the caller? + * Presumably we can ignore the possibility of multiple APs. + */ + swjdp->apsel = !0; + dap_ap_select(swjdp, 0); + + /* DP initialization */ + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_dp_write(swjdp, DP_CTRL_STAT, SSTICKYERR); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + retval = dap_queue_dp_write(swjdp, DP_CTRL_STAT, swjdp->dp_ctrl_stat); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) + return retval; + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + + /* Check that we have debug power domains activated */ + while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) + { + LOG_DEBUG("DAP: wait CDBGPWRUPACK"); + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) + return retval; + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + alive_sleep(10); + } + + while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) + { + LOG_DEBUG("DAP: wait CSYSPWRUPACK"); + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) + return retval; + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + alive_sleep(10); + } + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + /* With debug power on we can activate OVERRUN checking */ + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; + retval = dap_queue_dp_write(swjdp, DP_CTRL_STAT, swjdp->dp_ctrl_stat); + if (retval != ERROR_OK) + return retval; + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + + /* + * REVISIT this isn't actually *initializing* anything in an AP, + * and doesn't care if it's a MEM-AP at all (much less AHB-AP). + * Should it? If the ROM address is valid, is this the right + * place to scan the table and do any topology detection? + */ + retval = dap_queue_ap_read(swjdp, AP_REG_IDR, &idreg); + retval = dap_queue_ap_read(swjdp, AP_REG_BASE, &romaddr); + + LOG_DEBUG("MEM-AP #%d ID Register 0x%" PRIx32 + ", Debug ROM Address 0x%" PRIx32, + swjdp->apsel, idreg, romaddr); + + return ERROR_OK; +} + +/* CID interpretation -- see ARM IHI 0029B section 3 + * and ARM IHI 0031A table 13-3. + */ +static const char *class_description[16] ={ + "Reserved", "ROM table", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "CoreSight component", "Reserved", "Peripheral Test Block", + "Reserved", "OptimoDE DESS", + "Generic IP component", "PrimeCell or System component" +}; + +static bool +is_dap_cid_ok(uint32_t cid3, uint32_t cid2, uint32_t cid1, uint32_t cid0) +{ + return cid3 == 0xb1 && cid2 == 0x05 + && ((cid1 & 0x0f) == 0) && cid0 == 0x0d; +} + +static int dap_info_command(struct command_context *cmd_ctx, + struct adiv5_dap *swjdp, int apsel) +{ + int retval; + uint32_t dbgbase, apid; + int romtable_present = 0; + uint8_t mem_ap; + uint32_t apselold; + + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + + apselold = swjdp->apsel; + dap_ap_select(swjdp, apsel); + retval = dap_queue_ap_read(swjdp, AP_REG_BASE, &dbgbase); + retval = dap_queue_ap_read(swjdp, AP_REG_IDR, &apid); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + return retval; + + /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ + mem_ap = ((apid&0x10000) && ((apid&0x0F) != 0)); + command_print(cmd_ctx, "AP ID register 0x%8.8" PRIx32, apid); + if (apid) + { + switch (apid&0x0F) + { + case 0: + command_print(cmd_ctx, "\tType is JTAG-AP"); + break; + case 1: + command_print(cmd_ctx, "\tType is MEM-AP AHB"); + break; + case 2: + command_print(cmd_ctx, "\tType is MEM-AP APB"); + break; + default: + command_print(cmd_ctx, "\tUnknown AP type"); + break; + } + + /* NOTE: a MEM-AP may have a single CoreSight component that's + * not a ROM table ... or have no such components at all. + */ + if (mem_ap) + command_print(cmd_ctx, "AP BASE 0x%8.8" PRIx32, + dbgbase); + } + else + { + command_print(cmd_ctx, "No AP found at this apsel 0x%x", apsel); + } + + romtable_present = ((mem_ap) && (dbgbase != 0xFFFFFFFF)); + if (romtable_present) + { + uint32_t cid0,cid1,cid2,cid3,memtype,romentry; + uint16_t entry_offset; + + /* bit 16 of apid indicates a memory access port */ + if (dbgbase & 0x02) + command_print(cmd_ctx, "\tValid ROM table present"); + else + command_print(cmd_ctx, "\tROM table in legacy format"); + + /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFF0, &cid0); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFF4, &cid1); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFF8, &cid2); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFFC, &cid3); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFCC, &memtype); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + return retval; + + if (!is_dap_cid_ok(cid3, cid2, cid1, cid0)) + command_print(cmd_ctx, "\tCID3 0x%2.2" PRIx32 + ", CID2 0x%2.2" PRIx32 + ", CID1 0x%2.2" PRIx32 + ", CID0 0x%2.2" PRIx32, + cid3, cid2, cid1, cid0); + if (memtype & 0x01) + command_print(cmd_ctx, "\tMEMTYPE system memory present on bus"); + else + command_print(cmd_ctx, "\tMEMTYPE System memory not present. " + "Dedicated debug bus."); + + /* Now we read ROM table entries from dbgbase&0xFFFFF000) | 0x000 until we get 0x00000000 */ + entry_offset = 0; + do + { + mem_ap_read_atomic_u32(swjdp, (dbgbase&0xFFFFF000) | entry_offset, &romentry); + command_print(cmd_ctx, "\tROMTABLE[0x%x] = 0x%" PRIx32 "",entry_offset,romentry); + if (romentry&0x01) + { + uint32_t c_cid0, c_cid1, c_cid2, c_cid3; + uint32_t c_pid0, c_pid1, c_pid2, c_pid3, c_pid4; + uint32_t component_start, component_base; + unsigned part_num; + char *type, *full; + + component_base = (uint32_t)((dbgbase & 0xFFFFF000) + + (int)(romentry & 0xFFFFF000)); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFE0, &c_pid0); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFE4, &c_pid1); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFE8, &c_pid2); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFEC, &c_pid3); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFD0, &c_pid4); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFF0, &c_cid0); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFF4, &c_cid1); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFF8, &c_cid2); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFFC, &c_cid3); + component_start = component_base - 0x1000*(c_pid4 >> 4); + + command_print(cmd_ctx, "\t\tComponent base address 0x%" PRIx32 + ", start address 0x%" PRIx32, + component_base, component_start); + command_print(cmd_ctx, "\t\tComponent class is 0x%x, %s", + (int) (c_cid1 >> 4) & 0xf, + /* See ARM IHI 0029B Table 3-3 */ + class_description[(c_cid1 >> 4) & 0xf]); + + /* CoreSight component? */ + if (((c_cid1 >> 4) & 0x0f) == 9) { + uint32_t devtype; + unsigned minor; + char *major = "Reserved", *subtype = "Reserved"; + + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xfffff000) | 0xfcc, + &devtype); + minor = (devtype >> 4) & 0x0f; + switch (devtype & 0x0f) { + case 0: + major = "Miscellaneous"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 4: + subtype = "Validation component"; + break; + } + break; + case 1: + major = "Trace Sink"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Port"; + break; + case 2: + subtype = "Buffer"; + break; + } + break; + case 2: + major = "Trace Link"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Funnel, router"; + break; + case 2: + subtype = "Filter"; + break; + case 3: + subtype = "FIFO, buffer"; + break; + } + break; + case 3: + major = "Trace Source"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Processor"; + break; + case 2: + subtype = "DSP"; + break; + case 3: + subtype = "Engine/Coprocessor"; + break; + case 4: + subtype = "Bus"; + break; + } + break; + case 4: + major = "Debug Control"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Trigger Matrix"; + break; + case 2: + subtype = "Debug Auth"; + break; + } + break; + case 5: + major = "Debug Logic"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Processor"; + break; + case 2: + subtype = "DSP"; + break; + case 3: + subtype = "Engine/Coprocessor"; + break; + } + break; + } + command_print(cmd_ctx, "\t\tType is 0x%2.2x, %s, %s", + (unsigned) (devtype & 0xff), + major, subtype); + /* REVISIT also show 0xfc8 DevId */ + } + + if (!is_dap_cid_ok(cid3, cid2, cid1, cid0)) + command_print(cmd_ctx, "\t\tCID3 0x%2.2" PRIx32 + ", CID2 0x%2.2" PRIx32 + ", CID1 0x%2.2" PRIx32 + ", CID0 0x%2.2" PRIx32, + c_cid3, c_cid2, c_cid1, c_cid0); + command_print(cmd_ctx, "\t\tPeripheral ID[4..0] = hex " + "%2.2x %2.2x %2.2x %2.2x %2.2x", + (int) c_pid4, + (int) c_pid3, (int) c_pid2, + (int) c_pid1, (int) c_pid0); + + /* Part number interpretations are from Cortex + * core specs, the CoreSight components TRM + * (ARM DDI 0314H), and ETM specs; also from + * chip observation (e.g. TI SDTI). + */ + part_num = c_pid0 & 0xff; + part_num |= (c_pid1 & 0x0f) << 8; + switch (part_num) { + case 0x000: + type = "Cortex-M3 NVIC"; + full = "(Interrupt Controller)"; + break; + case 0x001: + type = "Cortex-M3 ITM"; + full = "(Instrumentation Trace Module)"; + break; + case 0x002: + type = "Cortex-M3 DWT"; + full = "(Data Watchpoint and Trace)"; + break; + case 0x003: + type = "Cortex-M3 FBP"; + full = "(Flash Patch and Breakpoint)"; + break; + case 0x00d: + type = "CoreSight ETM11"; + full = "(Embedded Trace)"; + break; + // case 0x113: what? + case 0x120: /* from OMAP3 memmap */ + type = "TI SDTI"; + full = "(System Debug Trace Interface)"; + break; + case 0x343: /* from OMAP3 memmap */ + type = "TI DAPCTL"; + full = ""; + break; + case 0x906: + type = "Coresight CTI"; + full = "(Cross Trigger)"; + break; + case 0x907: + type = "Coresight ETB"; + full = "(Trace Buffer)"; + break; + case 0x908: + type = "Coresight CSTF"; + full = "(Trace Funnel)"; + break; + case 0x910: + type = "CoreSight ETM9"; + full = "(Embedded Trace)"; + break; + case 0x912: + type = "Coresight TPIU"; + full = "(Trace Port Interface Unit)"; + break; + case 0x921: + type = "Cortex-A8 ETM"; + full = "(Embedded Trace)"; + break; + case 0x922: + type = "Cortex-A8 CTI"; + full = "(Cross Trigger)"; + break; + case 0x923: + type = "Cortex-M3 TPIU"; + full = "(Trace Port Interface Unit)"; + break; + case 0x924: + type = "Cortex-M3 ETM"; + full = "(Embedded Trace)"; + break; + case 0xc08: + type = "Cortex-A8 Debug"; + full = "(Debug Unit)"; + break; + default: + type = "-*- unrecognized -*-"; + full = ""; + break; + } + command_print(cmd_ctx, "\t\tPart is %s %s", + type, full); + } + else + { + if (romentry) + command_print(cmd_ctx, "\t\tComponent not present"); + else + command_print(cmd_ctx, "\t\tEnd of ROM table"); + } + entry_offset += 4; + } while (romentry > 0); + } + else + { + command_print(cmd_ctx, "\tNo ROM table present"); + } + dap_ap_select(swjdp, apselold); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_dap_info_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + uint32_t apsel; + + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return dap_info_command(CMD_CTX, dap, apsel); +} + +COMMAND_HANDLER(dap_baseaddr_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t apsel, apselsave, baseaddr; + int retval; + + apselsave = dap->apsel; + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (apselsave != apsel) + dap_ap_select(dap, apsel); + + /* NOTE: assumes we're talking to a MEM-AP, which + * has a base address. There are other kinds of AP, + * though they're not common for now. This should + * use the ID register to verify it's a MEM-AP. + */ + retval = dap_queue_ap_read(dap, AP_REG_BASE, &baseaddr); + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "0x%8.8" PRIx32, baseaddr); + + if (apselsave != apsel) + dap_ap_select(dap, apselsave); + + return retval; +} + +COMMAND_HANDLER(dap_memaccess_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t memaccess_tck; + + switch (CMD_ARGC) { + case 0: + memaccess_tck = dap->memaccess_tck; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], memaccess_tck); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + dap->memaccess_tck = memaccess_tck; + + command_print(CMD_CTX, "memory bus access delay set to %" PRIi32 " tck", + dap->memaccess_tck); + + return ERROR_OK; +} + +COMMAND_HANDLER(dap_apsel_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t apsel, apid; + int retval; + + switch (CMD_ARGC) { + case 0: + apsel = 0; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + dap_ap_select(dap, apsel); + retval = dap_queue_ap_read(dap, AP_REG_IDR, &apid); + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32, + apsel, apid); + + return retval; +} + +COMMAND_HANDLER(dap_apid_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t apsel, apselsave, apid; + int retval; + + apselsave = dap->apsel; + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (apselsave != apsel) + dap_ap_select(dap, apsel); + + retval = dap_queue_ap_read(dap, AP_REG_IDR, &apid); + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "0x%8.8" PRIx32, apid); + if (apselsave != apsel) + dap_ap_select(dap, apselsave); + + return retval; +} + +static const struct command_registration dap_commands[] = { + { + .name = "info", + .handler = handle_dap_info_command, + .mode = COMMAND_EXEC, + .help = "display ROM table for MEM-AP " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + { + .name = "apsel", + .handler = dap_apsel_command, + .mode = COMMAND_EXEC, + .help = "Set the currently selected AP (default 0) " + "and display the result", + .usage = "[ap_num]", + }, + { + .name = "apid", + .handler = dap_apid_command, + .mode = COMMAND_EXEC, + .help = "return ID register from AP " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + { + .name = "baseaddr", + .handler = dap_baseaddr_command, + .mode = COMMAND_EXEC, + .help = "return debug base address from MEM-AP " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + { + .name = "memaccess", + .handler = dap_memaccess_command, + .mode = COMMAND_EXEC, + .help = "set/get number of extra tck for MEM-AP memory " + "bus access [0-255]", + .usage = "[cycles]", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration dap_command_handlers[] = { + { + .name = "dap", + .mode = COMMAND_EXEC, + .help = "DAP command group", + .chain = dap_commands, + }, + COMMAND_REGISTRATION_DONE +}; + + +/* + * This represents the bits which must be sent out on TMS/SWDIO to + * switch a DAP implemented using an SWJ-DP module into SWD mode. + * These bits are stored (and transmitted) LSB-first. + * + * See the DAP-Lite specification, section 2.2.5 for information + * about making the debug link select SWD or JTAG. (Similar info + * is in a few other ARM documents.) + */ +static const uint8_t jtag2swd_bitseq[] = { + /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, + * putting both JTAG and SWD logic into reset state. + */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* Switching sequence enables SWD and disables JTAG + * NOTE: bits in the DP's IDCODE may expose the need for + * an old/deprecated sequence (0xb6 0xed). + */ + 0x9e, 0xe7, + /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, + * putting both JTAG and SWD logic into reset state. + */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +/** + * Put the debug link into SWD mode, if the target supports it. + * The link's initial mode may be either JTAG (for example, + * with SWJ-DP after reset) or SWD. + * + * @param target Enters SWD mode (if possible). + * + * Note that targets using the JTAG-DP do not support SWD, and that + * some targets which could otherwise support it may have have been + * configured to disable SWD signaling + * + * @return ERROR_OK or else a fault code. + */ +int dap_to_swd(struct target *target) +{ + int retval; + + LOG_DEBUG("Enter SWD mode"); + + /* REVISIT it's nasty to need to make calls to a "jtag" + * subsystem if the link isn't in JTAG mode... + */ + + retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq), + jtag2swd_bitseq, TAP_INVALID); + if (retval == ERROR_OK) + retval = jtag_execute_queue(); + + /* REVISIT set up the DAP's ops vector for SWD mode. */ + + return retval; +} + diff --git a/src/target/arm_adi_v5.c~ b/src/target/arm_adi_v5.c~ new file mode 100644 index 0000000000..708e8581fd --- /dev/null +++ b/src/target/arm_adi_v5.c~ @@ -0,0 +1,1981 @@ +/*************************************************************************** + * Copyright (C) 2006 by Magnus Lundin * + * lundin@mlu.mine.nu * + * * + * Copyright (C) 2008 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * Copyright (C) 2009 by Oyvind Harboe * + * oyvind.harboe@zylin.com * + * * + * Copyright (C) 2009-2010 by David Brownell * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/** + * @file + * This file implements support for the ARM Debug Interface version 5 (ADIv5) + * debugging architecture. Compared with previous versions, this includes + * a low pin-count Serial Wire Debug (SWD) alternative to JTAG for message + * transport, and focusses on memory mapped resources as defined by the + * CoreSight architecture. + * + * A key concept in ADIv5 is the Debug Access Port, or DAP. A DAP has two + * basic components: a Debug Port (DP) transporting messages to and from a + * debugger, and an Access Port (AP) accessing resources. Three types of DP + * are defined. One uses only JTAG for communication, and is called JTAG-DP. + * One uses only SWD for communication, and is called SW-DP. The third can + * use either SWD or JTAG, and is called SWJ-DP. The most common type of AP + * is used to access memory mapped resources and is called a MEM-AP. Also a + * JTAG-AP is also defined, bridging to JTAG resources; those are uncommon. + * + * This programming interface allows DAP pipelined operations through a + * transaction queue. This primarily affects AP operations (such as using + * a MEM-AP to access memory or registers). If the current transaction has + * not finished by the time the next one must begin, and the ORUNDETECT bit + * is set in the DP_CTRL_STAT register, the SSTICKYORUN status is set and + * further AP operations will fail. There are two basic methods to avoid + * such overrun errors. One involves polling for status instead of using + * transaction piplining. The other involves adding delays to ensure the + * AP has enough time to complete one operation before starting the next + * one. (For JTAG these delays are controlled by memaccess_tck.) + */ + +/* + * Relevant specifications from ARM include: + * + * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031A + * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B + * + * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D + * Cortex-M3(tm) TRM, ARM DDI 0337G + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm.h" +#include "arm_adi_v5.h" +#include + + +/* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */ + +/* + uint32_t tar_block_size(uint32_t address) + Return the largest block starting at address that does not cross a tar block size alignment boundary +*/ +static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address) +{ + return (tar_autoincr_block - ((tar_autoincr_block - 1) & address)) >> 2; +} + +/*************************************************************************** + * * +<<<<<<< HEAD:src/target/arm_adi_v5.c +======= + * DPACC and APACC scanchain access through JTAG-DP * + * * +***************************************************************************/ + +/** + * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness + * conversions are performed. See section 4.4.3 of the ADIv5 spec, which + * discusses operations which access these registers. + * + * Note that only one scan is performed. If RnW is set, a separate scan + * will be needed to collect the data which was read; the "invalue" collects + * the posted result of a preceding operation, not the current one. + * + * @param swjdp the DAP + * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access) + * @param reg_addr two significant bits; A[3:2]; for APACC access, the + * SELECT register has more addressing bits. + * @param RnW false iff outvalue will be written to the DP or AP + * @param outvalue points to a 32-bit (little-endian) integer + * @param invalue NULL, or points to a 32-bit (little-endian) integer + * @param ack points to where the three bit JTAG_ACK_* code will be stored + */ +static int adi_jtag_dp_scan(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint8_t *outvalue, uint8_t *invalue, uint8_t *ack) +{ + struct arm_jtag *jtag_info = swjdp->jtag_info; + struct scan_field fields[2]; + uint8_t out_addr_buf; + + jtag_set_end_state(TAP_IDLE); + arm_jtag_set_instr(jtag_info, instr, NULL); + + /* Scan out a read or write operation using some DP or AP register. + * For APACC access with any sticky error flag set, this is discarded. + */ + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].in_value = ack; + + /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not + * complete; data we write is discarded, data we read is unpredictable. + * When overrun detect is active, STICKYORUN is set. + */ + + fields[1].num_bits = 32; + fields[1].out_value = outvalue; + fields[1].in_value = invalue; + + jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); + + /* Add specified number of tck clocks after starting memory bus + * access, giving the hardware time to complete the access. + * They provide more time for the (MEM) AP to complete the read ... + * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec. + */ + if ((instr == JTAG_DP_APACC) + && ((reg_addr == AP_REG_DRW) + || ((reg_addr & 0xF0) == AP_REG_BD0)) + && (swjdp->memaccess_tck != 0)) + jtag_add_runtest(swjdp->memaccess_tck, + TAP_IDLE); + + return jtag_get_error(); +} + +/** + * Scan DPACC or APACC out and in from host ordered uint32_t buffers. + * This is exactly like adi_jtag_dp_scan(), except that endianness + * conversions are performed (so the types of invalue and outvalue + * must be different). + */ +static int adi_jtag_dp_scan_u32(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint32_t outvalue, uint32_t *invalue, uint8_t *ack) +{ + uint8_t out_value_buf[4]; + int retval; + + buf_set_u32(out_value_buf, 0, 32, outvalue); + + retval = adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW, + out_value_buf, (uint8_t *)invalue, ack); + if (retval != ERROR_OK) + return retval; + + if (invalue) + jtag_add_callback(arm_le_to_h_u32, + (jtag_callback_data_t) invalue); + + return retval; +} + +/** + * Utility to write AP registers. + */ +static inline int adi_jtag_ap_write_check(struct adiv5_dap *dap, + uint8_t reg_addr, uint8_t *outvalue) +{ + return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE, + outvalue, NULL, NULL); +} + +static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint32_t outvalue, uint32_t *invalue) +{ + int retval; + + /* Issue the read or write */ + retval = adi_jtag_dp_scan_u32(swjdp, instr, reg_addr, + RnW, outvalue, NULL, NULL); + if (retval != ERROR_OK) + return retval; + + /* For reads, collect posted value; RDBUFF has no other effect. + * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK". + */ + if ((RnW == DPAP_READ) && (invalue != NULL)) + retval = adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC, + DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack); + return retval; +} + +static int jtagdp_transaction_endcheck(struct adiv5_dap *swjdp) +{ + int retval; + uint32_t ctrlstat; + + /* too expensive to call keep_alive() here */ + +#if 0 + /* Danger!!!! BROKEN!!!! */ + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + /* Danger!!!! BROKEN!!!! Why will jtag_execute_queue() fail here???? + R956 introduced the check on return value here and now Michael Schwingen reports + that this code no longer works.... + + https://lists.berlios.de/pipermail/openocd-development/2008-September/003107.html + */ + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + LOG_ERROR("BUG: Why does this fail the first time????"); + } + /* Why??? second time it works??? */ +#endif + + /* Post CTRL/STAT read; discard any previous posted read value + * but collect its ACK status. + */ + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + swjdp->ack = swjdp->ack & 0x7; + + /* common code path avoids calling timeval_ms() */ + if (swjdp->ack != JTAG_ACK_OK_FAULT) + { + long long then = timeval_ms(); + + while (swjdp->ack != JTAG_ACK_OK_FAULT) + { + if (swjdp->ack == JTAG_ACK_WAIT) + { + if ((timeval_ms()-then) > 1000) + { + /* NOTE: this would be a good spot + * to use JTAG_DP_ABORT. + */ + LOG_WARNING("Timeout (1000ms) waiting " + "for ACK=OK/FAULT " + "in JTAG-DP transaction"); + return ERROR_JTAG_DEVICE_ERROR; + } + } + else + { + LOG_WARNING("Invalid ACK %#x " + "in JTAG-DP transaction", + swjdp->ack); + return ERROR_JTAG_DEVICE_ERROR; + } + + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + swjdp->ack = swjdp->ack & 0x7; + } + } + + /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */ + + /* Check for STICKYERR and STICKYORUN */ + if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) + { + LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat); + /* Check power to debug regions */ + if ((ctrlstat & 0xf0000000) != 0xf0000000) + ahbap_debugport_init(swjdp); + else + { + uint32_t mem_ap_csw, mem_ap_tar; + + /* Maybe print information about last intended + * MEM-AP access; but not if autoincrementing. + * *Real* CSW and TAR values are always shown. + */ + if (swjdp->ap_tar_value != (uint32_t) -1) + LOG_DEBUG("MEM-AP Cached values: " + "ap_bank 0x%" PRIx32 + ", ap_csw 0x%" PRIx32 + ", ap_tar 0x%" PRIx32, + swjdp->ap_bank_value, + swjdp->ap_csw_value, + swjdp->ap_tar_value); + + if (ctrlstat & SSTICKYORUN) + LOG_ERROR("JTAG-DP OVERRUN - check clock, " + "memaccess, or reduce jtag speed"); + + if (ctrlstat & SSTICKYERR) + LOG_ERROR("JTAG-DP STICKY ERROR"); + + /* Clear Sticky Error Bits */ + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_WRITE, + swjdp->dp_ctrl_stat | SSTICKYORUN + | SSTICKYERR, NULL); + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + + LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat); + + retval = dap_queue_ap_read(swjdp, + AP_REG_CSW, &mem_ap_csw); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_ap_read(swjdp, + AP_REG_TAR, &mem_ap_tar); + if (retval != ERROR_OK) + return retval; + + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%" + PRIx32, mem_ap_csw, mem_ap_tar); + + } + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/*************************************************************************** + * * +>>>>>>> jtag: cut down on usage of unintended modification of global end state:src/target/arm_adi_v5.c + * DP and MEM-AP register access through APACC and DPACC * + * * +***************************************************************************/ + +/** + * Select one of the APs connected to the specified DAP. The + * selection is implicitly used with future AP transactions. + * This is a NOP if the specified AP is already selected. + * + * @param swjdp The DAP + * @param apsel Number of the AP to (implicitly) use with further + * transactions. This normally identifies a MEM-AP. + */ +void dap_ap_select(struct adiv5_dap *swjdp,uint8_t apsel) +{ + uint32_t select = (apsel << 24) & 0xFF000000; + + if (select != swjdp->apsel) + { + swjdp->apsel = select; + /* Switching AP invalidates cached values. + * Values MUST BE UPDATED BEFORE AP ACCESS. + */ + swjdp->ap_bank_value = -1; + swjdp->ap_csw_value = -1; + swjdp->ap_tar_value = -1; + } +} + +/** + * Queue transactions setting up transfer parameters for the + * currently selected MEM-AP. + * + * Subsequent transfers using registers like AP_REG_DRW or AP_REG_BD2 + * initiate data reads or writes using memory or peripheral addresses. + * If the CSW is configured for it, the TAR may be automatically + * incremented after each transfer. + * + * @todo Rename to reflect it being specifically a MEM-AP function. + * + * @param swjdp The DAP connected to the MEM-AP. + * @param csw MEM-AP Control/Status Word (CSW) register to assign. If this + * matches the cached value, the register is not changed. + * @param tar MEM-AP Transfer Address Register (TAR) to assign. If this + * matches the cached address, the register is not changed. + * + * @return ERROR_OK if the transaction was properly queued, else a fault code. + */ +int dap_setup_accessport(struct adiv5_dap *swjdp, uint32_t csw, uint32_t tar) +{ + int retval; + + csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT; + if (csw != swjdp->ap_csw_value) + { + /* LOG_DEBUG("DAP: Set CSW %x",csw); */ + retval = dap_queue_ap_write(swjdp, AP_REG_CSW, csw); + if (retval != ERROR_OK) + return retval; + swjdp->ap_csw_value = csw; + } + if (tar != swjdp->ap_tar_value) + { + /* LOG_DEBUG("DAP: Set TAR %x",tar); */ + retval = dap_queue_ap_write(swjdp, AP_REG_TAR, tar); + if (retval != ERROR_OK) + return retval; + swjdp->ap_tar_value = tar; + } + /* Disable TAR cache when autoincrementing */ + if (csw & CSW_ADDRINC_MASK) + swjdp->ap_tar_value = -1; + return ERROR_OK; +} + +/** + * Asynchronous (queued) read of a word from memory or a system register. + * + * @param swjdp The DAP connected to the MEM-AP performing the read. + * @param address Address of the 32-bit word to read; it must be + * readable by the currently selected MEM-AP. + * @param value points to where the word will be stored when the + * transaction queue is flushed (assuming no errors). + * + * @return ERROR_OK for success. Otherwise a fault code. + */ +int mem_ap_read_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t *value) +{ + int retval; + + /* Use banked addressing (REG_BDx) to avoid some link traffic + * (updating TAR) when reading several consecutive addresses. + */ + retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, + address & 0xFFFFFFF0); + if (retval != ERROR_OK) + return retval; + + return dap_queue_ap_read(swjdp, AP_REG_BD0 | (address & 0xC), value); +} + +/** + * Synchronous read of a word from memory or a system register. + * As a side effect, this flushes any queued transactions. + * + * @param swjdp The DAP connected to the MEM-AP performing the read. + * @param address Address of the 32-bit word to read; it must be + * readable by the currently selected MEM-AP. + * @param value points to where the result will be stored. + * + * @return ERROR_OK for success; *value holds the result. + * Otherwise a fault code. + */ +int mem_ap_read_atomic_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t *value) +{ + int retval; + + retval = mem_ap_read_u32(swjdp, address, value); + if (retval != ERROR_OK) + return retval; + + return dap_run(swjdp); +} + +/** + * Asynchronous (queued) write of a word to memory or a system register. + * + * @param swjdp The DAP connected to the MEM-AP. + * @param address Address to be written; it must be writable by + * the currently selected MEM-AP. + * @param value Word that will be written to the address when transaction + * queue is flushed (assuming no errors). + * + * @return ERROR_OK for success. Otherwise a fault code. + */ +int mem_ap_write_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t value) +{ + int retval; + + /* Use banked addressing (REG_BDx) to avoid some link traffic + * (updating TAR) when writing several consecutive addresses. + */ + retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, + address & 0xFFFFFFF0); + if (retval != ERROR_OK) + return retval; + + return dap_queue_ap_write(swjdp, AP_REG_BD0 | (address & 0xC), + value); +} + +/** + * Synchronous write of a word to memory or a system register. + * As a side effect, this flushes any queued transactions. + * + * @param swjdp The DAP connected to the MEM-AP. + * @param address Address to be written; it must be writable by + * the currently selected MEM-AP. + * @param value Word that will be written. + * + * @return ERROR_OK for success; the data was written. Otherwise a fault code. + */ +int mem_ap_write_atomic_u32(struct adiv5_dap *swjdp, uint32_t address, + uint32_t value) +{ + int retval = mem_ap_write_u32(swjdp, address, value); + + if (retval != ERROR_OK) + return retval; + + return dap_run(swjdp); +} + +/***************************************************************************** +* * +* mem_ap_write_buf(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) * +* * +* Write a buffer in target order (little endian) * +* * +*****************************************************************************/ +int mem_ap_write_buf_u32(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) +{ + int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; + uint32_t adr = address; + uint8_t* pBuffer = buffer; + + count >>= 2; + wcount = count; + + /* if we have an unaligned access - reorder data */ + if (adr & 0x3u) + { + for (writecount = 0; writecount < count; writecount++) + { + int i; + uint32_t outvalue; + memcpy(&outvalue, pBuffer, sizeof(uint32_t)); + + for (i = 0; i < 4; i++) + { + *((uint8_t*)pBuffer + (adr & 0x3)) = outvalue; + outvalue >>= 8; + adr++; + } + pBuffer += sizeof(uint32_t); + } + } + + while (wcount > 0) + { + /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + if (wcount < blocksize) + blocksize = wcount; + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + + dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + + for (writecount = 0; writecount < blocksize; writecount++) + { + retval = dap_queue_ap_write(swjdp, AP_REG_DRW, + *(uint32_t *) (buffer + 4 * writecount)); + if (retval != ERROR_OK) + break; + } + + if (dap_run(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address = address + 4 * blocksize; + buffer = buffer + 4 * blocksize; + } + else + { + errorcount++; + } + + if (errorcount > 1) + { + LOG_WARNING("Block write error address 0x%" PRIx32 ", wcount 0x%x", address, wcount); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + return retval; +} + +static int mem_ap_write_buf_packed_u16(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + int wcount, blocksize, writecount, i; + + wcount = count >> 1; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + + if (wcount < blocksize) + blocksize = wcount; + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_PACKED, address); + writecount = blocksize; + + do + { + nbytes = MIN((writecount << 1), 4); + + if (nbytes < 4) + { + if (mem_ap_write_buf_u16(swjdp, buffer, + nbytes, address) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + + address += nbytes >> 1; + } + else + { + uint32_t outvalue; + memcpy(&outvalue, buffer, sizeof(uint32_t)); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer + (address & 0x3)) = outvalue; + outvalue >>= 8; + address++; + } + + memcpy(&outvalue, buffer, sizeof(uint32_t)); + retval = dap_queue_ap_write(swjdp, + AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + /* REVISIT return *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + buffer += nbytes >> 1; + writecount -= nbytes >> 1; + + } while (writecount); + wcount -= blocksize; + } + + return retval; +} + +int mem_ap_write_buf_u16(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_write_buf_packed_u16(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + uint16_t svalue; + memcpy(&svalue, buffer, sizeof(uint16_t)); + uint32_t outvalue = (uint32_t)svalue << 8 * (address & 0x3); + retval = dap_queue_ap_write(swjdp, AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +static int mem_ap_write_buf_packed_u8(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + int wcount, blocksize, writecount, i; + + wcount = count; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + + if (wcount < blocksize) + blocksize = wcount; + + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_PACKED, address); + writecount = blocksize; + + do + { + nbytes = MIN(writecount, 4); + + if (nbytes < 4) + { + if (mem_ap_write_buf_u8(swjdp, buffer, nbytes, address) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + + address += nbytes; + } + else + { + uint32_t outvalue; + memcpy(&outvalue, buffer, sizeof(uint32_t)); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer + (address & 0x3)) = outvalue; + outvalue >>= 8; + address++; + } + + memcpy(&outvalue, buffer, sizeof(uint32_t)); + retval = dap_queue_ap_write(swjdp, + AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block write error address " + "0x%" PRIx32 ", count 0x%x", + address, count); + /* REVISIT return *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + buffer += nbytes; + writecount -= nbytes; + + } while (writecount); + wcount -= blocksize; + } + + return retval; +} + +int mem_ap_write_buf_u8(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address) +{ + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_write_buf_packed_u8(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + uint32_t outvalue = (uint32_t)*buffer << 8 * (address & 0x3); + retval = dap_queue_ap_write(swjdp, AP_REG_DRW, outvalue); + if (retval != ERROR_OK) + break; + + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + count--; + address++; + buffer++; + } + + return retval; +} + +/* FIXME don't import ... this is a temporary workaround for the + * mem_ap_read_buf_u32() mess, until it's no longer JTAG-specific. + */ +extern int adi_jtag_dp_scan(struct adiv5_dap *swjdp, + uint8_t instr, uint8_t reg_addr, uint8_t RnW, + uint8_t *outvalue, uint8_t *invalue, uint8_t *ack); + +/** + * Synchronously read a block of 32-bit words into a buffer + * @param swjdp The DAP connected to the MEM-AP. + * @param buffer where the words will be stored (in host byte order). + * @param count How many words to read. + * @param address Memory address from which to read words; all the + * words must be readable by the currently selected MEM-AP. + */ +int mem_ap_read_buf_u32(struct adiv5_dap *swjdp, uint8_t *buffer, + int count, uint32_t address) +{ + int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; + uint32_t adr = address; + uint8_t* pBuffer = buffer; + + count >>= 2; + wcount = count; + + while (wcount > 0) + { + /* Adjust to read blocks within boundaries aligned to the + * TAR autoincrement size (at least 2^10). Autoincrement + * mode avoids an extra per-word roundtrip to update TAR. + */ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, + address); + if (wcount < blocksize) + blocksize = wcount; + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + + dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, + address); + + /* FIXME remove these three calls to adi_jtag_dp_scan(), + * so this routine becomes transport-neutral. Be careful + * not to cause performance problems with JTAG; would it + * suffice to loop over dap_queue_ap_read(), or would that + * be slower when JTAG is the chosen transport? + */ + + /* Scan out first read */ + adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW, + DPAP_READ, 0, NULL, NULL); + for (readcount = 0; readcount < blocksize - 1; readcount++) + { + /* Scan out next read; scan in posted value for the + * previous one. Assumes read is acked "OK/FAULT", + * and CTRL_STAT says that meant "OK". + */ + adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW, + DPAP_READ, 0, buffer + 4 * readcount, + &swjdp->ack); + } + + /* Scan in last posted value; RDBUFF has no other effect, + * assuming ack is OK/FAULT and CTRL_STAT says "OK". + */ + adi_jtag_dp_scan(swjdp, JTAG_DP_DPACC, DP_RDBUFF, + DPAP_READ, 0, buffer + 4 * readcount, + &swjdp->ack); + if (dap_run(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address += 4 * blocksize; + buffer += 4 * blocksize; + } + else + { + errorcount++; + } + + if (errorcount > 1) + { + LOG_WARNING("Block read error address 0x%" PRIx32 + ", count 0x%x", address, count); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + } + + /* if we have an unaligned access - reorder data */ + if (adr & 0x3u) + { + for (readcount = 0; readcount < count; readcount++) + { + int i; + uint32_t data; + memcpy(&data, pBuffer, sizeof(uint32_t)); + + for (i = 0; i < 4; i++) + { + *((uint8_t*)pBuffer) = + (data >> 8 * (adr & 0x3)); + pBuffer++; + adr++; + } + } + } + + return retval; +} + +static int mem_ap_read_buf_packed_u16(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + uint32_t invalue; + int retval = ERROR_OK; + int wcount, blocksize, readcount, i; + + wcount = count >> 1; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + if (wcount < blocksize) + blocksize = wcount; + + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_PACKED, address); + + /* handle unaligned data at 4k boundary */ + if (blocksize == 0) + blocksize = 1; + readcount = blocksize; + + do + { + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + + nbytes = MIN((readcount << 1), 4); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + buffer++; + address++; + } + + readcount -= (nbytes >> 1); + } while (readcount); + wcount -= blocksize; + } + + return retval; +} + +/** + * Synchronously read a block of 16-bit halfwords into a buffer + * @param swjdp The DAP connected to the MEM-AP. + * @param buffer where the halfwords will be stored (in host byte order). + * @param count How many halfwords to read. + * @param address Memory address from which to read words; all the + * words must be readable by the currently selected MEM-AP. + */ +int mem_ap_read_buf_u16(struct adiv5_dap *swjdp, uint8_t *buffer, + int count, uint32_t address) +{ + uint32_t invalue, i; + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_read_buf_packed_u16(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + if (retval != ERROR_OK) + break; + + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + if (address & 0x1) + { + for (i = 0; i < 2; i++) + { + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + buffer++; + address++; + } + } + else + { + uint16_t svalue = (invalue >> 8 * (address & 0x3)); + memcpy(buffer, &svalue, sizeof(uint16_t)); + address += 2; + buffer += 2; + } + count -= 2; + } + + return retval; +} + +/* FIX!!! is this a potential performance bottleneck w.r.t. requiring too many + * roundtrips when jtag_execute_queue() has a large overhead(e.g. for USB)s? + * + * The solution is to arrange for a large out/in scan in this loop and + * and convert data afterwards. + */ +static int mem_ap_read_buf_packed_u8(struct adiv5_dap *swjdp, + uint8_t *buffer, int count, uint32_t address) +{ + uint32_t invalue; + int retval = ERROR_OK; + int wcount, blocksize, readcount, i; + + wcount = count; + + while (wcount > 0) + { + int nbytes; + + /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/ + blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + + if (wcount < blocksize) + blocksize = wcount; + + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_PACKED, address); + readcount = blocksize; + + do + { + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + if (dap_run(swjdp) != ERROR_OK) + { + LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count); + /* REVISIT return the *actual* fault code */ + return ERROR_JTAG_DEVICE_ERROR; + } + + nbytes = MIN(readcount, 4); + + for (i = 0; i < nbytes; i++) + { + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + buffer++; + address++; + } + + readcount -= nbytes; + } while (readcount); + wcount -= blocksize; + } + + return retval; +} + +/** + * Synchronously read a block of bytes into a buffer + * @param swjdp The DAP connected to the MEM-AP. + * @param buffer where the bytes will be stored. + * @param count How many bytes to read. + * @param address Memory address from which to read data; all the + * data must be readable by the currently selected MEM-AP. + */ +int mem_ap_read_buf_u8(struct adiv5_dap *swjdp, uint8_t *buffer, + int count, uint32_t address) +{ + uint32_t invalue; + int retval = ERROR_OK; + + if (count >= 4) + return mem_ap_read_buf_packed_u8(swjdp, buffer, count, address); + + while (count > 0) + { + dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + retval = dap_queue_ap_read(swjdp, AP_REG_DRW, &invalue); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + break; + + *((uint8_t*)buffer) = (invalue >> 8 * (address & 0x3)); + count--; + address++; + buffer++; + } + + return retval; +} + +/*--------------------------------------------------------------------------*/ + +<<<<<<< HEAD:src/target/arm_adi_v5.c +======= +static int jtag_idcode_q_read(struct adiv5_dap *dap, + uint8_t *ack, uint32_t *data) +{ + struct arm_jtag *jtag_info = dap->jtag_info; + int retval; + struct scan_field fields[1]; + + jtag_set_end_state(TAP_IDLE); + + /* This is a standard JTAG operation -- no DAP tweakage */ + retval = arm_jtag_set_instr(jtag_info, JTAG_DP_IDCODE, NULL); + if (retval != ERROR_OK) + return retval; + + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].in_value = (void *) data; + + jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE); + retval = jtag_get_error(); + if (retval != ERROR_OK) + return retval; + + jtag_add_callback(arm_le_to_h_u32, + (jtag_callback_data_t) data); + + return retval; +} + +static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data) +{ + return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, + reg, DPAP_READ, 0, data); +} + +static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data) +{ + return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, + reg, DPAP_WRITE, data, NULL); +} + +/** Select the AP register bank matching bits 7:4 of reg. */ +static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg) +{ + uint32_t select = reg & 0x000000F0; + + if (select == dap->ap_bank_value) + return ERROR_OK; + dap->ap_bank_value = select; + + select |= dap->apsel; + + return jtag_dp_q_write(dap, DP_SELECT, select); +} + +static int jtag_ap_q_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data) +{ + int retval = jtag_ap_q_bankselect(dap, reg); + + if (retval != ERROR_OK) + return retval; + + return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_APACC, reg, + DPAP_READ, 0, data); +} + +static int jtag_ap_q_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data) +{ + uint8_t out_value_buf[4]; + + int retval = jtag_ap_q_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; +>>>>>>> jtag: cut down on usage of unintended modification of global end state:src/target/arm_adi_v5.c + +/* FIXME don't import ... just initialize as + * part of DAP transport setup +*/ +extern const struct dap_ops jtag_dp_ops; + +/*--------------------------------------------------------------------------*/ + +/** + * Initialize a DAP. This sets up the power domains, prepares the DP + * for further use, and arranges to use AP #0 for all AP operations + * until dap_ap-select() changes that policy. + * + * @param swjdp The DAP being initialized. + * + * @todo Rename this. We also need an initialization scheme which account + * for SWD transports not just JTAG; that will need to address differences + * in layering. (JTAG is useful without any debug target; but not SWD.) + * And this may not even use an AHB-AP ... e.g. DAP-Lite uses an APB-AP. + */ +int ahbap_debugport_init(struct adiv5_dap *swjdp) +{ + uint32_t idreg, romaddr, dummy; + uint32_t ctrlstat; + int cnt = 0; + int retval; + + LOG_DEBUG(" "); + + /* JTAG-DP or SWJ-DP, in JTAG mode */ + swjdp->ops = &jtag_dp_ops; + + /* Default MEM-AP setup. + * + * REVISIT AP #0 may be an inappropriate default for this. + * Should we probe, or take a hint from the caller? + * Presumably we can ignore the possibility of multiple APs. + */ + swjdp->apsel = !0; + dap_ap_select(swjdp, 0); + + /* DP initialization */ + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_dp_write(swjdp, DP_CTRL_STAT, SSTICKYERR); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + retval = dap_queue_dp_write(swjdp, DP_CTRL_STAT, swjdp->dp_ctrl_stat); + if (retval != ERROR_OK) + return retval; + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) + return retval; + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + + /* Check that we have debug power domains activated */ + while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) + { + LOG_DEBUG("DAP: wait CDBGPWRUPACK"); + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) + return retval; + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + alive_sleep(10); + } + + while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) + { + LOG_DEBUG("DAP: wait CSYSPWRUPACK"); + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) + return retval; + if ((retval = dap_run(swjdp)) != ERROR_OK) + return retval; + alive_sleep(10); + } + + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + /* With debug power on we can activate OVERRUN checking */ + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; + retval = dap_queue_dp_write(swjdp, DP_CTRL_STAT, swjdp->dp_ctrl_stat); + if (retval != ERROR_OK) + return retval; + retval = dap_queue_dp_read(swjdp, DP_CTRL_STAT, &dummy); + if (retval != ERROR_OK) + return retval; + + /* + * REVISIT this isn't actually *initializing* anything in an AP, + * and doesn't care if it's a MEM-AP at all (much less AHB-AP). + * Should it? If the ROM address is valid, is this the right + * place to scan the table and do any topology detection? + */ + retval = dap_queue_ap_read(swjdp, AP_REG_IDR, &idreg); + retval = dap_queue_ap_read(swjdp, AP_REG_BASE, &romaddr); + + LOG_DEBUG("MEM-AP #%d ID Register 0x%" PRIx32 + ", Debug ROM Address 0x%" PRIx32, + swjdp->apsel, idreg, romaddr); + + return ERROR_OK; +} + +/* CID interpretation -- see ARM IHI 0029B section 3 + * and ARM IHI 0031A table 13-3. + */ +static const char *class_description[16] ={ + "Reserved", "ROM table", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "CoreSight component", "Reserved", "Peripheral Test Block", + "Reserved", "OptimoDE DESS", + "Generic IP component", "PrimeCell or System component" +}; + +static bool +is_dap_cid_ok(uint32_t cid3, uint32_t cid2, uint32_t cid1, uint32_t cid0) +{ + return cid3 == 0xb1 && cid2 == 0x05 + && ((cid1 & 0x0f) == 0) && cid0 == 0x0d; +} + +static int dap_info_command(struct command_context *cmd_ctx, + struct adiv5_dap *swjdp, int apsel) +{ + int retval; + uint32_t dbgbase, apid; + int romtable_present = 0; + uint8_t mem_ap; + uint32_t apselold; + + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + + apselold = swjdp->apsel; + dap_ap_select(swjdp, apsel); + retval = dap_queue_ap_read(swjdp, AP_REG_BASE, &dbgbase); + retval = dap_queue_ap_read(swjdp, AP_REG_IDR, &apid); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + return retval; + + /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ + mem_ap = ((apid&0x10000) && ((apid&0x0F) != 0)); + command_print(cmd_ctx, "AP ID register 0x%8.8" PRIx32, apid); + if (apid) + { + switch (apid&0x0F) + { + case 0: + command_print(cmd_ctx, "\tType is JTAG-AP"); + break; + case 1: + command_print(cmd_ctx, "\tType is MEM-AP AHB"); + break; + case 2: + command_print(cmd_ctx, "\tType is MEM-AP APB"); + break; + default: + command_print(cmd_ctx, "\tUnknown AP type"); + break; + } + + /* NOTE: a MEM-AP may have a single CoreSight component that's + * not a ROM table ... or have no such components at all. + */ + if (mem_ap) + command_print(cmd_ctx, "AP BASE 0x%8.8" PRIx32, + dbgbase); + } + else + { + command_print(cmd_ctx, "No AP found at this apsel 0x%x", apsel); + } + + romtable_present = ((mem_ap) && (dbgbase != 0xFFFFFFFF)); + if (romtable_present) + { + uint32_t cid0,cid1,cid2,cid3,memtype,romentry; + uint16_t entry_offset; + + /* bit 16 of apid indicates a memory access port */ + if (dbgbase & 0x02) + command_print(cmd_ctx, "\tValid ROM table present"); + else + command_print(cmd_ctx, "\tROM table in legacy format"); + + /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFF0, &cid0); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFF4, &cid1); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFF8, &cid2); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFFC, &cid3); + mem_ap_read_u32(swjdp, (dbgbase&0xFFFFF000) | 0xFCC, &memtype); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + return retval; + + if (!is_dap_cid_ok(cid3, cid2, cid1, cid0)) + command_print(cmd_ctx, "\tCID3 0x%2.2" PRIx32 + ", CID2 0x%2.2" PRIx32 + ", CID1 0x%2.2" PRIx32 + ", CID0 0x%2.2" PRIx32, + cid3, cid2, cid1, cid0); + if (memtype & 0x01) + command_print(cmd_ctx, "\tMEMTYPE system memory present on bus"); + else + command_print(cmd_ctx, "\tMEMTYPE System memory not present. " + "Dedicated debug bus."); + + /* Now we read ROM table entries from dbgbase&0xFFFFF000) | 0x000 until we get 0x00000000 */ + entry_offset = 0; + do + { + mem_ap_read_atomic_u32(swjdp, (dbgbase&0xFFFFF000) | entry_offset, &romentry); + command_print(cmd_ctx, "\tROMTABLE[0x%x] = 0x%" PRIx32 "",entry_offset,romentry); + if (romentry&0x01) + { + uint32_t c_cid0, c_cid1, c_cid2, c_cid3; + uint32_t c_pid0, c_pid1, c_pid2, c_pid3, c_pid4; + uint32_t component_start, component_base; + unsigned part_num; + char *type, *full; + + component_base = (uint32_t)((dbgbase & 0xFFFFF000) + + (int)(romentry & 0xFFFFF000)); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFE0, &c_pid0); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFE4, &c_pid1); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFE8, &c_pid2); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFEC, &c_pid3); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFD0, &c_pid4); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFF0, &c_cid0); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFF4, &c_cid1); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFF8, &c_cid2); + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xFFFFF000) | 0xFFC, &c_cid3); + component_start = component_base - 0x1000*(c_pid4 >> 4); + + command_print(cmd_ctx, "\t\tComponent base address 0x%" PRIx32 + ", start address 0x%" PRIx32, + component_base, component_start); + command_print(cmd_ctx, "\t\tComponent class is 0x%x, %s", + (int) (c_cid1 >> 4) & 0xf, + /* See ARM IHI 0029B Table 3-3 */ + class_description[(c_cid1 >> 4) & 0xf]); + + /* CoreSight component? */ + if (((c_cid1 >> 4) & 0x0f) == 9) { + uint32_t devtype; + unsigned minor; + char *major = "Reserved", *subtype = "Reserved"; + + mem_ap_read_atomic_u32(swjdp, + (component_base & 0xfffff000) | 0xfcc, + &devtype); + minor = (devtype >> 4) & 0x0f; + switch (devtype & 0x0f) { + case 0: + major = "Miscellaneous"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 4: + subtype = "Validation component"; + break; + } + break; + case 1: + major = "Trace Sink"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Port"; + break; + case 2: + subtype = "Buffer"; + break; + } + break; + case 2: + major = "Trace Link"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Funnel, router"; + break; + case 2: + subtype = "Filter"; + break; + case 3: + subtype = "FIFO, buffer"; + break; + } + break; + case 3: + major = "Trace Source"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Processor"; + break; + case 2: + subtype = "DSP"; + break; + case 3: + subtype = "Engine/Coprocessor"; + break; + case 4: + subtype = "Bus"; + break; + } + break; + case 4: + major = "Debug Control"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Trigger Matrix"; + break; + case 2: + subtype = "Debug Auth"; + break; + } + break; + case 5: + major = "Debug Logic"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Processor"; + break; + case 2: + subtype = "DSP"; + break; + case 3: + subtype = "Engine/Coprocessor"; + break; + } + break; + } + command_print(cmd_ctx, "\t\tType is 0x%2.2x, %s, %s", + (unsigned) (devtype & 0xff), + major, subtype); + /* REVISIT also show 0xfc8 DevId */ + } + + if (!is_dap_cid_ok(cid3, cid2, cid1, cid0)) + command_print(cmd_ctx, "\t\tCID3 0x%2.2" PRIx32 + ", CID2 0x%2.2" PRIx32 + ", CID1 0x%2.2" PRIx32 + ", CID0 0x%2.2" PRIx32, + c_cid3, c_cid2, c_cid1, c_cid0); + command_print(cmd_ctx, "\t\tPeripheral ID[4..0] = hex " + "%2.2x %2.2x %2.2x %2.2x %2.2x", + (int) c_pid4, + (int) c_pid3, (int) c_pid2, + (int) c_pid1, (int) c_pid0); + + /* Part number interpretations are from Cortex + * core specs, the CoreSight components TRM + * (ARM DDI 0314H), and ETM specs; also from + * chip observation (e.g. TI SDTI). + */ + part_num = c_pid0 & 0xff; + part_num |= (c_pid1 & 0x0f) << 8; + switch (part_num) { + case 0x000: + type = "Cortex-M3 NVIC"; + full = "(Interrupt Controller)"; + break; + case 0x001: + type = "Cortex-M3 ITM"; + full = "(Instrumentation Trace Module)"; + break; + case 0x002: + type = "Cortex-M3 DWT"; + full = "(Data Watchpoint and Trace)"; + break; + case 0x003: + type = "Cortex-M3 FBP"; + full = "(Flash Patch and Breakpoint)"; + break; + case 0x00d: + type = "CoreSight ETM11"; + full = "(Embedded Trace)"; + break; + // case 0x113: what? + case 0x120: /* from OMAP3 memmap */ + type = "TI SDTI"; + full = "(System Debug Trace Interface)"; + break; + case 0x343: /* from OMAP3 memmap */ + type = "TI DAPCTL"; + full = ""; + break; + case 0x906: + type = "Coresight CTI"; + full = "(Cross Trigger)"; + break; + case 0x907: + type = "Coresight ETB"; + full = "(Trace Buffer)"; + break; + case 0x908: + type = "Coresight CSTF"; + full = "(Trace Funnel)"; + break; + case 0x910: + type = "CoreSight ETM9"; + full = "(Embedded Trace)"; + break; + case 0x912: + type = "Coresight TPIU"; + full = "(Trace Port Interface Unit)"; + break; + case 0x921: + type = "Cortex-A8 ETM"; + full = "(Embedded Trace)"; + break; + case 0x922: + type = "Cortex-A8 CTI"; + full = "(Cross Trigger)"; + break; + case 0x923: + type = "Cortex-M3 TPIU"; + full = "(Trace Port Interface Unit)"; + break; + case 0x924: + type = "Cortex-M3 ETM"; + full = "(Embedded Trace)"; + break; + case 0xc08: + type = "Cortex-A8 Debug"; + full = "(Debug Unit)"; + break; + default: + type = "-*- unrecognized -*-"; + full = ""; + break; + } + command_print(cmd_ctx, "\t\tPart is %s %s", + type, full); + } + else + { + if (romentry) + command_print(cmd_ctx, "\t\tComponent not present"); + else + command_print(cmd_ctx, "\t\tEnd of ROM table"); + } + entry_offset += 4; + } while (romentry > 0); + } + else + { + command_print(cmd_ctx, "\tNo ROM table present"); + } + dap_ap_select(swjdp, apselold); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_dap_info_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + uint32_t apsel; + + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return dap_info_command(CMD_CTX, dap, apsel); +} + +COMMAND_HANDLER(dap_baseaddr_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t apsel, apselsave, baseaddr; + int retval; + + apselsave = dap->apsel; + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (apselsave != apsel) + dap_ap_select(dap, apsel); + + /* NOTE: assumes we're talking to a MEM-AP, which + * has a base address. There are other kinds of AP, + * though they're not common for now. This should + * use the ID register to verify it's a MEM-AP. + */ + retval = dap_queue_ap_read(dap, AP_REG_BASE, &baseaddr); + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "0x%8.8" PRIx32, baseaddr); + + if (apselsave != apsel) + dap_ap_select(dap, apselsave); + + return retval; +} + +COMMAND_HANDLER(dap_memaccess_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t memaccess_tck; + + switch (CMD_ARGC) { + case 0: + memaccess_tck = dap->memaccess_tck; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], memaccess_tck); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + dap->memaccess_tck = memaccess_tck; + + command_print(CMD_CTX, "memory bus access delay set to %" PRIi32 " tck", + dap->memaccess_tck); + + return ERROR_OK; +} + +COMMAND_HANDLER(dap_apsel_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t apsel, apid; + int retval; + + switch (CMD_ARGC) { + case 0: + apsel = 0; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + dap_ap_select(dap, apsel); + retval = dap_queue_ap_read(dap, AP_REG_IDR, &apid); + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32, + apsel, apid); + + return retval; +} + +COMMAND_HANDLER(dap_apid_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + + uint32_t apsel, apselsave, apid; + int retval; + + apselsave = dap->apsel; + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + /* AP address is in bits 31:24 of DP_SELECT */ + if (apsel >= 256) + return ERROR_INVALID_ARGUMENTS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (apselsave != apsel) + dap_ap_select(dap, apsel); + + retval = dap_queue_ap_read(dap, AP_REG_IDR, &apid); + retval = dap_run(dap); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "0x%8.8" PRIx32, apid); + if (apselsave != apsel) + dap_ap_select(dap, apselsave); + + return retval; +} + +static const struct command_registration dap_commands[] = { + { + .name = "info", + .handler = handle_dap_info_command, + .mode = COMMAND_EXEC, + .help = "display ROM table for MEM-AP " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + { + .name = "apsel", + .handler = dap_apsel_command, + .mode = COMMAND_EXEC, + .help = "Set the currently selected AP (default 0) " + "and display the result", + .usage = "[ap_num]", + }, + { + .name = "apid", + .handler = dap_apid_command, + .mode = COMMAND_EXEC, + .help = "return ID register from AP " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + { + .name = "baseaddr", + .handler = dap_baseaddr_command, + .mode = COMMAND_EXEC, + .help = "return debug base address from MEM-AP " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + { + .name = "memaccess", + .handler = dap_memaccess_command, + .mode = COMMAND_EXEC, + .help = "set/get number of extra tck for MEM-AP memory " + "bus access [0-255]", + .usage = "[cycles]", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration dap_command_handlers[] = { + { + .name = "dap", + .mode = COMMAND_EXEC, + .help = "DAP command group", + .chain = dap_commands, + }, + COMMAND_REGISTRATION_DONE +}; + + +/* + * This represents the bits which must be sent out on TMS/SWDIO to + * switch a DAP implemented using an SWJ-DP module into SWD mode. + * These bits are stored (and transmitted) LSB-first. + * + * See the DAP-Lite specification, section 2.2.5 for information + * about making the debug link select SWD or JTAG. (Similar info + * is in a few other ARM documents.) + */ +static const uint8_t jtag2swd_bitseq[] = { + /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, + * putting both JTAG and SWD logic into reset state. + */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* Switching sequence enables SWD and disables JTAG + * NOTE: bits in the DP's IDCODE may expose the need for + * an old/deprecated sequence (0xb6 0xed). + */ + 0x9e, 0xe7, + /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, + * putting both JTAG and SWD logic into reset state. + */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +/** + * Put the debug link into SWD mode, if the target supports it. + * The link's initial mode may be either JTAG (for example, + * with SWJ-DP after reset) or SWD. + * + * @param target Enters SWD mode (if possible). + * + * Note that targets using the JTAG-DP do not support SWD, and that + * some targets which could otherwise support it may have have been + * configured to disable SWD signaling + * + * @return ERROR_OK or else a fault code. + */ +int dap_to_swd(struct target *target) +{ + int retval; + + LOG_DEBUG("Enter SWD mode"); + + /* REVISIT it's nasty to need to make calls to a "jtag" + * subsystem if the link isn't in JTAG mode... + */ + + retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq), + jtag2swd_bitseq, TAP_INVALID); + if (retval == ERROR_OK) + retval = jtag_execute_queue(); + + /* REVISIT set up the DAP's ops vector for SWD mode. */ + + return retval; +} + diff --git a/src/target/avrt.c b/src/target/avrt.c index 720261eea4..17f7c241e6 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -190,8 +190,7 @@ int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_l } { - jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, - jtag_set_end_state(TAP_IDLE)); + jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); } return ERROR_OK; @@ -206,7 +205,7 @@ int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_l } { - jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, jtag_set_end_state(TAP_IDLE)); + jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); } return ERROR_OK; diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 4be7f3b5ed..b42e7b3ece 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -863,8 +863,7 @@ int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t * ir_in, uint8_t * ir_out, } { - jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, - jtag_set_end_state(TAP_IDLE)); + jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); } return ERROR_OK; @@ -880,8 +879,7 @@ int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t * dr_in, uint8_t * dr_out, } { - jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, - jtag_set_end_state(TAP_IDLE)); + jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); } return ERROR_OK; diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index 4693fcc227..fe266d6281 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -372,7 +372,7 @@ int embeddedice_read_reg_w_check(struct reg *reg, fields[2].check_mask = NULL; /* traverse Update-DR, setting address for the next read */ - jtag_add_dr_scan(ice_reg->jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE); /* bits 31:0 -- the data we're reading (and maybe checking) */ fields[0].in_value = reg->value; @@ -386,7 +386,7 @@ int embeddedice_read_reg_w_check(struct reg *reg, fields[1].out_value[0] = eice_regs[EICE_COMMS_CTRL].addr; /* traverse Update-DR, reading but with no other side effects */ - jtag_add_dr_scan_check(ice_reg->jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan_check(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } @@ -423,7 +423,7 @@ int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t siz fields[2].out_value[0] = 0; fields[2].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); while (size > 0) { @@ -434,7 +434,7 @@ int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t siz fields[1].out_value[0] = eice_regs[EICE_COMMS_CTRL].addr; fields[0].in_value = (uint8_t *)data; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)data); data++; @@ -545,7 +545,7 @@ int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size) while (size > 0) { buf_set_u32(fields[0].out_value, 0, 32, *data); - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); data++; size--; @@ -594,10 +594,10 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou fields[2].out_value[0] = 0; fields[2].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); gettimeofday(&lap, NULL); do { - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); if ((retval = jtag_execute_queue()) != ERROR_OK) return retval; diff --git a/src/target/etb.c b/src/target/etb.c index 2c4e3ebe90..99710700ec 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -191,7 +191,7 @@ static int etb_read_ram(struct etb *etb, uint32_t *data, int num_frames) buf_set_u32(fields[2].out_value, 0, 1, 0); fields[2].in_value = NULL; - jtag_add_dr_scan(etb->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE); for (i = 0; i < num_frames; i++) { @@ -205,7 +205,7 @@ static int etb_read_ram(struct etb *etb, uint32_t *data, int num_frames) buf_set_u32(fields[1].out_value, 0, 7, 0); fields[0].in_value = (uint8_t *)(data + i); - jtag_add_dr_scan(etb->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE); jtag_add_callback(etb_getbuf, (jtag_callback_data_t)(data + i)); } @@ -251,7 +251,7 @@ static int etb_read_reg_w_check(struct reg *reg, fields[2].check_value = NULL; fields[2].check_mask = NULL; - jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, TAP_IDLE); /* read the identification register in the second run, to make sure we * don't read the ETB data register twice, skipping every second entry @@ -261,7 +261,7 @@ static int etb_read_reg_w_check(struct reg *reg, fields[0].check_value = check_value; fields[0].check_mask = check_mask; - jtag_add_dr_scan_check(etb_reg->etb->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan_check(etb_reg->etb->tap, 3, fields, TAP_IDLE); free(fields[1].out_value); free(fields[2].out_value); diff --git a/src/target/etm.c b/src/target/etm.c index 67dac06fad..a1c77b0ff3 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -528,13 +528,13 @@ static int etm_read_reg_w_check(struct reg *reg, fields[2].check_value = NULL; fields[2].check_mask = NULL; - jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; - jtag_add_dr_scan_check(etm_reg->jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan_check(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); free(fields[1].out_value); free(fields[2].out_value); @@ -609,7 +609,7 @@ static int etm_write_reg(struct reg *reg, uint32_t value) buf_set_u32(fields[2].out_value, 0, 1, 1); fields[2].in_value = NULL; - jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } diff --git a/src/target/feroceon.c b/src/target/feroceon.c index 133ad4f66c..22ddb5573e 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -101,9 +101,9 @@ int feroceon_dummy_clock_out(struct arm_jtag *jtag_info, uint32_t instr) fields[2].out_value = instr_buf; fields[2].in_value = NULL; - jtag_add_dr_scan(jtag_info->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); - /* no jtag_add_runtest(0, jtag_get_end_state()) here */ + /* no jtag_add_runtest(0, TAP_DRPAUSE) here */ return ERROR_OK; } diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 42dc6e0b54..974c836dce 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -64,7 +64,7 @@ int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode) field.out_value = NULL; field.in_value = (void*)idcode; - jtag_add_dr_scan(ejtag_info->tap, 1, &field, jtag_get_end_state()); + jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { @@ -86,7 +86,7 @@ int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info, uint32_t *impcode) field.out_value = NULL; field.in_value = (void*)impcode; - jtag_add_dr_scan(ejtag_info->tap, 1, &field, jtag_get_end_state()); + jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { diff --git a/src/target/xscale.c b/src/target/xscale.c index dd4a7ee622..f5aada507d 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -213,7 +213,7 @@ static int xscale_read_dcsr(struct target *target) uint8_t tmp2; fields[2].in_value = &tmp2; - jtag_add_dr_scan(target->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); @@ -236,7 +236,7 @@ static int xscale_read_dcsr(struct target *target) jtag_set_end_state(TAP_IDLE); - jtag_add_dr_scan(target->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE); /* DANGER!!! this must be here. It will make sure that the arguments * to jtag_set_check_value() does not go out of scope! */ @@ -288,7 +288,7 @@ static int xscale_receive(struct target *target, uint32_t *buffer, int num_words jtag_set_end_state(TAP_IDLE); xscale_jtag_set_instr(target->tap, XSCALE_DBGTX << xscale->xscale_variant); - jtag_add_runtest(1, jtag_get_end_state()); /* ensures that we're in the TAP_IDLE state as the above could be a no-op */ + jtag_add_runtest(1, TAP_IDLE); /* ensures that we're in the TAP_IDLE state as the above could be a no-op */ /* repeat until all words have been collected */ int attempts = 0; @@ -304,7 +304,7 @@ static int xscale_receive(struct target *target, uint32_t *buffer, int num_words fields[1].in_value = (uint8_t *)(field1 + i); - jtag_add_dr_scan_check(target->tap, 3, fields, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan_check(target->tap, 3, fields, TAP_IDLE); jtag_add_callback(xscale_getbuf, (jtag_callback_data_t)(field1 + i)); @@ -411,7 +411,7 @@ static int xscale_read_tx(struct target *target, int consume) jtag_add_pathmove(ARRAY_SIZE(noconsume_path), noconsume_path); } - jtag_add_dr_scan(target->tap, 3, fields, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); @@ -489,7 +489,7 @@ static int xscale_write_rx(struct target *target) LOG_DEBUG("polling RX"); for (;;) { - jtag_add_dr_scan(target->tap, 3, fields, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); @@ -521,7 +521,7 @@ static int xscale_write_rx(struct target *target) /* set rx_valid */ field2 = 0x1; - jtag_add_dr_scan(target->tap, 3, fields, jtag_set_end_state(TAP_IDLE)); + jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); if ((retval = jtag_execute_queue()) != ERROR_OK) { @@ -585,7 +585,7 @@ static int xscale_send(struct target *target, uint8_t *buffer, int count, int si 3, bits, t, - jtag_set_end_state(TAP_IDLE)); + TAP_IDLE); buffer += size; } @@ -646,7 +646,7 @@ static int xscale_write_dcsr(struct target *target, int hold_rst, int ext_dbg_br uint8_t tmp2; fields[2].in_value = &tmp2; - jtag_add_dr_scan(target->tap, 3, fields, jtag_get_end_state()); + jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); @@ -707,7 +707,7 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] fields[1].num_bits = 27; fields[1].out_value = packet; - jtag_add_dr_scan(target->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); /* rest of packet is a cacheline: 8 instructions, with parity */ fields[0].num_bits = 32; @@ -724,7 +724,7 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] memcpy(&value, packet, sizeof(uint32_t)); cmd = parity(value); - jtag_add_dr_scan(target->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); } return jtag_execute_queue(); @@ -755,7 +755,7 @@ static int xscale_invalidate_ic_line(struct target *target, uint32_t va) fields[1].num_bits = 27; fields[1].out_value = packet; - jtag_add_dr_scan(target->tap, 2, fields, jtag_get_end_state()); + jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); return ERROR_OK; } @@ -1556,7 +1556,7 @@ static int xscale_deassert_reset(struct target *target) /* wait 300ms; 150 and 100ms were not enough */ jtag_add_sleep(300*1000); - jtag_add_runtest(2030, jtag_set_end_state(TAP_IDLE)); + jtag_add_runtest(2030, TAP_IDLE); jtag_execute_queue(); /* set Hold reset, Halt mode and Trap Reset */ @@ -1613,7 +1613,7 @@ static int xscale_deassert_reset(struct target *target) if (retval != ERROR_OK) return retval; - jtag_add_runtest(30, jtag_set_end_state(TAP_IDLE)); + jtag_add_runtest(30, TAP_IDLE); jtag_add_sleep(100000); diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index f2c1a4220a..dff1a1ec2a 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -482,9 +482,9 @@ COMMAND_HANDLER(handle_xsvf_command) if (tap == NULL) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, - jtag_set_end_state(TAP_DRPAUSE)); + TAP_DRPAUSE); else - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); jtag_check_value_mask(&field, dr_in_buf, dr_in_mask); @@ -939,9 +939,9 @@ COMMAND_HANDLER(handle_xsvf_command) if (tap == NULL) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, - jtag_set_end_state(TAP_DRPAUSE)); + TAP_DRPAUSE); else - jtag_add_dr_scan(tap, 1, &field, jtag_set_end_state(TAP_DRPAUSE)); + jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); jtag_check_value_mask(&field, dr_in_buf, dr_in_mask); -- 2.30.2