Ignore:
File:
1 edited

Legend:

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

    r8316547f r34847e2  
    3434 */
    3535
     36#include <arch/cache.h>
    3637#include <arch/cpu.h>
     38#include <arch/cp15.h>
    3739#include <cpu.h>
    3840#include <arch.h>
    3941#include <print.h>
    4042
    41 /** Number of indexes left out in the #imp_data array */
    42 #define IMP_DATA_START_OFFSET 0x40
    43 
    44 /** Implementators (vendor) names */
    45 static const char *imp_data[] = {
    46         "?",                                     /* IMP_DATA_START_OFFSET */
    47         "ARM Limited",                           /* 0x41 */
    48         "", "",                                  /* 0x42 - 0x43 */
    49         "Digital Equipment Corporation",         /* 0x44 */
    50         "", "", "", "", "", "", "", "",          /* 0x45 - 0x4c */
    51         "Motorola, Freescale Semicondutor Inc.", /* 0x4d */
    52         "", "", "",                              /* 0x4e - 0x50 */
    53         "Qualcomm Inc.",                         /* 0x51 */
    54         "", "", "", "",                          /* 0x52 - 0x55 */
    55         "Marvell Semiconductor",                 /* 0x56 */
    56         "", "", "", "", "", "", "", "", "", "",  /* 0x57 - 0x60 */
    57         "", "", "", "", "", "", "", "",          /* 0x61 - 0x68 */
    58         "Intel Corporation"                      /* 0x69 */
    59 };
    60 
    61 /** Length of the #imp_data array */
    62 static unsigned int imp_data_length = sizeof(imp_data) / sizeof(char *);
     43static 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
     54static unsigned dcache_ways(unsigned level);
     55static unsigned dcache_sets(unsigned level);
     56static unsigned dcache_linesize_log(unsigned level);
     57
     58
     59/** Implementers (vendor) names */
     60static 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}
    6373
    6474/** Architecture names */
    65 static const char *arch_data[] = {
    66         "?",       /* 0x0 */
    67         "4",       /* 0x1 */
    68         "4T",      /* 0x2 */
    69         "5",       /* 0x3 */
    70         "5T",      /* 0x4 */
    71         "5TE",     /* 0x5 */
    72         "5TEJ",    /* 0x6 */
    73         "6"        /* 0x7 */
    74 };
    75 
    76 /** Length of the #arch_data array */
    77 static unsigned int arch_data_length = sizeof(arch_data) / sizeof(char *);
     75static 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}
    7892
    7993
    8094/** Retrieves processor identification from CP15 register 0.
    81  * 
     95 *
    8296 * @param cpu Structure for storing CPU identification.
     97 * See page B4-1630 of ARM Architecture Reference Manual.
    8398 */
    8499static void arch_cpu_identify(cpu_arch_t *cpu)
    85100{
    86         uint32_t ident;
    87         asm volatile (
    88                 "mrc p15, 0, %[ident], c0, c0, 0\n"
    89                 : [ident] "=r" (ident)
    90         );
    91        
    92         cpu->imp_num = ident >> 24;
    93         cpu->variant_num = (ident << 8) >> 28;
    94         cpu->arch_num = (ident << 12) >> 28;
    95         cpu->prim_part_num = (ident << 16) >> 20;
    96         cpu->rev_num = (ident << 28) >> 28;
     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        }
    97123}
    98124
     
    100126void cpu_arch_init(void)
    101127{
    102 #if defined(PROCESSOR_armv7_a) | defined(PROCESSOR_armv6)
    103         uint32_t control_reg = 0;
    104         asm volatile (
    105                 "mrc p15, 0, %[control_reg], c1, c0"
    106                 : [control_reg] "=r" (control_reg)
    107         );
     128        uint32_t control_reg = SCTLR_read();
    108129       
    109         /* Turn off tex remap, RAZ ignores writes prior to armv7 */
    110         control_reg &= ~CP15_R1_TEX_REMAP_EN;
    111         /* Turn off accessed flag, RAZ ignores writes prior to armv7 */
    112         control_reg &= ~(CP15_R1_ACCESS_FLAG_EN | CP15_R1_HW_ACCESS_FLAG_EN);
    113         /* Enable unaligned access, RAZ ignores writes prior to armv6
    114          * switchable on armv6, RAO ignores writes on armv7,
     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,
    115139         * see ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
    116140         * L.3.1 (p. 2456) */
    117         control_reg |= CP15_R1_UNALIGNED_EN;
     141        control_reg |= SCTLR_UNALIGNED_EN_FLAG;
    118142        /* Disable alignment checks, this turns unaligned access to undefined,
    119143         * unless U bit is set. */
    120         control_reg &= ~CP15_R1_ALIGN_CHECK_EN;
     144        control_reg &= ~SCTLR_ALIGN_CHECK_EN_FLAG;
    121145        /* Enable caching, On arm prior to armv7 there is only one level
    122146         * of caches. Data cache is coherent.
     
    126150         *    ARM Architecture Reference Manual ARMv7-A and ARMv7-R Edition
    127151         *    B3.11.1 (p. 1383)
    128          * ICache coherency is elaborate on in barrier.h.
    129          * We are safe to turn these on.
     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).
    130155         */
    131         control_reg |= CP15_R1_CACHE_EN | CP15_R1_INST_CACHE_EN;
    132        
    133         asm volatile (
    134                 "mcr p15, 0, %[control_reg], c1, c0"
    135                 :: [control_reg] "r" (control_reg)
    136         );
     156        control_reg |= SCTLR_CACHE_EN_FLAG;
     157#endif
     158#ifdef PROCESSOR_ARCH_armv7_a
     159         /* ICache coherency is elaborated 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        } else {
     169                control_reg &=
     170                    ~(SCTLR_INST_CACHE_EN_FLAG | SCTLR_BRANCH_PREDICT_EN_FLAG);
     171        }
     172#endif
     173        SCTLR_write(control_reg);
     174
     175#ifdef CONFIG_FPU
     176        fpu_setup();
     177#endif
     178
     179#ifdef PROCESSOR_ARCH_armv7_a
     180        if ((ID_PFR1_read() & ID_PFR1_GEN_TIMER_EXT_MASK) !=
     181            ID_PFR1_GEN_TIMER_EXT) {
     182                PMCR_write(PMCR_read() | PMCR_E_FLAG | PMCR_D_FLAG);
     183                PMCNTENSET_write(PMCNTENSET_CYCLE_COUNTER_EN_FLAG);
     184        }
    137185#endif
    138186}
     
    147195void cpu_print_report(cpu_t *m)
    148196{
    149         const char *vendor = imp_data[0];
    150         const char *architecture = arch_data[0];
    151         cpu_arch_t * cpu_arch = &m->arch;
    152 
    153         const unsigned imp_offset = cpu_arch->imp_num - IMP_DATA_START_OFFSET;
    154 
    155         if (imp_offset < imp_data_length) {
    156                 vendor = imp_data[cpu_arch->imp_num - IMP_DATA_START_OFFSET];
    157         }
    158 
    159         // TODO CPUs with arch_num == 0xf use CPUID scheme for identification
    160         if (cpu_arch->arch_num < arch_data_length) {
    161                 architecture = arch_data[cpu_arch->arch_num];
    162         }
    163 
    164         printf("cpu%d: vendor=%s, architecture=ARM%s, part number=%x, "
     197        printf("cpu%d: vendor=%s, architecture=%s, part number=%x, "
    165198            "variant=%x, revision=%x\n",
    166             m->id, vendor, architecture, cpu_arch->prim_part_num,
    167             cpu_arch->variant_num, cpu_arch->rev_num);
     199            m->id, implementer(m->arch.imp_num),
     200            architecture_string(&m->arch), m->arch.prim_part_num,
     201            m->arch.variant_num, m->arch.rev_num);
     202}
     203
     204/** See chapter B4.1.19 of ARM Architecture Reference Manual */
     205static unsigned dcache_linesize_log(unsigned level)
     206{
     207#ifdef PROCESSOR_ARCH_armv7_a
     208        CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT);
     209        const uint32_t ccsidr = CCSIDR_read();
     210        return CCSIDR_LINESIZE_LOG(ccsidr);
     211#endif
     212        return 0;
     213
     214}
     215
     216/** See chapter B4.1.19 of ARM Architecture Reference Manual */
     217static unsigned dcache_ways(unsigned level)
     218{
     219#ifdef PROCESSOR_ARCH_armv7_a
     220        CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT);
     221        const uint32_t ccsidr = CCSIDR_read();
     222        return CCSIDR_WAYS(ccsidr);
     223#endif
     224        return 0;
     225}
     226
     227/** See chapter B4.1.19 of ARM Architecture Reference Manual */
     228static unsigned dcache_sets(unsigned level)
     229{
     230#ifdef PROCESSOR_ARCH_armv7_a
     231        CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT);
     232        const uint32_t ccsidr = CCSIDR_read();
     233        return CCSIDR_SETS(ccsidr);
     234#endif
     235        return 0;
     236}
     237
     238unsigned 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 = 0; i < 8; ++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
     258static 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
     275void 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 = 32 - 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
     288void 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 = 32 - 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
     302void 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
     310void 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
     319void icache_invalidate(void)
     320{
     321        ICIALLU_write(0);
    168322}
    169323
Note: See TracChangeset for help on using the changeset viewer.