xref: /openbmc/u-boot/arch/x86/include/asm/lapic.h (revision 63d54a67)
1 /*
2  * From coreboot file of same name
3  *
4  * Copyright (C) 2014 Google, Inc
5  *
6  * SPDX-License-Identifier:	GPL-2.0
7  */
8 
9 #ifndef _ARCH_ASM_LAPIC_H
10 #define _ARCH_ASM_LAPIC_H
11 
12 #include <asm/io.h>
13 #include <asm/msr.h>
14 #include <asm/msr-index.h>
15 #include <asm/processor.h>
16 
17 #define LAPIC_DEFAULT_BASE		0xfee00000
18 
19 #define LAPIC_ID			0x020
20 #define LAPIC_LVR			0x030
21 
22 #define LAPIC_TASKPRI			0x080
23 #define LAPIC_TPRI_MASK			0xff
24 
25 #define LAPIC_RRR			0x0c0
26 
27 #define LAPIC_SPIV			0x0f0
28 #define LAPIC_SPIV_ENABLE		0x100
29 
30 #define LAPIC_ICR			0x300
31 #define LAPIC_DEST_SELF			0x40000
32 #define LAPIC_DEST_ALLINC		0x80000
33 #define LAPIC_DEST_ALLBUT		0xc0000
34 #define LAPIC_ICR_RR_MASK		0x30000
35 #define LAPIC_ICR_RR_INVALID		0x00000
36 #define LAPIC_ICR_RR_INPROG		0x10000
37 #define LAPIC_ICR_RR_VALID		0x20000
38 #define LAPIC_INT_LEVELTRIG		0x08000
39 #define LAPIC_INT_ASSERT		0x04000
40 #define LAPIC_ICR_BUSY			0x01000
41 #define LAPIC_DEST_LOGICAL		0x00800
42 #define LAPIC_DM_FIXED			0x00000
43 #define LAPIC_DM_LOWEST			0x00100
44 #define LAPIC_DM_SMI			0x00200
45 #define LAPIC_DM_REMRD			0x00300
46 #define LAPIC_DM_NMI			0x00400
47 #define LAPIC_DM_INIT			0x00500
48 #define LAPIC_DM_STARTUP		0x00600
49 #define LAPIC_DM_EXTINT			0x00700
50 #define LAPIC_VECTOR_MASK		0x000ff
51 
52 #define LAPIC_ICR2			0x310
53 #define GET_LAPIC_DEST_FIELD(x)		(((x) >> 24) & 0xff)
54 #define SET_LAPIC_DEST_FIELD(x)		((x) << 24)
55 
56 #define LAPIC_LVT0			0x350
57 #define LAPIC_LVT1			0x360
58 #define LAPIC_LVT_MASKED		(1 << 16)
59 #define LAPIC_LVT_LEVEL_TRIGGER		(1 << 15)
60 #define LAPIC_LVT_REMOTE_IRR		(1 << 14)
61 #define LAPIC_INPUT_POLARITY		(1 << 13)
62 #define LAPIC_SEND_PENDING		(1 << 12)
63 #define LAPIC_LVT_RESERVED_1		(1 << 11)
64 #define LAPIC_DELIVERY_MODE_MASK	(7 << 8)
65 #define LAPIC_DELIVERY_MODE_FIXED	(0 << 8)
66 #define LAPIC_DELIVERY_MODE_NMI		(4 << 8)
67 #define LAPIC_DELIVERY_MODE_EXTINT	(7 << 8)
68 
69 static inline __attribute__((always_inline))
70 		unsigned long lapic_read(unsigned long reg)
71 {
72 	return readl(LAPIC_DEFAULT_BASE + reg);
73 }
74 
75 static inline __attribute__((always_inline))
76 		void lapic_write(unsigned long reg, unsigned long val)
77 {
78 	writel(val, LAPIC_DEFAULT_BASE + reg);
79 }
80 
81 static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void)
82 {
83 	do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
84 }
85 
86 static inline void enable_lapic(void)
87 {
88 	msr_t msr;
89 
90 	msr = msr_read(MSR_IA32_APICBASE);
91 	msr.hi &= 0xffffff00;
92 	msr.lo |= MSR_IA32_APICBASE_ENABLE;
93 	msr.lo &= ~MSR_IA32_APICBASE_BASE;
94 	msr.lo |= LAPIC_DEFAULT_BASE;
95 	msr_write(MSR_IA32_APICBASE, msr);
96 }
97 
98 static inline void disable_lapic(void)
99 {
100 	msr_t msr;
101 
102 	msr = msr_read(MSR_IA32_APICBASE);
103 	msr.lo &= ~MSR_IA32_APICBASE_ENABLE;
104 	msr_write(MSR_IA32_APICBASE, msr);
105 }
106 
107 static inline __attribute__((always_inline)) unsigned long lapicid(void)
108 {
109 	return lapic_read(LAPIC_ID) >> 24;
110 }
111 
112 static inline __attribute__((always_inline)) void stop_this_cpu(void)
113 {
114 	/* Called by an AP when it is ready to halt and wait for a new task */
115 	for (;;)
116 		cpu_hlt();
117 }
118 
119 #define xchg(ptr, v)	((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
120 						    sizeof(*(ptr))))
121 
122 struct __xchg_dummy	{ unsigned long a[100]; };
123 #define __xg(x)		((struct __xchg_dummy *)(x))
124 
125 /*
126  * Note: no "lock" prefix even on SMP. xchg always implies lock anyway.
127  *
128  * Note 2: xchg has side effect, so that attribute volatile is necessary,
129  *         but generally the primitive is invalid, *ptr is output argument.
130  */
131 static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
132 				   int size)
133 {
134 	switch (size) {
135 	case 1:
136 		__asm__ __volatile__("xchgb %b0,%1"
137 			: "=q" (x)
138 			: "m" (*__xg(ptr)), "0" (x)
139 			: "memory");
140 		break;
141 	case 2:
142 		__asm__ __volatile__("xchgw %w0,%1"
143 			: "=r" (x)
144 			: "m" (*__xg(ptr)), "0" (x)
145 			: "memory");
146 		break;
147 	case 4:
148 		__asm__ __volatile__("xchgl %0,%1"
149 			: "=r" (x)
150 			: "m" (*__xg(ptr)), "0" (x)
151 			: "memory");
152 		break;
153 	}
154 
155 	return x;
156 }
157 
158 static inline void lapic_write_atomic(unsigned long reg, unsigned long v)
159 {
160 	(void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
161 }
162 
163 #define lapic_read_around(x)		lapic_read(x)
164 #define lapic_write_around(x, y)	lapic_write_atomic((x), (y))
165 
166 static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
167 {
168 	int timeout;
169 	unsigned long status;
170 	int result;
171 
172 	lapic_wait_icr_idle();
173 	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
174 	lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
175 
176 	timeout = 0;
177 	do {
178 		status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
179 	} while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
180 
181 	result = -1;
182 	if (status == LAPIC_ICR_RR_VALID) {
183 		*pvalue = lapic_read(LAPIC_RRR);
184 		result = 0;
185 	}
186 
187 	return result;
188 }
189 
190 void lapic_setup(void);
191 
192 #endif
193