target: restructure dap support
[fw/openocd] / src / target / armv7a.c
index e274785226e7aa099be7fdf522df1bdb8de83cd2..fab7363105c33c9f19a92d733c80eca87d9da1ae 100644 (file)
@@ -14,9 +14,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -131,9 +129,13 @@ 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, ttbcr_n;
-       int retval = dpm->prepare(dpm);
+       int ttbidx;
+       int retval;
+
+       retval = dpm->prepare(dpm);
        if (retval != ERROR_OK)
                goto done;
+
        /*  MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
        retval = dpm->instr_read_data_r0(dpm,
                        ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
@@ -147,6 +149,15 @@ static int armv7a_read_ttbcr(struct target *target)
        armv7a->armv7a_mmu.ttbcr = ttbcr;
        armv7a->armv7a_mmu.cached = 1;
 
+       for (ttbidx = 0; ttbidx < 2; ttbidx++) {
+               /*  MRC p15,0,<Rt>,c2,c0,ttbidx */
+               retval = dpm->instr_read_data_r0(dpm,
+                               ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx),
+                               &armv7a->armv7a_mmu.ttbr[ttbidx]);
+               if (retval != ERROR_OK)
+                       goto done;
+       }
+
        /*
         * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition),
         * document # ARM DDI 0406C
@@ -172,61 +183,33 @@ static int armv7a_read_ttbcr(struct target *target)
                  armv7a->armv7a_mmu.ttbr_mask[0],
                  armv7a->armv7a_mmu.ttbr_mask[1]);
 
-       /* FIXME: default is hard coded LINUX border  */
-       armv7a->armv7a_mmu.os_border = 0xc0000000;
-       if (ttbcr_n != 0) {
-               LOG_INFO("SVC access above %" PRIx32,
-                       armv7a->armv7a_mmu.ttbr_range[0] + 1);
-               armv7a->armv7a_mmu.os_border = armv7a->armv7a_mmu.ttbr_range[0] + 1;
-       }
 done:
        dpm->finish(dpm);
        return retval;
 }
 
-/*  method adapted to cortex A : reused arm v4 v5 method*/
+/*  method adapted to Cortex-A : reused ARM v4 v5 method */
 int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val)
 {
        uint32_t first_lvl_descriptor = 0x0;
        uint32_t second_lvl_descriptor = 0x0;
        int retval;
        struct armv7a_common *armv7a = target_to_armv7a(target);
-       struct arm_dpm *dpm = armv7a->arm.dpm;
        uint32_t ttbidx = 0;    /*  default to ttbr0 */
        uint32_t ttb_mask;
        uint32_t va_mask;
-       uint32_t ttbcr;
        uint32_t ttb;
 
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /*  MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
-       retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
-                       &ttbcr);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /* if ttbcr has changed or was not read before, re-read the information */
-       if ((armv7a->armv7a_mmu.cached == 0) ||
-               (armv7a->armv7a_mmu.ttbcr != ttbcr)) {
-               armv7a_read_ttbcr(target);
-       }
+       if (target->state != TARGET_HALTED)
+               LOG_INFO("target not halted, using cached values for translation table!");
 
        /* if va is above the range handled by ttbr0, select ttbr1 */
        if (va > armv7a->armv7a_mmu.ttbr_range[0]) {
                /*  select ttb 1 */
                ttbidx = 1;
        }
-       /*  MRC p15,0,<Rt>,c2,c0,ttbidx */
-       retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx),
-                       &ttb);
-       if (retval != ERROR_OK)
-               return retval;
 
+       ttb = armv7a->armv7a_mmu.ttbr[ttbidx];
        ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx];
        va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx];
 
@@ -288,9 +271,6 @@ int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val)
        }
 
        return ERROR_OK;
-
-done:
-       return retval;
 }
 
 /*  V7 method VA TO PA  */
