cpu-v6.h revision 278635
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: stable/10/sys/arm/include/cpu-v6.h 278635 2015-02-12 21:10:24Z 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 40276333Sian/* 41276333Sian * Macros to generate CP15 (system control processor) read/write functions. 42276333Sian */ 43276333Sian#define _FX(s...) #s 44276333Sian 45276333Sian#define _RF0(fname, aname...) \ 46276333Sianstatic __inline register_t \ 47276333Sianfname(void) \ 48276333Sian{ \ 49276333Sian register_t reg; \ 50276333Sian __asm __volatile("mrc\t" _FX(aname): "=r" (reg)); \ 51276333Sian return(reg); \ 52276333Sian} 53276333Sian 54276333Sian#define _WF0(fname, aname...) \ 55276333Sianstatic __inline void \ 56276333Sianfname(void) \ 57276333Sian{ \ 58276333Sian __asm __volatile("mcr\t" _FX(aname)); \ 59276333Sian} 60276333Sian 61276333Sian#define _WF1(fname, aname...) \ 62276333Sianstatic __inline void \ 63276333Sianfname(register_t reg) \ 64276333Sian{ \ 65276333Sian __asm __volatile("mcr\t" _FX(aname):: "r" (reg)); \ 66276333Sian} 67276333Sian 68276333Sian/* 69276333Sian * Raw CP15 maintenance operations 70276333Sian * !!! not for external use !!! 71276333Sian */ 72276333Sian 73276333Sian/* TLB */ 74276333Sian 75276333Sian_WF0(_CP15_TLBIALL, CP15_TLBIALL) /* Invalidate entire unified TLB */ 76276333Sian#if __ARM_ARCH >= 7 && defined SMP 77276333Sian_WF0(_CP15_TLBIALLIS, CP15_TLBIALLIS) /* Invalidate entire unified TLB IS */ 78276333Sian#endif 79276333Sian_WF1(_CP15_TLBIASID, CP15_TLBIASID(%0)) /* Invalidate unified TLB by ASID */ 80276333Sian#if __ARM_ARCH >= 7 && defined SMP 81276333Sian_WF1(_CP15_TLBIASIDIS, CP15_TLBIASIDIS(%0)) /* Invalidate unified TLB by ASID IS */ 82276333Sian#endif 83276333Sian_WF1(_CP15_TLBIMVAA, CP15_TLBIMVAA(%0)) /* Invalidate unified TLB by MVA, all ASID */ 84276333Sian#if __ARM_ARCH >= 7 && defined SMP 85276333Sian_WF1(_CP15_TLBIMVAAIS, CP15_TLBIMVAAIS(%0)) /* Invalidate unified TLB by MVA, all ASID IS */ 86276333Sian#endif 87276333Sian_WF1(_CP15_TLBIMVA, CP15_TLBIMVA(%0)) /* Invalidate unified TLB by MVA */ 88276333Sian 89276333Sian_WF1(_CP15_TTB_SET, CP15_TTBR0(%0)) 90276333Sian 91276333Sian/* Cache and Branch predictor */ 92276333Sian 93276333Sian_WF0(_CP15_BPIALL, CP15_BPIALL) /* Branch predictor invalidate all */ 94276333Sian#if __ARM_ARCH >= 7 && defined SMP 95276333Sian_WF0(_CP15_BPIALLIS, CP15_BPIALLIS) /* Branch predictor invalidate all IS */ 96276333Sian#endif 97276333Sian_WF1(_CP15_BPIMVA, CP15_BPIMVA(%0)) /* Branch predictor invalidate by MVA */ 98276333Sian_WF1(_CP15_DCCIMVAC, CP15_DCCIMVAC(%0)) /* Data cache clean and invalidate by MVA PoC */ 99276333Sian_WF1(_CP15_DCCISW, CP15_DCCISW(%0)) /* Data cache clean and invalidate by set/way */ 100276333Sian_WF1(_CP15_DCCMVAC, CP15_DCCMVAC(%0)) /* Data cache clean by MVA PoC */ 101276333Sian#if __ARM_ARCH >= 7 102276333Sian_WF1(_CP15_DCCMVAU, CP15_DCCMVAU(%0)) /* Data cache clean by MVA PoU */ 103276333Sian#endif 104276333Sian_WF1(_CP15_DCCSW, CP15_DCCSW(%0)) /* Data cache clean by set/way */ 105276333Sian_WF1(_CP15_DCIMVAC, CP15_DCIMVAC(%0)) /* Data cache invalidate by MVA PoC */ 106276333Sian_WF1(_CP15_DCISW, CP15_DCISW(%0)) /* Data cache invalidate by set/way */ 107276333Sian_WF0(_CP15_ICIALLU, CP15_ICIALLU) /* Instruction cache invalidate all PoU */ 108276333Sian#if __ARM_ARCH >= 7 && defined SMP 109276333Sian_WF0(_CP15_ICIALLUIS, CP15_ICIALLUIS) /* Instruction cache invalidate all PoU IS */ 110276333Sian#endif 111276333Sian_WF1(_CP15_ICIMVAU, CP15_ICIMVAU(%0)) /* Instruction cache invalidate */ 112276333Sian 113276333Sian/* 114276333Sian * Publicly accessible functions 115276333Sian */ 116276333Sian 117276333Sian/* Various control registers */ 118276333Sian 119276333Sian_RF0(cp15_dfsr_get, CP15_DFSR(%0)) 120276333Sian_RF0(cp15_ifsr_get, CP15_IFSR(%0)) 121276333Sian_WF1(cp15_prrr_set, CP15_PRRR(%0)) 122276333Sian_WF1(cp15_nmrr_set, CP15_NMRR(%0)) 123276333Sian_RF0(cp15_ttbr_get, CP15_TTBR0(%0)) 124276333Sian_RF0(cp15_dfar_get, CP15_DFAR(%0)) 125276333Sian#if __ARM_ARCH >= 7 126276333Sian_RF0(cp15_ifar_get, CP15_IFAR(%0)) 127276333Sian#endif 128276333Sian 129276333Sian/*CPU id registers */ 130276333Sian_RF0(cp15_midr_get, CP15_MIDR(%0)) 131276333Sian_RF0(cp15_ctr_get, CP15_CTR(%0)) 132276333Sian_RF0(cp15_tcmtr_get, CP15_TCMTR(%0)) 133276333Sian_RF0(cp15_tlbtr_get, CP15_TLBTR(%0)) 134276333Sian_RF0(cp15_mpidr_get, CP15_MPIDR(%0)) 135276333Sian_RF0(cp15_revidr_get, CP15_REVIDR(%0)) 136276333Sian_RF0(cp15_aidr_get, CP15_AIDR(%0)) 137276333Sian_RF0(cp15_id_pfr0_get, CP15_ID_PFR0(%0)) 138276333Sian_RF0(cp15_id_pfr1_get, CP15_ID_PFR1(%0)) 139276333Sian_RF0(cp15_id_dfr0_get, CP15_ID_DFR0(%0)) 140276333Sian_RF0(cp15_id_afr0_get, CP15_ID_AFR0(%0)) 141276333Sian_RF0(cp15_id_mmfr0_get, CP15_ID_MMFR0(%0)) 142276333Sian_RF0(cp15_id_mmfr1_get, CP15_ID_MMFR1(%0)) 143276333Sian_RF0(cp15_id_mmfr2_get, CP15_ID_MMFR2(%0)) 144276333Sian_RF0(cp15_id_mmfr3_get, CP15_ID_MMFR3(%0)) 145276333Sian_RF0(cp15_id_isar0_get, CP15_ID_ISAR0(%0)) 146276333Sian_RF0(cp15_id_isar1_get, CP15_ID_ISAR1(%0)) 147276333Sian_RF0(cp15_id_isar2_get, CP15_ID_ISAR2(%0)) 148276333Sian_RF0(cp15_id_isar3_get, CP15_ID_ISAR3(%0)) 149276333Sian_RF0(cp15_id_isar4_get, CP15_ID_ISAR4(%0)) 150276333Sian_RF0(cp15_id_isar5_get, CP15_ID_ISAR5(%0)) 151276333Sian_RF0(cp15_cbar_get, CP15_CBAR(%0)) 152276333Sian 153276333Sian#undef _FX 154276333Sian#undef _RF0 155276333Sian#undef _WF0 156276333Sian#undef _WF1 157276333Sian 158278635Sian/* 159278635Sian * TLB maintenance operations. 160278635Sian */ 161278635Sian 162278635Sian/* Local (i.e. not broadcasting ) operations. */ 163278635Sian 164278635Sian/* Flush all TLB entries (even global). */ 165278635Sianstatic __inline void 166278635Siantlb_flush_all_local(void) 167278635Sian{ 168278635Sian 169278635Sian dsb(); 170278635Sian _CP15_TLBIALL(); 171278635Sian dsb(); 172278635Sian} 173278635Sian 174278635Sian/* Flush all not global TLB entries. */ 175278635Sianstatic __inline void 176278635Siantlb_flush_all_ng_local(void) 177278635Sian{ 178278635Sian 179278635Sian dsb(); 180278635Sian _CP15_TLBIASID(CPU_ASID_KERNEL); 181278635Sian dsb(); 182278635Sian} 183278635Sian 184278635Sian/* Flush single TLB entry (even global). */ 185278635Sianstatic __inline void 186278635Siantlb_flush_local(vm_offset_t sva) 187278635Sian{ 188278635Sian 189278635Sian dsb(); 190278635Sian _CP15_TLBIMVA((sva & ~PAGE_MASK ) | CPU_ASID_KERNEL); 191278635Sian dsb(); 192278635Sian} 193278635Sian 194278635Sian/* Flush range of TLB entries (even global). */ 195278635Sianstatic __inline void 196278635Siantlb_flush_range_local(vm_offset_t sva, vm_size_t size) 197278635Sian{ 198278635Sian vm_offset_t va; 199278635Sian vm_offset_t eva = sva + size; 200278635Sian 201278635Sian dsb(); 202278635Sian for (va = sva; va < eva; va += PAGE_SIZE) 203278635Sian _CP15_TLBIMVA((va & ~PAGE_MASK ) | CPU_ASID_KERNEL); 204278635Sian dsb(); 205278635Sian} 206278635Sian 207278635Sian/* Broadcasting operations. */ 208278635Sian#ifndef SMP 209278635Sian 210278635Sian#define tlb_flush_all() tlb_flush_all_local() 211278635Sian#define tlb_flush_all_ng() tlb_flush_all_ng_local() 212278635Sian#define tlb_flush(sva) tlb_flush_local(sva) 213278635Sian#define tlb_flush_range(sva, size) tlb_flush_range_local(sva, size) 214278635Sian 215278635Sian#else /* SMP */ 216278635Sian 217278635Sianstatic __inline void 218278635Siantlb_flush_all(void) 219278635Sian{ 220278635Sian 221278635Sian dsb(); 222278635Sian _CP15_TLBIALLIS(); 223278635Sian dsb(); 224278635Sian} 225278635Sian 226278635Sianstatic __inline void 227278635Siantlb_flush_all_ng(void) 228278635Sian{ 229278635Sian 230278635Sian dsb(); 231278635Sian _CP15_TLBIASIDIS(CPU_ASID_KERNEL); 232278635Sian dsb(); 233278635Sian} 234278635Sian 235278635Sianstatic __inline void 236278635Siantlb_flush(vm_offset_t sva) 237278635Sian{ 238278635Sian 239278635Sian dsb(); 240278635Sian _CP15_TLBIMVAAIS(sva); 241278635Sian dsb(); 242278635Sian} 243278635Sian 244278635Sianstatic __inline void 245278635Siantlb_flush_range(vm_offset_t sva, vm_size_t size) 246278635Sian{ 247278635Sian vm_offset_t va; 248278635Sian vm_offset_t eva = sva + size; 249278635Sian 250278635Sian dsb(); 251278635Sian for (va = sva; va < eva; va += PAGE_SIZE) 252278635Sian _CP15_TLBIMVAAIS(va); 253278635Sian dsb(); 254278635Sian} 255278635Sian#endif /* SMP */ 256278635Sian 257278635Sian/* 258278635Sian * Cache maintenance operations. 259278635Sian */ 260278635Sian 261278635Sian/* Sync I and D caches to PoU */ 262278635Sianstatic __inline void 263278635Sianicache_sync(vm_offset_t sva, vm_size_t size) 264278635Sian{ 265278635Sian vm_offset_t va; 266278635Sian vm_offset_t eva = sva + size; 267278635Sian 268278635Sian dsb(); 269278635Sian for (va = sva; va < eva; va += arm_dcache_align) { 270278635Sian#ifdef SMP 271278635Sian _CP15_DCCMVAU(va); 272278635Sian#else 273278635Sian _CP15_DCCMVAC(va); 274278635Sian#endif 275278635Sian } 276278635Sian dsb(); 277278635Sian#ifdef SMP 278278635Sian _CP15_ICIALLUIS(); 279278635Sian#else 280278635Sian _CP15_ICIALLU(); 281278635Sian#endif 282278635Sian dsb(); 283278635Sian isb(); 284278635Sian} 285278635Sian 286278635Sian/* Invalidate I cache */ 287278635Sianstatic __inline void 288278635Sianicache_inv_all(void) 289278635Sian{ 290278635Sian#ifdef SMP 291278635Sian _CP15_ICIALLUIS(); 292278635Sian#else 293278635Sian _CP15_ICIALLU(); 294278635Sian#endif 295278635Sian dsb(); 296278635Sian isb(); 297278635Sian} 298278635Sian 299278635Sian/* Write back D-cache to PoU */ 300278635Sianstatic __inline void 301278635Siandcache_wb_pou(vm_offset_t sva, vm_size_t size) 302278635Sian{ 303278635Sian vm_offset_t va; 304278635Sian vm_offset_t eva = sva + size; 305278635Sian 306278635Sian dsb(); 307278635Sian for (va = sva; va < eva; va += arm_dcache_align) { 308278635Sian#ifdef SMP 309278635Sian _CP15_DCCMVAU(va); 310278635Sian#else 311278635Sian _CP15_DCCMVAC(va); 312278635Sian#endif 313278635Sian } 314278635Sian dsb(); 315278635Sian} 316278635Sian 317278635Sian/* Invalidate D-cache to PoC */ 318278635Sianstatic __inline void 319278635Siandcache_inv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 320278635Sian{ 321278635Sian vm_offset_t va; 322278635Sian vm_offset_t eva = sva + size; 323278635Sian 324278635Sian /* invalidate L1 first */ 325278635Sian for (va = sva; va < eva; va += arm_dcache_align) { 326278635Sian _CP15_DCIMVAC(va); 327278635Sian } 328278635Sian dsb(); 329278635Sian 330278635Sian /* then L2 */ 331278635Sian cpu_l2cache_inv_range(pa, size); 332278635Sian dsb(); 333278635Sian 334278635Sian /* then L1 again */ 335278635Sian for (va = sva; va < eva; va += arm_dcache_align) { 336278635Sian _CP15_DCIMVAC(va); 337278635Sian } 338278635Sian dsb(); 339278635Sian} 340278635Sian 341278635Sian/* Write back D-cache to PoC */ 342278635Sianstatic __inline void 343278635Siandcache_wb_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 344278635Sian{ 345278635Sian vm_offset_t va; 346278635Sian vm_offset_t eva = sva + size; 347278635Sian 348278635Sian dsb(); 349278635Sian 350278635Sian for (va = sva; va < eva; va += arm_dcache_align) { 351278635Sian _CP15_DCCMVAC(va); 352278635Sian } 353278635Sian dsb(); 354278635Sian 355278635Sian cpu_l2cache_wb_range(pa, size); 356278635Sian} 357278635Sian 358278635Sian/* Write back and invalidate D-cache to PoC */ 359278635Sianstatic __inline void 360278635Siandcache_wbinv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) 361278635Sian{ 362278635Sian vm_offset_t va; 363278635Sian vm_offset_t eva = sva + size; 364278635Sian 365278635Sian dsb(); 366278635Sian 367278635Sian /* write back L1 first */ 368278635Sian for (va = sva; va < eva; va += arm_dcache_align) { 369278635Sian _CP15_DCCMVAC(va); 370278635Sian } 371278635Sian dsb(); 372278635Sian 373278635Sian /* then write back and invalidate L2 */ 374278635Sian cpu_l2cache_wbinv_range(pa, size); 375278635Sian 376278635Sian /* then invalidate L1 */ 377278635Sian for (va = sva; va < eva; va += arm_dcache_align) { 378278635Sian _CP15_DCIMVAC(va); 379278635Sian } 380278635Sian dsb(); 381278635Sian} 382278635Sian 383278635Sian/* Set TTB0 register */ 384278635Sianstatic __inline void 385278635Siancp15_ttbr_set(uint32_t reg) 386278635Sian{ 387278635Sian dsb(); 388278635Sian _CP15_TTB_SET(reg); 389278635Sian dsb(); 390278635Sian _CP15_BPIALL(); 391278635Sian dsb(); 392278635Sian isb(); 393278635Sian tlb_flush_all_ng_local(); 394278635Sian} 395278635Sian 396276333Sian#endif /* !MACHINE_CPU_V6_H */ 397