Changes in kernel/arch/arm32/src/cpu/cpu.c [c8a5c8c:a000878c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/arm32/src/cpu/cpu.c
rc8a5c8c ra000878c 34 34 */ 35 35 36 #include <arch/cache.h>37 36 #include <arch/cpu.h> 38 #include <arch/cp15.h>39 37 #include <cpu.h> 40 38 #include <arch.h> 41 39 #include <print.h> 42 40 43 static inline unsigned log2(unsigned val) 44 { 45 unsigned log = 0; 46 --val; 47 while (val) { 48 ++log; 49 val >>= 1; 50 } 51 return log; 52 } 41 /** Number of indexes left out in the #imp_data array */ 42 #define IMP_DATA_START_OFFSET 0x40 53 43 54 static unsigned dcache_ways(unsigned level); 55 static unsigned dcache_sets(unsigned level); 56 static unsigned dcache_linesize_log(unsigned level); 44 /** Implementators (vendor) names */ 45 static const char *imp_data[] = { 46 "?", /* IMP_DATA_START_OFFSET */ 47 "ARM Ltd", /* 0x41 */ 48 "", /* 0x42 */ 49 "", /* 0x43 */ 50 "Digital Equipment Corporation", /* 0x44 */ 51 "", "", "", "", "", "", "", "", "", "", /* 0x45 - 0x4e */ 52 "", "", "", "", "", "", "", "", "", "", /* 0x4f - 0x58 */ 53 "", "", "", "", "", "", "", "", "", "", /* 0x59 - 0x62 */ 54 "", "", "", "", "", "", /* 0x63 - 0x68 */ 55 "Intel Corporation" /* 0x69 */ 56 }; 57 57 58 59 /** Implementers (vendor) names */ 60 static const char * implementer(unsigned id) 61 { 62 switch (id) 63 { 64 case 0x41: return "ARM Limited"; 65 case 0x44: return "Digital Equipment Corporation"; 66 case 0x4d: return "Motorola, Freescale Semiconductor Inc."; 67 case 0x51: return "Qualcomm Inc."; 68 case 0x56: return "Marvell Semiconductor Inc."; 69 case 0x69: return "Intel Corporation"; 70 } 71 return "Unknown implementer"; 72 } 58 /** Length of the #imp_data array */ 59 static unsigned int imp_data_length = sizeof(imp_data) / sizeof(char *); 73 60 74 61 /** Architecture names */ 75 static const char * architecture_string(cpu_arch_t *arch) 76 { 77 static const char *arch_data[] = { 78 "ARM", /* 0x0 */ 79 "ARMv4", /* 0x1 */ 80 "ARMv4T", /* 0x2 */ 81 "ARMv5", /* 0x3 */ 82 "ARMv5T", /* 0x4 */ 83 "ARMv5TE", /* 0x5 */ 84 "ARMv5TEJ", /* 0x6 */ 85 "ARMv6" /* 0x7 */ 86 }; 87 if (arch->arch_num < (sizeof(arch_data) / sizeof(arch_data[0]))) 88 return arch_data[arch->arch_num]; 89 else 90 return arch_data[0]; 91 } 62 static const char *arch_data[] = { 63 "?", /* 0x0 */ 64 "4", /* 0x1 */ 65 "4T", /* 0x2 */ 66 "5", /* 0x3 */ 67 "5T", /* 0x4 */ 68 "5TE", /* 0x5 */ 69 "5TEJ", /* 0x6 */ 70 "6" /* 0x7 */ 71 }; 72 73 /** Length of the #arch_data array */ 74 static unsigned int arch_data_length = sizeof(arch_data) / sizeof(char *); 92 75 93 76 94 77 /** Retrieves processor identification from CP15 register 0. 95 * 78 * 96 79 * @param cpu Structure for storing CPU identification. 97 * See page B4-1630 of ARM Architecture Reference Manual.98 80 */ 99 81 static void arch_cpu_identify(cpu_arch_t *cpu) 100 82 { 101 const uint32_t ident = MIDR_read(); 102 103 cpu->imp_num = (ident >> MIDR_IMPLEMENTER_SHIFT) & MIDR_IMPLEMENTER_MASK; 104 cpu->variant_num = (ident >> MIDR_VARIANT_SHIFT) & MIDR_VARIANT_MASK; 105 cpu->arch_num = (ident >> MIDR_ARCHITECTURE_SHIFT) & MIDR_ARCHITECTURE_MASK; 106 cpu->prim_part_num = (ident >> MIDR_PART_NUMBER_SHIFT) & MIDR_PART_NUMBER_MASK; 107 cpu->rev_num = (ident >> MIDR_REVISION_SHIFT) & MIDR_REVISION_MASK; 108 109 // TODO CPUs with arch_num == 0xf use CPUID scheme for identification 110 cpu->dcache_levels = dcache_levels(); 111 112 for (unsigned i = 0; i < cpu->dcache_levels; ++i) { 113 cpu->dcache[i].ways = dcache_ways(i); 114 cpu->dcache[i].sets = dcache_sets(i); 115 cpu->dcache[i].way_shift = 31 - log2(cpu->dcache[i].ways); 116 cpu->dcache[i].set_shift = dcache_linesize_log(i); 117 cpu->dcache[i].line_size = 1 << dcache_linesize_log(i); 118 printf("Found DCache L%u: %u-way, %u sets, %u byte lines " 119 "(shifts: w%u, s%u)\n", i + 1, cpu->dcache[i].ways, 120 cpu->dcache[i].sets, cpu->dcache[i].line_size, 121 cpu->dcache[i].way_shift, cpu->dcache[i].set_shift); 122 } 83 uint32_t ident; 84 asm volatile ( 85 "mrc p15, 0, %[ident], c0, c0, 0\n" 86 : [ident] "=r" (ident) 87 ); 88 89 cpu->imp_num = ident >> 24; 90 cpu->variant_num = (ident << 8) >> 28; 91 cpu->arch_num = (ident << 12) >> 28; 92 cpu->prim_part_num = (ident << 16) >> 20; 93 cpu->rev_num = (ident << 28) >> 28; 123 94 } 124 95 125 /** Enables unaligned access and caching for armv6+*/96 /** Does nothing on ARM. */ 126 97 void cpu_arch_init(void) 127 98 { 128 uint32_t control_reg = SCTLR_read();129 130 /* Turn off tex remap, RAZ/WI prior to armv7 */131 control_reg &= ~SCTLR_TEX_REMAP_EN_FLAG;132 /* Turn off accessed flag, RAZ/WI prior to armv7 */133 control_reg &= ~(SCTLR_ACCESS_FLAG_EN_FLAG | SCTLR_HW_ACCESS_FLAG_EN_FLAG);134 135 /* Unaligned access is supported on armv6+ */136 #if defined(PROCESSOR_ARCH_armv7_a) | defined(PROCESSOR_ARCH_armv6)137 /* Enable unaligned access, RAZ/WI prior to armv6138 * switchable on armv6, RAO/WI writes on armv7,139 * see ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition140 * L.3.1 (p. 2456) */141 control_reg |= SCTLR_UNALIGNED_EN_FLAG;142 /* Disable alignment checks, this turns unaligned access to undefined,143 * unless U bit is set. */144 control_reg &= ~SCTLR_ALIGN_CHECK_EN_FLAG;145 /* Enable caching, On arm prior to armv7 there is only one level146 * of caches. Data cache is coherent.147 * "This means that the behavior of accesses from the same observer to148 * different VAs, that are translated to the same PA149 * with the same memory attributes, is fully coherent."150 * ARM Architecture Reference Manual ARMv7-A and ARMv7-R Edition151 * B3.11.1 (p. 1383)152 * We are safe to turn this on. For arm v6 see ch L.6.2 (p. 2469)153 * L2 Cache for armv7 is enabled by default (i.e. controlled by154 * this flag).155 */156 control_reg |= SCTLR_CACHE_EN_FLAG;157 #endif158 #ifdef PROCESSOR_ARCH_armv7_a159 /* ICache coherency is elaborate on in barrier.h.160 * VIPT and PIPT caches need maintenance only on code modify,161 * so it should be safe for general use.162 * Enable branch predictors too as they follow the same rules163 * as ICache and they can be flushed together164 */165 if ((CTR_read() & CTR_L1I_POLICY_MASK) != CTR_L1I_POLICY_AIVIVT) {166 control_reg |=167 SCTLR_INST_CACHE_EN_FLAG | SCTLR_BRANCH_PREDICT_EN_FLAG;168 }169 #endif170 SCTLR_write(control_reg);171 172 #ifdef CONFIG_FPU173 fpu_setup();174 #endif175 176 #ifdef PROCESSOR_ARCH_armv7_a177 if ((ID_PFR1_read() & ID_PFR1_GEN_TIMER_EXT_MASK) !=178 ID_PFR1_GEN_TIMER_EXT) {179 PMCR_write(PMCR_read() | PMCR_E_FLAG | PMCR_D_FLAG);180 PMCNTENSET_write(PMCNTENSET_CYCLE_COUNTER_EN_FLAG);181 }182 #endif183 99 } 184 100 185 101 /** Retrieves processor identification and stores it to #CPU.arch */ 186 void cpu_identify(void) 102 void cpu_identify(void) 187 103 { 188 104 arch_cpu_identify(&CPU->arch); … … 192 108 void cpu_print_report(cpu_t *m) 193 109 { 194 printf("cpu%d: vendor=%s, architecture=%s, part number=%x, " 110 const char *vendor = imp_data[0]; 111 const char *architecture = arch_data[0]; 112 cpu_arch_t * cpu_arch = &m->arch; 113 114 if ((cpu_arch->imp_num) > 0 && 115 (cpu_arch->imp_num < (imp_data_length + IMP_DATA_START_OFFSET))) { 116 vendor = imp_data[cpu_arch->imp_num - IMP_DATA_START_OFFSET]; 117 } 118 119 if ((cpu_arch->arch_num) > 0 && 120 (cpu_arch->arch_num < arch_data_length)) { 121 architecture = arch_data[cpu_arch->arch_num]; 122 } 123 124 printf("cpu%d: vendor=%s, architecture=ARM%s, part number=%x, " 195 125 "variant=%x, revision=%x\n", 196 m->id, implementer(m->arch.imp_num), 197 architecture_string(&m->arch), m->arch.prim_part_num, 198 m->arch.variant_num, m->arch.rev_num); 199 } 200 201 /** See chapter B4.1.19 of ARM Architecture Reference Manual */ 202 static unsigned dcache_linesize_log(unsigned level) 203 { 204 #ifdef PROCESSOR_ARCH_armv7_a 205 CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT); 206 const unsigned ls_log = 2 + 207 ((CCSIDR_read() >> CCSIDR_LINESIZE_SHIFT) & CCSIDR_LINESIZE_MASK); 208 return ls_log + 2; //return log2(bytes) 209 #endif 210 return 0; 211 212 } 213 214 /** See chapter B4.1.19 of ARM Architecture Reference Manual */ 215 static unsigned dcache_ways(unsigned level) 216 { 217 #ifdef PROCESSOR_ARCH_armv7_a 218 CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT); 219 const unsigned ways = 1 + 220 ((CCSIDR_read() >> CCSIDR_ASSOC_SHIFT) & CCSIDR_ASSOC_MASK); 221 return ways; 222 #endif 223 return 0; 224 } 225 226 /** See chapter B4.1.19 of ARM Architecture Reference Manual */ 227 static unsigned dcache_sets(unsigned level) 228 { 229 #ifdef PROCESSOR_ARCH_armv7_a 230 CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT); 231 const unsigned sets = 1 + 232 ((CCSIDR_read() >> CCSIDR_NUMSETS_SHIFT) & CCSIDR_NUMSETS_MASK); 233 return sets; 234 #endif 235 return 0; 236 } 237 238 unsigned dcache_levels(void) 239 { 240 unsigned levels = 0; 241 #ifdef PROCESSOR_ARCH_armv7_a 242 const uint32_t val = CLIDR_read(); 243 for (unsigned i = 1; i <= 7; ++i) { 244 const unsigned ctype = CLIDR_CACHE(i, val); 245 switch (ctype) { 246 case CLIDR_DCACHE_ONLY: 247 case CLIDR_SEP_CACHE: 248 case CLIDR_UNI_CACHE: 249 ++levels; 250 default: 251 (void)0; 252 } 253 } 254 #endif 255 return levels; 256 } 257 258 static void dcache_clean_manual(unsigned level, bool invalidate, 259 unsigned ways, unsigned sets, unsigned way_shift, unsigned set_shift) 260 { 261 262 for (unsigned i = 0; i < ways; ++i) { 263 for (unsigned j = 0; j < sets; ++j) { 264 const uint32_t val = 265 ((level & 0x7) << 1) | 266 (j << set_shift) | (i << way_shift); 267 if (invalidate) 268 DCCISW_write(val); 269 else 270 DCCSW_write(val); 271 } 272 } 273 } 274 275 void dcache_flush(void) 276 { 277 /* See ARM Architecture Reference Manual ch. B4.2.1 p. B4-1724 */ 278 const unsigned levels = dcache_levels(); 279 for (unsigned i = 0; i < levels; ++i) { 280 const unsigned ways = dcache_ways(i); 281 const unsigned sets = dcache_sets(i); 282 const unsigned way_shift = 31 - log2(ways); 283 const unsigned set_shift = dcache_linesize_log(i); 284 dcache_clean_manual(i, false, ways, sets, way_shift, set_shift); 285 } 286 } 287 288 void dcache_flush_invalidate(void) 289 { 290 /* See ARM Architecture Reference Manual ch. B4.2.1 p. B4-1724 */ 291 const unsigned levels = dcache_levels(); 292 for (unsigned i = 0; i < levels; ++i) { 293 const unsigned ways = dcache_ways(i); 294 const unsigned sets = dcache_sets(i); 295 const unsigned way_shift = 31 - log2(ways); 296 const unsigned set_shift = dcache_linesize_log(i); 297 dcache_clean_manual(i, true, ways, sets, way_shift, set_shift); 298 } 299 } 300 301 302 void cpu_dcache_flush(void) 303 { 304 for (unsigned i = 0; i < CPU->arch.dcache_levels; ++i) 305 dcache_clean_manual(i, false, 306 CPU->arch.dcache[i].ways, CPU->arch.dcache[i].sets, 307 CPU->arch.dcache[i].way_shift, CPU->arch.dcache[i].set_shift); 308 } 309 310 void cpu_dcache_flush_invalidate(void) 311 { 312 const unsigned levels = dcache_levels(); 313 for (unsigned i = 0; i < levels; ++i) 314 dcache_clean_manual(i, true, 315 CPU->arch.dcache[i].ways, CPU->arch.dcache[i].sets, 316 CPU->arch.dcache[i].way_shift, CPU->arch.dcache[i].set_shift); 317 } 318 319 void icache_invalidate(void) 320 { 321 ICIALLU_write(0); 126 m->id, vendor, architecture, cpu_arch->prim_part_num, 127 cpu_arch->variant_num, cpu_arch->rev_num); 322 128 } 323 129
Note:
See TracChangeset
for help on using the changeset viewer.