@@ -364,7 +344,7 @@ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
                                break;
                        case 7:
                                LOG_INFO("inner: Write-Back, no Write-Allocate");
-
+                               break;
                        default:
                                LOG_INFO("inner: %" PRIx32 " ???", INNER);
                }
@@ -376,31 +356,6 @@ done:
        return retval;
 }
 
-static int armv7a_handle_inner_cache_info_command(struct command_context *cmd_ctx,
-       struct armv7a_cache_common *armv7a_cache)
-{
-       if (armv7a_cache->ctype == -1) {
-               command_print(cmd_ctx, "cache not yet identified");
-               return ERROR_OK;
-       }
-
-       command_print(cmd_ctx,
-               "D-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes",
-               armv7a_cache->d_u_size.linelen,
-               armv7a_cache->d_u_size.associativity,
-               armv7a_cache->d_u_size.nsets,
-               armv7a_cache->d_u_size.cachesize);
-
-       command_print(cmd_ctx,
-               "I-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes",
-               armv7a_cache->i_size.linelen,
-               armv7a_cache->i_size.associativity,
-               armv7a_cache->i_size.nsets,
-               armv7a_cache->i_size.cachesize);
-
-       return ERROR_OK;
-}
-
 /* FIXME: remove it */
 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
 {
@@ -457,13 +412,43 @@ int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
        struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
                (armv7a_cache->outer_cache);
 
-       if (armv7a_cache->ctype == -1) {
+       int cl;
+
+       if (armv7a_cache->info == -1) {
                command_print(cmd_ctx, "cache not yet identified");
                return ERROR_OK;
        }
 
-       if (armv7a_cache->display_cache_info)
-               armv7a_cache->display_cache_info(cmd_ctx, armv7a_cache);
+       for (cl = 0; cl < armv7a_cache->loc; cl++) {
+               struct armv7a_arch_cache *arch = &(armv7a_cache->arch[cl]);
+
+               if (arch->ctype & 1) {
+                       command_print(cmd_ctx,
+                               "L%d I-Cache: linelen %" PRIi32
+                               ", associativity %" PRIi32
+                               ", nsets %" PRIi32
+                               ", cachesize %" PRId32 " KBytes",
+                               cl+1,
+                               arch->i_size.linelen,
+                               arch->i_size.associativity,
+                               arch->i_size.nsets,
+                               arch->i_size.cachesize);
+               }
+
+               if (arch->ctype >= 2) {
+                       command_print(cmd_ctx,
+                               "L%d D-Cache: linelen %" PRIi32
+                               ", associativity %" PRIi32
+                               ", nsets %" PRIi32
+                               ", cachesize %" PRId32 " KBytes",
+                               cl+1,
+                               arch->d_u_size.linelen,
+                               arch->d_u_size.associativity,
+                               arch->d_u_size.nsets,
+                               arch->d_u_size.cachesize);
+               }
+       }
+
        if (l2x_cache != NULL)
                command_print(cmd_ctx, "Outer unified cache Base Address 0x%" PRIx32 ", %" PRId32 " ways",
                        l2x_cache->base, l2x_cache->way);
@@ -517,17 +502,61 @@ done:
 
 }
 
+static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg)
+{
+       int retval = ERROR_OK;
+
+       /*  select cache level */
+       retval = dpm->instr_write_data_r0(dpm,
+                       ARMV4_5_MCR(15, 2, 0, 0, 0, 0),
+                       (cl << 1) | (ct == 1 ? 1 : 0));
+       if (retval != ERROR_OK)
+               goto done;
+
+       retval = dpm->instr_read_data_r0(dpm,
+                       ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
+                       cache_reg);
+ done:
+       return retval;
+}
+
+static struct armv7a_cachesize decode_cache_reg(uint32_t cache_reg)
+{
+       struct armv7a_cachesize size;
+       int i = 0;
+
+       size.linelen = 16 << (cache_reg & 0x7);
+       size.associativity = ((cache_reg >> 3) & 0x3ff) + 1;
+       size.nsets = ((cache_reg >> 13) & 0x7fff) + 1;
+       size.cachesize = size.linelen * size.associativity * size.nsets / 1024;
+
+       /*  compute info for set way operation on cache */
+       size.index_shift = (cache_reg & 0x7) + 4;
+       size.index = (cache_reg >> 13) & 0x7fff;
+       size.way = ((cache_reg >> 3) & 0x3ff);
+
+       while (((size.way << i) & 0x80000000) == 0)
+               i++;
+       size.way_shift = i;
+
+       return size;
+}
+
 int armv7a_identify_cache(struct target *target)
 {
        /*  read cache descriptor */
        int retval = ERROR_FAIL;
        struct armv7a_common *armv7a = target_to_armv7a(target);
        struct arm_dpm *dpm = armv7a->arm.dpm;
-       uint32_t cache_selected, clidr, ctr;
-       uint32_t cache_i_reg, cache_d_reg;
-       struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
+       uint32_t csselr, clidr, ctr;
+       uint32_t cache_reg;
+       int cl, ctype;
+       struct armv7a_cache_common *cache =
+               &(armv7a->armv7a_mmu.armv7a_cache);
+
        if (!armv7a->is_armv7r)
                armv7a_read_ttbcr(target);
+
        retval = dpm->prepare(dpm);
        if (retval != ERROR_OK)
                goto done;
@@ -552,129 +581,86 @@ int armv7a_identify_cache(struct target *target)
                        &clidr);
        if (retval != ERROR_OK)
                goto done;
