Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/arm32/src/cpu/cpu.c

    rc8a5c8c r65871bb  
    3434 */
    3535
    36 #include <arch/cache.h>
    3736#include <arch/cpu.h>
    38 #include <arch/cp15.h>
    3937#include <cpu.h>
    4038#include <arch.h>
    4139#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 
    5840
    5941/** Implementers (vendor) names */
     
    9981static void arch_cpu_identify(cpu_arch_t *cpu)
    10082{
    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;
    10994        // 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         }
    12395}
    12496
     
    12698void cpu_arch_init(void)
    12799{
    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        );
    129106       
    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,
    139113         * see ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
    140114         * L.3.1 (p. 2456) */
    141         control_reg |= SCTLR_UNALIGNED_EN_FLAG;
     115        control_reg |= CP15_R1_UNALIGNED_EN;
    142116        /* Disable alignment checks, this turns unaligned access to undefined,
    143117         * unless U bit is set. */
    144         control_reg &= ~SCTLR_ALIGN_CHECK_EN_FLAG;
     118        control_reg &= ~CP15_R1_ALIGN_CHECK_EN;
    145119        /* Enable caching, On arm prior to armv7 there is only one level
    146120         * of caches. Data cache is coherent.
     
    150124         *    ARM Architecture Reference Manual ARMv7-A and ARMv7-R Edition
    151125         *    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.
    155128         */
    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        );
    157135#endif
    158 #ifdef PROCESSOR_ARCH_armv7_a
    159          /* 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 rules
    163           * as ICache and they can be flushed together
    164           */
    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 #endif
    170         SCTLR_write(control_reg);
    171 
    172136#ifdef CONFIG_FPU
    173137        fpu_setup();
    174 #endif
    175 
    176 #ifdef PROCESSOR_ARCH_armv7_a
    177         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         }
    182138#endif
    183139}
     
    199155}
    200156
    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);
    322 }
    323 
    324157/** @}
    325158 */
Note: See TracChangeset for help on using the changeset viewer.