After this has been brought up many times before, rename src/arch/i386 to
[coreboot.git] / src / cpu / via / model_c7 / model_c7_init.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * (C) 2007-2009 coresystems GmbH
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; version 2 of
9  * the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19  * MA 02110-1301 USA
20  */
21
22 #include <device/device.h>
23 #include <console/console.h>
24 #include <delay.h>
25 #include <stdlib.h>
26 #include <cpu/cpu.h>
27 #include <cpu/x86/mtrr.h>
28 #include <cpu/x86/msr.h>
29 #include <cpu/x86/lapic.h>
30 #include <cpu/x86/cache.h>
31
32 #define MSR_IA32_PERF_STATUS    0x00000198
33 #define MSR_IA32_PERF_CTL       0x00000199
34 #define MSR_IA32_MISC_ENABLE    0x000001a0
35
36 static int c7a_speed_translation[] = {
37 //      LFM     HFM
38         0x0409, 0x0f13,         // 400MHz, 844mV --> 1500MHz, 1.004V    C7-M
39         0x0409, 0x1018,         // 400MHz, 844mV --> 1600MHz, 1.084V
40         0x0409, 0x0c18,         // 533MHz, 844mV --> 1600MHz, 1.084V
41         0x0409, 0x121c,         // 400MHz, 844mV --> 1800MHz, 1.148V
42         0x0409, 0x0e1c,         // 533MHz, 844mV --> 1860MHz, 1.148V
43         0x0409, 0x141f,         // 400MHz, 844mV --> 2000MHz, 1.196V
44         0x0409, 0x0f1f,         // 533MHz, 844mV --> 2000MHz, 1.196V
45         0x0406, 0x0a06,         // 400MHz, 796mV --> 1000MHz, 796mV     C7-M ULV
46         0x0406, 0x0a09,         // 400MHz, 796mV --> 1000MHz, 844mV
47         0x0406, 0x0c09,         // 400MHz, 796mV --> 1200MHz, 844mV
48         0x0406, 0x0f10,         // 400MHz, 796mV --> 1500MHz, 956mV
49 };
50
51 static int c7d_speed_translation[] = {
52 //      LFM     HFM
53         0x0409, 0x1018,         // 400MHz, 844mV --> 1600MHz, 1.084V    C7-M
54         0x0409, 0x121f,         // 400MHz, 844mV --> 1800MHz, 1.196V
55         0x0809, 0x121f,         // 800MHz, 844mV --> 1800MHz, 1.196V
56         0x0409, 0x141f,         // 400MHz, 844mV --> 2000MHz, 1.196V
57         0x0809, 0x141f,         // 800MHz, 844mV --> 2000MHz, 1.196V
58         0x0406, 0x0806,         // 400MHz, 796mV --> 800MHz, 796mV      C7-M ULV
59         0x0406, 0x0a06,         // 400MHz, 796mV --> 1000MHz, 796mV
60         0x0406, 0x0c09,         // 400MHz, 796mV --> 1200MHz, 844mV
61         0x0806, 0x0c09,         // 800MHz, 796mV --> 1200MHz, 844mV
62         0x0406, 0x0f10,         // 400MHz, 796mV --> 1500MHz, 956mV
63         0x0806, 0x1010,         // 800MHz, 796mV --> 1600MHz, 956mV
64 };
65
66 static void set_c7_speed(int model) {
67         int cnt, current, new, i;
68         msr_t msr;
69         printk(BIOS_DEBUG, "Enabling improved C7 clock and voltage.\n");
70
71         // Enable Speedstep
72         msr = rdmsr(MSR_IA32_MISC_ENABLE);
73         msr.lo |= (1 << 16);
74         wrmsr(MSR_IA32_MISC_ENABLE, msr);
75
76         msr = rdmsr(MSR_IA32_PERF_STATUS);
77
78         printk(BIOS_INFO, "Voltage: %dmV (min %dmV; max %dmV)\n",
79                     ((int)(msr.lo & 0xff) * 16 + 700),
80                     ((int)((msr.hi >> 16) & 0xff) * 16 + 700),
81                     ((int)(msr.hi & 0xff) * 16 + 700));
82
83         printk(BIOS_INFO, "CPU multiplier: %dx (min %dx; max %dx)\n",
84                     (int)((msr.lo >> 8) & 0xff),
85                     (int)((msr.hi >> 24) & 0xff), (int)((msr.hi >> 8) & 0xff));
86
87         printk(BIOS_DEBUG, " msr.lo = %x\n", msr.lo);
88
89         /* Wait while CPU is busy */
90         cnt = 0;
91         while (msr.lo & ((1 << 16) | (1 << 17))) {
92                 udelay(16);
93                 msr = rdmsr(MSR_IA32_PERF_STATUS);
94                 cnt++;
95                 if (cnt > 128) {
96                         printk(BIOS_WARNING, "Could not update multiplier and voltage.\n");
97                         return;
98                 }
99         }
100
101         current = msr.lo & 0xffff;
102
103         // Start out with no change.
104         new = current;
105         switch (model) {
106         case 10:                // model A
107                 for (i = 0; i < ARRAY_SIZE(c7a_speed_translation); i += 2) {
108                         if ((c7a_speed_translation[i] == current) &&
109                             ((c7a_speed_translation[i + 1] & 0xff00) ==
110                              (msr.hi & 0xff00))) {
111                                 new = c7a_speed_translation[i + 1];
112                         }
113                 }
114                 break;
115         case 13:                // model D
116                 for (i = 0; i < ARRAY_SIZE(c7d_speed_translation); i += 2) {
117                         if ((c7d_speed_translation[i] == current) &&
118                             ((c7d_speed_translation[i + 1] & 0xff00) ==
119                              (msr.hi & 0xff00))) {
120                                 new = c7d_speed_translation[i + 1];
121                         }
122                 }
123                 break;
124         default:
125                 print_info("CPU type not known, multiplier unchanged.\n");
126         }
127
128         msr.lo = new;
129         msr.hi = 0;
130         printk(BIOS_DEBUG, " new msr.lo = %x\n", msr.lo);
131
132         wrmsr(MSR_IA32_PERF_CTL, msr);
133
134         /* Wait until the power transition ends */
135         cnt = 0;
136         do {
137                 udelay(16);
138                 msr = rdmsr(MSR_IA32_PERF_STATUS);
139                 cnt++;
140                 if (cnt > 128) {
141                         printk(BIOS_WARNING, "Error while updating multiplier and voltage\n");
142                         break;
143                 }
144         } while (msr.lo & ((1 << 16) | (1 << 17)));
145
146         printk(BIOS_INFO, "Current voltage: %dmV\n", ((int)(msr.lo & 0xff) * 16 + 700));
147         printk(BIOS_INFO, "Current CPU multiplier: %dx\n", (int)((msr.lo >> 8) & 0xff));
148 }
149
150 static void model_c7_init(device_t dev)
151 {
152         u8 brand;
153         struct cpuinfo_x86 c;
154         msr_t msr;
155
156         get_fms(&c, dev->device);
157
158         printk(BIOS_INFO, "Detected VIA ");
159
160         switch (c.x86_model) {
161         case 10:
162                 msr = rdmsr(0x1153);
163                 brand = (((msr.lo >> 2) ^ msr.lo) >> 18) & 3;
164                 printk(BIOS_INFO, "Model A ");
165                 break;
166         case 13:
167                 msr = rdmsr(0x1154);
168                 brand = (((msr.lo >> 4) ^ (msr.lo >> 2))) & 0x000000ff;
169                 printk(BIOS_INFO, "Model D ");
170                 break;
171         default:
172                 printk(BIOS_INFO, "Model Unknown ");
173                 brand = 0xff;
174         }
175
176         switch (brand) {
177         case 0:
178                 printk(BIOS_INFO, "C7-M\n");
179                 break;
180         case 1:
181                 printk(BIOS_INFO, "C7\n");
182                 break;
183         case 2:
184                 printk(BIOS_INFO, "Eden\n");
185                 break;
186         case 3:
187                 printk(BIOS_INFO, "C7-D\n");
188                 break;
189         default:
190                 printk(BIOS_INFO, "%02x (please report)\n", brand);
191         }
192
193         /* Gear up */
194         set_c7_speed(c.x86_model);
195
196         /* Enable APIC */
197         msr = rdmsr(0x1107);
198         msr.lo |= 1<<24;
199         wrmsr(0x1107, msr);
200
201         /* Turn on cache */
202         x86_enable_cache();
203
204         /* Set up Memory Type Range Registers */
205         x86_setup_mtrrs(36);
206         x86_mtrr_check();
207
208         /* Enable the local cpu apics */
209         setup_lapic();
210 };
211
212 static struct device_operations cpu_dev_ops = {
213         .init = model_c7_init,
214 };
215
216 /* Look in arch/x86/lib/cpu.c:cpu_initialize. If there is no CPU with an exact
217  * ID, the cpu mask (stepping) is masked out and the check is repeated. This
218  * allows us to keep the table significantly smaller.
219  */
220
221 static struct cpu_device_id cpu_table[] = {
222         {X86_VENDOR_CENTAUR, 0x06A0},   // VIA C7 Esther
223         {X86_VENDOR_CENTAUR, 0x06A9},   // VIA C7 Esther
224         {X86_VENDOR_CENTAUR, 0x06D0},   // VIA C7-M
225         {0, 0},
226 };
227
228 static const struct cpu_driver driver __cpu_driver = {
229         .ops = &cpu_dev_ops,
230         .id_table = cpu_table,
231 };