-       clidr = (clidr & 0x7000000) >> 23;
-       LOG_INFO("number of cache level %" PRIx32, (uint32_t)(clidr / 2));
-       if ((clidr / 2) > 1) {
-               /* FIXME not supported present in cortex A8 and later */
-               /*  in cortex A7, A15 */
-               LOG_ERROR("cache l2 present :not supported");
-       }
-       /*  retrieve selected cache
+
+       cache->loc = (clidr & 0x7000000) >> 24;
+       LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc);
+
+       /*  retrieve selected cache for later restore
         *  MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
        retval = dpm->instr_read_data_r0(dpm,
                        ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-                       &cache_selected);
+                       &csselr);
        if (retval != ERROR_OK)
                goto done;
 
-       retval = armv7a->arm.mrc(target, 15,
-                       2, 0,   /* op1, op2 */
-                       0, 0,   /* CRn, CRm */
-                       &cache_selected);
-       if (retval != ERROR_OK)
-               goto done;
-       /* select instruction cache
-        *  MCR p15, 2,<Rd>, c0, c0, 0; Write CSSELR
-        *  [0]  : 1 instruction cache selection , 0 data cache selection */
-       retval = dpm->instr_write_data_r0(dpm,
-                       ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-                       1);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /* read CCSIDR
-        * MRC P15,1,<RT>,C0, C0,0 ;on cortex A9 read CCSIDR
-        * [2:0] line size  001 eight word per line
-        * [27:13] NumSet 0x7f 16KB, 0xff 32Kbytes, 0x1ff 64Kbytes */
-       retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
-                       &cache_i_reg);
-       if (retval != ERROR_OK)
-               goto done;
+       /* retrieve all available inner caches */
+       for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) {
+
+               /* isolate cache type at current level */
+               ctype = clidr & 7;
+
+               /* skip reserved values */
+               if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE)
+                       continue;
+
+               /* separate d or unified d/i cache at this level ? */
+               if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) {
+                       /* retrieve d-cache info */
+                       retval = get_cache_info(dpm, cl, 0, &cache_reg);
+                       if (retval != ERROR_OK)
+                               goto done;
+                       cache->arch[cl].d_u_size = decode_cache_reg(cache_reg);
+
+                       LOG_DEBUG("data/unified cache index %d << %d, way %d << %d",
+                                       cache->arch[cl].d_u_size.index,
+                                       cache->arch[cl].d_u_size.index_shift,
+                                       cache->arch[cl].d_u_size.way,
+                                       cache->arch[cl].d_u_size.way_shift);
+
+                       LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
+                                       cache->arch[cl].d_u_size.linelen,
+                                       cache->arch[cl].d_u_size.cachesize,
+                                       cache->arch[cl].d_u_size.associativity);
+               }
 
