blob: f60974a878aa8d48979ae404bdd83b517c54fab6 [file] [log] [blame]
Simon Glass3eafce02014-11-12 22:42:27 -07001/*
Bin Meng63d54a62015-06-17 11:15:38 +08002 * From coreboot file of same name
Simon Glass3eafce02014-11-12 22:42:27 -07003 *
4 * Copyright (C) 2014 Google, Inc
5 *
6 * SPDX-License-Identifier: GPL-2.0
7 */
8
9#ifndef _ARCH_ASM_LAPIC_H
10#define _ARCH_ASM_LAPIC_H
11
12#include <asm/io.h>
Simon Glass3eafce02014-11-12 22:42:27 -070013#include <asm/msr.h>
Bin Meng63d54a62015-06-17 11:15:38 +080014#include <asm/msr-index.h>
Simon Glass3eafce02014-11-12 22:42:27 -070015#include <asm/processor.h>
16
Bin Meng63d54a62015-06-17 11:15:38 +080017#define LAPIC_DEFAULT_BASE 0xfee00000
18
19#define LAPIC_ID 0x020
20#define LAPIC_LVR 0x030
21
22#define LAPIC_TASKPRI 0x080
23#define LAPIC_TPRI_MASK 0xff
24
25#define LAPIC_RRR 0x0c0
26
27#define LAPIC_SPIV 0x0f0
28#define LAPIC_SPIV_ENABLE 0x100
29
30#define LAPIC_ICR 0x300
31#define LAPIC_DEST_SELF 0x40000
32#define LAPIC_DEST_ALLINC 0x80000
33#define LAPIC_DEST_ALLBUT 0xc0000
34#define LAPIC_ICR_RR_MASK 0x30000
35#define LAPIC_ICR_RR_INVALID 0x00000
36#define LAPIC_ICR_RR_INPROG 0x10000
37#define LAPIC_ICR_RR_VALID 0x20000
38#define LAPIC_INT_LEVELTRIG 0x08000
39#define LAPIC_INT_ASSERT 0x04000
40#define LAPIC_ICR_BUSY 0x01000
41#define LAPIC_DEST_LOGICAL 0x00800
42#define LAPIC_DM_FIXED 0x00000
43#define LAPIC_DM_LOWEST 0x00100
44#define LAPIC_DM_SMI 0x00200
45#define LAPIC_DM_REMRD 0x00300
46#define LAPIC_DM_NMI 0x00400
47#define LAPIC_DM_INIT 0x00500
48#define LAPIC_DM_STARTUP 0x00600
49#define LAPIC_DM_EXTINT 0x00700
50#define LAPIC_VECTOR_MASK 0x000ff
51
52#define LAPIC_ICR2 0x310
53#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xff)
54#define SET_LAPIC_DEST_FIELD(x) ((x) << 24)
55
56#define LAPIC_LVT0 0x350
57#define LAPIC_LVT1 0x360
58#define LAPIC_LVT_MASKED (1 << 16)
59#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15)
60#define LAPIC_LVT_REMOTE_IRR (1 << 14)
61#define LAPIC_INPUT_POLARITY (1 << 13)
62#define LAPIC_SEND_PENDING (1 << 12)
63#define LAPIC_LVT_RESERVED_1 (1 << 11)
64#define LAPIC_DELIVERY_MODE_MASK (7 << 8)
65#define LAPIC_DELIVERY_MODE_FIXED (0 << 8)
66#define LAPIC_DELIVERY_MODE_NMI (4 << 8)
67#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8)
Simon Glass0c9075e2014-11-24 21:18:15 -070068
Simon Glass3eafce02014-11-12 22:42:27 -070069static inline __attribute__((always_inline))
70 unsigned long lapic_read(unsigned long reg)
71{
72 return readl(LAPIC_DEFAULT_BASE + reg);
73}
74
75static inline __attribute__((always_inline))
76 void lapic_write(unsigned long reg, unsigned long val)
77{
78 writel(val, LAPIC_DEFAULT_BASE + reg);
79}
80
81static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void)
82{
83 do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
84}
85
86static inline void enable_lapic(void)
87{
88 msr_t msr;
89
Bin Meng63d54a62015-06-17 11:15:38 +080090 msr = msr_read(MSR_IA32_APICBASE);
Simon Glass3eafce02014-11-12 22:42:27 -070091 msr.hi &= 0xffffff00;
Bin Meng63d54a62015-06-17 11:15:38 +080092 msr.lo |= MSR_IA32_APICBASE_ENABLE;
93 msr.lo &= ~MSR_IA32_APICBASE_BASE;
Simon Glass0c9075e2014-11-24 21:18:15 -070094 msr.lo |= LAPIC_DEFAULT_BASE;
Bin Meng63d54a62015-06-17 11:15:38 +080095 msr_write(MSR_IA32_APICBASE, msr);
Simon Glass3eafce02014-11-12 22:42:27 -070096}
97
98static inline void disable_lapic(void)
99{
100 msr_t msr;
101
Bin Meng63d54a62015-06-17 11:15:38 +0800102 msr = msr_read(MSR_IA32_APICBASE);
103 msr.lo &= ~MSR_IA32_APICBASE_ENABLE;
104 msr_write(MSR_IA32_APICBASE, msr);
Simon Glass3eafce02014-11-12 22:42:27 -0700105}
106
107static inline __attribute__((always_inline)) unsigned long lapicid(void)
108{
109 return lapic_read(LAPIC_ID) >> 24;
110}
111
Simon Glass0c9075e2014-11-24 21:18:15 -0700112static inline __attribute__((always_inline)) void stop_this_cpu(void)
113{
114 /* Called by an AP when it is ready to halt and wait for a new task */
115 for (;;)
116 cpu_hlt();
117}
Simon Glass0c9075e2014-11-24 21:18:15 -0700118
Bin Meng63d54a62015-06-17 11:15:38 +0800119#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
120 sizeof(*(ptr))))
Simon Glass0c9075e2014-11-24 21:18:15 -0700121
Bin Meng63d54a62015-06-17 11:15:38 +0800122struct __xchg_dummy { unsigned long a[100]; };
123#define __xg(x) ((struct __xchg_dummy *)(x))
Simon Glass0c9075e2014-11-24 21:18:15 -0700124
125/*
Bin Meng63d54a62015-06-17 11:15:38 +0800126 * Note: no "lock" prefix even on SMP. xchg always implies lock anyway.
127 *
Simon Glass0c9075e2014-11-24 21:18:15 -0700128 * Note 2: xchg has side effect, so that attribute volatile is necessary,
Bin Meng63d54a62015-06-17 11:15:38 +0800129 * but generally the primitive is invalid, *ptr is output argument.
Simon Glass0c9075e2014-11-24 21:18:15 -0700130 */
131static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
132 int size)
133{
134 switch (size) {
135 case 1:
136 __asm__ __volatile__("xchgb %b0,%1"
137 : "=q" (x)
138 : "m" (*__xg(ptr)), "0" (x)
139 : "memory");
140 break;
141 case 2:
142 __asm__ __volatile__("xchgw %w0,%1"
143 : "=r" (x)
144 : "m" (*__xg(ptr)), "0" (x)
145 : "memory");
146 break;
147 case 4:
148 __asm__ __volatile__("xchgl %0,%1"
149 : "=r" (x)
150 : "m" (*__xg(ptr)), "0" (x)
151 : "memory");
152 break;
153 }
154
155 return x;
156}
157
158static inline void lapic_write_atomic(unsigned long reg, unsigned long v)
159{
160 (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
161}
162
Bin Meng63d54a62015-06-17 11:15:38 +0800163#define lapic_read_around(x) lapic_read(x)
164#define lapic_write_around(x, y) lapic_write_atomic((x), (y))
Simon Glass0c9075e2014-11-24 21:18:15 -0700165
166static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
167{
168 int timeout;
169 unsigned long status;
170 int result;
Bin Meng63d54a62015-06-17 11:15:38 +0800171
Simon Glass0c9075e2014-11-24 21:18:15 -0700172 lapic_wait_icr_idle();
173 lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
174 lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
Bin Meng63d54a62015-06-17 11:15:38 +0800175
Simon Glass0c9075e2014-11-24 21:18:15 -0700176 timeout = 0;
177 do {
178 status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
179 } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
180
181 result = -1;
182 if (status == LAPIC_ICR_RR_VALID) {
183 *pvalue = lapic_read(LAPIC_RRR);
184 result = 0;
185 }
Bin Meng63d54a62015-06-17 11:15:38 +0800186
Simon Glass0c9075e2014-11-24 21:18:15 -0700187 return result;
188}
189
Simon Glass0c9075e2014-11-24 21:18:15 -0700190void lapic_setup(void);
191
Simon Glass3eafce02014-11-12 22:42:27 -0700192#endif