+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t csselr, clidr, ctr;
+ uint32_t cache_reg;
+ int cl, ctype;
+ struct armv7a_cache_common *cache =
+ &(armv7a->armv7a_mmu.armv7a_cache);
+
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ goto done;
+
+ /* retrieve CTR
+ * mrc p15, 0, r0, c0, c0, 1 @ read ctr */
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV4_5_MRC(15, 0, 0, 0, 0, 1),
+ &ctr);
+ if (retval != ERROR_OK)
+ goto done;
+
+ cache->iminline = 4UL << (ctr & 0xf);
+ cache->dminline = 4UL << ((ctr & 0xf0000) >> 16);
+ LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32,
+ ctr, cache->iminline, cache->dminline);
+
+ /* retrieve CLIDR
+ * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
+ &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,
+ ARMV4_5_MRC(15, 2, 0, 0, 0, 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 %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
+ 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 %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " 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 %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
+ 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 %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " 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,
+ ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
+ csselr);
+
+ if (retval != ERROR_OK)
+ goto done;
+
+ /* if no l2 cache initialize l1 data cache flush function function */
+ if (!armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache) {
+ armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
+ armv7a_cache_auto_flush_all_data;
+ }
+
+ armv7a->armv7a_mmu.armv7a_cache.info = 1;
+done:
+ dpm->finish(dpm);
+ armv7a_read_mpidr(target);
+ return retval;