1276333Sian/*- 2276333Sian * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com> 3276333Sian * Copyright 2014 Michal Meloun <meloun@miracle.cz> 4276333Sian * All rights reserved. 5276333Sian * 6276333Sian * Redistribution and use in source and binary forms, with or without 7276333Sian * modification, are permitted provided that the following conditions 8276333Sian * are met: 9276333Sian * 1. Redistributions of source code must retain the above copyright 10276333Sian * notice, this list of conditions and the following disclaimer. 11276333Sian * 2. Redistributions in binary form must reproduce the above copyright 12276333Sian * notice, this list of conditions and the following disclaimer in the 13276333Sian * documentation and/or other materials provided with the distribution. 14276333Sian * 15276333Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16276333Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17276333Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18276333Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19276333Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20276333Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21276333Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22276333Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23276333Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24276333Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25276333Sian * SUCH DAMAGE. 26276333Sian * 27276333Sian * $FreeBSD: releng/10.3/sys/arm/include/cpu-v6.h 283336 2015-05-23 23:05:31Z ian $ 28276333Sian */ 29276333Sian#ifndef MACHINE_CPU_V6_H 30276333Sian#define MACHINE_CPU_V6_H 31276333Sian 32276333Sian#include "machine/atomic.h" 33276333Sian#include "machine/cpufunc.h" 34276333Sian#include "machine/cpuinfo.h" 35276333Sian#include "machine/sysreg.h" 36276333Sian 37276333Sian 38276333Sian#define CPU_ASID_KERNEL 0 39276333Sian 40283336Sianvm_offset_t dcache_wb_pou_checked(vm_offset_t, vm_size_t); 41283336Sianvm_offset_t icache_inv_pou_checked(vm_offset_t, vm_size_t); 42283336Sian 43276333Sian/* 44276333Sian * Macros to generate CP15 (system control processor) read/write functions. 45276333Sian */ 46276333Sian#define _FX(s...) #s 47276333Sian 48276333Sian#define _RF0(fname, aname...) \ 49276333Sianstatic __inline register_t \ 50276333Sianfname(void) \ 51276333Sian{ \ 52276333Sian register_t reg; \ 53276333Sian __asm __volatile("mrc\t" _FX(aname): "=r" (reg)); \ 54276333Sian return(reg); \ 55276333Sian} 56276333Sian 57276333Sian#define _WF0(fname, aname...) \ 58276333Sianstatic __inline void \ 59276333Sianfname(void) \ 60276333Sian{ \ 61276333Sian __asm __volatile("mcr\t" _FX(aname)); \ 62276333Sian} 63276333Sian 64276333Sian#define _WF1(fname, aname...) \ 65276333Sianstatic __inline void \ 66276333Sianfname(register_t reg) \ 67276333Sian{ \ 68276333Sian __asm __volatile("mcr\t" _FX(aname):: "r" (reg)); \ 69276333Sian} 70276333Sian 71276333Sian/* 72276333Sian * Raw CP15 maintenance operations 73276333Sian * !!! not for external use !!! 74276333Sian */ 75276333Sian 76276333Sian/* TLB */ 77276333Sian 78276333Sian_WF0(_CP15_TLBIALL, CP15_TLBIALL) /* Invalidate entire unified TLB */ 79276333Sian#if __ARM_ARCH >= 7 && defined SMP 80276333Sian_WF0(_CP15_TLBIALLIS, CP15_TLBIALLIS) /* Invalidate entire unified TLB IS */ 81276333Sian#endif 82276333Sian_WF1(_CP15_TLBIASID, CP15_TLBIASID(%0)) /* Invalidate unified TLB by ASID */ 83276333Sian#if __ARM_ARCH >= 7 && defined SMP 84276333Sian_WF1(_CP15_TLBIASIDIS, CP15_TLBIASIDIS(%0)) /* Invalidate unified TLB by ASID IS */ 85276333Sian#endif 86276333Sian_WF1(_CP15_TLBIMVAA, CP15_TLBIMVAA(%0)) /* Invalidate unified TLB by MVA, all ASID */ 87276333Sian#if __ARM_ARCH >= 7 && defined SMP 88276333Sian_WF1(_CP15_TLBIMVAAIS, CP15_TLBIMVAAIS(%0)) /* Invalidate unified TLB by MVA, all ASID IS */ 89276333Sian#endif 90276333Sian_WF1(_CP15_TLBIMVA, CP15_TLBIMVA(%0)) /* Invalidate unified TLB by MVA */ 91276333Sian 92276333Sian_WF1(_CP15_TTB_SET, CP15_TTBR0(%0)) 93276333Sian 94276333Sian/* Cache and Branch predictor */ 95276333Sian 96276333Sian_WF0(_CP15_BPIALL, CP15_BPIALL) /* Branch predictor invalidate all */ 97276333Sian#if __ARM_ARCH >= 7 && defined SMP 98276333Sian_WF0(_CP15_BPIALLIS, CP15_BPIALLIS) /* Branch predictor invalidate all IS */ 99276333Sian#endif 100276333Sian_WF1(_CP15_BPIMVA, CP15_BPIMVA(%0)) /* Branch predictor invalidate by MVA */ 101276333Sian_WF1(_CP15_DCCIMVAC, CP15_DCCIMVAC(%0)) /* Data cache clean and invalidate by MVA PoC */ 102276333Sian_WF1(_CP15_DCCISW, CP15_DCCISW(%0)) /* Data cache clean and invalidate by set/way */ 103276333Sian_WF1(_CP15_DCCMVAC, CP15_DCCMVAC(%0)) /* Data cache clean by MVA PoC */ 104276333Sian#if __ARM_ARCH >= 7 105276333Sian_WF1(_CP15_DCCMVAU, CP15_DCCMVAU(%0)) /* Data cache clean by MVA PoU */ 106276333Sian#endif 107276333Sian_WF1(_CP15_DCCSW, CP15_DCCSW(%0)) /* Data cache clean by set/way */ 108276333Sian_WF1(_CP15_DCIMVAC, CP15_DCIMVAC(%0)) /* Data cache invalidate by MVA PoC */ 109276333Sian_WF1(_CP15_DCISW, CP15_DCISW(%0)) /* Data cache invalidate by set/way */ 110276333Sian_WF0(_CP15_ICIALLU, CP15_ICIALLU) /* Instruction cache invalidate all PoU */ 111276333Sian#if __ARM_ARCH >= 7 && defined SMP 112276333Sian_WF0(_CP15_ICIALLUIS, CP15_ICIALLUIS) /* Instruction cache invalidate all PoU IS */ 113276333Sian#endif 114276333Sian_WF1(_CP15_ICIMVAU, CP15_ICIMVAU(%0)) /* Instruction cache invalidate */ 115276333Sian 116276333Sian/* 117276333Sian * Publicly accessible functions 118276333Sian */ 119276333Sian 120276333Sian/* Various control registers */ 121276333Sian 122276333Sian_RF0(cp15_dfsr_get, CP15_DFSR(%0)) 123276333Sian_RF0(cp15_ifsr_get, CP15_IFSR(%0)) 124276333Sian_WF1(cp15_prrr_set, CP15_PRRR(%0)) 125276333Sian_WF1(cp15_nmrr_set, CP15_NMRR(%0)) 126276333Sian_RF0(cp15_ttbr_get, CP15_TTBR0(%0)) 127276333Sian_RF0(cp15_dfar_get, CP15_DFAR(%0)) 128276333Sian#if __ARM_ARCH >= 7 129276333Sian_RF0(cp15_ifar_get, CP15_IFAR(%0)) 130276333Sian#endif 131276333Sian 132276333Sian/*CPU id registers */ 133276333Sian_RF0(cp15_midr_get, CP15_MIDR(%0)) 134276333Sian_RF0(cp15_ctr_get, CP15_CTR(%0)) 135276333Sian_RF0(cp15_tcmtr_get, CP15_TCMTR(%0)) 136276333Sian_RF0(cp15_tlbtr_get, CP15_TLBTR(%0)) 137276333Sian_RF0(cp15_mpidr_get, CP15_MPIDR(%0)) 138276333Sian_RF0(cp15_revidr_get, CP15_REVIDR(%0)) 139276333Sian_RF0(cp15_aidr_get, CP15_AIDR(%0)) 140276333Sian_RF0(cp15_id_pfr0_get, CP15_ID_PFR0(%0)) 141276333Sian_RF0(cp15_id_pfr1_get, CP15_ID_PFR1(%0)) 142276333Sian_RF0(cp15_id_dfr0_get, CP15_ID_DFR0(%0)) 143276333Sian_RF0(cp15_id_afr0_get, CP15_ID_AFR0(%0)) 144276333Sian_RF0(cp15_id_mmfr0_get, CP15_ID_MMFR0(%0)) 145276333Sian_RF0(cp15_id_mmfr1_get, CP15_ID_MMFR1(%0)) 146276333Sian_RF0(cp15_id_mmfr2_get, CP15_ID_MMFR2(%0)) 147276333Sian_RF0(cp15_id_mmfr3_get, CP15_ID_MMFR3(%0)) 148276333Sian_RF0(cp15_id_isar0_get, CP15_ID_ISAR0(%0)) 149276333Sian_RF0(cp15_id_isar1_get, CP15_ID_ISAR1(%0)) 150276333Sian_RF0(cp15_id_isar2_get, CP15_ID_ISAR2(%0)) 151276333Sian_RF0(cp15_id_isar3_get, CP15_ID_ISAR3(%0)) 152276333Sian_RF0(cp15_id_isar4_get, CP15_ID_ISAR4(%0)) 153276333Sian_RF0(cp15_id_isar5_get, CP15_ID_ISAR5(%0)) 154276333Sian_RF0(cp15_cbar_get, CP15_CBAR(%0)) 155276333Sian 156278684Sian/* Performance Monitor registers */ 157278684Sian 158278684Sian#if __ARM_ARCH == 6 && defined(CPU_ARM1176) 159278684Sian_RF0(cp15_pmccntr_get, CP15_PMCCNTR(%0)) 160278684Sian_WF1(cp15_pmccntr_set, CP15_PMCCNTR(%0)) 161278684Sian#elif __ARM_ARCH > 6 162278684Sian_RF0(cp15_pmcr_get, CP15_PMCR(%0)) 163278684Sian_WF1(cp15_pmcr_set, CP15_PMCR(%0)) 164278684Sian_RF0(cp15_pmcnten_get, CP15_PMCNTENSET(%0)) 165278684Sian_WF1(cp15_pmcnten_set, CP15_PMCNTENSET(%0)) 166278684Sian_WF1(cp15_pmcnten_clr, CP15_PMCNTENCLR(%0)) 167278684Sian_RF0(cp15_pmovsr_get, CP15_PMOVSR(%0)) 168278684Sian_WF1(cp15_pmovsr_set, CP15_PMOVSR(%0)) 169278684Sian_WF1(cp15_pmswinc_set, CP15_PMSWINC(%0)) 170278684Sian_RF0(cp15_pmselr_get, CP15_PMSELR(%0)) 171278684Sian_WF1(cp15_pmselr_set, CP15_PMSELR(%0)) 172278684Sian_RF0(cp15_pmccntr_get, CP15_PMCCNTR(%0)) 173278684Sian_WF1(cp15_pmccntr_set, CP15_PMCCNTR(%0)) 174278684Sian_RF0(cp15_pmxevtyper_get, CP15_PMXEVTYPER(%0)) 175278684Sian_WF1(cp15_pmxevtyper_set, CP15_PMXEVTYPER(%0)) 176278684Sian_RF0(cp15_pmxevcntr_get, CP15_PMXEVCNTRR(%0)) 177278684Sian_WF1(cp15_pmxevcntr_set, CP15_PMXEVCNTRR(%0)) 178278684Sian_RF0(cp15_pmuserenr_get, CP15_PMUSERENR(%0)) 179278684Sian_WF1(cp15_pmuserenr_set, CP15_PMUSERENR(%0)) 180278684Sian_RF0(cp15_pminten_get, CP15_PMINTENSET(%0)) 181278684Sian_WF1(cp15_pminten_set, CP15_PMINTENSET(%0)) 182278684Sian_WF1(cp15_pminten_clr, CP15_PMINTENCLR(%0)) 183278684Sian#endif 184278684Sian 185276333Sian#undef _FX 186276333Sian#undef _RF0 187276333Sian#undef _WF0 188276333Sian#undef _WF1 189276333Sian 190278635Sian/* 191278635Sian * TLB maintenance operations. 192278635Sian */ 193278635Sian 194278635Sian/* Local (i.e. not broadcasting ) operations. */ 195278635Sian 196278635Sian/* Flush all TLB entries (even global). */ 197278635Sianstatic __inline void 198278635Siantlb_flush_all_local(void) 199278635Sian{ 200278635Sian 201278635Sian dsb(); 202278635Sian _CP15_TLBIALL(); 203278635Sian dsb(); 204278635Sian} 205278635Sian 206278635Sian/* Flush all not global TLB entries. */ 207278635Sianstatic __inline void 208278635Siantlb_flush_all_ng_local(void) 209278635Sian{ 210278635Sian 211278635Sian dsb(); 212278635Sian _CP15_TLBIASID(CPU_ASID_KERNEL); 213278635Sian dsb(); 214278635Sian} 215278635Sian 216278635Sian/* Flush single TLB entry (even global). */ 217278635Sianstatic __inline void 218278635Siantlb_flush_local(vm_offset_t sva) 219278635Sian{ 220278635Sian 221278635Sian dsb(); 222278635Sian _CP15_TLBIMVA((sva & ~PAGE_MASK ) | CPU_ASID_KERNEL); 223278635Sian dsb(); 224278635Sian} 225278635Sian 226278635Sian/* Flush range of TLB entries (even global). */ 227278635Sianstatic __inline void 228278635Siantlb_flush_range_local(vm_offset_t sva, vm_size_t size) 229278635Sian{ 230278635Sian vm_offset_t va; 231278635Sian vm_offset_t eva = sva + size; 232278635Sian 233278635Sian dsb(); 234278635Sian for (va = sva; va < eva; va += PAGE_SIZE) 235278635Sian _CP15_TLBIMVA((va & ~PAGE_MASK ) | CPU_ASID_KERNEL); 236278635Sian dsb(); 237278635Sian} 238278635Sian 239278635Sian/* Broadcasting operations. */ 240278684Sian#if __ARM_ARCH >= 7 && defined SMP 241278635Sian 242278635Sianstatic __inline void 243278635Siantlb_flush_all(void) 244278635Sian{ 245278635Sian 246278635Sian dsb(); 247278635Sian _CP15_TLBIALLIS(); 248278635Sian dsb(); 249278635Sian} 250278635Sian 251278635Sianstatic __inline void 252278635Siantlb_flush_all_ng(void) 253278635Sian{ 254278635Sian 255278635Sian dsb(); 256278635Sian _CP15_TLBIASIDIS(CPU_ASID_KERNEL); 257278635Sian dsb(); 258278635Sian} 259278635Sian 260278635Sianstatic __inline void 261278635Siantlb_flush(vm_offset_t sva) 262278635Sian{ 263278635Sian 264278635Sian dsb(); 265278635Sian _CP15_TLBIMVAAIS(sva); 266278635Sian dsb(); 267278635Sian} 268278635Sian 269278635Sianstatic __inline void 270278635Siantlb_flush_range(vm_offset_t sva, vm_size_t size) 271278635Sian{ 272278635Sian vm_offset_t va; 273278635Sian vm_offset_t eva = sva + size; 274278635Sian 275278635Sian dsb(); 276278635Sian for (va = sva; va < eva; va += PAGE_SIZE) 277278635Sian _CP15_TLBIMVAAIS(va); 278278635Sian dsb(); 279278635Sian} 280278684Sian#else /* SMP */ 281278684Sian 282278684Sian#define tlb_flush_all() tlb_flush_all_local() 283278684Sian#define tlb_flush_all_ng() tlb_flush_all_ng_local() 284278684Sian#define tlb_flush(sva) tlb_flush_local(sva) 285278684Sian#define tlb_flush_range(sva, size) tlb_flush_range_local(sva, size) 286278684Sian 287278635Sian#endif /* SMP */ 288278635Sian 289278635Sian/* 290278635Sian * Cache maintenance operations. 291278635Sian */ 292278635Sian 293278635Sian/* Sync I and D caches to PoU */ 294278635Sianstatic __inline void 295278635Sianicache_sync(vm_offset_t sva, vm_size_t size) 296278635Sian{ 297278635Sian vm_offset_t va; 298278635Sian vm_offset_t eva = sva + size; 299278635Sian 300278635Sian dsb(); 301283336Sian for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 302278684Sian#if __ARM_ARCH >= 7 && defined SMP 303278635Sian _CP15_DCCMVAU(va); 304278635Sian#else 305278635Sian _CP15_DCCMVAC(va); 306278635Sian#endif 307278635Sian } 308278635Sian dsb(); 309278684Sian#if __ARM_ARCH >= 7 && defined SMP 310278635Sian _CP15_ICIALLUIS(); 311278635Sian#else 312278635Sian _CP15_ICIALLU(); 313278635Sian#endif 314278635Sian dsb(); 315278635Sian isb(); 316278635Sian} 317278635Sian 318278635Sian/* Invalidate I cache */ 319278635Sianstatic __inline void 320278635Sianicache_inv_all(void) 321278635Sian{ 322278684Sian#if __ARM_ARCH >= 7 && defined SMP 323278635Sian _CP15_ICIALLUIS(); 324278635Sian#else 325278635Sian _CP15_ICIALLU(); 326278635Sian#endif 327278635Sian dsb(); 328278635Sian isb(); 329278635Sian} 330278635Sian 331283336Sian/* Invalidate branch predictor buffer */ 332283336Sianstatic __inline void 333283336Sianbpb_inv_all(void) 334283336Sian{ 335283336Sian#if __ARM_ARCH >= 7 && defined SMP 336283336Sian _CP15_BPIALLIS(); 337283336Sian#else 338283336Sian _CP15_BPIALL(); 339283336Sian#endif 340283336Sian dsb(); 341283336Sian isb(); 342283336Sian} 343283336Sian 344278635Sian/* Write back D-cache to PoU */ 345278635Sianstatic __inline void 346278635Siandcache_wb_pou(vm_offset_t sva, vm_size_t size) 347278635Sian{ 348278635Sian vm_offset_t va; 349278635Sian vm_offset_t eva = sva + size; 350278635Sian 351278635Sian dsb(); 352283336Sian for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 353278684Sian#if __ARM_ARCH >= 7 && defined SMP 354278635Sian _CP15_DCCMVAU(va); 355278635Sian#else 356278635Sian _CP15_DCCMVAC(va); 357278635Sian#endif 358278635Sian } 359278635Sian dsb(); 360278635Sian} 361278635Sian 362278635Sian/* Invalidate D-cache to PoC */ 363278635Sianstatic __inline void 364278635Siandcache_inv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 365278635Sian{ 366278635Sian vm_offset_t va; 367278635Sian vm_offset_t eva = sva + size; 368278635Sian 369278635Sian /* invalidate L1 first */ 370283336Sian for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 371278635Sian _CP15_DCIMVAC(va); 372278635Sian } 373278635Sian dsb(); 374278635Sian 375278635Sian /* then L2 */ 376278635Sian cpu_l2cache_inv_range(pa, size); 377278635Sian dsb(); 378278635Sian 379278635Sian /* then L1 again */ 380283336Sian for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 381278635Sian _CP15_DCIMVAC(va); 382278635Sian } 383278635Sian dsb(); 384278635Sian} 385278635Sian 386278635Sian/* Write back D-cache to PoC */ 387278635Sianstatic __inline void 388278635Siandcache_wb_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 389278635Sian{ 390278635Sian vm_offset_t va; 391278635Sian vm_offset_t eva = sva + size; 392278635Sian 393278635Sian dsb(); 394278635Sian 395283336Sian for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 396278635Sian _CP15_DCCMVAC(va); 397278635Sian } 398278635Sian dsb(); 399278635Sian 400278635Sian cpu_l2cache_wb_range(pa, size); 401278635Sian} 402278635Sian 403278635Sian/* Write back and invalidate D-cache to PoC */ 404278635Sianstatic __inline void 405278635Siandcache_wbinv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 406278635Sian{ 407278635Sian vm_offset_t va; 408278635Sian vm_offset_t eva = sva + size; 409278635Sian 410278635Sian dsb(); 411278635Sian 412278635Sian /* write back L1 first */ 413283336Sian for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 414278635Sian _CP15_DCCMVAC(va); 415278635Sian } 416278635Sian dsb(); 417278635Sian 418278635Sian /* then write back and invalidate L2 */ 419278635Sian cpu_l2cache_wbinv_range(pa, size); 420278635Sian 421278635Sian /* then invalidate L1 */ 422283336Sian for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { 423278635Sian _CP15_DCIMVAC(va); 424278635Sian } 425278635Sian dsb(); 426278635Sian} 427278635Sian 428278635Sian/* Set TTB0 register */ 429278635Sianstatic __inline void 430278635Siancp15_ttbr_set(uint32_t reg) 431278635Sian{ 432278635Sian dsb(); 433278635Sian _CP15_TTB_SET(reg); 434278635Sian dsb(); 435278635Sian _CP15_BPIALL(); 436278635Sian dsb(); 437278635Sian isb(); 438278635Sian tlb_flush_all_ng_local(); 439278635Sian} 440278635Sian 441276333Sian#endif /* !MACHINE_CPU_V6_H */ 442