cpu-v4.h revision 282767
1/*- 2 * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com> 3 * Copyright 2014 Michal Meloun <meloun@miracle.cz> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/arm/include/cpu-v6.h 282767 2015-05-11 12:44:02Z andrew $ 28 */ 29#ifndef MACHINE_CPU_V6_H 30#define MACHINE_CPU_V6_H 31 32/* There are no user serviceable parts here, they may change without notice */ 33#ifndef _KERNEL 34#error Only include this file in the kernel 35#else 36 37#include "machine/atomic.h" 38#include "machine/cpufunc.h" 39#include "machine/cpuinfo.h" 40#include "machine/sysreg.h" 41 42 43#define CPU_ASID_KERNEL 0 44 45vm_offset_t dcache_wb_pou_checked(vm_offset_t, vm_size_t); 46vm_offset_t icache_inv_pou_checked(vm_offset_t, vm_size_t); 47 48/* 49 * Macros to generate CP15 (system control processor) read/write functions. 50 */ 51#define _FX(s...) #s 52 53#define _RF0(fname, aname...) \ 54static __inline register_t \ 55fname(void) \ 56{ \ 57 register_t reg; \ 58 __asm __volatile("mrc\t" _FX(aname): "=r" (reg)); \ 59 return(reg); \ 60} 61 62#define _R64F0(fname, aname) \ 63static __inline uint64_t \ 64fname(void) \ 65{ \ 66 uint64_t reg; \ 67 __asm __volatile("mrrc\t" _FX(aname): "=r" (reg)); \ 68 return(reg); \ 69} 70 71#define _WF0(fname, aname...) \ 72static __inline void \ 73fname(void) \ 74{ \ 75 __asm __volatile("mcr\t" _FX(aname)); \ 76} 77 78#define _WF1(fname, aname...) \ 79static __inline void \ 80fname(register_t reg) \ 81{ \ 82 __asm __volatile("mcr\t" _FX(aname):: "r" (reg)); \ 83} 84 85#define _W64F1(fname, aname...) \ 86static __inline void \ 87fname(uint64_t reg) \ 88{ \ 89 __asm __volatile("mcrr\t" _FX(aname):: "r" (reg)); \ 90} 91 92/* 93 * Raw CP15 maintenance operations 94 * !!! not for external use !!! 95 */ 96 97/* TLB */ 98 99_WF0(_CP15_TLBIALL, CP15_TLBIALL) /* Invalidate entire unified TLB */ 100#if __ARM_ARCH >= 7 && defined SMP 101_WF0(_CP15_TLBIALLIS, CP15_TLBIALLIS) /* Invalidate entire unified TLB IS */ 102#endif 103_WF1(_CP15_TLBIASID, CP15_TLBIASID(%0)) /* Invalidate unified TLB by ASID */ 104#if __ARM_ARCH >= 7 && defined SMP 105_WF1(_CP15_TLBIASIDIS, CP15_TLBIASIDIS(%0)) /* Invalidate unified TLB by ASID IS */ 106#endif 107_WF1(_CP15_TLBIMVAA, CP15_TLBIMVAA(%0)) /* Invalidate unified TLB by MVA, all ASID */ 108#if __ARM_ARCH >= 7 && defined SMP 109_WF1(_CP15_TLBIMVAAIS, CP15_TLBIMVAAIS(%0)) /* Invalidate unified TLB by MVA, all ASID IS */ 110#endif 111_WF1(_CP15_TLBIMVA, CP15_TLBIMVA(%0)) /* Invalidate unified TLB by MVA */ 112 113_WF1(_CP15_TTB_SET, CP15_TTBR0(%0)) 114 115/* Cache and Branch predictor */ 116 117_WF0(_CP15_BPIALL, CP15_BPIALL) /* Branch predictor invalidate all */ 118#if __ARM_ARCH >= 7 && defined SMP 119_WF0(_CP15_BPIALLIS, CP15_BPIALLIS) /* Branch predictor invalidate all IS */ 120#endif 121_WF1(_CP15_BPIMVA, CP15_BPIMVA(%0)) /* Branch predictor invalidate by MVA */ 122_WF1(_CP15_DCCIMVAC, CP15_DCCIMVAC(%0)) /* Data cache clean and invalidate by MVA PoC */ 123_WF1(_CP15_DCCISW, CP15_DCCISW(%0)) /* Data cache clean and invalidate by set/way */ 124_WF1(_CP15_DCCMVAC, CP15_DCCMVAC(%0)) /* Data cache clean by MVA PoC */ 125#if __ARM_ARCH >= 7 126_WF1(_CP15_DCCMVAU, CP15_DCCMVAU(%0)) /* Data cache clean by MVA PoU */ 127#endif 128_WF1(_CP15_DCCSW, CP15_DCCSW(%0)) /* Data cache clean by set/way */ 129_WF1(_CP15_DCIMVAC, CP15_DCIMVAC(%0)) /* Data cache invalidate by MVA PoC */ 130_WF1(_CP15_DCISW, CP15_DCISW(%0)) /* Data cache invalidate by set/way */ 131_WF0(_CP15_ICIALLU, CP15_ICIALLU) /* Instruction cache invalidate all PoU */ 132#if __ARM_ARCH >= 7 && defined SMP 133_WF0(_CP15_ICIALLUIS, CP15_ICIALLUIS) /* Instruction cache invalidate all PoU IS */ 134#endif 135_WF1(_CP15_ICIMVAU, CP15_ICIMVAU(%0)) /* Instruction cache invalidate */ 136 137/* 138 * Publicly accessible functions 139 */ 140 141/* Various control registers */ 142 143_RF0(cp15_dfsr_get, CP15_DFSR(%0)) 144_RF0(cp15_ifsr_get, CP15_IFSR(%0)) 145_WF1(cp15_prrr_set, CP15_PRRR(%0)) 146_WF1(cp15_nmrr_set, CP15_NMRR(%0)) 147_RF0(cp15_ttbr_get, CP15_TTBR0(%0)) 148_RF0(cp15_dfar_get, CP15_DFAR(%0)) 149#if __ARM_ARCH >= 7 150_RF0(cp15_ifar_get, CP15_IFAR(%0)) 151_RF0(cp15_l2ctlr_get, CP15_L2CTLR(%0)) 152#endif 153#if __ARM_ARCH >= 6 154_RF0(cp15_actlr_get, CP15_ACTLR(%0)) 155_WF1(cp15_ats1cpr_set, CP15_ATS1CPR(%0)); 156_RF0(cp15_par_get, CP15_PAR); 157_RF0(cp15_sctlr_get, CP15_SCTLR(%0)) 158#endif 159 160/*CPU id registers */ 161_RF0(cp15_midr_get, CP15_MIDR(%0)) 162_RF0(cp15_ctr_get, CP15_CTR(%0)) 163_RF0(cp15_tcmtr_get, CP15_TCMTR(%0)) 164_RF0(cp15_tlbtr_get, CP15_TLBTR(%0)) 165_RF0(cp15_mpidr_get, CP15_MPIDR(%0)) 166_RF0(cp15_revidr_get, CP15_REVIDR(%0)) 167_RF0(cp15_aidr_get, CP15_AIDR(%0)) 168_RF0(cp15_id_pfr0_get, CP15_ID_PFR0(%0)) 169_RF0(cp15_id_pfr1_get, CP15_ID_PFR1(%0)) 170_RF0(cp15_id_dfr0_get, CP15_ID_DFR0(%0)) 171_RF0(cp15_id_afr0_get, CP15_ID_AFR0(%0)) 172_RF0(cp15_id_mmfr0_get, CP15_ID_MMFR0(%0)) 173_RF0(cp15_id_mmfr1_get, CP15_ID_MMFR1(%0)) 174_RF0(cp15_id_mmfr2_get, CP15_ID_MMFR2(%0)) 175_RF0(cp15_id_mmfr3_get, CP15_ID_MMFR3(%0)) 176_RF0(cp15_id_isar0_get, CP15_ID_ISAR0(%0)) 177_RF0(cp15_id_isar1_get, CP15_ID_ISAR1(%0)) 178_RF0(cp15_id_isar2_get, CP15_ID_ISAR2(%0)) 179_RF0(cp15_id_isar3_get, CP15_ID_ISAR3(%0)) 180_RF0(cp15_id_isar4_get, CP15_ID_ISAR4(%0)) 181_RF0(cp15_id_isar5_get, CP15_ID_ISAR5(%0)) 182_RF0(cp15_cbar_get, CP15_CBAR(%0)) 183 184/* Performance Monitor registers */ 185 186#if __ARM_ARCH == 6 && defined(CPU_ARM1176) 187_RF0(cp15_pmccntr_get, CP15_PMCCNTR(%0)) 188_WF1(cp15_pmccntr_set, CP15_PMCCNTR(%0)) 189#elif __ARM_ARCH > 6 190_RF0(cp15_pmcr_get, CP15_PMCR(%0)) 191_WF1(cp15_pmcr_set, CP15_PMCR(%0)) 192_RF0(cp15_pmcnten_get, CP15_PMCNTENSET(%0)) 193_WF1(cp15_pmcnten_set, CP15_PMCNTENSET(%0)) 194_WF1(cp15_pmcnten_clr, CP15_PMCNTENCLR(%0)) 195_RF0(cp15_pmovsr_get, CP15_PMOVSR(%0)) 196_WF1(cp15_pmovsr_set, CP15_PMOVSR(%0)) 197_WF1(cp15_pmswinc_set, CP15_PMSWINC(%0)) 198_RF0(cp15_pmselr_get, CP15_PMSELR(%0)) 199_WF1(cp15_pmselr_set, CP15_PMSELR(%0)) 200_RF0(cp15_pmccntr_get, CP15_PMCCNTR(%0)) 201_WF1(cp15_pmccntr_set, CP15_PMCCNTR(%0)) 202_RF0(cp15_pmxevtyper_get, CP15_PMXEVTYPER(%0)) 203_WF1(cp15_pmxevtyper_set, CP15_PMXEVTYPER(%0)) 204_RF0(cp15_pmxevcntr_get, CP15_PMXEVCNTRR(%0)) 205_WF1(cp15_pmxevcntr_set, CP15_PMXEVCNTRR(%0)) 206_RF0(cp15_pmuserenr_get, CP15_PMUSERENR(%0)) 207_WF1(cp15_pmuserenr_set, CP15_PMUSERENR(%0)) 208_RF0(cp15_pminten_get, CP15_PMINTENSET(%0)) 209_WF1(cp15_pminten_set, CP15_PMINTENSET(%0)) 210_WF1(cp15_pminten_clr, CP15_PMINTENCLR(%0)) 211#endif 212 213_RF0(cp15_tpidrurw_get, CP15_TPIDRURW(%0)) 214_WF1(cp15_tpidrurw_set, CP15_TPIDRURW(%0)) 215_RF0(cp15_tpidruro_get, CP15_TPIDRURO(%0)) 216_WF1(cp15_tpidruro_set, CP15_TPIDRURO(%0)) 217_RF0(cp15_tpidrpwr_get, CP15_TPIDRPRW(%0)) 218_WF1(cp15_tpidrpwr_set, CP15_TPIDRPRW(%0)) 219 220/* Generic Timer registers - only use when you know the hardware is available */ 221_RF0(cp15_cntfrq_get, CP15_CNTFRQ(%0)) 222_WF1(cp15_cntfrq_set, CP15_CNTFRQ(%0)) 223_RF0(cp15_cntkctl_get, CP15_CNTKCTL(%0)) 224_WF1(cp15_cntkctl_set, CP15_CNTKCTL(%0)) 225_RF0(cp15_cntp_tval_get, CP15_CNTP_TVAL(%0)) 226_WF1(cp15_cntp_tval_set, CP15_CNTP_TVAL(%0)) 227_RF0(cp15_cntp_ctl_get, CP15_CNTP_CTL(%0)) 228_WF1(cp15_cntp_ctl_set, CP15_CNTP_CTL(%0)) 229_RF0(cp15_cntv_tval_get, CP15_CNTV_TVAL(%0)) 230_WF1(cp15_cntv_tval_set, CP15_CNTV_TVAL(%0)) 231_RF0(cp15_cntv_ctl_get, CP15_CNTV_CTL(%0)) 232_WF1(cp15_cntv_ctl_set, CP15_CNTV_CTL(%0)) 233_RF0(cp15_cnthctl_get, CP15_CNTHCTL(%0)) 234_WF1(cp15_cnthctl_set, CP15_CNTHCTL(%0)) 235_RF0(cp15_cnthp_tval_get, CP15_CNTHP_TVAL(%0)) 236_WF1(cp15_cnthp_tval_set, CP15_CNTHP_TVAL(%0)) 237_RF0(cp15_cnthp_ctl_get, CP15_CNTHP_CTL(%0)) 238_WF1(cp15_cnthp_ctl_set, CP15_CNTHP_CTL(%0)) 239 240_R64F0(cp15_cntpct_get, CP15_CNTPCT(%Q0, %R0)) 241_R64F0(cp15_cntvct_get, CP15_CNTVCT(%Q0, %R0)) 242_R64F0(cp15_cntp_cval_get, CP15_CNTP_CVAL(%Q0, %R0)) 243_W64F1(cp15_cntp_cval_set, CP15_CNTP_CVAL(%Q0, %R0)) 244_R64F0(cp15_cntv_cval_get, CP15_CNTV_CVAL(%Q0, %R0)) 245_W64F1(cp15_cntv_cval_set, CP15_CNTV_CVAL(%Q0, %R0)) 246_R64F0(cp15_cntvoff_get, CP15_CNTVOFF(%Q0, %R0)) 247_W64F1(cp15_cntvoff_set, CP15_CNTVOFF(%Q0, %R0)) 248_R64F0(cp15_cnthp_cval_get, CP15_CNTHP_CVAL(%Q0, %R0)) 249_W64F1(cp15_cnthp_cval_set, CP15_CNTHP_CVAL(%Q0, %R0)) 250 251#undef _FX 252#undef _RF0 253#undef _WF0 254#undef _WF1 255 256/* 257 * TLB maintenance operations. 258 */ 259 260/* Local (i.e. not broadcasting ) operations. */ 261 262/* Flush all TLB entries (even global). */ 263static __inline void 264tlb_flush_all_local(void) 265{ 266 267 dsb(); 268 _CP15_TLBIALL(); 269 dsb(); 270} 271 272/* Flush all not global TLB entries. */ 273static __inline void 274tlb_flush_all_ng_local(void) 275{ 276 277 dsb(); 278 _CP15_TLBIASID(CPU_ASID_KERNEL); 279 dsb(); 280} 281 282/* Flush single TLB entry (even global). */ 283static __inline void 284tlb_flush_local(vm_offset_t sva) 285{ 286 287 dsb(); 288 _CP15_TLBIMVA((sva & ~PAGE_MASK ) | CPU_ASID_KERNEL); 289 dsb(); 290} 291 292/* Flush range of TLB entries (even global). */ 293static __inline void 294tlb_flush_range_local(vm_offset_t sva, vm_size_t size) 295{ 296 vm_offset_t va; 297 vm_offset_t eva = sva + size; 298 299 dsb(); 300 for (va = sva; va < eva; va += PAGE_SIZE) 301 _CP15_TLBIMVA((va & ~PAGE_MASK ) | CPU_ASID_KERNEL); 302 dsb(); 303} 304 305/* Broadcasting operations. */ 306#if __ARM_ARCH >= 7 && defined SMP 307 308static __inline void 309tlb_flush_all(void) 310{ 311 312 dsb(); 313 _CP15_TLBIALLIS(); 314 dsb(); 315} 316 317static __inline void 318tlb_flush_all_ng(void) 319{ 320 321 dsb(); 322 _CP15_TLBIASIDIS(CPU_ASID_KERNEL); 323 dsb(); 324} 325 326static __inline void 327tlb_flush(vm_offset_t sva) 328{ 329 330 dsb(); 331 _CP15_TLBIMVAAIS(sva); 332 dsb(); 333} 334 335static __inline void 336tlb_flush_range(vm_offset_t sva, vm_size_t size) 337{ 338 vm_offset_t va; 339 vm_offset_t eva = sva + size; 340 341 dsb(); 342 for (va = sva; va < eva; va += PAGE_SIZE) 343 _CP15_TLBIMVAAIS(va); 344 dsb(); 345} 346#else /* SMP */ 347 348#define tlb_flush_all() tlb_flush_all_local() 349#define tlb_flush_all_ng() tlb_flush_all_ng_local() 350#define tlb_flush(sva) tlb_flush_local(sva) 351#define tlb_flush_range(sva, size) tlb_flush_range_local(sva, size) 352 353#endif /* SMP */ 354 355/* 356 * Cache maintenance operations. 357 */ 358 359/* Sync I and D caches to PoU */ 360static __inline void 361icache_sync(vm_offset_t sva, vm_size_t size) 362{ 363 vm_offset_t va; 364 vm_offset_t eva = sva + size; 365 366 dsb(); 367 for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 368#if __ARM_ARCH >= 7 && defined SMP 369 _CP15_DCCMVAU(va); 370#else 371 _CP15_DCCMVAC(va); 372#endif 373 } 374 dsb(); 375#if __ARM_ARCH >= 7 && defined SMP 376 _CP15_ICIALLUIS(); 377#else 378 _CP15_ICIALLU(); 379#endif 380 dsb(); 381 isb(); 382} 383 384/* Invalidate I cache */ 385static __inline void 386icache_inv_all(void) 387{ 388#if __ARM_ARCH >= 7 && defined SMP 389 _CP15_ICIALLUIS(); 390#else 391 _CP15_ICIALLU(); 392#endif 393 dsb(); 394 isb(); 395} 396 397/* Invalidate branch predictor buffer */ 398static __inline void 399bpb_inv_all(void) 400{ 401#if __ARM_ARCH >= 7 && defined SMP 402 _CP15_BPIALLIS(); 403#else 404 _CP15_BPIALL(); 405#endif 406 dsb(); 407 isb(); 408} 409 410/* Write back D-cache to PoU */ 411static __inline void 412dcache_wb_pou(vm_offset_t sva, vm_size_t size) 413{ 414 vm_offset_t va; 415 vm_offset_t eva = sva + size; 416 417 dsb(); 418 for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 419#if __ARM_ARCH >= 7 && defined SMP 420 _CP15_DCCMVAU(va); 421#else 422 _CP15_DCCMVAC(va); 423#endif 424 } 425 dsb(); 426} 427 428/* Invalidate D-cache to PoC */ 429static __inline void 430dcache_inv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 431{ 432 vm_offset_t va; 433 vm_offset_t eva = sva + size; 434 435 /* invalidate L1 first */ 436 for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 437 _CP15_DCIMVAC(va); 438 } 439 dsb(); 440 441 /* then L2 */ 442 cpu_l2cache_inv_range(pa, size); 443 dsb(); 444 445 /* then L1 again */ 446 for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 447 _CP15_DCIMVAC(va); 448 } 449 dsb(); 450} 451 452/* Write back D-cache to PoC */ 453static __inline void 454dcache_wb_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 455{ 456 vm_offset_t va; 457 vm_offset_t eva = sva + size; 458 459 dsb(); 460 461 for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 462 _CP15_DCCMVAC(va); 463 } 464 dsb(); 465 466 cpu_l2cache_wb_range(pa, size); 467} 468 469/* Write back and invalidate D-cache to PoC */ 470static __inline void 471dcache_wbinv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 472{ 473 vm_offset_t va; 474 vm_offset_t eva = sva + size; 475 476 dsb(); 477 478 /* write back L1 first */ 479 for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 480 _CP15_DCCMVAC(va); 481 } 482 dsb(); 483 484 /* then write back and invalidate L2 */ 485 cpu_l2cache_wbinv_range(pa, size); 486 487 /* then invalidate L1 */ 488 for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 489 _CP15_DCIMVAC(va); 490 } 491 dsb(); 492} 493 494/* Set TTB0 register */ 495static __inline void 496cp15_ttbr_set(uint32_t reg) 497{ 498 dsb(); 499 _CP15_TTB_SET(reg); 500 dsb(); 501 _CP15_BPIALL(); 502 dsb(); 503 isb(); 504 tlb_flush_all_ng_local(); 505} 506 507#endif /* _KERNEL */ 508 509#endif /* !MACHINE_CPU_V6_H */ 510