X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Farm_adi_v5.c;h=115ccf12d78644e2c793f10c84ed3b5585819834;hb=5b311865788009445a1457f62204899a4aa1c7b3;hp=0a6a7ef7cbabbd054c2a2fecb8ecadd4bfd4c33f;hpb=46b6d5bfe644b5f6a1fe50930c850f09a78b5bad;p=openocd.git diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 0a6a7ef7cb..115ccf12d7 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -8,6 +8,8 @@ * 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 * @@ -40,6 +42,17 @@ * 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.) */ /* @@ -59,17 +72,6 @@ #include "arm_adi_v5.h" #include -/* - * Transaction Mode: - * swjdp->trans_mode = TRANS_MODE_COMPOSITE; - * Uses Overrun checking mode and does not do actual JTAG send/receive or transaction - * result checking until swjdp_end_transaction() - * This must be done before using or deallocating any return variables. - * swjdp->trans_mode == TRANS_MODE_ATOMIC - * All reads and writes to the AHB bus are checked for valid completion, and return values - * are immediatley available. -*/ - /* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */ @@ -117,18 +119,6 @@ static int adi_jtag_dp_scan(struct swjdp_common *swjdp, jtag_set_end_state(TAP_IDLE); arm_jtag_set_instr(jtag_info, instr, NULL); - /* Add specified number of tck clocks before accessing memory bus */ - - /* REVISIT these TCK cycles should be *AFTER* updating APACC, since - * 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, jtag_set_end_state(TAP_IDLE)); - /* 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. */ @@ -150,103 +140,77 @@ static int adi_jtag_dp_scan(struct swjdp_common *swjdp, jtag_add_dr_scan(2, fields, jtag_get_end_state()); - return ERROR_OK; + /* 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, + jtag_set_end_state(TAP_IDLE)); + + return jtag_get_error(); } -/* Scan out and in from host ordered uint32_t variables */ +/** + * 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 swjdp_common *swjdp, uint8_t instr, uint8_t reg_addr, uint8_t RnW, uint32_t outvalue, uint32_t *invalue, uint8_t *ack) { - struct arm_jtag *jtag_info = swjdp->jtag_info; - struct scan_field fields[2]; uint8_t out_value_buf[4]; - uint8_t out_addr_buf; - - jtag_set_end_state(TAP_IDLE); - arm_jtag_set_instr(jtag_info, instr, NULL); - - /* Add specified number of tck clocks before accessing memory bus */ - - /* REVISIT these TCK cycles should be *AFTER* updating APACC, since - * they provide more time for the (MEM) AP to complete the read ... - */ - 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, jtag_set_end_state(TAP_IDLE)); - - fields[0].tap = jtag_info->tap; - 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; + int retval; - fields[1].tap = jtag_info->tap; - fields[1].num_bits = 32; buf_set_u32(out_value_buf, 0, 32, outvalue); - fields[1].out_value = out_value_buf; - fields[1].in_value = NULL; - if (invalue) - { - fields[1].in_value = (uint8_t *)invalue; - jtag_add_dr_scan(2, fields, jtag_get_end_state()); - - jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t) invalue); - } else - { + retval = adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW, + out_value_buf, (uint8_t *)invalue, ack); + if (retval != ERROR_OK) + return retval; - jtag_add_dr_scan(2, fields, jtag_get_end_state()); - } + if (invalue) + jtag_add_callback(arm_le_to_h_u32, + (jtag_callback_data_t) invalue); - return ERROR_OK; + return retval; } -/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */ -static int scan_inout_check(struct swjdp_common *swjdp, - uint8_t instr, uint8_t reg_addr, uint8_t RnW, - uint8_t *outvalue, uint8_t *invalue) +/** + * Utility to write AP registers. + */ +static inline int adi_jtag_ap_write_check(struct swjdp_common *dap, + uint8_t reg_addr, uint8_t *outvalue) { - adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW, outvalue, NULL, NULL); - - if ((RnW == DPAP_READ) && (invalue != NULL)) - adi_jtag_dp_scan(swjdp, JTAG_DP_DPACC, - DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack); - - /* In TRANS_MODE_ATOMIC all JTAG_DP_APACC transactions wait for - * ack = OK/FAULT and the check CTRL_STAT - */ - if ((instr == JTAG_DP_APACC) - && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) - return jtagdp_transaction_endcheck(swjdp); - - return ERROR_OK; + return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE, + outvalue, NULL, NULL); } -static int scan_inout_check_u32(struct swjdp_common *swjdp, +static int adi_jtag_scan_inout_check_u32(struct swjdp_common *swjdp, uint8_t instr, uint8_t reg_addr, uint8_t RnW, uint32_t outvalue, uint32_t *invalue) { + int retval; + /* Issue the read or write */ - adi_jtag_dp_scan_u32(swjdp, instr, reg_addr, RnW, outvalue, NULL, NULL); + 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)) - adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC, + retval = adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack); - - /* In TRANS_MODE_ATOMIC all JTAG_DP_APACC transactions wait for - * ack = OK/FAULT and then check CTRL_STAT - */ - if ((instr == JTAG_DP_APACC) - && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) - return jtagdp_transaction_endcheck(swjdp); - - return ERROR_OK; + return retval; } int jtagdp_transaction_endcheck(struct swjdp_common *swjdp) @@ -258,7 +222,7 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp) #if 0 /* Danger!!!! BROKEN!!!! */ - scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + 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 @@ -276,7 +240,7 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp) /* Post CTRL/STAT read; discard any previous posted read value * but collect its ACK status. */ - scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + 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; @@ -311,7 +275,7 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp) return ERROR_JTAG_DEVICE_ERROR; } - scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + 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; @@ -319,37 +283,45 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp) } } + /* 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; - /* Print information about last AHBAP access */ - LOG_ERROR("AHBAP Cached values: dp_select 0x%" PRIx32 - ", ap_csw 0x%" PRIx32 ", ap_tar 0x%" PRIx32, - swjdp->dp_select_value, swjdp->ap_csw_value, - swjdp->ap_tar_value); + /* 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 or reduce jtag speed"); + 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 */ - scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, swjdp->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL); - scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + 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; @@ -381,153 +353,252 @@ int jtagdp_transaction_endcheck(struct swjdp_common *swjdp) static int dap_dp_write_reg(struct swjdp_common *swjdp, uint32_t value, uint8_t reg_addr) { - return scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + return adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, reg_addr, DPAP_WRITE, value, NULL); } static int dap_dp_read_reg(struct swjdp_common *swjdp, uint32_t *value, uint8_t reg_addr) { - return scan_inout_check_u32(swjdp, JTAG_DP_DPACC, + return adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC, reg_addr, DPAP_READ, 0, value); } -int dap_ap_select(struct swjdp_common *swjdp,uint8_t apsel) +/** + * 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 swjdp_common *swjdp,uint8_t apsel) { - uint32_t select; - select = (apsel << 24) & 0xFF000000; + uint32_t select = (apsel << 24) & 0xFF000000; if (select != swjdp->apsel) { swjdp->apsel = select; - /* Switching AP invalidates cached values */ - swjdp->dp_select_value = -1; + /* 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; } - - return ERROR_OK; } -static int dap_dp_bankselect(struct swjdp_common *swjdp, uint32_t ap_reg) +/** Select the AP register bank matching bits 7:4 of ap_reg. */ +static int dap_ap_bankselect(struct swjdp_common *swjdp, uint32_t ap_reg) { - uint32_t select; - select = (ap_reg & 0x000000F0); + uint32_t select = (ap_reg & 0x000000F0); - if (select != swjdp->dp_select_value) + if (select != swjdp->ap_bank_value) { - dap_dp_write_reg(swjdp, select | swjdp->apsel, DP_SELECT); - swjdp->dp_select_value = select; - } - - return ERROR_OK; + swjdp->ap_bank_value = select; + select |= swjdp->apsel; + return dap_dp_write_reg(swjdp, select, DP_SELECT); + } else + return ERROR_OK; } static int dap_ap_write_reg(struct swjdp_common *swjdp, uint32_t reg_addr, uint8_t *out_value_buf) { - dap_dp_bankselect(swjdp, reg_addr); - scan_inout_check(swjdp, JTAG_DP_APACC, reg_addr, - DPAP_WRITE, out_value_buf, NULL); + int retval; - return ERROR_OK; + retval = dap_ap_bankselect(swjdp, reg_addr); + if (retval != ERROR_OK) + return retval; + + return adi_jtag_ap_write_check(swjdp, reg_addr, out_value_buf); } -int dap_ap_write_reg_u32(struct swjdp_common *swjdp, uint32_t reg_addr, uint32_t value) +/** + * Asynchronous (queued) AP register write. + * + * @param swjdp The DAP whose currently selected AP will be written. + * @param reg_addr Eight bit AP register address. + * @param value Word to be written at reg_addr + * + * @return ERROR_OK if the transaction was properly queued, else a fault code. + */ +int dap_ap_write_reg_u32(struct swjdp_common *swjdp, + uint32_t reg_addr, uint32_t value) { uint8_t out_value_buf[4]; buf_set_u32(out_value_buf, 0, 32, value); - dap_dp_bankselect(swjdp, reg_addr); - scan_inout_check(swjdp, JTAG_DP_APACC, reg_addr, - DPAP_WRITE, out_value_buf, NULL); - - return ERROR_OK; + return dap_ap_write_reg(swjdp, + reg_addr, out_value_buf); } -int dap_ap_read_reg_u32(struct swjdp_common *swjdp, uint32_t reg_addr, uint32_t *value) +/** + * Asynchronous (queued) AP register eread. + * + * @param swjdp The DAP whose currently selected AP will be read. + * @param reg_addr Eight bit AP register address. + * @param value Points to where the 32-bit (little-endian) word will be stored. + * + * @return ERROR_OK if the transaction was properly queued, else a fault code. + */ +int dap_ap_read_reg_u32(struct swjdp_common *swjdp, + uint32_t reg_addr, uint32_t *value) { - dap_dp_bankselect(swjdp, reg_addr); - scan_inout_check_u32(swjdp, JTAG_DP_APACC, reg_addr, - DPAP_READ, 0, value); + int retval; - return ERROR_OK; -} + retval = dap_ap_bankselect(swjdp, reg_addr); + if (retval != ERROR_OK) + return retval; -/*************************************************************************** - * * - * AHB-AP access to memory and system registers on AHB bus * - * * -***************************************************************************/ + return adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_APACC, reg_addr, + DPAP_READ, 0, value); +} +/** + * 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 swjdp_common *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); */ - dap_ap_write_reg_u32(swjdp, AP_REG_CSW, csw); + retval = dap_ap_write_reg_u32(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); */ - dap_ap_write_reg_u32(swjdp, AP_REG_TAR, tar); + retval = dap_ap_write_reg_u32(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) - { - /* Do not cache TAR value when autoincrementing */ swjdp->ap_tar_value = -1; - } return ERROR_OK; } -/***************************************************************************** -* * -* mem_ap_read_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t *value) * -* * -* Read a uint32_t value from memory or system register * -* Functionally equivalent to target_read_u32(target, address, uint32_t *value), * -* but with less overhead * -*****************************************************************************/ -int mem_ap_read_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t *value) +/** + * 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 swjdp_common *swjdp, uint32_t address, + uint32_t *value) { - swjdp->trans_mode = TRANS_MODE_COMPOSITE; + int retval; - dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); - dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC), value); + /* 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 ERROR_OK; + return dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC), value); } -int mem_ap_read_atomic_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t *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 swjdp_common *swjdp, uint32_t address, + uint32_t *value) { - mem_ap_read_u32(swjdp, address, value); + int retval; + + retval = mem_ap_read_u32(swjdp, address, value); + if (retval != ERROR_OK) + return retval; return jtagdp_transaction_endcheck(swjdp); } -/***************************************************************************** -* * -* mem_ap_write_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t value) * -* * -* Write a uint32_t value to memory or memory mapped register * -* * -*****************************************************************************/ -int mem_ap_write_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t value) +/** + * 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 swjdp_common *swjdp, uint32_t address, + uint32_t value) { - swjdp->trans_mode = TRANS_MODE_COMPOSITE; + int retval; - dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); - dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC), value); + /* 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 ERROR_OK; + return dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (address & 0xC), + value); } -int mem_ap_write_atomic_u32(struct swjdp_common *swjdp, uint32_t address, uint32_t 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 swjdp_common *swjdp, uint32_t address, + uint32_t value) { - mem_ap_write_u32(swjdp, address, value); + int retval = mem_ap_write_u32(swjdp, address, value); + + if (retval != ERROR_OK) + return retval; return jtagdp_transaction_endcheck(swjdp); } @@ -545,8 +616,6 @@ int mem_ap_write_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t adr = address; uint8_t* pBuffer = buffer; - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - count >>= 2; wcount = count; @@ -614,8 +683,6 @@ static int mem_ap_write_buf_packed_u16(struct swjdp_common *swjdp, int retval = ERROR_OK; int wcount, blocksize, writecount, i; - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - wcount = count >> 1; while (wcount > 0) @@ -692,8 +759,6 @@ int mem_ap_write_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer, int count, if (count >= 4) return mem_ap_write_buf_packed_u16(swjdp, buffer, count, address); - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - while (count > 0) { dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); @@ -716,8 +781,6 @@ static int mem_ap_write_buf_packed_u8(struct swjdp_common *swjdp, int retval = ERROR_OK; int wcount, blocksize, writecount, i; - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - wcount = count; while (wcount > 0) @@ -789,8 +852,6 @@ int mem_ap_write_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, if (count >= 4) return mem_ap_write_buf_packed_u8(swjdp, buffer, count, address); - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - while (count > 0) { dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); @@ -805,28 +866,32 @@ int mem_ap_write_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, return retval; } -/********************************************************************************* -* * -* mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address) * -* * -* Read block fast in target order (little endian) into a buffer * -* * -**********************************************************************************/ -int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address) +/** + * 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 swjdp_common *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; - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - count >>= 2; wcount = count; while (wcount > 0) { - /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/ - blocksize = max_tar_block_size(swjdp->tar_autoincr_block, address); + /* 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; @@ -834,7 +899,8 @@ int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, if (blocksize == 0) blocksize = 1; - dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, + address); /* Scan out first read */ adi_jtag_dp_scan(swjdp, JTAG_DP_APACC, AP_REG_DRW, @@ -869,7 +935,8 @@ int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, if (errorcount > 1) { - LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count); + LOG_WARNING("Block read error address 0x%" PRIx32 + ", count 0x%x", address, count); return ERROR_JTAG_DEVICE_ERROR; } } @@ -885,7 +952,8 @@ int mem_ap_read_buf_u32(struct swjdp_common *swjdp, uint8_t *buffer, int count, for (i = 0; i < 4; i++) { - *((uint8_t*)pBuffer) = (data >> 8 * (adr & 0x3)); + *((uint8_t*)pBuffer) = + (data >> 8 * (adr & 0x3)); pBuffer++; adr++; } @@ -902,8 +970,6 @@ static int mem_ap_read_buf_packed_u16(struct swjdp_common *swjdp, int retval = ERROR_OK; int wcount, blocksize, readcount, i; - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - wcount = count >> 1; while (wcount > 0) @@ -948,7 +1014,16 @@ static int mem_ap_read_buf_packed_u16(struct swjdp_common *swjdp, return retval; } -int mem_ap_read_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address) +/** + * 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 swjdp_common *swjdp, uint8_t *buffer, + int count, uint32_t address) { uint32_t invalue, i; int retval = ERROR_OK; @@ -956,8 +1031,6 @@ int mem_ap_read_buf_u16(struct swjdp_common *swjdp, uint8_t *buffer, int count, if (count >= 4) return mem_ap_read_buf_packed_u16(swjdp, buffer, count, address); - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - while (count > 0) { dap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); @@ -998,8 +1071,6 @@ static int mem_ap_read_buf_packed_u8(struct swjdp_common *swjdp, int retval = ERROR_OK; int wcount, blocksize, readcount, i; - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - wcount = count; while (wcount > 0) @@ -1041,7 +1112,16 @@ static int mem_ap_read_buf_packed_u8(struct swjdp_common *swjdp, return retval; } -int mem_ap_read_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, uint32_t address) +/** + * 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 swjdp_common *swjdp, uint8_t *buffer, + int count, uint32_t address) { uint32_t invalue; int retval = ERROR_OK; @@ -1049,8 +1129,6 @@ int mem_ap_read_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, u if (count >= 4) return mem_ap_read_buf_packed_u8(swjdp, buffer, count, address); - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - while (count > 0) { dap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); @@ -1066,7 +1144,11 @@ int mem_ap_read_buf_u8(struct swjdp_common *swjdp, uint8_t *buffer, int count, u } /** - * Initialize a DAP. + * 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 @@ -1085,15 +1167,13 @@ int ahbap_debugport_init(struct swjdp_common *swjdp) /* Default MEM-AP setup. * * REVISIT AP #0 may be an inappropriate default for this. - * Should we probe, or receve a hint from the caller? + * Should we probe, or take a hint from the caller? * Presumably we can ignore the possibility of multiple APs. */ - swjdp->apsel = 0; - swjdp->ap_csw_value = -1; - swjdp->ap_tar_value = -1; + swjdp->apsel = !0; + dap_ap_select(swjdp, 0); /* DP initialization */ - swjdp->trans_mode = TRANS_MODE_ATOMIC; dap_dp_read_reg(swjdp, &dummy, DP_CTRL_STAT); dap_dp_write_reg(swjdp, SSTICKYERR, DP_CTRL_STAT); dap_dp_read_reg(swjdp, &dummy, DP_CTRL_STAT); @@ -1164,7 +1244,8 @@ is_dap_cid_ok(uint32_t cid3, uint32_t cid2, uint32_t cid1, uint32_t cid0) && ((cid1 & 0x0f) == 0) && cid0 == 0x0d; } -int dap_info_command(struct command_context *cmd_ctx, struct swjdp_common *swjdp, int apsel) +int dap_info_command(struct command_context *cmd_ctx, + struct swjdp_common *swjdp, int apsel) { uint32_t dbgbase, apid; @@ -1172,6 +1253,10 @@ int dap_info_command(struct command_context *cmd_ctx, struct swjdp_common *swjdp 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); dap_ap_read_reg_u32(swjdp, AP_REG_BASE, &dbgbase); @@ -1445,10 +1530,6 @@ int dap_info_command(struct command_context *cmd_ctx, struct swjdp_common *swjdp type = "TI DAPCTL"; full = ""; break; - case 0x4e0: - type = "Cortex-M3 ETM"; - full = "(Embedded Trace)"; - break; case 0x906: type = "Coresight CTI"; full = "(Cross Trigger)"; @@ -1481,6 +1562,10 @@ int dap_info_command(struct command_context *cmd_ctx, struct swjdp_common *swjdp 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)"; @@ -1524,6 +1609,9 @@ DAP_COMMAND_HANDLER(dap_baseaddr_command) 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; @@ -1580,6 +1668,9 @@ DAP_COMMAND_HANDLER(dap_apsel_command) 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; @@ -1606,6 +1697,9 @@ DAP_COMMAND_HANDLER(dap_apid_command) 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; @@ -1622,3 +1716,116 @@ DAP_COMMAND_HANDLER(dap_apid_command) return retval; } + +/* + * 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; +} + +/** + * This represents the bits which must be sent out on TMS/SWDIO to + * switch a DAP implemented using an SWJ-DP module into JTAG mode. + * These bits are stored (and transmitted) LSB-first. + * + * These bits are stored (and transmitted) LSB-first. + */ +static const uint8_t swd2jtag_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 equence disables SWD and enables JTAG + * NOTE: bits in the DP's IDCODE can expose the need for + * the old/deprecated sequence (0xae 0xde). + */ + 0x3c, 0xe7, + /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high, + * putting both JTAG and SWD logic into reset state. + * NOTE: some docs say "at least 5". + */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +/** Put the debug link into JTAG mode, if the target supports it. + * The link's initial mode may be either SWD or JTAG. + * + * @param target Enters JTAG mode (if possible). + * + * Note that targets implemented with SW-DP do not support JTAG, and + * that some targets which could otherwise support it may have been + * configured to disable JTAG signaling + * + * @return ERROR_OK or else a fault code. + */ +int dap_to_jtag(struct target *target) +{ + int retval; + + LOG_DEBUG("Enter JTAG 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(swd2jtag_bitseq), + swd2jtag_bitseq, TAP_RESET); + if (retval == ERROR_OK) + retval = jtag_execute_queue(); + + /* REVISIT set up the DAP's ops vector for JTAG mode. */ + + return retval; +}