summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-11-24 21:24:44 -0800
committerDavid Brownell <dbrownell@users.sourceforge.net>2009-11-24 21:24:44 -0800
commitc008d30fe85a674842632e32d732e22e0a91b95d (patch)
treea2de30f8dd613f9347980406fef10e58563849b6
parent991daa03ebbc69829be4a3899b77efb981254038 (diff)
downloadopenocd+libswd-c008d30fe85a674842632e32d732e22e0a91b95d.tar.gz
openocd+libswd-c008d30fe85a674842632e32d732e22e0a91b95d.tar.bz2
openocd+libswd-c008d30fe85a674842632e32d732e22e0a91b95d.tar.xz
openocd+libswd-c008d30fe85a674842632e32d732e22e0a91b95d.zip
Cortex-A8: implement DPM
This implements the DPM interface for Cortex-A8 cores. It also adds a synchronization operation to the DPM framework, which is needed by the Cortex-A8 after CPSR writes. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
-rw-r--r--src/target/arm_dpm.c13
-rw-r--r--src/target/arm_dpm.h3
-rw-r--r--src/target/armv7a.h2
-rw-r--r--src/target/cortex_a8.c167
4 files changed, 176 insertions, 9 deletions
diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c
index 18a9dcc7..b8107d78 100644
--- a/src/target/arm_dpm.c
+++ b/src/target/arm_dpm.c
@@ -52,10 +52,8 @@ static int dpm_modeswitch(struct arm_dpm *dpm, enum armv4_5_mode mode)
retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MSR_GP(0, 0xf, 0), cpsr);
- /* REVISIT on Cortex-A8, we need a Prefetch Flush operation too ...
- cortex_a8_exec_opcode(target,
- ARMV4_5_MCR(15, 0, 0, 7, 5, 4));
- */
+ if (dpm->instr_cpsr_sync)
+ retval = dpm->instr_cpsr_sync(dpm);
return retval;
}
@@ -142,11 +140,8 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
ARMV4_5_MSR_GP(0, 0xf, regnum & 1),
value);
- /* REVISIT on Cortex-A8, we need a Prefetch Flush operation
- * after writing CPSR ...
- cortex_a8_exec_opcode(target,
- ARMV4_5_MCR(15, 0, 0, 7, 5, 4));
- */
+ if (regnum == 16 && dpm->instr_cpsr_sync)
+ retval = dpm->instr_cpsr_sync(dpm);
break;
}
diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h
index 06b548ec..67ce2180 100644
--- a/src/target/arm_dpm.h
+++ b/src/target/arm_dpm.h
@@ -61,6 +61,9 @@ struct arm_dpm {
int (*instr_write_data_r0)(struct arm_dpm *,
uint32_t opcode, uint32_t data);
+ /** Optional core-specific operation invoked after CPSR writes. */
+ int (*instr_cpsr_sync)(struct arm_dpm *dpm);
+
/* READ FROM CPU */
/** Runs one instruction, reading data from dcc after execution. */
diff --git a/src/target/armv7a.h b/src/target/armv7a.h
index 51f7b45a..942bf8bf 100644
--- a/src/target/armv7a.h
+++ b/src/target/armv7a.h
@@ -23,6 +23,7 @@
#include "armv4_5.h"
#include "armv4_5_mmu.h"
#include "armv4_5_cache.h"
+#include "arm_dpm.h"
enum
{
@@ -53,6 +54,7 @@ struct armv7a_common
struct swjdp_common swjdp_info;
/* Core Debug Unit */
+ struct arm_dpm dpm;
uint32_t debug_base;
uint8_t debug_ap;
uint8_t memory_ap;
diff --git a/src/target/cortex_a8.c b/src/target/cortex_a8.c
index f549fb39..28c75b59 100644
--- a/src/target/cortex_a8.c
+++ b/src/target/cortex_a8.c
@@ -352,6 +352,173 @@ static int cortex_a8_dap_write_memap_register_u32(struct target *target, uint32_
}
/*
+ * Cortex-A8 implementation of Debug Programmer's Model
+ *
+ * NOTE that in several of these cases the "stall" mode might be useful.
+ * It'd let us queue a few operations together... prepare/finish might
+ * be the places to enable/disable that mode.
+ */
+
+static inline struct cortex_a8_common *dpm_to_a8(struct arm_dpm *dpm)
+{
+ return container_of(dpm, struct cortex_a8_common, armv7a_common.dpm);
+}
+
+static int cortex_a8_write_dcc(struct cortex_a8_common *a8, uint32_t data)
+{
+ LOG_DEBUG("write DCC 0x%08" PRIx32, data);
+ return mem_ap_write_u32(&a8->armv7a_common.swjdp_info,
+ a8->armv7a_common.debug_base + CPUDBG_DTRRX, data);
+}
+
+static int cortex_a8_read_dcc(struct cortex_a8_common *a8, uint32_t *data)
+{
+ struct swjdp_common *swjdp = &a8->armv7a_common.swjdp_info;
+ uint32_t dscr;
+ int retval;
+
+ /* Wait for DTRRXfull */
+ do {
+ retval = mem_ap_read_atomic_u32(swjdp,
+ a8->armv7a_common.debug_base + CPUDBG_DSCR,
+ &dscr);
+ } while ((dscr & (1 << DSCR_DTR_TX_FULL)) == 0);
+
+ retval = mem_ap_read_atomic_u32(swjdp,
+ a8->armv7a_common.debug_base + CPUDBG_DTRTX, data);
+ LOG_DEBUG("read DCC 0x%08" PRIx32, *data);
+
+ return retval;
+}
+
+static int cortex_a8_dpm_prepare(struct arm_dpm *dpm)
+{
+ struct cortex_a8_common *a8 = dpm_to_a8(dpm);
+ struct swjdp_common *swjdp = &a8->armv7a_common.swjdp_info;
+ uint32_t dscr;
+ int retval;
+
+ retval = mem_ap_read_atomic_u32(swjdp,
+ a8->armv7a_common.debug_base + CPUDBG_DSCR,
+ &dscr);
+
+ /* this "should never happen" ... */
+ if (dscr & (1 << DSCR_DTR_RX_FULL)) {
+ LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr);
+ /* Clear DCCRX */
+ retval = cortex_a8_exec_opcode(
+ a8->armv7a_common.armv4_5_common.target,
+ ARMV4_5_MRC(14, 0, 0, 0, 5, 0));
+ }
+
+ return retval;
+}
+
+static int cortex_a8_dpm_finish(struct arm_dpm *dpm)
+{
+ /* REVISIT what could be done here? */
+ return ERROR_OK;
+}
+
+static int cortex_a8_instr_write_data_dcc(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t data)
+{
+ struct cortex_a8_common *a8 = dpm_to_a8(dpm);
+ int retval;
+
+ retval = cortex_a8_write_dcc(a8, data);
+
+ return cortex_a8_exec_opcode(
+ a8->armv7a_common.armv4_5_common.target,
+ opcode);
+}
+
+static int cortex_a8_instr_write_data_r0(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t data)
+{
+ struct cortex_a8_common *a8 = dpm_to_a8(dpm);
+ int retval;
+
+ retval = cortex_a8_write_dcc(a8, data);
+
+ /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */
+ retval = cortex_a8_exec_opcode(
+ a8->armv7a_common.armv4_5_common.target,
+ ARMV4_5_MRC(14, 0, 0, 0, 5, 0));
+
+ /* then the opcode, taking data from R0 */
+ retval = cortex_a8_exec_opcode(
+ a8->armv7a_common.armv4_5_common.target,
+ opcode);
+
+ return retval;
+}
+
+static int cortex_a8_instr_cpsr_sync(struct arm_dpm *dpm)
+{
+ struct target *target = dpm->arm->target;
+
+ /* "Prefetch flush" after modifying execution status in CPSR */
+ return cortex_a8_exec_opcode(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 4));
+}
+
+static int cortex_a8_instr_read_data_dcc(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t *data)
+{
+ struct cortex_a8_common *a8 = dpm_to_a8(dpm);
+ int retval;
+
+ /* the opcode, writing data to DCC */
+ retval = cortex_a8_exec_opcode(
+ a8->armv7a_common.armv4_5_common.target,
+ opcode);
+
+ return cortex_a8_read_dcc(a8, data);
+}
+
+
+static int cortex_a8_instr_read_data_r0(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t *data)
+{
+ struct cortex_a8_common *a8 = dpm_to_a8(dpm);
+ int retval;
+
+ /* the opcode, writing data to R0 */
+ retval = cortex_a8_exec_opcode(
+ a8->armv7a_common.armv4_5_common.target,
+ opcode);
+
+ /* write R0 to DCC */
+ retval = cortex_a8_exec_opcode(
+ a8->armv7a_common.armv4_5_common.target,
+ ARMV4_5_MCR(14, 0, 0, 0, 5, 0));
+
+ return cortex_a8_read_dcc(a8, data);
+}
+
+// static
+int cortex_a8_dpm_setup(struct cortex_a8_common *a8, uint32_t didr)
+{
+ struct arm_dpm *dpm = &a8->armv7a_common.dpm;
+
+ dpm->arm = &a8->armv7a_common.armv4_5_common;
+ dpm->didr = didr;
+
+ dpm->prepare = cortex_a8_dpm_prepare;
+ dpm->finish = cortex_a8_dpm_finish;
+
+ dpm->instr_write_data_dcc = cortex_a8_instr_write_data_dcc;
+ dpm->instr_write_data_r0 = cortex_a8_instr_write_data_r0;
+ dpm->instr_cpsr_sync = cortex_a8_instr_cpsr_sync;
+
+ dpm->instr_read_data_dcc = cortex_a8_instr_read_data_dcc;
+ dpm->instr_read_data_r0 = cortex_a8_instr_read_data_r0;
+
+ return arm_dpm_setup(dpm);
+}
+
+
+/*
* Cortex-A8 Run control
*/