Ignore:
File:
1 edited

Legend:

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

    rc8a5c8c r9d58539  
    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>
    4240
    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
    5343
    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 */
     45static 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};
    5757
    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 */
     59static unsigned int imp_data_length = sizeof(imp_data) / sizeof(char *);
    7360
    7461/** 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 }
     62static 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 */
     74static unsigned int arch_data_length = sizeof(arch_data) / sizeof(char *);
    9275
    9376
    9477/** Retrieves processor identification from CP15 register 0.
    95  *
     78 * 
    9679 * @param cpu Structure for storing CPU identification.
    97  * See page B4-1630 of ARM Architecture Reference Manual.
    9880 */
    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 
    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;
    12394}
    12495
    125 /** Enables unaligned access and caching for armv6+ */
     96/** Does nothing on ARM. */
    12697void cpu_arch_init(void)
    12798{
    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 armv6
    138          * switchable on armv6, RAO/WI writes on armv7,
    139          * see ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
    140          * 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 level
    146          * of caches. Data cache is coherent.
    147          * "This means that the behavior of accesses from the same observer to
    148          * different VAs, that are translated to the same PA
    149          * with the same memory attributes, is fully coherent."
    150          *    ARM Architecture Reference Manual ARMv7-A and ARMv7-R Edition
    151          *    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).
    155          */
    156         control_reg |= SCTLR_CACHE_EN_FLAG;
    157 #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 
    172 #ifdef CONFIG_FPU
    173         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         }
    182 #endif
    18399}
    184100
    185101/** Retrieves processor identification and stores it to #CPU.arch */
    186 void cpu_identify(void)
     102void cpu_identify(void) 
    187103{
    188104        arch_cpu_identify(&CPU->arch);
     
    192108void cpu_print_report(cpu_t *m)
    193109{
    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, "
    195125            "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);
    322128}
    323129
Note: See TracChangeset for help on using the changeset viewer.