aarch64: armv8 cache functions update
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>
Thu, 22 Sep 2016 19:29:42 +0000 (21:29 +0200)
committerMatthias Welwarsky <matthias.welwarsky@sysgo.com>
Fri, 10 Feb 2017 13:18:34 +0000 (14:18 +0100)
Update cache identification to match functionality present in
armv7a_cache.c

Change-Id: I2dc4bee80f5a22b8728334d40331c183d1406f27
Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com>
src/target/aarch64.c
src/target/armv8.c
src/target/armv8.h
src/target/armv8_cache.c
src/target/armv8_opcodes.h

index 1d2abc702713655cb27c5fcb1a5b9d89f2fb2e1f..05abe6b717c5ab5350723609384b31226002a8bd 100644 (file)
@@ -735,8 +735,10 @@ static int aarch64_post_debug_entry(struct target *target)
        LOG_DEBUG("System_register: %8.8" PRIx32, aarch64->system_control_reg);
        aarch64->system_control_reg_curr = aarch64->system_control_reg;
 
-       if (armv8->armv8_mmu.armv8_cache.ctype == -1)
-               armv8_identify_cache(target);
+       if (armv8->armv8_mmu.armv8_cache.info == -1) {
+               armv8_identify_cache(armv8);
+               armv8_read_mpidr(armv8);
+       }
 
        armv8->armv8_mmu.mmu_enabled =
                        (aarch64->system_control_reg & 0x1U) ? 1 : 0;
index 306a06e7a0b14ef5cc27ee7e93e81e62a8b4a93b..467c7716fc741bd0e1a4cd82544c0fde43aa41bb 100644 (file)
@@ -37,6 +37,8 @@
 #include "target.h"
 #include "target_type.h"
 
+#define __unused __attribute__((unused))
+
 static const char * const armv8_state_strings[] = {
        "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64",
 };
@@ -208,6 +210,38 @@ static int armv8_write_core_reg(struct target *target, struct reg *r,
        return ERROR_OK;
 }
 #endif
