Add support for Intel Sandybridge CPU
[coreboot.git] / src / cpu / intel / model_206ax / bootblock.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2011 Google Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include <stdint.h>
21 #include <arch/cpu.h>
22 #include <cpu/x86/cache.h>
23 #include <cpu/x86/msr.h>
24 #include <cpu/x86/mtrr.h>
25
26 static const uint32_t microcode_updates[] = {
27         #include "x06_microcode.h"
28 };
29
30 struct microcode {
31         u32 hdrver;     /* Header Version */
32         u32 rev;        /* Patch ID       */
33         u32 date;       /* DATE           */
34         u32 sig;        /* CPUID          */
35
36         u32 cksum;      /* Checksum       */
37         u32 ldrver;     /* Loader Version */
38         u32 pf;         /* Platform ID    */
39
40         u32 data_size;  /* Data size      */
41         u32 total_size; /* Total size     */
42
43         u32 reserved[3];
44         u32 bits[1012];
45 };
46
47 static inline u32 read_microcode_rev(void)
48 {
49         /* Some Intel Cpus can be very finicky about the
50          * CPUID sequence used.  So this is implemented in
51          * assembly so that it works reliably.
52          */
53         msr_t msr;
54         __asm__ volatile (
55                 "wrmsr\n\t"
56                 "xorl %%eax, %%eax\n\t"
57                 "xorl %%edx, %%edx\n\t"
58                 "movl $0x8b, %%ecx\n\t"
59                 "wrmsr\n\t"
60                 "movl $0x01, %%eax\n\t"
61                 "cpuid\n\t"
62                 "movl $0x08b, %%ecx\n\t"
63                 "rdmsr \n\t"
64                 : /* outputs */
65                 "=a" (msr.lo), "=d" (msr.hi)
66                 : /* inputs */
67                 : /* trashed */
68                  "ecx"
69         );
70         return msr.hi;
71 }
72
73 void intel_update_microcode(const void *microcode_updates)
74 {
75         unsigned int eax;
76         unsigned int pf, rev, sig;
77         unsigned int x86_model, x86_family;
78         const struct microcode *m;
79         const char *c;
80         msr_t msr;
81
82         /* cpuid sets msr 0x8B iff a microcode update has been loaded. */
83         msr.lo = 0;
84         msr.hi = 0;
85         wrmsr(0x8B, msr);
86         eax = cpuid_eax(1);
87         msr = rdmsr(0x8B);
88         rev = msr.hi;
89         x86_model = (eax >>4) & 0x0f;
90         x86_family = (eax >>8) & 0x0f;
91         sig = eax;
92
93         pf = 0;
94         if ((x86_model >= 5)||(x86_family>6)) {
95                 msr = rdmsr(0x17);
96                 pf = 1 << ((msr.hi >> 18) & 7);
97         }
98
99         m = microcode_updates;
100         for(c = microcode_updates; m->hdrver;  m = (const struct microcode *)c) {
101                 if ((m->sig == sig) && (m->pf & pf)) {
102                         unsigned int new_rev;
103                         msr.lo = (unsigned long)(&m->bits) & 0xffffffff;
104                         msr.hi = 0;
105                         wrmsr(0x79, msr);
106
107                         /* Read back the new microcode version */
108                         new_rev = read_microcode_rev();
109                         break;
110                 }
111                 if (m->total_size) {
112                         c += m->total_size;
113                 } else {
114                         c += 2048;
115                 }
116         }
117 }
118
119 static void set_var_mtrr(
120         unsigned reg, unsigned base, unsigned size, unsigned type)
121
122 {
123         /* Bit Bit 32-35 of MTRRphysMask should be set to 1 */
124         /* FIXME: It only support 4G less range */
125         msr_t basem, maskm;
126         basem.lo = base | type;
127         basem.hi = 0;
128         wrmsr(MTRRphysBase_MSR(reg), basem);
129         maskm.lo = ~(size - 1) | MTRRphysMaskValid;
130         maskm.hi = (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1;
131         wrmsr(MTRRphysMask_MSR(reg), maskm);
132 }
133
134 static void enable_rom_caching(void)
135 {
136         msr_t msr;
137
138         disable_cache();
139         set_var_mtrr(1, 0xffc00000, 4*1024*1024, MTRR_TYPE_WRPROT);
140         enable_cache();
141
142         /* Enable Variable MTRRs */
143         msr.hi = 0x00000000;
144         msr.lo = 0x00000800;
145         wrmsr(MTRRdefType_MSR, msr);
146 }
147
148 static void bootblock_cpu_init(void)
149 {
150         enable_rom_caching();
151         intel_update_microcode(microcode_updates);
152 }