-       /*  select data cache*/
-       retval = dpm->instr_write_data_r0(dpm,
-                       ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-                       0);
-       if (retval != ERROR_OK)
-               goto done;
+               /* separate i-cache at this level ? */
+               if (ctype & CACHE_LEVEL_HAS_I_CACHE) {
+                       /* retrieve i-cache info */
+                       retval = get_cache_info(dpm, cl, 1, &cache_reg);
+                       if (retval != ERROR_OK)
+                               goto done;
+                       cache->arch[cl].i_size = decode_cache_reg(cache_reg);
+
+                       LOG_DEBUG("instruction cache index %d << %d, way %d << %d",
+                                       cache->arch[cl].i_size.index,
+                                       cache->arch[cl].i_size.index_shift,
+                                       cache->arch[cl].i_size.way,
+                                       cache->arch[cl].i_size.way_shift);
+
+                       LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
+                                       cache->arch[cl].i_size.linelen,
+                                       cache->arch[cl].i_size.cachesize,
+                                       cache->arch[cl].i_size.associativity);
+               }
 
-       retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
-                       &cache_d_reg);
-       if (retval != ERROR_OK)
-               goto done;
+               cache->arch[cl].ctype = ctype;
+       }
 
        /*  restore selected cache  */
        dpm->instr_write_data_r0(dpm,
                ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
-               cache_selected);
+               csselr);
 
        if (retval != ERROR_OK)
                goto done;
-       dpm->finish(dpm);
 
-       /* put fake type */
-       cache->d_u_size.linelen = 16 << (cache_d_reg & 0x7);
-       cache->d_u_size.cachesize = (((cache_d_reg >> 13) & 0x7fff)+1)/8;
-       cache->d_u_size.nsets = (cache_d_reg >> 13) & 0x7fff;
-       cache->d_u_size.associativity = ((cache_d_reg >> 3) & 0x3ff) + 1;
-       /*  compute info for set way operation on cache */
-       cache->d_u_size.index_shift = (cache_d_reg & 0x7) + 4;
-       cache->d_u_size.index = (cache_d_reg >> 13) & 0x7fff;
-       cache->d_u_size.way = ((cache_d_reg >> 3) & 0x3ff);
-       cache->d_u_size.way_shift = cache->d_u_size.way + 1;
-       {
-               int i = 0;
-               while (((cache->d_u_size.way_shift >> i) & 1) != 1)
-                       i++;
-               cache->d_u_size.way_shift = 32-i;
-       }
-#if 0
-       LOG_INFO("data cache index %d << %d, way %d << %d",
-                       cache->d_u_size.index, cache->d_u_size.index_shift,
-                       cache->d_u_size.way,
-                       cache->d_u_size.way_shift);
-
-       LOG_INFO("data cache %d bytes %d KBytes asso %d ways",
-                       cache->d_u_size.linelen,
-                       cache->d_u_size.cachesize,
-                       cache->d_u_size.associativity);
-#endif
-       cache->i_size.linelen = 16 << (cache_i_reg & 0x7);
-       cache->i_size.associativity = ((cache_i_reg >> 3) & 0x3ff) + 1;
-       cache->i_size.nsets = (cache_i_reg >> 13) & 0x7fff;
-       cache->i_size.cachesize = (((cache_i_reg >> 13) & 0x7fff)+1)/8;
-       /*  compute info for set way operation on cache */
-       cache->i_size.index_shift = (cache_i_reg & 0x7) + 4;
-       cache->i_size.index = (cache_i_reg >> 13) & 0x7fff;
-       cache->i_size.way = ((cache_i_reg >> 3) & 0x3ff);
-       cache->i_size.way_shift = cache->i_size.way + 1;
-       {
-               int i = 0;
-               while (((cache->i_size.way_shift >> i) & 1) != 1)
-                       i++;
-               cache->i_size.way_shift = 32-i;
-       }
-#if 0
-       LOG_INFO("instruction cache index %d << %d, way %d << %d",
-                       cache->i_size.index, cache->i_size.index_shift,
-                       cache->i_size.way, cache->i_size.way_shift);
-
-       LOG_INFO("instruction cache %d bytes %d KBytes asso %d ways",
-                       cache->i_size.linelen,
-                       cache->i_size.cachesize,
-                       cache->i_size.associativity);
-#endif
        /*  if no l2 cache initialize l1 data cache flush function function */
        if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) {
-               armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
-                       armv7a_handle_inner_cache_info_command;
                armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
                        armv7a_cache_auto_flush_all_data;
        }