+
+/*  retrieve core id cluster id  */
+int armv8_read_mpidr(struct armv8_common *armv8)
+{
+       int retval = ERROR_FAIL;
+       struct arm_dpm *dpm = armv8->arm.dpm;
+       uint32_t mpidr;
+
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+
+       retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr);
+       if (retval != ERROR_OK)
+               goto done;
+       if (mpidr & 1<<31) {
+               armv8->multi_processor_system = (mpidr >> 30) & 1;
+               armv8->cluster_id = (mpidr >> 8) & 0xf;
+               armv8->cpu_id = mpidr & 0x3;
+               LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target),
+                       armv8->cluster_id,
+                       armv8->cpu_id,
+                       armv8->multi_processor_system == 0 ? "multi core" : "mono core");
+
+       } else
+               LOG_ERROR("mpdir not in multiprocessor format");
+
+done:
+       dpm->finish(dpm);
+       return retval;
+}
+
 /**
  * Configures host-side ARM records to reflect the specified CPSR.
  * Later, code can use arm_reg_current() to map register numbers
@@ -368,7 +402,7 @@ static uint8_t armv8_pa_size(uint32_t ps)
        return ret;
 }
 
-static int armv8_read_ttbcr32(struct target *target)
+static __unused int armv8_read_ttbcr32(struct target *target)
 {
        struct armv8_common *armv8 = target_to_armv8(target);
        struct arm_dpm *dpm = armv8->arm.dpm;
@@ -528,103 +562,10 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va,
        return ERROR_OK;
 }
 
-static int armv8_handle_inner_cache_info_command(struct command_context *cmd_ctx,
-       struct armv8_cache_common *armv8_cache)
-{
-       if (armv8_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",
-               armv8_cache->d_u_size.linelen,
-               armv8_cache->d_u_size.associativity,
-               armv8_cache->d_u_size.nsets,
-               armv8_cache->d_u_size.cachesize);
-
-       command_print(cmd_ctx,
-               "I-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes",
-               armv8_cache->i_size.linelen,
-               armv8_cache->i_size.associativity,
-               armv8_cache->i_size.nsets,
-               armv8_cache->i_size.cachesize);
-
-       return ERROR_OK;
-}
-
-static int _armv8_flush_all_data(struct target *target)
-{
-       struct armv8_common *armv8 = target_to_armv8(target);
-       struct arm_dpm *dpm = armv8->arm.dpm;
-       struct armv8_cachesize *d_u_size =
-               &(armv8->armv8_mmu.armv8_cache.d_u_size);
-       int32_t c_way, c_index = d_u_size->index;
-       int retval;
-       /*  check that cache data is on at target halt */
-       if (!armv8->armv8_mmu.armv8_cache.d_u_cache_enabled) {
-               LOG_INFO("flushed not performed :cache not on at target halt");
-               return ERROR_OK;
-       }
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-       do {
-               c_way = d_u_size->way;
-               do {
-                       uint32_t value = (c_index << d_u_size->index_shift)
-                               | (c_way << d_u_size->way_shift);
-                       /*  DCCISW */
-                       /* LOG_INFO ("%d %d %x",c_way,c_index,value); */
-                       retval = dpm->instr_write_data_r0(dpm,
-                                       ARMV8_MSR_GP(SYSTEM_DCCISW, 0),
-                                       value);
-                       if (retval != ERROR_OK)
-                               goto done;
-                       c_way -= 1;
-               } while (c_way >= 0);
-               c_index -= 1;
-       } while (c_index >= 0);
-       return retval;
-done:
-       LOG_ERROR("flushed failed");
-       dpm->finish(dpm);
-       return retval;
-}
-
-static int  armv8_flush_all_data(struct target *target)
-{
-       int retval = ERROR_FAIL;
-       /*  check that armv8_cache is correctly identify */
-       struct armv8_common *armv8 = target_to_armv8(target);
-       if (armv8->armv8_mmu.armv8_cache.ctype == -1) {
-               LOG_ERROR("trying to flush un-identified cache");
-               return retval;
-       }
-
-       if (target->smp) {
-               /*  look if all the other target have been flushed in order to flush level
-                *  2 */
-               struct target_list *head;
-               struct target *curr;
-               head = target->head;
-               while (head != (struct target_list *)NULL) {
-                       curr = head->target;
-                       if (curr->state == TARGET_HALTED) {
-                               LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid);
-                               retval = _armv8_flush_all_data(curr);
-                       }
-                       head = head->next;
-               }
-       } else
-               retval = _armv8_flush_all_data(target);
-       return retval;
-}
-
 int armv8_handle_cache_info_command(struct command_context *cmd_ctx,
        struct armv8_cache_common *armv8_cache)
 {
-       if (armv8_cache->ctype == -1) {
+       if (armv8_cache->info == -1) {
                command_print(cmd_ctx, "cache not yet identified");
                return ERROR_OK;
        }
@@ -634,174 +575,6 @@ int armv8_handle_cache_info_command(struct command_context *cmd_ctx,
        return ERROR_OK;
 }
 
-/*  retrieve core id cluster id  */
-static int armv8_read_mpidr(struct target *target)
-{
-       int retval = ERROR_FAIL;
-       struct armv8_common *armv8 = target_to_armv8(target);
-       struct arm_dpm *dpm = armv8->arm.dpm;
-       uint32_t mpidr;
-
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-       /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
-
-       retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr);
-       if (retval != ERROR_OK)
-               goto done;
-       if (mpidr & 1<<31) {
-               armv8->multi_processor_system = (mpidr >> 30) & 1;
-               armv8->cluster_id = (mpidr >> 8) & 0xf;
-               armv8->cpu_id = mpidr & 0x3;
-               LOG_INFO("%s cluster %x core %x %s", target_name(target),
-                       armv8->cluster_id,
-                       armv8->cpu_id,
-                       armv8->multi_processor_system == 0 ? "multi core" : "mono core");
-
-       } else
-               LOG_ERROR("mpdir not in multiprocessor format");
-
-done:
-       dpm->finish(dpm);
-       return retval;
-
-
-}
-
-int armv8_identify_cache(struct target *target)
-{
-       /*      read cache descriptor */
-       int retval = ERROR_FAIL;
-       struct armv8_common *armv8 = target_to_armv8(target);
-       struct arm_dpm *dpm = armv8->arm.dpm;
-       uint32_t cache_selected, clidr;
-       uint32_t cache_i_reg, cache_d_reg;
-       struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache);
-       int is_aarch64 = armv8->arm.core_state == ARM_STATE_AARCH64;
-
-       retval = is_aarch64 ? armv8_read_ttbcr(target) : armv8_read_ttbcr32(target);
-       if (retval != ERROR_OK)
-               return retval;
-
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /*      retrieve CLIDR */
-       retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CLIDR), &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*/
-       retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CSSELR), &cache_selected);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /* select instruction cache
-        *      [0]  : 1 instruction cache selection , 0 data cache selection */
-       retval = dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), 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, armv8_opcode(armv8, READ_REG_CCSIDR), &cache_i_reg);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /*      select data cache*/
-       retval = dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), 0);
-       if (retval != ERROR_OK)
-               goto done;
-
-       retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CCSIDR), &cache_d_reg);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /*      restore selected cache  */
-       dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), cache_selected);
-       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 (armv8->armv8_mmu.armv8_cache.flush_all_data_cache == NULL) {
-               armv8->armv8_mmu.armv8_cache.display_cache_info =
-                       armv8_handle_inner_cache_info_command;
-               armv8->armv8_mmu.armv8_cache.flush_all_data_cache =
-                       armv8_flush_all_data;
-       }
-       armv8->armv8_mmu.armv8_cache.ctype = 0;
-
-done:
-       dpm->finish(dpm);
-       armv8_read_mpidr(target);
-       return retval;
-
-}
-
 int armv8_init_arch_info(struct target *target, struct armv8_common *armv8)
 {
        struct arm *arm = &armv8->arm;
@@ -818,7 +591,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8)
 #endif
 
        armv8->armv8_mmu.armv8_cache.l2_cache = NULL;
