12b71562fSIan Lepore /*- 22b71562fSIan Lepore * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com> 32b71562fSIan Lepore * Copyright 2014 Michal Meloun <meloun@miracle.cz> 42b71562fSIan Lepore * All rights reserved. 52b71562fSIan Lepore * 62b71562fSIan Lepore * Redistribution and use in source and binary forms, with or without 72b71562fSIan Lepore * modification, are permitted provided that the following conditions 82b71562fSIan Lepore * are met: 92b71562fSIan Lepore * 1. Redistributions of source code must retain the above copyright 102b71562fSIan Lepore * notice, this list of conditions and the following disclaimer. 112b71562fSIan Lepore * 2. Redistributions in binary form must reproduce the above copyright 122b71562fSIan Lepore * notice, this list of conditions and the following disclaimer in the 132b71562fSIan Lepore * documentation and/or other materials provided with the distribution. 142b71562fSIan Lepore * 152b71562fSIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 162b71562fSIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 172b71562fSIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 182b71562fSIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 192b71562fSIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 202b71562fSIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 212b71562fSIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 222b71562fSIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 232b71562fSIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 242b71562fSIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 252b71562fSIan Lepore * SUCH DAMAGE. 262b71562fSIan Lepore */ 272b71562fSIan Lepore 282b71562fSIan Lepore #include <sys/cdefs.h> 292b71562fSIan Lepore __FBSDID("$FreeBSD$"); 302b71562fSIan Lepore 312b71562fSIan Lepore #include <sys/param.h> 322b71562fSIan Lepore #include <sys/systm.h> 337bf5720aSMichal Meloun #include <sys/sysctl.h> 342b71562fSIan Lepore 353025d19dSMichal Meloun #include <machine/cpu.h> 362b71562fSIan Lepore #include <machine/cpuinfo.h> 372b71562fSIan Lepore 387bf5720aSMichal Meloun #if __ARM_ARCH >= 6 397bf5720aSMichal Meloun void reinit_mmu(uint32_t ttb, uint32_t aux_clr, uint32_t aux_set); 407bf5720aSMichal Meloun #endif 417bf5720aSMichal Meloun 42a286c311SIan Lepore struct cpuinfo cpuinfo = 43a286c311SIan Lepore { 44a286c311SIan Lepore /* Use safe defaults for start */ 45a286c311SIan Lepore .dcache_line_size = 32, 46a286c311SIan Lepore .dcache_line_mask = 31, 47a286c311SIan Lepore .icache_line_size = 32, 48a286c311SIan Lepore .icache_line_mask = 31, 49a286c311SIan Lepore }; 502b71562fSIan Lepore 517bf5720aSMichal Meloun static SYSCTL_NODE(_hw, OID_AUTO, cpu, CTLFLAG_RD, 0, 527bf5720aSMichal Meloun "CPU"); 537bf5720aSMichal Meloun static SYSCTL_NODE(_hw_cpu, OID_AUTO, quirks, CTLFLAG_RD, 0, 547bf5720aSMichal Meloun "CPU quirks"); 557bf5720aSMichal Meloun 567bf5720aSMichal Meloun /* 577bf5720aSMichal Meloun * Tunable CPU quirks. 587bf5720aSMichal Meloun * Be careful, ACTRL cannot be changed if CPU is started in secure 597bf5720aSMichal Meloun * mode(world) and write to ACTRL can cause exception! 607bf5720aSMichal Meloun * These quirks are intended for optimizing CPU performance, not for 617bf5720aSMichal Meloun * applying errata workarounds. Nobody can expect that CPU with unfixed 627bf5720aSMichal Meloun * errata is stable enough to execute the kernel until quirks are applied. 637bf5720aSMichal Meloun */ 647bf5720aSMichal Meloun static uint32_t cpu_quirks_actlr_mask; 657bf5720aSMichal Meloun SYSCTL_INT(_hw_cpu_quirks, OID_AUTO, actlr_mask, 667bf5720aSMichal Meloun CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &cpu_quirks_actlr_mask, 0, 677bf5720aSMichal Meloun "Bits to be masked in ACTLR"); 687bf5720aSMichal Meloun 697bf5720aSMichal Meloun static uint32_t cpu_quirks_actlr_set; 707bf5720aSMichal Meloun SYSCTL_INT(_hw_cpu_quirks, OID_AUTO, actlr_set, 717bf5720aSMichal Meloun CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &cpu_quirks_actlr_set, 0, 727bf5720aSMichal Meloun "Bits to be set in ACTLR"); 737bf5720aSMichal Meloun 747bf5720aSMichal Meloun 752b71562fSIan Lepore /* Read and parse CPU id scheme */ 762b71562fSIan Lepore void 772b71562fSIan Lepore cpuinfo_init(void) 782b71562fSIan Lepore { 792b71562fSIan Lepore 802b71562fSIan Lepore cpuinfo.midr = cp15_midr_get(); 812b71562fSIan Lepore /* Test old version id schemes first */ 822b71562fSIan Lepore if ((cpuinfo.midr & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD) { 832b71562fSIan Lepore if (CPU_ID_ISOLD(cpuinfo.midr)) { 842b71562fSIan Lepore /* obsolete ARMv2 or ARMv3 CPU */ 852b71562fSIan Lepore cpuinfo.midr = 0; 862b71562fSIan Lepore return; 872b71562fSIan Lepore } 882b71562fSIan Lepore if (CPU_ID_IS7(cpuinfo.midr)) { 892b71562fSIan Lepore if ((cpuinfo.midr & (1 << 23)) == 0) { 902b71562fSIan Lepore /* obsolete ARMv3 CPU */ 912b71562fSIan Lepore cpuinfo.midr = 0; 922b71562fSIan Lepore return; 932b71562fSIan Lepore } 942b71562fSIan Lepore /* ARMv4T CPU */ 952b71562fSIan Lepore cpuinfo.architecture = 1; 962b71562fSIan Lepore cpuinfo.revision = (cpuinfo.midr >> 16) & 0x7F; 978e6dd301SIan Lepore } else { 988e6dd301SIan Lepore /* ARM new id scheme */ 998e6dd301SIan Lepore cpuinfo.architecture = (cpuinfo.midr >> 16) & 0x0F; 1008e6dd301SIan Lepore cpuinfo.revision = (cpuinfo.midr >> 20) & 0x0F; 1012b71562fSIan Lepore } 1022b71562fSIan Lepore } else { 1038e6dd301SIan Lepore /* non ARM -> must be new id scheme */ 1042b71562fSIan Lepore cpuinfo.architecture = (cpuinfo.midr >> 16) & 0x0F; 1052b71562fSIan Lepore cpuinfo.revision = (cpuinfo.midr >> 20) & 0x0F; 1062b71562fSIan Lepore } 1072b71562fSIan Lepore /* Parse rest of MIDR */ 1082b71562fSIan Lepore cpuinfo.implementer = (cpuinfo.midr >> 24) & 0xFF; 1092b71562fSIan Lepore cpuinfo.part_number = (cpuinfo.midr >> 4) & 0xFFF; 1102b71562fSIan Lepore cpuinfo.patch = cpuinfo.midr & 0x0F; 1112b71562fSIan Lepore 1122b71562fSIan Lepore /* CP15 c0,c0 regs 0-7 exist on all CPUs (although aliased with MIDR) */ 1132b71562fSIan Lepore cpuinfo.ctr = cp15_ctr_get(); 1142b71562fSIan Lepore cpuinfo.tcmtr = cp15_tcmtr_get(); 1153025d19dSMichal Meloun #if __ARM_ARCH >= 6 1162b71562fSIan Lepore cpuinfo.tlbtr = cp15_tlbtr_get(); 1172b71562fSIan Lepore cpuinfo.mpidr = cp15_mpidr_get(); 1182b71562fSIan Lepore cpuinfo.revidr = cp15_revidr_get(); 1193025d19dSMichal Meloun #endif 1202b71562fSIan Lepore 1212b71562fSIan Lepore /* if CPU is not v7 cpu id scheme */ 1222b71562fSIan Lepore if (cpuinfo.architecture != 0xF) 1232b71562fSIan Lepore return; 1243025d19dSMichal Meloun #if __ARM_ARCH >= 6 1252b71562fSIan Lepore cpuinfo.id_pfr0 = cp15_id_pfr0_get(); 1262b71562fSIan Lepore cpuinfo.id_pfr1 = cp15_id_pfr1_get(); 1272b71562fSIan Lepore cpuinfo.id_dfr0 = cp15_id_dfr0_get(); 1282b71562fSIan Lepore cpuinfo.id_afr0 = cp15_id_afr0_get(); 1292b71562fSIan Lepore cpuinfo.id_mmfr0 = cp15_id_mmfr0_get(); 1302b71562fSIan Lepore cpuinfo.id_mmfr1 = cp15_id_mmfr1_get(); 1312b71562fSIan Lepore cpuinfo.id_mmfr2 = cp15_id_mmfr2_get(); 1322b71562fSIan Lepore cpuinfo.id_mmfr3 = cp15_id_mmfr3_get(); 1332b71562fSIan Lepore cpuinfo.id_isar0 = cp15_id_isar0_get(); 1342b71562fSIan Lepore cpuinfo.id_isar1 = cp15_id_isar1_get(); 1352b71562fSIan Lepore cpuinfo.id_isar2 = cp15_id_isar2_get(); 1362b71562fSIan Lepore cpuinfo.id_isar3 = cp15_id_isar3_get(); 1372b71562fSIan Lepore cpuinfo.id_isar4 = cp15_id_isar4_get(); 1382b71562fSIan Lepore cpuinfo.id_isar5 = cp15_id_isar5_get(); 1392b71562fSIan Lepore 1402b71562fSIan Lepore /* Not yet - CBAR only exist on ARM SMP Cortex A CPUs 1412b71562fSIan Lepore cpuinfo.cbar = cp15_cbar_get(); 1422b71562fSIan Lepore */ 143ba0bb206SMichal Meloun if (CPU_CT_FORMAT(cpuinfo.ctr) == CPU_CT_ARMV7) { 144ba0bb206SMichal Meloun cpuinfo.ccsidr = cp15_ccsidr_get(); 145ba0bb206SMichal Meloun cpuinfo.clidr = cp15_clidr_get(); 146ba0bb206SMichal Meloun } 1472b71562fSIan Lepore 1482b71562fSIan Lepore /* Test if revidr is implemented */ 1492b71562fSIan Lepore if (cpuinfo.revidr == cpuinfo.midr) 1502b71562fSIan Lepore cpuinfo.revidr = 0; 1512b71562fSIan Lepore 1522b71562fSIan Lepore /* parsed bits of above registers */ 1532b71562fSIan Lepore /* id_mmfr0 */ 1542b71562fSIan Lepore cpuinfo.outermost_shareability = (cpuinfo.id_mmfr0 >> 8) & 0xF; 1552b71562fSIan Lepore cpuinfo.shareability_levels = (cpuinfo.id_mmfr0 >> 12) & 0xF; 1562b71562fSIan Lepore cpuinfo.auxiliary_registers = (cpuinfo.id_mmfr0 >> 20) & 0xF; 1572b71562fSIan Lepore cpuinfo.innermost_shareability = (cpuinfo.id_mmfr0 >> 28) & 0xF; 1582b71562fSIan Lepore /* id_mmfr2 */ 1592b71562fSIan Lepore cpuinfo.mem_barrier = (cpuinfo.id_mmfr2 >> 20) & 0xF; 1602b71562fSIan Lepore /* id_mmfr3 */ 1612b71562fSIan Lepore cpuinfo.coherent_walk = (cpuinfo.id_mmfr3 >> 20) & 0xF; 1622b71562fSIan Lepore cpuinfo.maintenance_broadcast =(cpuinfo.id_mmfr3 >> 12) & 0xF; 1632b71562fSIan Lepore /* id_pfr1 */ 1642b71562fSIan Lepore cpuinfo.generic_timer_ext = (cpuinfo.id_pfr1 >> 16) & 0xF; 1652b71562fSIan Lepore cpuinfo.virtualization_ext = (cpuinfo.id_pfr1 >> 12) & 0xF; 1662b71562fSIan Lepore cpuinfo.security_ext = (cpuinfo.id_pfr1 >> 4) & 0xF; 167d029cb61SAndrew Turner /* mpidr */ 168d029cb61SAndrew Turner cpuinfo.mp_ext = (cpuinfo.mpidr >> 31u) & 0x1; 169a286c311SIan Lepore 170a286c311SIan Lepore /* L1 Cache sizes */ 171a22f8196SIan Lepore if (CPU_CT_FORMAT(cpuinfo.ctr) == CPU_CT_ARMV7) { 172a22f8196SIan Lepore cpuinfo.dcache_line_size = 173a22f8196SIan Lepore 1 << (CPU_CT_DMINLINE(cpuinfo.ctr) + 2); 174a22f8196SIan Lepore cpuinfo.icache_line_size = 175a22f8196SIan Lepore 1 << (CPU_CT_IMINLINE(cpuinfo.ctr) + 2); 176a22f8196SIan Lepore } else { 177a22f8196SIan Lepore cpuinfo.dcache_line_size = 178a22f8196SIan Lepore 1 << (CPU_CT_xSIZE_LEN(CPU_CT_DSIZE(cpuinfo.ctr)) + 3); 179a22f8196SIan Lepore cpuinfo.icache_line_size = 180a22f8196SIan Lepore 1 << (CPU_CT_xSIZE_LEN(CPU_CT_ISIZE(cpuinfo.ctr)) + 3); 181a22f8196SIan Lepore } 182a286c311SIan Lepore cpuinfo.dcache_line_mask = cpuinfo.dcache_line_size - 1; 183a286c311SIan Lepore cpuinfo.icache_line_mask = cpuinfo.icache_line_size - 1; 1843025d19dSMichal Meloun #endif 1852b71562fSIan Lepore } 186935c21a1SIan Lepore 1877bf5720aSMichal Meloun #if __ARM_ARCH >= 6 188935c21a1SIan Lepore /* 189935c21a1SIan Lepore * Get bits that must be set or cleared in ACLR register. 190935c21a1SIan Lepore * Note: Bits in ACLR register are IMPLEMENTATION DEFINED. 191935c21a1SIan Lepore * Its expected that SCU is in operational state before this 192935c21a1SIan Lepore * function is called. 193935c21a1SIan Lepore */ 1947bf5720aSMichal Meloun static void 195935c21a1SIan Lepore cpuinfo_get_actlr_modifier(uint32_t *actlr_mask, uint32_t *actlr_set) 196935c21a1SIan Lepore { 1977bf5720aSMichal Meloun 198935c21a1SIan Lepore *actlr_mask = 0; 199935c21a1SIan Lepore *actlr_set = 0; 200935c21a1SIan Lepore 201935c21a1SIan Lepore if (cpuinfo.implementer == CPU_IMPLEMENTER_ARM) { 202935c21a1SIan Lepore switch (cpuinfo.part_number) { 203ba0bb206SMichal Meloun case CPU_ARCH_CORTEX_A73: 20455e447c9SMichal Meloun case CPU_ARCH_CORTEX_A72: 20555e447c9SMichal Meloun case CPU_ARCH_CORTEX_A57: 20655e447c9SMichal Meloun case CPU_ARCH_CORTEX_A53: 20755e447c9SMichal Meloun /* Nothing to do for AArch32 */ 20855e447c9SMichal Meloun break; 209935c21a1SIan Lepore case CPU_ARCH_CORTEX_A17: 210935c21a1SIan Lepore case CPU_ARCH_CORTEX_A12: /* A12 is merged to A17 */ 211935c21a1SIan Lepore /* 212935c21a1SIan Lepore * Enable SMP mode 213935c21a1SIan Lepore */ 214935c21a1SIan Lepore *actlr_mask = (1 << 6); 215935c21a1SIan Lepore *actlr_set = (1 << 6); 216935c21a1SIan Lepore break; 217935c21a1SIan Lepore case CPU_ARCH_CORTEX_A15: 218935c21a1SIan Lepore /* 219935c21a1SIan Lepore * Enable snoop-delayed exclusive handling 220935c21a1SIan Lepore * Enable SMP mode 221935c21a1SIan Lepore */ 222935c21a1SIan Lepore *actlr_mask = (1U << 31) |(1 << 6); 223935c21a1SIan Lepore *actlr_set = (1U << 31) |(1 << 6); 224935c21a1SIan Lepore break; 225935c21a1SIan Lepore case CPU_ARCH_CORTEX_A9: 226935c21a1SIan Lepore /* 227935c21a1SIan Lepore * Disable exclusive L1/L2 cache control 228935c21a1SIan Lepore * Enable SMP mode 229935c21a1SIan Lepore * Enable Cache and TLB maintenance broadcast 230935c21a1SIan Lepore */ 231935c21a1SIan Lepore *actlr_mask = (1 << 7) | (1 << 6) | (1 << 0); 232935c21a1SIan Lepore *actlr_set = (1 << 6) | (1 << 0); 233935c21a1SIan Lepore break; 234935c21a1SIan Lepore case CPU_ARCH_CORTEX_A8: 235935c21a1SIan Lepore /* 236935c21a1SIan Lepore * Enable L2 cache 237935c21a1SIan Lepore * Enable L1 data cache hardware alias checks 238935c21a1SIan Lepore */ 239935c21a1SIan Lepore *actlr_mask = (1 << 1) | (1 << 0); 240935c21a1SIan Lepore *actlr_set = (1 << 1); 241935c21a1SIan Lepore break; 242935c21a1SIan Lepore case CPU_ARCH_CORTEX_A7: 243935c21a1SIan Lepore /* 244935c21a1SIan Lepore * Enable SMP mode 245935c21a1SIan Lepore */ 246935c21a1SIan Lepore *actlr_mask = (1 << 6); 247935c21a1SIan Lepore *actlr_set = (1 << 6); 248935c21a1SIan Lepore break; 249935c21a1SIan Lepore case CPU_ARCH_CORTEX_A5: 250935c21a1SIan Lepore /* 251935c21a1SIan Lepore * Disable exclusive L1/L2 cache control 252935c21a1SIan Lepore * Enable SMP mode 253935c21a1SIan Lepore * Enable Cache and TLB maintenance broadcast 254935c21a1SIan Lepore */ 255935c21a1SIan Lepore *actlr_mask = (1 << 7) | (1 << 6) | (1 << 0); 256935c21a1SIan Lepore *actlr_set = (1 << 6) | (1 << 0); 257935c21a1SIan Lepore break; 258935c21a1SIan Lepore case CPU_ARCH_ARM1176: 259935c21a1SIan Lepore /* 260935c21a1SIan Lepore * Restrict cache size to 16KB 261935c21a1SIan Lepore * Enable the return stack 262935c21a1SIan Lepore * Enable dynamic branch prediction 263935c21a1SIan Lepore * Enable static branch prediction 264935c21a1SIan Lepore */ 265935c21a1SIan Lepore *actlr_mask = (1 << 6) | (1 << 2) | (1 << 1) | (1 << 0); 266935c21a1SIan Lepore *actlr_set = (1 << 6) | (1 << 2) | (1 << 1) | (1 << 0); 267935c21a1SIan Lepore break; 268935c21a1SIan Lepore } 269935c21a1SIan Lepore return; 270935c21a1SIan Lepore } 271935c21a1SIan Lepore } 2727bf5720aSMichal Meloun 2737bf5720aSMichal Meloun /* Reinitialize MMU to final kernel mapping and apply all CPU quirks. */ 2747bf5720aSMichal Meloun void 2757bf5720aSMichal Meloun cpuinfo_reinit_mmu(uint32_t ttb) 2767bf5720aSMichal Meloun { 2777bf5720aSMichal Meloun uint32_t actlr_mask; 2787bf5720aSMichal Meloun uint32_t actlr_set; 2797bf5720aSMichal Meloun 2807bf5720aSMichal Meloun cpuinfo_get_actlr_modifier(&actlr_mask, &actlr_set); 2817bf5720aSMichal Meloun actlr_mask |= cpu_quirks_actlr_mask; 2827bf5720aSMichal Meloun actlr_set |= cpu_quirks_actlr_set; 2837bf5720aSMichal Meloun reinit_mmu(ttb, actlr_mask, actlr_set); 2847bf5720aSMichal Meloun } 2857bf5720aSMichal Meloun 2867bf5720aSMichal Meloun #endif /* __ARM_ARCH >= 6 */ 287