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