From e519099ab7fac4517eaee7dde3275e7b839460ff Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Thu, 29 Aug 2013 14:02:19 -0400 Subject: cortex_a: Add support for A15 MPCore Added Cortex-A15 support for DAP AHB-AP init code as per ADI V5 spec. Also added changes to make the APB MEM-AP to work with A15. Made the the cortex_a target code generic to work with A8, A9 and A15 single core or multicore implementation. Added armv7a code for os_border calculation to work for known A8, A9 and A15 platforms based on the ARM DDI 0344H, ARM DDI 0407F, ARM DDI 0406C ARMV7A architecture docs. Change-Id: Ib2803ab62588bf40f1ae4b9192b619af31525a1a Signed-off-by: Kamal Dasu Reviewed-on: http://openocd.zylin.com/1601 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/target/arm_adi_v5.c | 9 +++-- src/target/armv7a.c | 89 +++++++++++++++++++++++++++++++++++++++++++------ src/target/armv7a.h | 6 ++++ src/target/cortex_a.c | 85 ++++++++++++++++++++++++++++++++++++++++++---- src/target/cortex_a.h | 13 ++++++++ 5 files changed, 183 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index c76cc69..7bb2a0b 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1339,7 +1339,12 @@ static int dap_rom_display(struct command_context *cmd_ctx, type = "Cortex-A9 Debug"; full = "(Debug Unit)"; break; + case 0x4af: + type = "Cortex-A15 Debug"; + full = "(Debug Unit)"; + break; default: + LOG_DEBUG("Unrecognized Part number 0x%" PRIx32, part_num); type = "-*- unrecognized -*-"; full = ""; break; @@ -1408,9 +1413,9 @@ static int dap_info_command(struct command_context *cmd_ctx, command_print(cmd_ctx, "No AP found at this ap 0x%x", ap); romtable_present = ((mem_ap) && (dbgbase != 0xFFFFFFFF)); - if (romtable_present) { + if (romtable_present) dap_rom_display(cmd_ctx, dap, ap, dbgbase, 0); - } else + else command_print(cmd_ctx, "\tNo ROM table present"); dap_ap_select(dap, ap_old); diff --git a/src/target/armv7a.c b/src/target/armv7a.c index bf474d3..57b8799 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -88,11 +88,50 @@ done: /* (void) */ dpm->finish(dpm); } + +/* retrieve main id register */ +static int armv7a_read_midr(struct target *target) +{ + int retval = ERROR_FAIL; + struct armv7a_common *armv7a = target_to_armv7a(target); + struct arm_dpm *dpm = armv7a->arm.dpm; + uint32_t midr; + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + /* MRC p15,0,,c0,c0,0; read main id register*/ + + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 0, 0, 0), + &midr); + if (retval != ERROR_OK) + goto done; + + armv7a->rev = (midr & 0xf); + armv7a->partnum = (midr >> 4) & 0xfff; + armv7a->arch = (midr >> 16) & 0xf; + armv7a->variant = (midr >> 20) & 0xf; + armv7a->implementor = (midr >> 24) & 0xff; + LOG_INFO("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32 + ", variant %" PRIx32 ", implementor %" PRIx32, + target->cmd_name, + armv7a->rev, + armv7a->partnum, + armv7a->arch, + armv7a->variant, + armv7a->implementor); + +done: + dpm->finish(dpm); + return retval; +} + static int armv7a_read_ttbcr(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttbcr; + uint32_t ttbr0, ttbr1; int retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; @@ -102,27 +141,55 @@ static int armv7a_read_ttbcr(struct target *target) &ttbcr); if (retval != ERROR_OK) goto done; + + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 2, 0, 0), + &ttbr0); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 2, 0, 1), + &ttbr1); + if (retval != ERROR_OK) + goto done; + + LOG_INFO("ttbcr %" PRIx32 "ttbr0 %" PRIx32 "ttbr1 %" PRIx32, ttbcr, ttbr0, ttbr1); + armv7a->armv7a_mmu.ttbr1_used = ((ttbcr & 0x7) != 0) ? 1 : 0; - armv7a->armv7a_mmu.ttbr0_mask = 7 << (32 - ((ttbcr & 0x7))); -#if 0 - LOG_INFO("ttb1 %s ,ttb0_mask %x", - armv7a->armv7a_mmu.ttbr1_used ? "used" : "not used", - armv7a->armv7a_mmu.ttbr0_mask); -#endif - if (armv7a->armv7a_mmu.ttbr1_used == 1) { - LOG_INFO("SVC access above %" PRIx32, - (uint32_t)(0xffffffff & armv7a->armv7a_mmu.ttbr0_mask)); - armv7a->armv7a_mmu.os_border = 0xffffffff & armv7a->armv7a_mmu.ttbr0_mask; + armv7a->armv7a_mmu.ttbr0_mask = 0; + + retval = armv7a_read_midr(target); + if (retval != ERROR_OK) + goto done; + + if (armv7a->partnum & 0xf) { + /* + * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition), + * document # ARM DDI 0406C + */ + armv7a->armv7a_mmu.ttbr0_mask = 1 << (14 - ((ttbcr & 0x7))); } else { + /* ARM DDI 0344H , ARM DDI 0407F */ + armv7a->armv7a_mmu.ttbr0_mask = 7 << (32 - ((ttbcr & 0x7))); /* fix me , default is hard coded LINUX border */ armv7a->armv7a_mmu.os_border = 0xc0000000; } + + LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32, + armv7a->armv7a_mmu.ttbr1_used ? "used" : "not used", + armv7a->armv7a_mmu.ttbr0_mask); + + if (armv7a->armv7a_mmu.ttbr1_used == 1) { + LOG_INFO("SVC access above %" PRIx32, + (0xffffffff & armv7a->armv7a_mmu.ttbr0_mask)); + armv7a->armv7a_mmu.os_border = 0xffffffff & armv7a->armv7a_mmu.ttbr0_mask; + } done: dpm->finish(dpm); return retval; } - /* method adapted to cortex A : reused arm v4 v5 method*/ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) { diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 341114b..4341aca 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -77,6 +77,7 @@ struct armv7a_cache_common { struct armv7a_mmu_common { /* following field mmu working way */ + int32_t ttbr0_used; int32_t ttbr1_used; /* -1 not initialized, 0 no ttbr1 1 ttbr1 used and */ uint32_t ttbr0_mask;/* masked to be used */ uint32_t os_border; @@ -105,6 +106,11 @@ struct armv7a_common { uint8_t cluster_id; uint8_t cpu_id; bool is_armv7r; + uint32_t rev; + uint32_t partnum; + uint32_t arch; + uint32_t variant; + uint32_t implementor; /* cache specific to V7 Memory Management Unit compatible with v4_5*/ struct armv7a_mmu_common armv7a_mmu; diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 0393a44..3075055 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -20,6 +20,9 @@ * Copyright (C) Broadcom 2012 * * ehunter@broadcom.com : Cortex R4 support * * * + * Copyright (C) 2013 Kamal Dasu * + * kdasu.kdev@gmail.com * + * * * 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 * @@ -164,12 +167,11 @@ static int cortex_a_mmu_modify(struct target *target, int enable) /* * Cortex-A Basic debug access, very low level assumes state is saved */ -static int cortex_a_init_debug_access(struct target *target) +static int cortex_a8_init_debug_access(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; int retval; - uint32_t dummy; LOG_DEBUG(" "); @@ -185,12 +187,57 @@ static int cortex_a_init_debug_access(struct target *target) LOG_USER( "Locking debug access failed on first, but succeeded on second try."); } + + return retval; +} + +/* + * Cortex-A Basic debug access, very low level assumes state is saved + */ +static int cortex_a_init_debug_access(struct target *target) +{ + struct armv7a_common *armv7a = target_to_armv7a(target); + struct adiv5_dap *swjdp = armv7a->arm.dap; + int retval; + uint32_t dbg_osreg; + uint32_t cortex_part_num; + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + + LOG_DEBUG(" "); + cortex_part_num = (cortex_a->cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> + CORTEX_A_MIDR_PARTNUM_SHIFT; + + switch (cortex_part_num) { + case CORTEX_A15_PARTNUM: + retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + armv7a->debug_base + CPUDBG_OSLSR, + &dbg_osreg); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("DBGOSLSR 0x%" PRIx32, dbg_osreg); + + if (dbg_osreg & CPUDBG_OSLAR_LK_MASK) + /* Unlocking the DEBUG OS registers for modification */ + retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + armv7a->debug_base + CPUDBG_OSLAR, + 0); + break; + + case CORTEX_A8_PARTNUM: + case CORTEX_A9_PARTNUM: + default: + retval = cortex_a8_init_debug_access(target); + } + if (retval != ERROR_OK) return retval; /* Clear Sticky Power Down status Bit in PRSR to enable access to the registers in the Core Power Domain */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_PRSR, &dummy); + armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); + LOG_DEBUG("target->coreid %d DBGPRSR 0x%x ", target->coreid, dbg_osreg); + if (retval != ERROR_OK) return retval; @@ -1799,6 +1846,7 @@ static int cortex_a_write_apb_ab_memory(struct target *target, uint32_t dscr; uint8_t *tmp_buff = NULL; + LOG_DEBUG("Writing APB-AP memory address 0x%" PRIx32 " size %" PRIu32 " count%" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { @@ -1846,7 +1894,6 @@ static int cortex_a_write_apb_ab_memory(struct target *target, /* If end of write is not aligned, or the write is less than 4 bytes */ if ((end_byte != 0) || ((total_u32 == 1) && (total_bytes != 4))) { - /* Read the last word to avoid corruption during 32 bit write */ int mem_offset = (total_u32-1) * 4; retval = cortex_a_read_apb_ab_memory(target, (address & ~0x3) + mem_offset, 4, 1, &tmp_buff[mem_offset]); @@ -2163,7 +2210,8 @@ static int cortex_a_read_memory(struct target *target, uint32_t address, virt, phys); address = phys; } - retval = cortex_a_read_phys_memory(target, address, size, count, buffer); + retval = cortex_a_read_phys_memory(target, address, size, + count, buffer); } else { if (mmu_enabled) { retval = cortex_a_check_address(target, address); @@ -2363,7 +2411,7 @@ static int cortex_a_examine_first(struct target *target) struct adiv5_dap *swjdp = armv7a->arm.dap; int i; int retval = ERROR_OK; - uint32_t didr, ctypr, ttypr, cpuid; + uint32_t didr, ctypr, ttypr, cpuid, dbg_osreg; /* We do one extra read to ensure DAP is configured, * we call ahbap_debugport_init(swjdp) instead @@ -2447,6 +2495,31 @@ static int cortex_a_examine_first(struct target *target) LOG_DEBUG("ttypr = 0x%08" PRIx32, ttypr); LOG_DEBUG("didr = 0x%08" PRIx32, didr); + cortex_a->cpuid = cpuid; + cortex_a->ctypr = ctypr; + cortex_a->ttypr = ttypr; + cortex_a->didr = didr; + + /* Unlocking the debug registers */ + if ((cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> CORTEX_A_MIDR_PARTNUM_SHIFT == + CORTEX_A15_PARTNUM) { + + retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + armv7a->debug_base + CPUDBG_OSLAR, + 0); + + if (retval != ERROR_OK) + return retval; + + } + retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); + + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("target->coreid %d DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); + armv7a->arm.core_type = ARM_MODE_MON; retval = cortex_a_dpm_setup(cortex_a, didr); if (retval != ERROR_OK) diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h index 7b56fea..043d96f 100644 --- a/src/target/cortex_a.h +++ b/src/target/cortex_a.h @@ -33,12 +33,20 @@ #include "armv7a.h" #define CORTEX_A_COMMON_MAGIC 0x411fc082 +#define CORTEX_A15_COMMON_MAGIC 0x413fc0f1 + +#define CORTEX_A8_PARTNUM 0xc08 +#define CORTEX_A9_PARTNUM 0xc09 +#define CORTEX_A15_PARTNUM 0xc0f +#define CORTEX_A_MIDR_PARTNUM_MASK 0x0000fff0 +#define CORTEX_A_MIDR_PARTNUM_SHIFT 4 #define CPUDBG_CPUID 0xD00 #define CPUDBG_CTYPR 0xD04 #define CPUDBG_TTYPR 0xD0C #define CPUDBG_LOCKACCESS 0xFB0 #define CPUDBG_LOCKSTATUS 0xFB4 +#define CPUDBG_OSLAR_LK_MASK (1 << 1) #define BRP_NORMAL 0 #define BRP_CONTEXT 1 @@ -76,6 +84,11 @@ struct cortex_a_common { /* Use cortex_a_read_regs_through_mem for fast register reads */ int fast_reg_read; + uint32_t cpuid; + uint32_t ctypr; + uint32_t ttypr; + uint32_t didr; + struct armv7a_common armv7a_common; }; -- cgit v1.1