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