root/lib/armutil/cache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. icache_flush_all
  2. log_2_n_round_up
  3. get_clidr
  4. get_ccsidr
  5. set_csselr
  6. v7_inval_dcache_level_setway
  7. v7_clean_inval_dcache_level_setway
  8. v7_maint_dcache_level_setway
  9. v7_maint_dcache_all
  10. dcache_clean_all
  11. cache_get_config
  12. dcache_get_size
  13. icache_flush_all
  14. dcache_clean_all

   1 /*
   2 Arm cache control functions
   3 TODO
   4 Only valid on processors with cp15 (e.g. not s1)
   5 */
   6 #ifdef THUMB_FW
   7 // ARMv7 cache control (based on U-BOOT cache_v7.c, utils.h, armv7.h)
   8 
   9 /* Invalidate entire I-cache and branch predictor array */
  10 void __attribute__((naked,noinline)) icache_flush_all(void)
  11 {
  12     /*
  13      * Invalidate all instruction caches to PoU.
  14      * Also flushes branch target cache.
  15      */
  16     asm volatile (
  17         "mov    r1, #0\n"
  18         "mcr    p15, 0, r1, c7, c5, 0\n"
  19         "mcr    p15, 0, r1, c7, c5, 6\n"
  20         "dsb    sy\n"
  21         "isb    sy\n"
  22         "bx     lr\n"
  23     );
  24 }
  25 
  26 /* Values for Ctype fields in CLIDR */
  27 #define ARMV7_CLIDR_CTYPE_NO_CACHE      0
  28 #define ARMV7_CLIDR_CTYPE_INSTRUCTION_ONLY  1
  29 #define ARMV7_CLIDR_CTYPE_DATA_ONLY     2
  30 #define ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA  3
  31 #define ARMV7_CLIDR_CTYPE_UNIFIED       4
  32 
  33 #define ARMV7_DCACHE_INVAL_ALL      1
  34 #define ARMV7_DCACHE_CLEAN_INVAL_ALL    2
  35 #define ARMV7_DCACHE_INVAL_RANGE    3
  36 #define ARMV7_DCACHE_CLEAN_INVAL_RANGE  4
  37 
  38 #define ARMV7_CSSELR_IND_DATA_UNIFIED   0
  39 #define ARMV7_CSSELR_IND_INSTRUCTION    1
  40 
  41 #define CCSIDR_LINE_SIZE_OFFSET     0
  42 #define CCSIDR_LINE_SIZE_MASK       0x7
  43 #define CCSIDR_ASSOCIATIVITY_OFFSET 3
  44 #define CCSIDR_ASSOCIATIVITY_MASK   (0x3FF << 3)
  45 #define CCSIDR_NUM_SETS_OFFSET      13
  46 #define CCSIDR_NUM_SETS_MASK        (0x7FFF << 13)
  47 
  48 typedef unsigned int u32;
  49 typedef int s32;
  50 
  51 static inline s32 log_2_n_round_up(u32 n)
  52 {
  53     s32 log2n = -1;
  54     u32 temp = n;
  55     
  56     while (temp) {
  57         log2n++;
  58         temp >>= 1;
  59     }
  60     
  61     if (n & (n - 1))
  62         return log2n + 1; /* not power of 2 - round up */
  63     else
  64         return log2n; /* power of 2 */
  65 }
  66 
  67 static u32 get_clidr(void)
  68 {
  69     u32 clidr;
  70 
  71     /* Read current CP15 Cache Level ID Register */
  72     asm volatile ("mrc p15,1,%0,c0,c0,1" : "=r" (clidr));
  73     return clidr;
  74 }
  75 
  76 static u32 get_ccsidr(void)
  77 {
  78     u32 ccsidr;
  79 
  80     /* Read current CP15 Cache Size ID Register */
  81     asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
  82     return ccsidr;
  83 }
  84 
  85 static void set_csselr(u32 level, u32 type)
  86 {   u32 csselr = level << 1 | type;
  87 
  88     /* Write to Cache Size Selection Register(CSSELR) */
  89     asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr));
  90 }
  91 
  92 static void v7_inval_dcache_level_setway(u32 level, u32 num_sets,
  93                      u32 num_ways, u32 way_shift,
  94                      u32 log2_line_len)
  95 {
  96     int way, set, setway;
  97 
  98     /*
  99      * For optimal assembly code:
 100      *  a. count down
 101      *  b. have bigger loop inside
 102      */
 103     for (way = num_ways - 1; way >= 0 ; way--) {
 104         for (set = num_sets - 1; set >= 0; set--) {
 105             setway = (level << 1) | (set << log2_line_len) |
 106                  (way << way_shift);
 107             /* Invalidate data/unified cache line by set/way */
 108             asm volatile (" mcr p15, 0, %0, c7, c6, 2"
 109                     : : "r" (setway));
 110         }
 111     }
 112     /* DSB to make sure the operation is complete */
 113     asm volatile("dsb sy\n");
 114 }
 115 
 116 static void v7_clean_inval_dcache_level_setway(u32 level, u32 num_sets,
 117                            u32 num_ways, u32 way_shift,
 118                            u32 log2_line_len)
 119 {
 120     int way, set, setway;
 121 
 122     /*
 123      * For optimal assembly code:
 124      *  a. count down
 125      *  b. have bigger loop inside
 126      */
 127     for (way = num_ways - 1; way >= 0 ; way--) {
 128         for (set = num_sets - 1; set >= 0; set--) {
 129             setway = (level << 1) | (set << log2_line_len) |
 130                  (way << way_shift);
 131             /*
 132              * Clean & Invalidate data/unified
 133              * cache line by set/way
 134              */
 135             asm volatile (" mcr p15, 0, %0, c7, c14, 2"
 136                     : : "r" (setway));
 137         }
 138     }
 139     /* DSB to make sure the operation is complete */
 140     asm volatile("dsb sy\n");
 141 }
 142 
 143 static void v7_maint_dcache_level_setway(u32 level, u32 operation)
 144 {
 145     u32 ccsidr;
 146     u32 num_sets, num_ways, log2_line_len, log2_num_ways;
 147     u32 way_shift;
 148 
 149     set_csselr(level, ARMV7_CSSELR_IND_DATA_UNIFIED);
 150 
 151     ccsidr = get_ccsidr();
 152 
 153     log2_line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
 154                 CCSIDR_LINE_SIZE_OFFSET) + 2;
 155     /* Converting from words to bytes */
 156     log2_line_len += 2;
 157 
 158     num_ways  = ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >>
 159             CCSIDR_ASSOCIATIVITY_OFFSET) + 1;
 160     num_sets  = ((ccsidr & CCSIDR_NUM_SETS_MASK) >>
 161             CCSIDR_NUM_SETS_OFFSET) + 1;
 162     /*
 163      * According to ARMv7 ARM number of sets and number of ways need
 164      * not be a power of 2
 165      */
 166     log2_num_ways = log_2_n_round_up(num_ways);
 167 
 168     way_shift = (32 - log2_num_ways);
 169     if (operation == ARMV7_DCACHE_INVAL_ALL) {
 170         v7_inval_dcache_level_setway(level, num_sets, num_ways,
 171                       way_shift, log2_line_len);
 172     } else if (operation == ARMV7_DCACHE_CLEAN_INVAL_ALL) {
 173         v7_clean_inval_dcache_level_setway(level, num_sets, num_ways,
 174                            way_shift, log2_line_len);
 175     }
 176 }
 177 
 178 static void v7_maint_dcache_all(u32 operation)
 179 {
 180     u32 level, cache_type, level_start_bit = 0;
 181 
 182     u32 clidr = get_clidr();
 183 
 184     for (level = 0; level < 7; level++) {
 185         cache_type = (clidr >> level_start_bit) & 0x7;
 186         if ((cache_type == ARMV7_CLIDR_CTYPE_DATA_ONLY) ||
 187             (cache_type == ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA) ||
 188             (cache_type == ARMV7_CLIDR_CTYPE_UNIFIED))
 189             v7_maint_dcache_level_setway(level, operation);
 190         level_start_bit += 3;
 191     }
 192 }
 193 
 194 void dcache_clean_all(void) {
 195     v7_maint_dcache_all(ARMV7_DCACHE_CLEAN_INVAL_ALL);
 196     /* anything else? */
 197 }
 198 
 199 #else // ARMv5 DIGIC
 200 
 201 /*
 202 get cache config word
 203 */
 204 void __attribute__((naked,noinline)) cache_get_config(void) {
 205   asm volatile (
 206     "MRC    p15, 0, R0,c0,c0,1\n"
 207     "BX     LR\n"
 208   );
 209 }
 210 
 211 /*
 212 get dcache size from word returned by get_config
 213 */
 214 unsigned dcache_get_size(unsigned config) {
 215     unsigned sz = (config>>18) & 0xF;
 216     // shouldn't happen, s1 might not have cache but also doesn't have cp15
 217     if(sz == 0) {
 218         return 0;
 219     }
 220     // per ARM DDI 0201D Table 2-5 Cache size encoding
 221     // starts at 4kb = 3, each subsequent value is 2x
 222     return 0x200 << sz;
 223 }
 224 
 225 /*
 226 flush (mark as invalid) entire instruction cache
 227 */
 228 void __attribute__((naked,noinline)) icache_flush_all(void) {
 229   asm volatile (
 230     "MOV    r1, #0\n"
 231     "MCR    p15, 0, r1,c7,c5\n"
 232     "BX     LR\n"
 233   );
 234 }
 235 
 236 /*
 237 clean (write all dirty) entire data cache
 238 also drains write buffer (like canon code)
 239 does *not* flush
 240 */
 241 void __attribute__((naked,noinline)) dcache_clean_all(void) {
 242   asm volatile (
 243     "PUSH   {LR}\n"
 244     "BL     cache_get_config\n"
 245     "BL     dcache_get_size\n"
 246     "CMP    r0, #0\n"
 247     "BEQ    3f\n"
 248     // index limit (max index+1)
 249     // per ARM DDI 0201D 4kb = bits 9:5
 250     "LSR    r3, r0, #2\n" 
 251     "MOV    r1, #0\n"
 252 "2:\n"
 253     "MOV    r0, #0\n"
 254 "1:\n"
 255     "ORR    r2,r1,r0\n"
 256     "MCR    p15, 0, r2, c7, c10, 2\n" // clean line
 257     "ADD    r0, r0, #0x20\n" // next line
 258     "CMP    r0, r3\n" // segment complete ?
 259     "BNE    1b\n"
 260     "ADD    r1, r1,#0x40000000\n" // next segment
 261     "CMP    r1, #0\n"
 262     "BNE    2b\n"
 263     "MCR    p15, 0, r1, c7, c10, 4\n" // drain write buffer
 264 "3:\n"
 265     "POP    {LR}\n"
 266     "BX     LR\n"
 267   );
 268 }

/* [<][>][^][v][top][bottom][index][help] */