xref: /openbmc/u-boot/arch/x86/include/asm/lapic.h (revision 63d54a67)
13eafce05SSimon Glass /*
2*63d54a67SBin Meng  * From coreboot file of same name
33eafce05SSimon Glass  *
43eafce05SSimon Glass  * Copyright (C) 2014 Google, Inc
53eafce05SSimon Glass  *
63eafce05SSimon Glass  * SPDX-License-Identifier:	GPL-2.0
73eafce05SSimon Glass  */
83eafce05SSimon Glass 
93eafce05SSimon Glass #ifndef _ARCH_ASM_LAPIC_H
103eafce05SSimon Glass #define _ARCH_ASM_LAPIC_H
113eafce05SSimon Glass 
123eafce05SSimon Glass #include <asm/io.h>
133eafce05SSimon Glass #include <asm/msr.h>
14*63d54a67SBin Meng #include <asm/msr-index.h>
153eafce05SSimon Glass #include <asm/processor.h>
163eafce05SSimon Glass 
17*63d54a67SBin Meng #define LAPIC_DEFAULT_BASE		0xfee00000
18*63d54a67SBin Meng 
19*63d54a67SBin Meng #define LAPIC_ID			0x020
20*63d54a67SBin Meng #define LAPIC_LVR			0x030
21*63d54a67SBin Meng 
22*63d54a67SBin Meng #define LAPIC_TASKPRI			0x080
23*63d54a67SBin Meng #define LAPIC_TPRI_MASK			0xff
24*63d54a67SBin Meng 
25*63d54a67SBin Meng #define LAPIC_RRR			0x0c0
26*63d54a67SBin Meng 
27*63d54a67SBin Meng #define LAPIC_SPIV			0x0f0
28*63d54a67SBin Meng #define LAPIC_SPIV_ENABLE		0x100
29*63d54a67SBin Meng 
30*63d54a67SBin Meng #define LAPIC_ICR			0x300
31*63d54a67SBin Meng #define LAPIC_DEST_SELF			0x40000
32*63d54a67SBin Meng #define LAPIC_DEST_ALLINC		0x80000
33*63d54a67SBin Meng #define LAPIC_DEST_ALLBUT		0xc0000
34*63d54a67SBin Meng #define LAPIC_ICR_RR_MASK		0x30000
35*63d54a67SBin Meng #define LAPIC_ICR_RR_INVALID		0x00000
36*63d54a67SBin Meng #define LAPIC_ICR_RR_INPROG		0x10000
37*63d54a67SBin Meng #define LAPIC_ICR_RR_VALID		0x20000
38*63d54a67SBin Meng #define LAPIC_INT_LEVELTRIG		0x08000
39*63d54a67SBin Meng #define LAPIC_INT_ASSERT		0x04000
40*63d54a67SBin Meng #define LAPIC_ICR_BUSY			0x01000
41*63d54a67SBin Meng #define LAPIC_DEST_LOGICAL		0x00800
42*63d54a67SBin Meng #define LAPIC_DM_FIXED			0x00000
43*63d54a67SBin Meng #define LAPIC_DM_LOWEST			0x00100
44*63d54a67SBin Meng #define LAPIC_DM_SMI			0x00200
45*63d54a67SBin Meng #define LAPIC_DM_REMRD			0x00300
46*63d54a67SBin Meng #define LAPIC_DM_NMI			0x00400
47*63d54a67SBin Meng #define LAPIC_DM_INIT			0x00500
48*63d54a67SBin Meng #define LAPIC_DM_STARTUP		0x00600
49*63d54a67SBin Meng #define LAPIC_DM_EXTINT			0x00700
50*63d54a67SBin Meng #define LAPIC_VECTOR_MASK		0x000ff
51*63d54a67SBin Meng 
52*63d54a67SBin Meng #define LAPIC_ICR2			0x310
53*63d54a67SBin Meng #define GET_LAPIC_DEST_FIELD(x)		(((x) >> 24) & 0xff)
54*63d54a67SBin Meng #define SET_LAPIC_DEST_FIELD(x)		((x) << 24)
55*63d54a67SBin Meng 
56*63d54a67SBin Meng #define LAPIC_LVT0			0x350
57*63d54a67SBin Meng #define LAPIC_LVT1			0x360
58*63d54a67SBin Meng #define LAPIC_LVT_MASKED		(1 << 16)
59*63d54a67SBin Meng #define LAPIC_LVT_LEVEL_TRIGGER		(1 << 15)
60*63d54a67SBin Meng #define LAPIC_LVT_REMOTE_IRR		(1 << 14)
61*63d54a67SBin Meng #define LAPIC_INPUT_POLARITY		(1 << 13)
62*63d54a67SBin Meng #define LAPIC_SEND_PENDING		(1 << 12)
63*63d54a67SBin Meng #define LAPIC_LVT_RESERVED_1		(1 << 11)
64*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_MASK	(7 << 8)
65*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_FIXED	(0 << 8)
66*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_NMI		(4 << 8)
67*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_EXTINT	(7 << 8)
680c9075e9SSimon Glass 
693eafce05SSimon Glass static inline __attribute__((always_inline))
703eafce05SSimon Glass 		unsigned long lapic_read(unsigned long reg)
713eafce05SSimon Glass {
723eafce05SSimon Glass 	return readl(LAPIC_DEFAULT_BASE + reg);
733eafce05SSimon Glass }
743eafce05SSimon Glass 
753eafce05SSimon Glass static inline __attribute__((always_inline))
763eafce05SSimon Glass 		void lapic_write(unsigned long reg, unsigned long val)
773eafce05SSimon Glass {
783eafce05SSimon Glass 	writel(val, LAPIC_DEFAULT_BASE + reg);
793eafce05SSimon Glass }
803eafce05SSimon Glass 
813eafce05SSimon Glass static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void)
823eafce05SSimon Glass {
833eafce05SSimon Glass 	do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
843eafce05SSimon Glass }
853eafce05SSimon Glass 
863eafce05SSimon Glass static inline void enable_lapic(void)
873eafce05SSimon Glass {
883eafce05SSimon Glass 	msr_t msr;
893eafce05SSimon Glass 
90*63d54a67SBin Meng 	msr = msr_read(MSR_IA32_APICBASE);
913eafce05SSimon Glass 	msr.hi &= 0xffffff00;
92*63d54a67SBin Meng 	msr.lo |= MSR_IA32_APICBASE_ENABLE;
93*63d54a67SBin Meng 	msr.lo &= ~MSR_IA32_APICBASE_BASE;
940c9075e9SSimon Glass 	msr.lo |= LAPIC_DEFAULT_BASE;
95*63d54a67SBin Meng 	msr_write(MSR_IA32_APICBASE, msr);
963eafce05SSimon Glass }
973eafce05SSimon Glass 
983eafce05SSimon Glass static inline void disable_lapic(void)
993eafce05SSimon Glass {
1003eafce05SSimon Glass 	msr_t msr;
1013eafce05SSimon Glass 
102*63d54a67SBin Meng 	msr = msr_read(MSR_IA32_APICBASE);
103*63d54a67SBin Meng 	msr.lo &= ~MSR_IA32_APICBASE_ENABLE;
104*63d54a67SBin Meng 	msr_write(MSR_IA32_APICBASE, msr);
1053eafce05SSimon Glass }
1063eafce05SSimon Glass 
1073eafce05SSimon Glass static inline __attribute__((always_inline)) unsigned long lapicid(void)
1083eafce05SSimon Glass {
1093eafce05SSimon Glass 	return lapic_read(LAPIC_ID) >> 24;
1103eafce05SSimon Glass }
1113eafce05SSimon Glass 
1120c9075e9SSimon Glass static inline __attribute__((always_inline)) void stop_this_cpu(void)
1130c9075e9SSimon Glass {
1140c9075e9SSimon Glass 	/* Called by an AP when it is ready to halt and wait for a new task */
1150c9075e9SSimon Glass 	for (;;)
1160c9075e9SSimon Glass 		cpu_hlt();
1170c9075e9SSimon Glass }
1180c9075e9SSimon Glass 
1190c9075e9SSimon Glass #define xchg(ptr, v)	((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
1200c9075e9SSimon Glass 						    sizeof(*(ptr))))
1210c9075e9SSimon Glass 
1220c9075e9SSimon Glass struct __xchg_dummy	{ unsigned long a[100]; };
1230c9075e9SSimon Glass #define __xg(x)		((struct __xchg_dummy *)(x))
1240c9075e9SSimon Glass 
1250c9075e9SSimon Glass /*
126*63d54a67SBin Meng  * Note: no "lock" prefix even on SMP. xchg always implies lock anyway.
127*63d54a67SBin Meng  *
1280c9075e9SSimon Glass  * Note 2: xchg has side effect, so that attribute volatile is necessary,
129*63d54a67SBin Meng  *         but generally the primitive is invalid, *ptr is output argument.
1300c9075e9SSimon Glass  */
1310c9075e9SSimon Glass static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
1320c9075e9SSimon Glass 				   int size)
1330c9075e9SSimon Glass {
1340c9075e9SSimon Glass 	switch (size) {
1350c9075e9SSimon Glass 	case 1:
1360c9075e9SSimon Glass 		__asm__ __volatile__("xchgb %b0,%1"
1370c9075e9SSimon Glass 			: "=q" (x)
1380c9075e9SSimon Glass 			: "m" (*__xg(ptr)), "0" (x)
1390c9075e9SSimon Glass 			: "memory");
1400c9075e9SSimon Glass 		break;
1410c9075e9SSimon Glass 	case 2:
1420c9075e9SSimon Glass 		__asm__ __volatile__("xchgw %w0,%1"
1430c9075e9SSimon Glass 			: "=r" (x)
1440c9075e9SSimon Glass 			: "m" (*__xg(ptr)), "0" (x)
1450c9075e9SSimon Glass 			: "memory");
1460c9075e9SSimon Glass 		break;
1470c9075e9SSimon Glass 	case 4:
1480c9075e9SSimon Glass 		__asm__ __volatile__("xchgl %0,%1"
1490c9075e9SSimon Glass 			: "=r" (x)
1500c9075e9SSimon Glass 			: "m" (*__xg(ptr)), "0" (x)
1510c9075e9SSimon Glass 			: "memory");
1520c9075e9SSimon Glass 		break;
1530c9075e9SSimon Glass 	}
1540c9075e9SSimon Glass 
1550c9075e9SSimon Glass 	return x;
1560c9075e9SSimon Glass }
1570c9075e9SSimon Glass 
1580c9075e9SSimon Glass static inline void lapic_write_atomic(unsigned long reg, unsigned long v)
1590c9075e9SSimon Glass {
1600c9075e9SSimon Glass 	(void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
1610c9075e9SSimon Glass }
1620c9075e9SSimon Glass 
1630c9075e9SSimon Glass #define lapic_read_around(x)		lapic_read(x)
1640c9075e9SSimon Glass #define lapic_write_around(x, y)	lapic_write_atomic((x), (y))
1650c9075e9SSimon Glass 
1660c9075e9SSimon Glass static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
1670c9075e9SSimon Glass {
1680c9075e9SSimon Glass 	int timeout;
1690c9075e9SSimon Glass 	unsigned long status;
1700c9075e9SSimon Glass 	int result;
171*63d54a67SBin Meng 
1720c9075e9SSimon Glass 	lapic_wait_icr_idle();
1730c9075e9SSimon Glass 	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
1740c9075e9SSimon Glass 	lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
175*63d54a67SBin Meng 
1760c9075e9SSimon Glass 	timeout = 0;
1770c9075e9SSimon Glass 	do {
1780c9075e9SSimon Glass 		status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
1790c9075e9SSimon Glass 	} while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
1800c9075e9SSimon Glass 
1810c9075e9SSimon Glass 	result = -1;
1820c9075e9SSimon Glass 	if (status == LAPIC_ICR_RR_VALID) {
1830c9075e9SSimon Glass 		*pvalue = lapic_read(LAPIC_RRR);
1840c9075e9SSimon Glass 		result = 0;
1850c9075e9SSimon Glass 	}
186*63d54a67SBin Meng 
1870c9075e9SSimon Glass 	return result;
1880c9075e9SSimon Glass }
1890c9075e9SSimon Glass 
1900c9075e9SSimon Glass void lapic_setup(void);
1910c9075e9SSimon Glass 
1923eafce05SSimon Glass #endif
193