xref: /openbmc/u-boot/arch/x86/cpu/lapic.c (revision a2d73fdb)
10c9075e9SSimon Glass /*
20c9075e9SSimon Glass  * From coreboot file of same name
30c9075e9SSimon Glass  *
40c9075e9SSimon Glass  * Copyright (C) 2008-2009 coresystems GmbH
50c9075e9SSimon Glass  * Copyright (C) 2014 Google, Inc
60c9075e9SSimon Glass  *
70c9075e9SSimon Glass  * SPDX-License-Identifier:	GPL-2.0
80c9075e9SSimon Glass  */
90c9075e9SSimon Glass 
100c9075e9SSimon Glass #include <common.h>
11*a2d73fdbSBin Meng #include <asm/io.h>
120c9075e9SSimon Glass #include <asm/lapic.h>
13*a2d73fdbSBin Meng #include <asm/msr.h>
14*a2d73fdbSBin Meng #include <asm/msr-index.h>
150c9075e9SSimon Glass #include <asm/post.h>
160c9075e9SSimon Glass 
17*a2d73fdbSBin Meng unsigned long lapic_read(unsigned long reg)
18*a2d73fdbSBin Meng {
19*a2d73fdbSBin Meng 	return readl(LAPIC_DEFAULT_BASE + reg);
20*a2d73fdbSBin Meng }
21*a2d73fdbSBin Meng 
22*a2d73fdbSBin Meng #define xchg(ptr, v)	((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
23*a2d73fdbSBin Meng 						    sizeof(*(ptr))))
24*a2d73fdbSBin Meng 
25*a2d73fdbSBin Meng struct __xchg_dummy	{ unsigned long a[100]; };
26*a2d73fdbSBin Meng #define __xg(x)		((struct __xchg_dummy *)(x))
27*a2d73fdbSBin Meng 
28*a2d73fdbSBin Meng /*
29*a2d73fdbSBin Meng  * Note: no "lock" prefix even on SMP. xchg always implies lock anyway.
30*a2d73fdbSBin Meng  *
31*a2d73fdbSBin Meng  * Note 2: xchg has side effect, so that attribute volatile is necessary,
32*a2d73fdbSBin Meng  *         but generally the primitive is invalid, *ptr is output argument.
33*a2d73fdbSBin Meng  */
34*a2d73fdbSBin Meng static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
35*a2d73fdbSBin Meng 				   int size)
36*a2d73fdbSBin Meng {
37*a2d73fdbSBin Meng 	switch (size) {
38*a2d73fdbSBin Meng 	case 1:
39*a2d73fdbSBin Meng 		__asm__ __volatile__("xchgb %b0,%1"
40*a2d73fdbSBin Meng 			: "=q" (x)
41*a2d73fdbSBin Meng 			: "m" (*__xg(ptr)), "0" (x)
42*a2d73fdbSBin Meng 			: "memory");
43*a2d73fdbSBin Meng 		break;
44*a2d73fdbSBin Meng 	case 2:
45*a2d73fdbSBin Meng 		__asm__ __volatile__("xchgw %w0,%1"
46*a2d73fdbSBin Meng 			: "=r" (x)
47*a2d73fdbSBin Meng 			: "m" (*__xg(ptr)), "0" (x)
48*a2d73fdbSBin Meng 			: "memory");
49*a2d73fdbSBin Meng 		break;
50*a2d73fdbSBin Meng 	case 4:
51*a2d73fdbSBin Meng 		__asm__ __volatile__("xchgl %0,%1"
52*a2d73fdbSBin Meng 			: "=r" (x)
53*a2d73fdbSBin Meng 			: "m" (*__xg(ptr)), "0" (x)
54*a2d73fdbSBin Meng 			: "memory");
55*a2d73fdbSBin Meng 		break;
56*a2d73fdbSBin Meng 	}
57*a2d73fdbSBin Meng 
58*a2d73fdbSBin Meng 	return x;
59*a2d73fdbSBin Meng }
60*a2d73fdbSBin Meng 
61*a2d73fdbSBin Meng void lapic_write(unsigned long reg, unsigned long v)
62*a2d73fdbSBin Meng {
63*a2d73fdbSBin Meng 	(void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
64*a2d73fdbSBin Meng }
65*a2d73fdbSBin Meng 
66*a2d73fdbSBin Meng void enable_lapic(void)
67*a2d73fdbSBin Meng {
68*a2d73fdbSBin Meng 	msr_t msr;
69*a2d73fdbSBin Meng 
70*a2d73fdbSBin Meng 	msr = msr_read(MSR_IA32_APICBASE);
71*a2d73fdbSBin Meng 	msr.hi &= 0xffffff00;
72*a2d73fdbSBin Meng 	msr.lo |= MSR_IA32_APICBASE_ENABLE;
73*a2d73fdbSBin Meng 	msr.lo &= ~MSR_IA32_APICBASE_BASE;
74*a2d73fdbSBin Meng 	msr.lo |= LAPIC_DEFAULT_BASE;
75*a2d73fdbSBin Meng 	msr_write(MSR_IA32_APICBASE, msr);
76*a2d73fdbSBin Meng }
77*a2d73fdbSBin Meng 
78*a2d73fdbSBin Meng void disable_lapic(void)
79*a2d73fdbSBin Meng {
80*a2d73fdbSBin Meng 	msr_t msr;
81*a2d73fdbSBin Meng 
82*a2d73fdbSBin Meng 	msr = msr_read(MSR_IA32_APICBASE);
83*a2d73fdbSBin Meng 	msr.lo &= ~MSR_IA32_APICBASE_ENABLE;
84*a2d73fdbSBin Meng 	msr_write(MSR_IA32_APICBASE, msr);
85*a2d73fdbSBin Meng }
86*a2d73fdbSBin Meng 
87*a2d73fdbSBin Meng unsigned long lapicid(void)
88*a2d73fdbSBin Meng {
89*a2d73fdbSBin Meng 	return lapic_read(LAPIC_ID) >> 24;
90*a2d73fdbSBin Meng }
91*a2d73fdbSBin Meng 
92*a2d73fdbSBin Meng static void lapic_wait_icr_idle(void)
93*a2d73fdbSBin Meng {
94*a2d73fdbSBin Meng 	do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
95*a2d73fdbSBin Meng }
96*a2d73fdbSBin Meng 
97*a2d73fdbSBin Meng int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
98*a2d73fdbSBin Meng {
99*a2d73fdbSBin Meng 	int timeout;
100*a2d73fdbSBin Meng 	unsigned long status;
101*a2d73fdbSBin Meng 	int result;
102*a2d73fdbSBin Meng 
103*a2d73fdbSBin Meng 	lapic_wait_icr_idle();
104*a2d73fdbSBin Meng 	lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
105*a2d73fdbSBin Meng 	lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
106*a2d73fdbSBin Meng 
107*a2d73fdbSBin Meng 	timeout = 0;
108*a2d73fdbSBin Meng 	do {
109*a2d73fdbSBin Meng 		status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
110*a2d73fdbSBin Meng 	} while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
111*a2d73fdbSBin Meng 
112*a2d73fdbSBin Meng 	result = -1;
113*a2d73fdbSBin Meng 	if (status == LAPIC_ICR_RR_VALID) {
114*a2d73fdbSBin Meng 		*pvalue = lapic_read(LAPIC_RRR);
115*a2d73fdbSBin Meng 		result = 0;
116*a2d73fdbSBin Meng 	}
117*a2d73fdbSBin Meng 
118*a2d73fdbSBin Meng 	return result;
119*a2d73fdbSBin Meng }
120*a2d73fdbSBin Meng 
1210c9075e9SSimon Glass void lapic_setup(void)
1220c9075e9SSimon Glass {
12363d54a67SBin Meng #ifdef CONFIG_SMP
1240c9075e9SSimon Glass 	/* Only Pentium Pro and later have those MSR stuff */
1250c9075e9SSimon Glass 	debug("Setting up local apic: ");
1260c9075e9SSimon Glass 
1270c9075e9SSimon Glass 	/* Enable the local apic */
1280c9075e9SSimon Glass 	enable_lapic();
1290c9075e9SSimon Glass 
13063d54a67SBin Meng 	/* Set Task Priority to 'accept all' */
131*a2d73fdbSBin Meng 	lapic_write(LAPIC_TASKPRI,
132*a2d73fdbSBin Meng 		    lapic_read(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK);
1330c9075e9SSimon Glass 
1340c9075e9SSimon Glass 	/* Put the local apic in virtual wire mode */
135*a2d73fdbSBin Meng 	lapic_write(LAPIC_SPIV, (lapic_read(LAPIC_SPIV) &
1360c9075e9SSimon Glass 		    ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE);
137*a2d73fdbSBin Meng 	lapic_write(LAPIC_LVT0, (lapic_read(LAPIC_LVT0) &
1380c9075e9SSimon Glass 		    ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER |
1390c9075e9SSimon Glass 		    LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY |
1400c9075e9SSimon Glass 		    LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 |
1410c9075e9SSimon Glass 		    LAPIC_DELIVERY_MODE_MASK)) |
1420c9075e9SSimon Glass 		    (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING |
1430c9075e9SSimon Glass 		    LAPIC_DELIVERY_MODE_EXTINT));
144*a2d73fdbSBin Meng 	lapic_write(LAPIC_LVT1, (lapic_read(LAPIC_LVT1) &
1450c9075e9SSimon Glass 		    ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER |
1460c9075e9SSimon Glass 		    LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY |
1470c9075e9SSimon Glass 		    LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 |
1480c9075e9SSimon Glass 		    LAPIC_DELIVERY_MODE_MASK)) |
1490c9075e9SSimon Glass 		    (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING |
1500c9075e9SSimon Glass 		    LAPIC_DELIVERY_MODE_NMI));
1510c9075e9SSimon Glass 
1520c9075e9SSimon Glass 	debug("apic_id: 0x%02lx, ", lapicid());
15363d54a67SBin Meng #else /* !CONFIG_SMP */
1540c9075e9SSimon Glass 	/* Only Pentium Pro and later have those MSR stuff */
1550c9075e9SSimon Glass 	debug("Disabling local apic: ");
1560c9075e9SSimon Glass 	disable_lapic();
15763d54a67SBin Meng #endif /* CONFIG_SMP */
1580c9075e9SSimon Glass 	debug("done.\n");
1590c9075e9SSimon Glass 	post_code(POST_LAPIC);
1600c9075e9SSimon Glass }
161