xref: /linux/arch/powerpc/include/asm/vdso/timebase.h (revision f9bff0e31881d03badf191d3b0005839391f5f2b)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Common timebase prototypes and such for all ppc machines.
4  */
5 
6 #ifndef _ASM_POWERPC_VDSO_TIMEBASE_H
7 #define _ASM_POWERPC_VDSO_TIMEBASE_H
8 
9 #include <asm/reg.h>
10 
11 /*
12  * We use __powerpc64__ here because we want the compat VDSO to use the 32-bit
13  * version below in the else case of the ifdef.
14  */
15 #if defined(__powerpc64__) && (defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_E500))
16 #define mftb()		({unsigned long rval;				\
17 			asm volatile(					\
18 				"90:	mfspr %0, %2;\n"		\
19 				ASM_FTR_IFSET(				\
20 					"97:	cmpwi %0,0;\n"		\
21 					"	beq- 90b;\n", "", %1)	\
22 			: "=r" (rval) \
23 			: "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL) : "cr0"); \
24 			rval;})
25 #elif defined(CONFIG_PPC_8xx)
26 #define mftb()		({unsigned long rval;	\
27 			asm volatile("mftbl %0" : "=r" (rval)); rval;})
28 #else
29 #define mftb()		({unsigned long rval;	\
30 			asm volatile("mfspr %0, %1" : \
31 				     "=r" (rval) : "i" (SPRN_TBRL)); rval;})
32 #endif /* !CONFIG_PPC_CELL */
33 
34 #if defined(CONFIG_PPC_8xx)
35 #define mftbu()		({unsigned long rval;	\
36 			asm volatile("mftbu %0" : "=r" (rval)); rval;})
37 #else
38 #define mftbu()		({unsigned long rval;	\
39 			asm volatile("mfspr %0, %1" : "=r" (rval) : \
40 				"i" (SPRN_TBRU)); rval;})
41 #endif
42 
43 #define mttbl(v)	asm volatile("mttbl %0":: "r"(v))
44 #define mttbu(v)	asm volatile("mttbu %0":: "r"(v))
45 
46 static __always_inline u64 get_tb(void)
47 {
48 	unsigned int tbhi, tblo, tbhi2;
49 
50 	/*
51 	 * We use __powerpc64__ here not CONFIG_PPC64 because we want the compat
52 	 * VDSO to use the 32-bit compatible version in the while loop below.
53 	 */
54 	if (__is_defined(__powerpc64__))
55 		return mftb();
56 
57 	do {
58 		tbhi = mftbu();
59 		tblo = mftb();
60 		tbhi2 = mftbu();
61 	} while (tbhi != tbhi2);
62 
63 	return ((u64)tbhi << 32) | tblo;
64 }
65 
66 static inline void set_tb(unsigned int upper, unsigned int lower)
67 {
68 	mtspr(SPRN_TBWL, 0);
69 	mtspr(SPRN_TBWU, upper);
70 	mtspr(SPRN_TBWL, lower);
71 }
72 
73 #endif /* _ASM_POWERPC_VDSO_TIMEBASE_H */
74