-       armv7a->armv7a_mmu.armv7a_cache.ctype = 0;
 
+       armv7a->armv7a_mmu.armv7a_cache.info = 1;
 done:
        dpm->finish(dpm);
        armv7a_read_mpidr(target);
@@ -682,19 +668,47 @@ done:
 
 }
 
+static int armv7a_setup_semihosting(struct target *target, int enable)
+{
+       struct armv7a_common *armv7a = target_to_armv7a(target);
+       uint32_t vcr;
+       int ret;
+
+       ret = mem_ap_read_atomic_u32(armv7a->debug_ap,
+                                        armv7a->debug_base + CPUDBG_VCR,
+                                        &vcr);
+       if (ret < 0) {
+               LOG_ERROR("Failed to read VCR register\n");
+               return ret;
+       }
+
+       if (enable)
+               vcr |= DBG_VCR_SVC_MASK;
+       else
+               vcr &= ~DBG_VCR_SVC_MASK;
+
+       ret = mem_ap_write_atomic_u32(armv7a->debug_ap,
+                                         armv7a->debug_base + CPUDBG_VCR,
+                                         vcr);
+       if (ret < 0)
+               LOG_ERROR("Failed to write VCR register\n");
+
+       return ret;
+}
+
 int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a)
 {
        struct arm *arm = &armv7a->arm;
        arm->arch_info = armv7a;
        target->arch_info = &armv7a->arm;
+       arm->setup_semihosting = armv7a_setup_semihosting;
        /*  target is useful in all function arm v4 5 compatible */
        armv7a->arm.target = target;
        armv7a->arm.common_magic = ARM_COMMON_MAGIC;
        armv7a->common_magic = ARMV7_COMMON_MAGIC;
-       armv7a->armv7a_mmu.armv7a_cache.ctype = -1;
+       armv7a->armv7a_mmu.armv7a_cache.info = -1;
        armv7a->armv7a_mmu.armv7a_cache.outer_cache = NULL;
        armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL;
-       armv7a->armv7a_mmu.armv7a_cache.display_cache_info = NULL;
        armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = 1;
        return ERROR_OK;
 }
@@ -715,6 +729,8 @@ int armv7a_arch_state(struct target *target)
 
        arm_arch_state(target);
 
+       armv7a_read_ttbcr(target);
+
        if (armv7a->is_armv7r) {
                LOG_USER("D-Cache: %s, I-Cache: %s",
                        state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
@@ -760,9 +776,6 @@ const struct command_registration l2x_cache_command_handlers[] = {
 };
 
 const struct command_registration armv7a_command_handlers[] = {
-       {
-               .chain = dap_command_handlers,
-       },
        {
                .chain = l2x_cache_command_handlers,
        },