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