13eafce05SSimon Glass /* 2*63d54a67SBin Meng * From coreboot file of same name 33eafce05SSimon Glass * 43eafce05SSimon Glass * Copyright (C) 2014 Google, Inc 53eafce05SSimon Glass * 63eafce05SSimon Glass * SPDX-License-Identifier: GPL-2.0 73eafce05SSimon Glass */ 83eafce05SSimon Glass 93eafce05SSimon Glass #ifndef _ARCH_ASM_LAPIC_H 103eafce05SSimon Glass #define _ARCH_ASM_LAPIC_H 113eafce05SSimon Glass 123eafce05SSimon Glass #include <asm/io.h> 133eafce05SSimon Glass #include <asm/msr.h> 14*63d54a67SBin Meng #include <asm/msr-index.h> 153eafce05SSimon Glass #include <asm/processor.h> 163eafce05SSimon Glass 17*63d54a67SBin Meng #define LAPIC_DEFAULT_BASE 0xfee00000 18*63d54a67SBin Meng 19*63d54a67SBin Meng #define LAPIC_ID 0x020 20*63d54a67SBin Meng #define LAPIC_LVR 0x030 21*63d54a67SBin Meng 22*63d54a67SBin Meng #define LAPIC_TASKPRI 0x080 23*63d54a67SBin Meng #define LAPIC_TPRI_MASK 0xff 24*63d54a67SBin Meng 25*63d54a67SBin Meng #define LAPIC_RRR 0x0c0 26*63d54a67SBin Meng 27*63d54a67SBin Meng #define LAPIC_SPIV 0x0f0 28*63d54a67SBin Meng #define LAPIC_SPIV_ENABLE 0x100 29*63d54a67SBin Meng 30*63d54a67SBin Meng #define LAPIC_ICR 0x300 31*63d54a67SBin Meng #define LAPIC_DEST_SELF 0x40000 32*63d54a67SBin Meng #define LAPIC_DEST_ALLINC 0x80000 33*63d54a67SBin Meng #define LAPIC_DEST_ALLBUT 0xc0000 34*63d54a67SBin Meng #define LAPIC_ICR_RR_MASK 0x30000 35*63d54a67SBin Meng #define LAPIC_ICR_RR_INVALID 0x00000 36*63d54a67SBin Meng #define LAPIC_ICR_RR_INPROG 0x10000 37*63d54a67SBin Meng #define LAPIC_ICR_RR_VALID 0x20000 38*63d54a67SBin Meng #define LAPIC_INT_LEVELTRIG 0x08000 39*63d54a67SBin Meng #define LAPIC_INT_ASSERT 0x04000 40*63d54a67SBin Meng #define LAPIC_ICR_BUSY 0x01000 41*63d54a67SBin Meng #define LAPIC_DEST_LOGICAL 0x00800 42*63d54a67SBin Meng #define LAPIC_DM_FIXED 0x00000 43*63d54a67SBin Meng #define LAPIC_DM_LOWEST 0x00100 44*63d54a67SBin Meng #define LAPIC_DM_SMI 0x00200 45*63d54a67SBin Meng #define LAPIC_DM_REMRD 0x00300 46*63d54a67SBin Meng #define LAPIC_DM_NMI 0x00400 47*63d54a67SBin Meng #define LAPIC_DM_INIT 0x00500 48*63d54a67SBin Meng #define LAPIC_DM_STARTUP 0x00600 49*63d54a67SBin Meng #define LAPIC_DM_EXTINT 0x00700 50*63d54a67SBin Meng #define LAPIC_VECTOR_MASK 0x000ff 51*63d54a67SBin Meng 52*63d54a67SBin Meng #define LAPIC_ICR2 0x310 53*63d54a67SBin Meng #define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xff) 54*63d54a67SBin Meng #define SET_LAPIC_DEST_FIELD(x) ((x) << 24) 55*63d54a67SBin Meng 56*63d54a67SBin Meng #define LAPIC_LVT0 0x350 57*63d54a67SBin Meng #define LAPIC_LVT1 0x360 58*63d54a67SBin Meng #define LAPIC_LVT_MASKED (1 << 16) 59*63d54a67SBin Meng #define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) 60*63d54a67SBin Meng #define LAPIC_LVT_REMOTE_IRR (1 << 14) 61*63d54a67SBin Meng #define LAPIC_INPUT_POLARITY (1 << 13) 62*63d54a67SBin Meng #define LAPIC_SEND_PENDING (1 << 12) 63*63d54a67SBin Meng #define LAPIC_LVT_RESERVED_1 (1 << 11) 64*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_MASK (7 << 8) 65*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_FIXED (0 << 8) 66*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_NMI (4 << 8) 67*63d54a67SBin Meng #define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) 680c9075e9SSimon Glass 693eafce05SSimon Glass static inline __attribute__((always_inline)) 703eafce05SSimon Glass unsigned long lapic_read(unsigned long reg) 713eafce05SSimon Glass { 723eafce05SSimon Glass return readl(LAPIC_DEFAULT_BASE + reg); 733eafce05SSimon Glass } 743eafce05SSimon Glass 753eafce05SSimon Glass static inline __attribute__((always_inline)) 763eafce05SSimon Glass void lapic_write(unsigned long reg, unsigned long val) 773eafce05SSimon Glass { 783eafce05SSimon Glass writel(val, LAPIC_DEFAULT_BASE + reg); 793eafce05SSimon Glass } 803eafce05SSimon Glass 813eafce05SSimon Glass static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void) 823eafce05SSimon Glass { 833eafce05SSimon Glass do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); 843eafce05SSimon Glass } 853eafce05SSimon Glass 863eafce05SSimon Glass static inline void enable_lapic(void) 873eafce05SSimon Glass { 883eafce05SSimon Glass msr_t msr; 893eafce05SSimon Glass 90*63d54a67SBin Meng msr = msr_read(MSR_IA32_APICBASE); 913eafce05SSimon Glass msr.hi &= 0xffffff00; 92*63d54a67SBin Meng msr.lo |= MSR_IA32_APICBASE_ENABLE; 93*63d54a67SBin Meng msr.lo &= ~MSR_IA32_APICBASE_BASE; 940c9075e9SSimon Glass msr.lo |= LAPIC_DEFAULT_BASE; 95*63d54a67SBin Meng msr_write(MSR_IA32_APICBASE, msr); 963eafce05SSimon Glass } 973eafce05SSimon Glass 983eafce05SSimon Glass static inline void disable_lapic(void) 993eafce05SSimon Glass { 1003eafce05SSimon Glass msr_t msr; 1013eafce05SSimon Glass 102*63d54a67SBin Meng msr = msr_read(MSR_IA32_APICBASE); 103*63d54a67SBin Meng msr.lo &= ~MSR_IA32_APICBASE_ENABLE; 104*63d54a67SBin Meng msr_write(MSR_IA32_APICBASE, msr); 1053eafce05SSimon Glass } 1063eafce05SSimon Glass 1073eafce05SSimon Glass static inline __attribute__((always_inline)) unsigned long lapicid(void) 1083eafce05SSimon Glass { 1093eafce05SSimon Glass return lapic_read(LAPIC_ID) >> 24; 1103eafce05SSimon Glass } 1113eafce05SSimon Glass 1120c9075e9SSimon Glass static inline __attribute__((always_inline)) void stop_this_cpu(void) 1130c9075e9SSimon Glass { 1140c9075e9SSimon Glass /* Called by an AP when it is ready to halt and wait for a new task */ 1150c9075e9SSimon Glass for (;;) 1160c9075e9SSimon Glass cpu_hlt(); 1170c9075e9SSimon Glass } 1180c9075e9SSimon Glass 1190c9075e9SSimon Glass #define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ 1200c9075e9SSimon Glass sizeof(*(ptr)))) 1210c9075e9SSimon Glass 1220c9075e9SSimon Glass struct __xchg_dummy { unsigned long a[100]; }; 1230c9075e9SSimon Glass #define __xg(x) ((struct __xchg_dummy *)(x)) 1240c9075e9SSimon Glass 1250c9075e9SSimon Glass /* 126*63d54a67SBin Meng * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. 127*63d54a67SBin Meng * 1280c9075e9SSimon Glass * Note 2: xchg has side effect, so that attribute volatile is necessary, 129*63d54a67SBin Meng * but generally the primitive is invalid, *ptr is output argument. 1300c9075e9SSimon Glass */ 1310c9075e9SSimon Glass static inline unsigned long __xchg(unsigned long x, volatile void *ptr, 1320c9075e9SSimon Glass int size) 1330c9075e9SSimon Glass { 1340c9075e9SSimon Glass switch (size) { 1350c9075e9SSimon Glass case 1: 1360c9075e9SSimon Glass __asm__ __volatile__("xchgb %b0,%1" 1370c9075e9SSimon Glass : "=q" (x) 1380c9075e9SSimon Glass : "m" (*__xg(ptr)), "0" (x) 1390c9075e9SSimon Glass : "memory"); 1400c9075e9SSimon Glass break; 1410c9075e9SSimon Glass case 2: 1420c9075e9SSimon Glass __asm__ __volatile__("xchgw %w0,%1" 1430c9075e9SSimon Glass : "=r" (x) 1440c9075e9SSimon Glass : "m" (*__xg(ptr)), "0" (x) 1450c9075e9SSimon Glass : "memory"); 1460c9075e9SSimon Glass break; 1470c9075e9SSimon Glass case 4: 1480c9075e9SSimon Glass __asm__ __volatile__("xchgl %0,%1" 1490c9075e9SSimon Glass : "=r" (x) 1500c9075e9SSimon Glass : "m" (*__xg(ptr)), "0" (x) 1510c9075e9SSimon Glass : "memory"); 1520c9075e9SSimon Glass break; 1530c9075e9SSimon Glass } 1540c9075e9SSimon Glass 1550c9075e9SSimon Glass return x; 1560c9075e9SSimon Glass } 1570c9075e9SSimon Glass 1580c9075e9SSimon Glass static inline void lapic_write_atomic(unsigned long reg, unsigned long v) 1590c9075e9SSimon Glass { 1600c9075e9SSimon Glass (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); 1610c9075e9SSimon Glass } 1620c9075e9SSimon Glass 1630c9075e9SSimon Glass #define lapic_read_around(x) lapic_read(x) 1640c9075e9SSimon Glass #define lapic_write_around(x, y) lapic_write_atomic((x), (y)) 1650c9075e9SSimon Glass 1660c9075e9SSimon Glass static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) 1670c9075e9SSimon Glass { 1680c9075e9SSimon Glass int timeout; 1690c9075e9SSimon Glass unsigned long status; 1700c9075e9SSimon Glass int result; 171*63d54a67SBin Meng 1720c9075e9SSimon Glass lapic_wait_icr_idle(); 1730c9075e9SSimon Glass lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); 1740c9075e9SSimon Glass lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); 175*63d54a67SBin Meng 1760c9075e9SSimon Glass timeout = 0; 1770c9075e9SSimon Glass do { 1780c9075e9SSimon Glass status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; 1790c9075e9SSimon Glass } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); 1800c9075e9SSimon Glass 1810c9075e9SSimon Glass result = -1; 1820c9075e9SSimon Glass if (status == LAPIC_ICR_RR_VALID) { 1830c9075e9SSimon Glass *pvalue = lapic_read(LAPIC_RRR); 1840c9075e9SSimon Glass result = 0; 1850c9075e9SSimon Glass } 186*63d54a67SBin Meng 1870c9075e9SSimon Glass return result; 1880c9075e9SSimon Glass } 1890c9075e9SSimon Glass 1900c9075e9SSimon Glass void lapic_setup(void); 1910c9075e9SSimon Glass 1923eafce05SSimon Glass #endif 193