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