-       armv8->armv8_mmu.armv8_cache.ctype = -1;
+       armv8->armv8_mmu.armv8_cache.info = -1;
        armv8->armv8_mmu.armv8_cache.flush_all_data_cache = NULL;
        armv8->armv8_mmu.armv8_cache.display_cache_info = NULL;
        return ERROR_OK;
index fa3674b1447e752030e5e130447d2da91328706d..2862ebd8c538e4fa9846e98f173559fad24d91ca 100644 (file)
@@ -97,12 +97,22 @@ struct armv8_cachesize {
        uint32_t way_shift;
 };
 
-struct armv8_cache_common {
-       int ctype;
+/* information about one architecture cache at any level */
+struct armv8_arch_cache {
+       int ctype;                              /* cache type, CLIDR encoding */
        struct armv8_cachesize d_u_size;        /* data cache */
        struct armv8_cachesize i_size;          /* instruction cache */
+};
+
+struct armv8_cache_common {
+       int info;
+       int loc;
+       uint32_t iminline;
+       uint32_t dminline;
+       struct armv8_arch_cache arch[6];        /* cache info, L1 - L7 */
        int i_cache_enabled;
        int d_u_cache_enabled;
+
        /* l2 external unified cache if some */
        void *l2_cache;
        int (*flush_all_data_cache)(struct target *target);
@@ -249,7 +259,8 @@ target_to_armv8(struct target *target)
 #define PAGE_SIZE_4KB_TRBBASE_MASK     0xFFFFFFFFF000
 
 int armv8_arch_state(struct target *target);
-int armv8_identify_cache(struct target *target);
+int armv8_read_mpidr(struct armv8_common *armv8);
+int armv8_identify_cache(struct armv8_common *armv8);
 int armv8_init_arch_info(struct target *target, struct armv8_common *armv8);
 int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va,
                target_addr_t *val, int meminfo);
index fb1880464f21a32740bab1490668eb68cb11ffe8..f496c3cf0519cb14c90d63cb2eba74d5855c94e0 100644 (file)
 #include "armv8_dpm.h"
 #include "armv8_opcodes.h"
 
+/* CLIDR cache types */
+#define CACHE_LEVEL_HAS_UNIFIED_CACHE  0x4
+#define CACHE_LEVEL_HAS_D_CACHE                0x2
+#define CACHE_LEVEL_HAS_I_CACHE                0x1
+
 static int armv8_d_cache_sanity_check(struct armv8_common *armv8)
 {
        struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
@@ -44,11 +49,72 @@ static int armv8_i_cache_sanity_check(struct armv8_common *armv8)
        return ERROR_TARGET_INVALID;
 }
 
+static int armv8_cache_d_inner_flush_level(struct arm_dpm *dpm, struct armv8_cachesize *size, int cl)
+{
+       int retval = ERROR_OK;
+       int32_t c_way, c_index = size->index;
+
+       LOG_DEBUG("cl %" PRId32, cl);
+       do {
+               c_way = size->way;
+               do {
+                       uint32_t value = (c_index << size->index_shift)
+                               | (c_way << size->way_shift) | (cl << 1);
+                       /*
+                        * DC CISW - Clean and invalidate data cache
+                        * line by Set/Way.
+                        */
+                       retval = dpm->instr_write_data_r0(dpm,
+                                       ARMV8_SYS(SYSTEM_DCCISW, 0), value);
+                       if (retval != ERROR_OK)
+                               goto done;
+                       c_way -= 1;
+               } while (c_way >= 0);
+               c_index -= 1;
+       } while (c_index >= 0);
+
+ done:
+       return retval;
+}
+
+static int armv8_cache_d_inner_clean_inval_all(struct armv8_common *armv8)
+{
+       struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache);
+       struct arm_dpm *dpm = armv8->arm.dpm;
+       int cl;
+       int retval;
+
+       retval = armv8_d_cache_sanity_check(armv8);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+
+       for (cl = 0; cl < cache->loc; cl++) {
+               /* skip i-only caches */
+               if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
+                       continue;
+
+               armv8_cache_d_inner_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
+       }
+
+       retval = dpm->finish(dpm);
+       return retval;
+
+done:
+       LOG_ERROR("clean invalidate failed");
+       dpm->finish(dpm);
+
+       return retval;
+}
+
 int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size)
 {
        struct arm_dpm *dpm = armv8->arm.dpm;
        struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
-       uint64_t linelen = armv8_cache->d_u_size.linelen;
+       uint64_t linelen = armv8_cache->dminline;
        target_addr_t va_line, va_end;
        int retval;
 
@@ -87,7 +153,7 @@ int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va,
 {
        struct arm_dpm *dpm = armv8->arm.dpm;
        struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
-       uint64_t linelen = armv8_cache->i_size.linelen;
+       uint64_t linelen = armv8_cache->iminline;
        target_addr_t va_line, va_end;
        int retval;
 
@@ -120,3 +186,232 @@ done:
 
        return retval;
 }
+
+static int armv8_handle_inner_cache_info_command(struct command_context *cmd_ctx,
+       struct armv8_cache_common *armv8_cache)
+{
+       int cl;
+
+       if (armv8_cache->info == -1) {
+               command_print(cmd_ctx, "cache not yet identified");
+               return ERROR_OK;
+       }
+
+       for (cl = 0; cl < armv8_cache->loc; cl++) {
+               struct armv8_arch_cache *arch = &(armv8_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);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int _armv8_flush_all_data(struct target *target)
+{
+       return armv8_cache_d_inner_clean_inval_all(target_to_armv8(target));
+}
+
+static int  armv8_flush_all_data(struct target *target)
+{
+       int retval = ERROR_FAIL;
+       /*  check that armv8_cache is correctly identify */
+       struct armv8_common *armv8 = target_to_armv8(target);
+       if (armv8->armv8_mmu.armv8_cache.info == -1) {
+               LOG_ERROR("trying to flush un-identified cache");
+               return retval;
+       }
+
+       if (target->smp) {
+               /*  look if all the other target have been flushed in order to flush level
+                *  2 */
+               struct target_list *head;
+               struct target *curr;
+               head = target->head;
+               while (head != (struct target_list *)NULL) {
+                       curr = head->target;
+                       if (curr->state == TARGET_HALTED) {
+                               LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid);
+                               retval = _armv8_flush_all_data(curr);
+                       }
+                       head = head->next;
+               }
+       } else
+               retval = _armv8_flush_all_data(target);
+       return retval;
+}
+
+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,
+                       ARMV8_MSR_GP(SYSTEM_CSSELR, 0),
+                       (cl << 1) | (ct == 1 ? 1 : 0));
+       if (retval != ERROR_OK)
+               goto done;
+
+       retval = dpm->instr_read_data_r0(dpm,
+                       ARMV8_MRS(SYSTEM_CCSIDR, 0),
+                       cache_reg);
+ done:
+       return retval;
+}
+
+static struct armv8_cachesize decode_cache_reg(uint32_t cache_reg)
+{
+       struct armv8_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 armv8_identify_cache(struct armv8_common *armv8)
+{
+       /*  read cache descriptor */
+       int retval = ERROR_FAIL;
+       struct arm_dpm *dpm = armv8->arm.dpm;
+       uint32_t csselr, clidr, ctr;
+       uint32_t cache_reg;
+       int cl, ctype;
+       struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache);
+
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+
+       /* retrieve CTR */
+       retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_CTR, 0), &ctr);
+       if (retval != ERROR_OK)
+               goto done;
+
+       cache->iminline = 4UL << (ctr & 0xf);
+       cache->dminline = 4UL << ((ctr & 0xf0000) >> 16);
+       LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRId32 " ctr.dminline %" PRId32,
+                ctr, cache->iminline, cache->dminline);
+
+       /*  retrieve CLIDR */
+       retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_CLIDR, 0), &clidr);
+       if (retval != ERROR_OK)
+               goto done;
+
+       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, ARMV8_MRS(SYSTEM_CSSELR, 0), &csselr);
+       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);
+               }
+
+               /* 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);
+               }
+
+               cache->arch[cl].ctype = ctype;
+       }
+
+       /*  restore selected cache  */
+       dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_CSSELR, 0), csselr);
+       if (retval != ERROR_OK)
+               goto done;
+
+       armv8->armv8_mmu.armv8_cache.info = 1;
+
+       /*  if no l2 cache initialize l1 data cache flush function function */
+       if (armv8->armv8_mmu.armv8_cache.flush_all_data_cache == NULL) {
+               armv8->armv8_mmu.armv8_cache.display_cache_info =
+                       armv8_handle_inner_cache_info_command;
+               armv8->armv8_mmu.armv8_cache.flush_all_data_cache =
+                       armv8_flush_all_data;
+       }
+
+done:
+       dpm->finish(dpm);
+       return retval;
+
+}
index 9f5ebf8dcf9d6ca4ed151f485392a006109d12ae..51dc15a5eb6403ba5f5cdd8add0705b22b4c761b 100644 (file)
@@ -77,6 +77,7 @@
 #define SYSTEM_CLIDR                   0b1100100000000001
 #define SYSTEM_CSSELR                  0b1101000000000000
 #define SYSTEM_CTYPE                   0b1101100000000001
+#define SYSTEM_CTR                             0b1101100000000001
 
 #define SYSTEM_DCCISW                  0b0100001111110010
 #define SYSTEM_DCCSW                   0b0100001111010010