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>
11a2d73fdbSBin Meng #include <asm/io.h>
120c9075e9SSimon Glass #include <asm/lapic.h>
13a2d73fdbSBin Meng #include <asm/msr.h>
14a2d73fdbSBin Meng #include <asm/msr-index.h>
150c9075e9SSimon Glass #include <asm/post.h>
160c9075e9SSimon Glass
lapic_read(unsigned long reg)17a2d73fdbSBin Meng unsigned long lapic_read(unsigned long reg)
18a2d73fdbSBin Meng {
19a2d73fdbSBin Meng return readl(LAPIC_DEFAULT_BASE + reg);
20a2d73fdbSBin Meng }
21a2d73fdbSBin Meng
22a2d73fdbSBin Meng #define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
23a2d73fdbSBin Meng sizeof(*(ptr))))
24a2d73fdbSBin Meng
25a2d73fdbSBin Meng struct __xchg_dummy { unsigned long a[100]; };
26a2d73fdbSBin Meng #define __xg(x) ((struct __xchg_dummy *)(x))
27a2d73fdbSBin Meng
28a2d73fdbSBin Meng /*
29a2d73fdbSBin Meng * Note: no "lock" prefix even on SMP. xchg always implies lock anyway.
30a2d73fdbSBin Meng *
31a2d73fdbSBin Meng * Note 2: xchg has side effect, so that attribute volatile is necessary,
32a2d73fdbSBin Meng * but generally the primitive is invalid, *ptr is output argument.
33a2d73fdbSBin Meng */
__xchg(unsigned long x,volatile void * ptr,int size)34a2d73fdbSBin Meng static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
35a2d73fdbSBin Meng int size)
36a2d73fdbSBin Meng {
37a2d73fdbSBin Meng switch (size) {
38a2d73fdbSBin Meng case 1:
39a2d73fdbSBin Meng __asm__ __volatile__("xchgb %b0,%1"
40a2d73fdbSBin Meng : "=q" (x)
41a2d73fdbSBin Meng : "m" (*__xg(ptr)), "0" (x)
42a2d73fdbSBin Meng : "memory");
43a2d73fdbSBin Meng break;
44a2d73fdbSBin Meng case 2:
45a2d73fdbSBin Meng __asm__ __volatile__("xchgw %w0,%1"
46a2d73fdbSBin Meng : "=r" (x)
47a2d73fdbSBin Meng : "m" (*__xg(ptr)), "0" (x)
48a2d73fdbSBin Meng : "memory");
49a2d73fdbSBin Meng break;
50a2d73fdbSBin Meng case 4:
51a2d73fdbSBin Meng __asm__ __volatile__("xchgl %0,%1"
52a2d73fdbSBin Meng : "=r" (x)
53a2d73fdbSBin Meng : "m" (*__xg(ptr)), "0" (x)
54a2d73fdbSBin Meng : "memory");
55a2d73fdbSBin Meng break;
56a2d73fdbSBin Meng }
57a2d73fdbSBin Meng
58a2d73fdbSBin Meng return x;
59a2d73fdbSBin Meng }
60a2d73fdbSBin Meng
lapic_write(unsigned long reg,unsigned long v)61a2d73fdbSBin Meng void lapic_write(unsigned long reg, unsigned long v)
62a2d73fdbSBin Meng {
63a2d73fdbSBin Meng (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
64a2d73fdbSBin Meng }
65a2d73fdbSBin Meng
enable_lapic(void)66a2d73fdbSBin Meng void enable_lapic(void)
67a2d73fdbSBin Meng {
683299be24SBin Meng if (!IS_ENABLED(CONFIG_INTEL_QUARK)) {
69a2d73fdbSBin Meng msr_t msr;
70a2d73fdbSBin Meng
71a2d73fdbSBin Meng msr = msr_read(MSR_IA32_APICBASE);
72a2d73fdbSBin Meng msr.hi &= 0xffffff00;
73a2d73fdbSBin Meng msr.lo |= MSR_IA32_APICBASE_ENABLE;
74a2d73fdbSBin Meng msr.lo &= ~MSR_IA32_APICBASE_BASE;
75a2d73fdbSBin Meng msr.lo |= LAPIC_DEFAULT_BASE;
76a2d73fdbSBin Meng msr_write(MSR_IA32_APICBASE, msr);
77a2d73fdbSBin Meng }
783299be24SBin Meng }
79a2d73fdbSBin Meng
disable_lapic(void)80a2d73fdbSBin Meng void disable_lapic(void)
81a2d73fdbSBin Meng {
823299be24SBin Meng if (!IS_ENABLED(CONFIG_INTEL_QUARK)) {
83a2d73fdbSBin Meng msr_t msr;
84a2d73fdbSBin Meng
85a2d73fdbSBin Meng msr = msr_read(MSR_IA32_APICBASE);
86a2d73fdbSBin Meng msr.lo &= ~MSR_IA32_APICBASE_ENABLE;
87a2d73fdbSBin Meng msr_write(MSR_IA32_APICBASE, msr);
88a2d73fdbSBin Meng }
893299be24SBin Meng }
90a2d73fdbSBin Meng
lapicid(void)91a2d73fdbSBin Meng unsigned long lapicid(void)
92a2d73fdbSBin Meng {
93a2d73fdbSBin Meng return lapic_read(LAPIC_ID) >> 24;
94a2d73fdbSBin Meng }
95a2d73fdbSBin Meng
lapic_wait_icr_idle(void)96a2d73fdbSBin Meng static void lapic_wait_icr_idle(void)
97a2d73fdbSBin Meng {
98a2d73fdbSBin Meng do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
99a2d73fdbSBin Meng }
100a2d73fdbSBin Meng
lapic_remote_read(int apicid,int reg,unsigned long * pvalue)101a2d73fdbSBin Meng int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
102a2d73fdbSBin Meng {
103a2d73fdbSBin Meng int timeout;
104a2d73fdbSBin Meng unsigned long status;
105a2d73fdbSBin Meng int result;
106a2d73fdbSBin Meng
107a2d73fdbSBin Meng lapic_wait_icr_idle();
108a2d73fdbSBin Meng lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
109a2d73fdbSBin Meng lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
110a2d73fdbSBin Meng
111a2d73fdbSBin Meng timeout = 0;
112a2d73fdbSBin Meng do {
113a2d73fdbSBin Meng status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
114a2d73fdbSBin Meng } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
115a2d73fdbSBin Meng
116a2d73fdbSBin Meng result = -1;
117a2d73fdbSBin Meng if (status == LAPIC_ICR_RR_VALID) {
118a2d73fdbSBin Meng *pvalue = lapic_read(LAPIC_RRR);
119a2d73fdbSBin Meng result = 0;
120a2d73fdbSBin Meng }
121a2d73fdbSBin Meng
122a2d73fdbSBin Meng return result;
123a2d73fdbSBin Meng }
124a2d73fdbSBin Meng
lapic_setup(void)1250c9075e9SSimon Glass void lapic_setup(void)
1260c9075e9SSimon Glass {
1270c9075e9SSimon Glass /* Only Pentium Pro and later have those MSR stuff */
1280c9075e9SSimon Glass debug("Setting up local apic: ");
1290c9075e9SSimon Glass
1300c9075e9SSimon Glass /* Enable the local apic */
1310c9075e9SSimon Glass enable_lapic();
1320c9075e9SSimon Glass
13363d54a67SBin Meng /* Set Task Priority to 'accept all' */
134a2d73fdbSBin Meng lapic_write(LAPIC_TASKPRI,
135a2d73fdbSBin Meng lapic_read(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK);
1360c9075e9SSimon Glass
1370c9075e9SSimon Glass /* Put the local apic in virtual wire mode */
138a2d73fdbSBin Meng lapic_write(LAPIC_SPIV, (lapic_read(LAPIC_SPIV) &
1390c9075e9SSimon Glass ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE);
140a2d73fdbSBin Meng lapic_write(LAPIC_LVT0, (lapic_read(LAPIC_LVT0) &
1410c9075e9SSimon Glass ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER |
1420c9075e9SSimon Glass LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY |
1430c9075e9SSimon Glass LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 |
1440c9075e9SSimon Glass LAPIC_DELIVERY_MODE_MASK)) |
1450c9075e9SSimon Glass (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING |
1460c9075e9SSimon Glass LAPIC_DELIVERY_MODE_EXTINT));
147a2d73fdbSBin Meng lapic_write(LAPIC_LVT1, (lapic_read(LAPIC_LVT1) &
1480c9075e9SSimon Glass ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER |
1490c9075e9SSimon Glass LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY |
1500c9075e9SSimon Glass LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 |
1510c9075e9SSimon Glass LAPIC_DELIVERY_MODE_MASK)) |
1520c9075e9SSimon Glass (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING |
1530c9075e9SSimon Glass LAPIC_DELIVERY_MODE_NMI));
1540c9075e9SSimon Glass
1550c9075e9SSimon Glass debug("apic_id: 0x%02lx, ", lapicid());
156*aaaa5575SBin Meng
1570c9075e9SSimon Glass debug("done.\n");
1580c9075e9SSimon Glass post_code(POST_LAPIC);
1590c9075e9SSimon Glass }
160