1129198Scognet/* $NetBSD: cpu.c,v 1.55 2004/02/13 11:36:10 wiz Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 1995 Mark Brinicombe. 5129198Scognet * Copyright (c) 1995 Brini. 6129198Scognet * All rights reserved. 7129198Scognet * 8129198Scognet * Redistribution and use in source and binary forms, with or without 9129198Scognet * modification, are permitted provided that the following conditions 10129198Scognet * are met: 11129198Scognet * 1. Redistributions of source code must retain the above copyright 12129198Scognet * notice, this list of conditions and the following disclaimer. 13129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 14129198Scognet * notice, this list of conditions and the following disclaimer in the 15129198Scognet * documentation and/or other materials provided with the distribution. 16129198Scognet * 3. All advertising materials mentioning features or use of this software 17129198Scognet * must display the following acknowledgement: 18129198Scognet * This product includes software developed by Brini. 19129198Scognet * 4. The name of the company nor the name of the author may be used to 20129198Scognet * endorse or promote products derived from this software without specific 21129198Scognet * prior written permission. 22129198Scognet * 23129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 24129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26129198Scognet * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33129198Scognet * SUCH DAMAGE. 34129198Scognet * 35129198Scognet * RiscBSD kernel project 36129198Scognet * 37129198Scognet * cpu.c 38129198Scognet * 39129198Scognet * Probing and configuration for the master CPU 40129198Scognet * 41129198Scognet * Created : 10/10/95 42129198Scognet */ 43129198Scognet 44129198Scognet#include <sys/cdefs.h> 45129198Scognet__FBSDID("$FreeBSD: stable/11/sys/arm/arm/identcpu-v6.c 358591 2020-03-03 18:01:03Z dim $"); 46314530Sian#include <sys/param.h> 47129198Scognet#include <sys/systm.h> 48129198Scognet#include <sys/conf.h> 49135652Scognet#include <sys/kernel.h> 50135652Scognet#include <sys/sysctl.h> 51129198Scognet#include <machine/cpu.h> 52197523Srpaulo#include <machine/md_var.h> 53129198Scognet 54129198Scognetchar machine[] = "arm"; 55129198Scognet 56135652ScognetSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, 57235062Simp machine, 0, "Machine class"); 58129198Scognet 59331524Sianstatic char cpu_model[64]; 60331524SianSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, 61331524Sian cpu_model, sizeof(cpu_model), "Machine model"); 62331524Sian 63306901Smmelstatic char hw_buf[81]; 64306901Smmelstatic int hw_buf_idx; 65306901Smmelstatic bool hw_buf_newline; 66129198Scognet 67306901Smmelstatic struct { 68306901Smmel int implementer; 69306901Smmel int part_number; 70306901Smmel char *impl_name; 71306901Smmel char *core_name; 72306901Smmel} cpu_names[] = { 73306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_ARM1176, "ARM", "ARM1176"}, 74306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A5 , "ARM", "Cortex-A5"}, 75306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A7 , "ARM", "Cortex-A7"}, 76306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A8 , "ARM", "Cortex-A8"}, 77306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A9 , "ARM", "Cortex-A9"}, 78306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A12, "ARM", "Cortex-A12"}, 79306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A15, "ARM", "Cortex-A15"}, 80306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A17, "ARM", "Cortex-A17"}, 81306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A53, "ARM", "Cortex-A53"}, 82306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A57, "ARM", "Cortex-A57"}, 83306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A72, "ARM", "Cortex-A72"}, 84306901Smmel {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A73, "ARM", "Cortex-A73"}, 85129198Scognet 86356064Sloos {CPU_IMPLEMENTER_MRVL, CPU_ARCH_SHEEVA_581, "Marvell", "PJ4 v7"}, 87356064Sloos {CPU_IMPLEMENTER_MRVL, CPU_ARCH_SHEEVA_584, "Marvell", "PJ4MP v7"}, 88172738Simp 89306901Smmel {CPU_IMPLEMENTER_QCOM, CPU_ARCH_KRAIT_300, "Qualcomm", "Krait 300"}, 90129198Scognet}; 91129198Scognet 92164080Scognet 93306901Smmelstatic void 94306901Smmelprint_v5_cache(void) 95306901Smmel{ 96306901Smmel uint32_t isize, dsize; 97306901Smmel uint32_t multiplier; 98306901Smmel int pcache_type; 99306901Smmel int pcache_unified; 100306901Smmel int picache_size; 101306901Smmel int picache_line_size; 102306901Smmel int picache_ways; 103306901Smmel int pdcache_size; 104306901Smmel int pdcache_line_size; 105306901Smmel int pdcache_ways; 106129198Scognet 107306901Smmel pcache_unified = 0; 108306901Smmel picache_size = 0 ; 109306901Smmel picache_line_size = 0 ; 110306901Smmel picache_ways = 0 ; 111306901Smmel pdcache_size = 0; 112306901Smmel pdcache_line_size = 0; 113306901Smmel pdcache_ways = 0; 114172738Simp 115306901Smmel if ((cpuinfo.ctr & CPU_CT_S) == 0) 116306901Smmel pcache_unified = 1; 117172738Simp 118306901Smmel /* 119306901Smmel * If you want to know how this code works, go read the ARM ARM. 120306901Smmel */ 121306901Smmel pcache_type = CPU_CT_CTYPE(cpuinfo.ctr); 122129198Scognet 123306901Smmel if (pcache_unified == 0) { 124306901Smmel isize = CPU_CT_ISIZE(cpuinfo.ctr); 125306901Smmel multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2; 126306901Smmel picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3); 127306901Smmel if (CPU_CT_xSIZE_ASSOC(isize) == 0) { 128306901Smmel if (isize & CPU_CT_xSIZE_M) 129306901Smmel picache_line_size = 0; /* not present */ 130306901Smmel else 131306901Smmel picache_ways = 1; 132306901Smmel } else { 133306901Smmel picache_ways = multiplier << 134306901Smmel (CPU_CT_xSIZE_ASSOC(isize) - 1); 135306901Smmel } 136306901Smmel picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8); 137306901Smmel } 138129198Scognet 139306901Smmel dsize = CPU_CT_DSIZE(cpuinfo.ctr); 140306901Smmel multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2; 141306901Smmel pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3); 142306901Smmel if (CPU_CT_xSIZE_ASSOC(dsize) == 0) { 143306901Smmel if (dsize & CPU_CT_xSIZE_M) 144306901Smmel pdcache_line_size = 0; /* not present */ 145306901Smmel else 146306901Smmel pdcache_ways = 1; 147306901Smmel } else { 148306901Smmel pdcache_ways = multiplier << 149306901Smmel (CPU_CT_xSIZE_ASSOC(dsize) - 1); 150306901Smmel } 151306901Smmel pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8); 152204122Skevlo 153129198Scognet 154306901Smmel /* Print cache info. */ 155306901Smmel if (picache_line_size == 0 && pdcache_line_size == 0) 156306901Smmel return; 157129198Scognet 158306901Smmel if (pcache_unified) { 159306901Smmel printf(" %dKB/%dB %d-way %s unified cache\n", 160306901Smmel pdcache_size / 1024, 161306901Smmel pdcache_line_size, pdcache_ways, 162306901Smmel pcache_type == 0 ? "WT" : "WB"); 163306901Smmel } else { 164306901Smmel printf(" %dKB/%dB %d-way instruction cache\n", 165306901Smmel picache_size / 1024, 166306901Smmel picache_line_size, picache_ways); 167306901Smmel printf(" %dKB/%dB %d-way %s data cache\n", 168306901Smmel pdcache_size / 1024, 169306901Smmel pdcache_line_size, pdcache_ways, 170306901Smmel pcache_type == 0 ? "WT" : "WB"); 171306901Smmel } 172306901Smmel} 173239268Sgonzo 174239268Sgonzostatic void 175306901Smmelprint_v7_cache(void ) 176239268Sgonzo{ 177306901Smmel uint32_t type, val, size, sets, ways, linesize; 178306901Smmel int i; 179153940Snetchild 180306901Smmel printf("LoUU:%d LoC:%d LoUIS:%d \n", 181306901Smmel CPU_CLIDR_LOUU(cpuinfo.clidr) + 1, 182306901Smmel CPU_CLIDR_LOC(cpuinfo.clidr) + 1, 183306901Smmel CPU_CLIDR_LOUIS(cpuinfo.clidr) + 1); 184239268Sgonzo 185306901Smmel for (i = 0; i < 7; i++) { 186306901Smmel type = CPU_CLIDR_CTYPE(cpuinfo.clidr, i); 187306901Smmel if (type == 0) 188306901Smmel break; 189306901Smmel printf("Cache level %d:\n", i + 1); 190306901Smmel if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE || 191306901Smmel type == CACHE_SEP_CACHE) { 192306901Smmel cp15_csselr_set(i << 1); 193306901Smmel val = cp15_ccsidr_get(); 194306901Smmel ways = CPUV7_CT_xSIZE_ASSOC(val) + 1; 195306901Smmel sets = CPUV7_CT_xSIZE_SET(val) + 1; 196306901Smmel linesize = 1 << (CPUV7_CT_xSIZE_LEN(val) + 4); 197306901Smmel size = (ways * sets * linesize) / 1024; 198239268Sgonzo 199306901Smmel if (type == CACHE_UNI_CACHE) 200306901Smmel printf(" %dKB/%dB %d-way unified cache", 201306901Smmel size, linesize,ways); 202306901Smmel else 203306901Smmel printf(" %dKB/%dB %d-way data cache", 204306901Smmel size, linesize, ways); 205306901Smmel if (val & CPUV7_CT_CTYPE_WT) 206306901Smmel printf(" WT"); 207306901Smmel if (val & CPUV7_CT_CTYPE_WB) 208306901Smmel printf(" WB"); 209358591Sdim if (val & CPUV7_CT_CTYPE_RA) 210306901Smmel printf(" Read-Alloc"); 211306901Smmel if (val & CPUV7_CT_CTYPE_WA) 212306901Smmel printf(" Write-Alloc"); 213306901Smmel printf("\n"); 214306901Smmel } 215239268Sgonzo 216306901Smmel if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) { 217306901Smmel cp15_csselr_set(i << 1 | 1); 218306901Smmel val = cp15_ccsidr_get(); 219306901Smmel ways = CPUV7_CT_xSIZE_ASSOC(val) + 1; 220306901Smmel sets = CPUV7_CT_xSIZE_SET(val) + 1; 221306901Smmel linesize = 1 << (CPUV7_CT_xSIZE_LEN(val) + 4); 222306901Smmel size = (ways * sets * linesize) / 1024; 223306901Smmel printf(" %dKB/%dB %d-way instruction cache", 224306901Smmel size, linesize, ways); 225306901Smmel if (val & CPUV7_CT_CTYPE_WT) 226306901Smmel printf(" WT"); 227306901Smmel if (val & CPUV7_CT_CTYPE_WB) 228306901Smmel printf(" WB"); 229306901Smmel if (val & CPUV7_CT_CTYPE_RA) 230306901Smmel printf(" Read-Alloc"); 231306901Smmel if (val & CPUV7_CT_CTYPE_WA) 232306901Smmel printf(" Write-Alloc"); 233306901Smmel printf("\n"); 234306901Smmel } 235239268Sgonzo } 236306901Smmel cp15_csselr_set(0); 237239268Sgonzo} 238239268Sgonzo 239306901Smmelstatic void 240306901Smmeladd_cap(char *cap) 241239268Sgonzo{ 242306901Smmel int len; 243239268Sgonzo 244306901Smmel len = strlen(cap); 245239268Sgonzo 246306901Smmel if ((hw_buf_idx + len + 2) >= 79) { 247306901Smmel printf("%s,\n", hw_buf); 248306901Smmel hw_buf_idx = 0; 249306901Smmel hw_buf_newline = true; 250306901Smmel } 251306901Smmel if (hw_buf_newline) 252306901Smmel hw_buf_idx += sprintf(hw_buf + hw_buf_idx, " "); 253306901Smmel else 254306901Smmel hw_buf_idx += sprintf(hw_buf + hw_buf_idx, ", "); 255306901Smmel hw_buf_newline = false; 256239268Sgonzo 257239268Sgonzo 258306901Smmel hw_buf_idx += sprintf(hw_buf + hw_buf_idx, "%s", cap); 259239268Sgonzo} 260239268Sgonzo 261129198Scognetvoid 262129198Scognetidentify_arm_cpu(void) 263129198Scognet{ 264129198Scognet int i; 265306901Smmel u_int val; 266129198Scognet 267306901Smmel /* 268306901Smmel * CPU 269306901Smmel */ 270306901Smmel for(i = 0; i < nitems(cpu_names); i++) { 271306901Smmel if (cpu_names[i].implementer == cpuinfo.implementer && 272306901Smmel cpu_names[i].part_number == cpuinfo.part_number) { 273331524Sian snprintf(cpu_model, sizeof(cpu_model), 274331524Sian "%s %s r%dp%d (ECO: 0x%08X)", 275306901Smmel cpu_names[i].impl_name, cpu_names[i].core_name, 276306901Smmel cpuinfo.revision, cpuinfo.patch, 277306901Smmel cpuinfo.midr != cpuinfo.revidr ? 278306901Smmel cpuinfo.revidr : 0); 279331524Sian printf("CPU: %s\n", cpu_model); 280306901Smmel break; 281306901Smmel } 282129198Scognet 283129198Scognet } 284306901Smmel if (i >= nitems(cpu_names)) 285306901Smmel printf("unknown CPU (ID = 0x%x)\n", cpuinfo.midr); 286129198Scognet 287306901Smmel printf("CPU Features: \n"); 288306901Smmel hw_buf_idx = 0; 289306901Smmel hw_buf_newline = true; 290129198Scognet 291306901Smmel val = (cpuinfo.mpidr >> 4)& 0xF; 292306901Smmel if (cpuinfo.mpidr & (1 << 31U)) 293306901Smmel add_cap("Multiprocessing"); 294306901Smmel val = (cpuinfo.id_pfr0 >> 4)& 0xF; 295306901Smmel if (val == 1) 296306901Smmel add_cap("Thumb"); 297306901Smmel else if (val == 3) 298306901Smmel add_cap("Thumb2"); 299239268Sgonzo 300306901Smmel val = (cpuinfo.id_pfr1 >> 4)& 0xF; 301306901Smmel if (val == 1 || val == 2) 302306901Smmel add_cap("Security"); 303239268Sgonzo 304306901Smmel val = (cpuinfo.id_pfr1 >> 12)& 0xF; 305306901Smmel if (val == 1) 306306901Smmel add_cap("Virtualization"); 307306901Smmel 308306901Smmel val = (cpuinfo.id_pfr1 >> 16)& 0xF; 309306901Smmel if (val == 1) 310306901Smmel add_cap("Generic Timer"); 311306901Smmel 312306901Smmel val = (cpuinfo.id_mmfr0 >> 0)& 0xF; 313306901Smmel if (val == 2) { 314306901Smmel add_cap("VMSAv6"); 315306901Smmel } else if (val >= 3) { 316306901Smmel add_cap("VMSAv7"); 317306901Smmel if (val >= 4) 318306901Smmel add_cap("PXN"); 319306901Smmel if (val >= 5) 320306901Smmel add_cap("LPAE"); 321129198Scognet } 322129198Scognet 323306901Smmel val = (cpuinfo.id_mmfr3 >> 20)& 0xF; 324306901Smmel if (val == 1) 325306901Smmel add_cap("Coherent Walk"); 326129198Scognet 327306901Smmel if (hw_buf_idx != 0) 328306901Smmel printf("%s\n", hw_buf); 329129198Scognet 330306901Smmel printf("Optional instructions: \n"); 331306901Smmel hw_buf_idx = 0; 332306901Smmel hw_buf_newline = true; 333306901Smmel val = (cpuinfo.id_isar0 >> 24)& 0xF; 334306901Smmel if (val == 1) 335306901Smmel add_cap("SDIV/UDIV (Thumb)"); 336306901Smmel else if (val == 2) 337306901Smmel add_cap("SDIV/UDIV"); 338239268Sgonzo 339306901Smmel val = (cpuinfo.id_isar2 >> 20)& 0xF; 340306901Smmel if (val == 1 || val == 2) 341306901Smmel add_cap("UMULL"); 342239268Sgonzo 343306901Smmel val = (cpuinfo.id_isar2 >> 16)& 0xF; 344306901Smmel if (val == 1 || val == 2 || val == 3) 345306901Smmel add_cap("SMULL"); 346239268Sgonzo 347306901Smmel val = (cpuinfo.id_isar2 >> 12)& 0xF; 348306901Smmel if (val == 1) 349306901Smmel add_cap("MLA"); 350239268Sgonzo 351306901Smmel val = (cpuinfo.id_isar3 >> 4)& 0xF; 352306901Smmel if (val == 1) 353306901Smmel add_cap("SIMD"); 354306901Smmel else if (val == 3) 355306901Smmel add_cap("SIMD(ext)"); 356306901Smmel if (hw_buf_idx != 0) 357306901Smmel printf("%s\n", hw_buf); 358239268Sgonzo 359306901Smmel /* 360306901Smmel * Cache 361306901Smmel */ 362306901Smmel if (CPU_CT_FORMAT(cpuinfo.ctr) == CPU_CT_ARMV7) 363306901Smmel print_v7_cache(); 364306901Smmel else 365306901Smmel print_v5_cache(); 366129198Scognet} 367