xref: /rk3399_rockchip-uboot/arch/x86/cpu/lapic.c (revision dc557e9a1fe00ca9d884bd88feef5bebf23fede4)
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