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