Cortex-A8: implement DPM
authorDavid Brownell <dbrownell@users.sourceforge.net>
Wed, 25 Nov 2009 05:24:44 +0000 (21:24 -0800)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Wed, 25 Nov 2009 05:24:44 +0000 (21:24 -0800)
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>
src/target/arm_dpm.c
src/target/arm_dpm.h
src/target/armv7a.h
src/target/cortex_a8.c

index 18a9dcc74f771f985cd690fc0851e4a9302328b5..b8107d78549f1c91640ee4f59775f375aee14e6c 100644 (file)
@@ -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;
        }
index 06b548ecc1618a697ac908d4e436b8f49a1107b9..67ce2180edd65360b555cd409b10b5538c868a98 100644 (file)
@@ -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. */
index 51f7b45aa6f0d82fb5e8eb1c122bddc657deead8..942bf8bff76353bae212950d92a093aaccc0e952 100644 (file)
@@ -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;
index f549fb394dffa6a1ad3468e1f042f01a570187a3..28c75b591da3f6dc4b9f2dd24bc3843cb8dd3bae 100644 (file)
@@ -351,6 +351,173 @@ static int cortex_a8_dap_write_memap_register_u32(struct target *target, uint32_
        return retval;
 }
 
+/*
+ * 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
  */