Changes in kernel/arch/arm32/src/cpu/cpu.c [c8a5c8c:65871bb] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/arm32/src/cpu/cpu.c
rc8a5c8c r65871bb 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 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 }53 54 static unsigned dcache_ways(unsigned level);55 static unsigned dcache_sets(unsigned level);56 static unsigned dcache_linesize_log(unsigned level);57 58 40 59 41 /** Implementers (vendor) names */ … … 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 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; 109 94 // 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 }123 95 } 124 96 … … 126 98 void cpu_arch_init(void) 127 99 { 128 uint32_t control_reg = SCTLR_read(); 100 #if defined(PROCESSOR_armv7_a) | defined(PROCESSOR_armv6) 101 uint32_t control_reg = 0; 102 asm volatile ( 103 "mrc p15, 0, %[control_reg], c1, c0" 104 : [control_reg] "=r" (control_reg) 105 ); 129 106 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 armv6 138 * switchable on armv6, RAO/WI writes on armv7, 107 /* Turn off tex remap, RAZ ignores writes prior to armv7 */ 108 control_reg &= ~CP15_R1_TEX_REMAP_EN; 109 /* Turn off accessed flag, RAZ ignores writes prior to armv7 */ 110 control_reg &= ~(CP15_R1_ACCESS_FLAG_EN | CP15_R1_HW_ACCESS_FLAG_EN); 111 /* Enable unaligned access, RAZ ignores writes prior to armv6 112 * switchable on armv6, RAO ignores writes on armv7, 139 113 * see ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition 140 114 * L.3.1 (p. 2456) */ 141 control_reg |= SCTLR_UNALIGNED_EN_FLAG;115 control_reg |= CP15_R1_UNALIGNED_EN; 142 116 /* Disable alignment checks, this turns unaligned access to undefined, 143 117 * unless U bit is set. */ 144 control_reg &= ~ SCTLR_ALIGN_CHECK_EN_FLAG;118 control_reg &= ~CP15_R1_ALIGN_CHECK_EN; 145 119 /* Enable caching, On arm prior to armv7 there is only one level 146 120 * of caches. Data cache is coherent. … … 150 124 * ARM Architecture Reference Manual ARMv7-A and ARMv7-R Edition 151 125 * 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 by 154 * this flag). 126 * ICache coherency is elaborate on in barrier.h. 127 * We are safe to turn these on. 155 128 */ 156 control_reg |= SCTLR_CACHE_EN_FLAG; 129 control_reg |= CP15_R1_CACHE_EN | CP15_R1_INST_CACHE_EN; 130 131 asm volatile ( 132 "mcr p15, 0, %[control_reg], c1, c0" 133 :: [control_reg] "r" (control_reg) 134 ); 157 135 #endif 158 #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 136 #ifdef CONFIG_FPU 173 137 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 138 #endif 183 139 } … … 199 155 } 200 156 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_a205 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 #endif210 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_a218 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 #endif223 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_a230 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 #endif235 return 0;236 }237 238 unsigned dcache_levels(void)239 {240 unsigned levels = 0;241 #ifdef PROCESSOR_ARCH_armv7_a242 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 #endif255 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 else270 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);322 }323 324 157 /** @} 325 158 */
Note:
See TracChangeset
for help on using the changeset viewer.