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>
This commit is contained in:
parent
991daa03eb
commit
c008d30fe8
|
@ -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);
|
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 ...
|
if (dpm->instr_cpsr_sync)
|
||||||
cortex_a8_exec_opcode(target,
|
retval = dpm->instr_cpsr_sync(dpm);
|
||||||
ARMV4_5_MCR(15, 0, 0, 7, 5, 4));
|
|
||||||
*/
|
|
||||||
|
|
||||||
return retval;
|
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),
|
ARMV4_5_MSR_GP(0, 0xf, regnum & 1),
|
||||||
value);
|
value);
|
||||||
|
|
||||||
/* REVISIT on Cortex-A8, we need a Prefetch Flush operation
|
if (regnum == 16 && dpm->instr_cpsr_sync)
|
||||||
* after writing CPSR ...
|
retval = dpm->instr_cpsr_sync(dpm);
|
||||||
cortex_a8_exec_opcode(target,
|
|
||||||
ARMV4_5_MCR(15, 0, 0, 7, 5, 4));
|
|
||||||
*/
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,9 @@ struct arm_dpm {
|
||||||
int (*instr_write_data_r0)(struct arm_dpm *,
|
int (*instr_write_data_r0)(struct arm_dpm *,
|
||||||
uint32_t opcode, uint32_t data);
|
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 */
|
/* READ FROM CPU */
|
||||||
|
|
||||||
/** Runs one instruction, reading data from dcc after execution. */
|
/** Runs one instruction, reading data from dcc after execution. */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "armv4_5.h"
|
#include "armv4_5.h"
|
||||||
#include "armv4_5_mmu.h"
|
#include "armv4_5_mmu.h"
|
||||||
#include "armv4_5_cache.h"
|
#include "armv4_5_cache.h"
|
||||||
|
#include "arm_dpm.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -53,6 +54,7 @@ struct armv7a_common
|
||||||
struct swjdp_common swjdp_info;
|
struct swjdp_common swjdp_info;
|
||||||
|
|
||||||
/* Core Debug Unit */
|
/* Core Debug Unit */
|
||||||
|
struct arm_dpm dpm;
|
||||||
uint32_t debug_base;
|
uint32_t debug_base;
|
||||||
uint8_t debug_ap;
|
uint8_t debug_ap;
|
||||||
uint8_t memory_ap;
|
uint8_t memory_ap;
|
||||||
|
|
|
@ -351,6 +351,173 @@ static int cortex_a8_dap_write_memap_register_u32(struct target *target, uint32_
|
||||||
return retval;
|
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
|
* Cortex-A8 Run control
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue