blob: 72311035ac0370fc7e2b9f6827a55d7ed555a6b3 [file] [log] [blame]
Marc Jonesc1cbff22008-04-24 20:03:13 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
5 * Copyright (C) 2008 Peter Stuge
Marc Jones1c5637d2010-09-16 21:04:54 +00006 * Copyright (C) 2010 Marc Jones <marcj303@gmail.com>
Timothy Pearson0d7f8d02015-01-30 23:47:12 -06007 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
Marc Jonesc1cbff22008-04-24 20:03:13 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Marc Jonesc1cbff22008-04-24 20:03:13 +000017 */
18
19/*
20 * This code sets the Processor Name String for AMD64 CPUs.
21 *
22 * Revision Guide for AMD Family 10h Processors
23 * Publication # 41322 Revision: 3.17 Issue Date: February 2008
24 */
25
26#include <console/console.h>
27#include <string.h>
28#include <cpu/x86/msr.h>
Kyösti Mälkki190011e2013-03-25 12:48:49 +020029#include <cpu/amd/mtrr.h>
Marc Jonesc1cbff22008-04-24 20:03:13 +000030#include <cpu/cpu.h>
Myles Watson7943fe62009-10-30 02:08:07 +000031#include <cpu/amd/model_10xxx_rev.h>
Timothy Pearson730a0432015-10-16 13:51:51 -050032#include <device/device.h>
33#include <device/pci.h>
34#include <device/pnp.h>
35#include <device/pci_ops.h>
Marc Jonesc1cbff22008-04-24 20:03:13 +000036
Marc Jonesc1cbff22008-04-24 20:03:13 +000037/* The maximum length of CPU names is 48 bytes, including the final NULL byte.
38 * If you change these names your BIOS will _NOT_ pass the AMD validation and
39 * your mainboard will not be posted on the AMD Recommended Motherboard Website
40 */
41
42struct str_s {
43 u8 Pg;
44 u8 NC;
45 u8 String;
46 char const *value;
47};
48
49
50static const struct str_s String1_socket_F[] = {
51 {0x00, 0x01, 0x00, "Dual-Core AMD Opteron(tm) Processor 83"},
52 {0x00, 0x01, 0x01, "Dual-Core AMD Opteron(tm) Processor 23"},
53 {0x00, 0x03, 0x00, "Quad-Core AMD Opteron(tm) Processor 83"},
54 {0x00, 0x03, 0x01, "Quad-Core AMD Opteron(tm) Processor 23"},
Timothy Pearson0d7f8d02015-01-30 23:47:12 -060055 {0x00, 0x05, 0x00, "Six-Core AMD Opteron(tm) Processor 84"},
56 {0x00, 0x05, 0x01, "Six-Core AMD Opteron(tm) Processor 24"},
Marc Jonesc1cbff22008-04-24 20:03:13 +000057 {0x00, 0x03, 0x02, "Embedded AMD Opteron(tm) Processor 83"},
58 {0x00, 0x03, 0x03, "Embedded AMD Opteron(tm) Processor 23"},
59 {0x00, 0x03, 0x04, "Embedded AMD Opteron(tm) Processor 13"},
60 {0x00, 0x03, 0x05, "AMD Phenom(tm) FX-"},
61 {0x01, 0x01, 0x01, "Embedded AMD Opteron(tm) Processor"},
62 {0, 0, 0, NULL}
63};
64
65static const struct str_s String2_socket_F[] = {
Timothy Pearson0d7f8d02015-01-30 23:47:12 -060066 {0x00, 0xFF, 0x02, " EE"},
Marc Jonesc1cbff22008-04-24 20:03:13 +000067 {0x00, 0xFF, 0x0A, " SE"},
68 {0x00, 0xFF, 0x0B, " HE"},
69 {0x00, 0xFF, 0x0C, " EE"},
70 {0x00, 0xFF, 0x0D, " Quad-Core Processor"},
71 {0x00, 0xFF, 0x0F, ""},
72 {0x01, 0x01, 0x01, "GF HE"},
73 {0, 0, 0, NULL}
74};
75
76
77static const struct str_s String1_socket_AM2[] = {
78 {0x00, 0x00, 0x00, "AMD Athlon(tm) Processor LE-"},
79 {0x00, 0x00, 0x01, "AMD Sempron(tm) Processor LE-"},
Marc Jones1c5637d2010-09-16 21:04:54 +000080 {0x00, 0x00, 0x02, "AMD Sempron(tm) 1"},
81 {0x00, 0x00, 0x03, "AMD Athlon(tm) II 1"},
Marc Jonesc1cbff22008-04-24 20:03:13 +000082 {0x00, 0x01, 0x00, "Dual-Core AMD Opteron(tm) Processor 13"},
83 {0x00, 0x01, 0x01, "AMD Athlon(tm)"},
Marc Jones1c5637d2010-09-16 21:04:54 +000084 {0x00, 0x01, 0x03, "AMD Athlon(tm) II X2 2"},
85 {0x00, 0x01, 0x04, "AMD Athlon(tm) II X2 B"},
86 {0x00, 0x01, 0x05, "AMD Athlon(tm) II X2"},
87 {0x00, 0x01, 0x07, "AMD Phenom(tm) II X2 5"},
88 {0x00, 0x01, 0x0A, "AMD Phenom(tm) II X2"},
89 {0x00, 0x01, 0x0B, "AMD Phenom(tm) II X2 B"},
Marc Jonesc1cbff22008-04-24 20:03:13 +000090 {0x00, 0x02, 0x00, "AMD Phenom(tm)"},
Marc Jones1c5637d2010-09-16 21:04:54 +000091 {0x00, 0x02, 0x03, "AMD Phenom(tm) II X3 B"},
92 {0x00, 0x02, 0x04, "AMD Phenom(tm) II X3"},
93 {0x00, 0x02, 0x07, "AMD Athlon(tm) II X3 4"},
94 {0x00, 0x02, 0x08, "AMD Phenom(tm) II X3 7"},
95 {0x00, 0x02, 0x0A, "AMD Athlon(tm) II X3"},
Marc Jonesc1cbff22008-04-24 20:03:13 +000096 {0x00, 0x03, 0x00, "Quad-Core AMD Opteron(tm) Processor 13"},
97 {0x00, 0x03, 0x01, "AMD Phenom(tm) FX-"},
98 {0x00, 0x03, 0x02, "AMD Phenom(tm)"},
Marc Jones1c5637d2010-09-16 21:04:54 +000099 {0x00, 0x03, 0x03, "AMD Phenom(tm) II X4 9"},
100 {0x00, 0x03, 0x04, "AMD Phenom(tm) II X4 8"},
101 {0x00, 0x03, 0x07, "AMD Phenom(tm) II X4 B"},
102 {0x00, 0x03, 0x08, "AMD Phenom(tm) II X4"},
103 {0x00, 0x03, 0x0A, "AMD Athlon(tm) II X4 6"},
104 {0x00, 0x03, 0x0F, "AMD Athlon(tm) II X4"},
Marc Jonesc1cbff22008-04-24 20:03:13 +0000105 {0, 0, 0, NULL}
106};
107
108static const struct str_s String2_socket_AM2[] = {
109 {0x00, 0x00, 0x00, "00"},
110 {0x00, 0x00, 0x01, "10"},
111 {0x00, 0x00, 0x02, "20"},
112 {0x00, 0x00, 0x03, "30"},
113 {0x00, 0x00, 0x04, "40"},
114 {0x00, 0x00, 0x05, "50"},
115 {0x00, 0x00, 0x06, "60"},
116 {0x00, 0x00, 0x07, "70"},
117 {0x00, 0x00, 0x08, "80"},
118 {0x00, 0x00, 0x09, "90"},
Marc Jones1c5637d2010-09-16 21:04:54 +0000119 {0x00, 0x00, 0x09, " Processor"},
120 {0x00, 0x00, 0x09, "u Processor"},
Marc Jonesc1cbff22008-04-24 20:03:13 +0000121 {0x00, 0x01, 0x00, "00 Dual-Core Processor"},
122 {0x00, 0x01, 0x01, "00e Dual-Core Processor"},
123 {0x00, 0x01, 0x02, "00B Dual-Core Processor"},
124 {0x00, 0x01, 0x03, "50 Dual-Core Processor"},
125 {0x00, 0x01, 0x04, "50e Dual-Core Processor"},
126 {0x00, 0x01, 0x05, "50B Dual-Core Processor"},
Marc Jones1c5637d2010-09-16 21:04:54 +0000127 {0x00, 0x01, 0x06, " Processor"},
128 {0x00, 0x01, 0x07, "e Processor"},
129 {0x00, 0x01, 0x09, "0 Processor"},
130 {0x00, 0x01, 0x0A, "0e Processor"},
131 {0x00, 0x01, 0x0B, "u Processor"},
Marc Jonesc1cbff22008-04-24 20:03:13 +0000132 {0x00, 0x02, 0x00, "00 Triple-Core Processor"},
133 {0x00, 0x02, 0x01, "00e Triple-Core Processor"},
134 {0x00, 0x02, 0x02, "00B Triple-Core Processor"},
135 {0x00, 0x02, 0x03, "50 Triple-Core Processor"},
136 {0x00, 0x02, 0x04, "50e Triple-Core Processor"},
137 {0x00, 0x02, 0x05, "50B Triple-Core Processor"},
Marc Jones1c5637d2010-09-16 21:04:54 +0000138 {0x00, 0x02, 0x06, " Processor"},
139 {0x00, 0x02, 0x07, "e Processor"},
140 {0x00, 0x02, 0x09, "0e Processor"},
141 {0x00, 0x02, 0x0A, "0 Processor"},
Marc Jonesc1cbff22008-04-24 20:03:13 +0000142 {0x00, 0x03, 0x00, "00 Quad-Core Processor"},
143 {0x00, 0x03, 0x01, "00e Quad-Core Processor"},
144 {0x00, 0x03, 0x02, "00B Quad-Core Processor"},
145 {0x00, 0x03, 0x03, "50 Quad-Core Processor"},
146 {0x00, 0x03, 0x04, "50e Quad-Core Processor"},
147 {0x00, 0x03, 0x05, "50B Quad-Core Processor"},
Marc Jones1c5637d2010-09-16 21:04:54 +0000148 {0x00, 0x03, 0x06, " Processor"},
149 {0x00, 0x03, 0x07, "e Processor"},
150 {0x00, 0x03, 0x09, "0e Processor"},
Marc Jonesc1cbff22008-04-24 20:03:13 +0000151 {0x00, 0x03, 0x0A, " SE"},
152 {0x00, 0x03, 0x0B, " HE"},
153 {0x00, 0x03, 0x0C, " EE"},
154 {0x00, 0x03, 0x0D, " Quad-Core Processor"},
Marc Jones1c5637d2010-09-16 21:04:54 +0000155 {0x00, 0x03, 0x0E, "0 Processor"},
Marc Jonesc1cbff22008-04-24 20:03:13 +0000156 {0x00, 0xFF, 0x0F, ""},
157 {0, 0, 0, NULL}
158};
159
Timothy Pearson1c4508e2015-09-05 17:50:29 -0500160static const struct str_s String1_socket_G34[] = {
161 {0x00, 0x07, 0x00, "AMD Opteron(tm) Processor 61"},
162 {0x00, 0x0B, 0x00, "AMD Opteron(tm) Processor 61"},
163 {0x01, 0x07, 0x01, "Embedded AMD Opteron(tm) Processor "},
164 {0, 0, 0, NULL}
165};
166
167static const struct str_s String2_socket_G34[] = {
168 {0x00, 0x07, 0x00, " HE"},
169 {0x00, 0x07, 0x01, " SE"},
170 {0x00, 0x0B, 0x00, " HE"},
171 {0x00, 0x0B, 0x01, " SE"},
172 {0x00, 0x0B, 0x0F, ""},
173 {0x01, 0x07, 0x01, " QS"},
174 {0x01, 0x07, 0x02, " KS"},
175 {0, 0, 0, NULL}
176};
177
Zheng Bao2ca2f172011-03-28 04:29:14 +0000178static const struct str_s String1_socket_C32[] = {
179 {0x00, 0x03, 0x00, "AMD Opteron(tm) Processor 41"},
180 {0x00, 0x05, 0x00, "AMD Opteron(tm) Processor 41"},
181 {0x01, 0x03, 0x01, "Embedded AMD Opteron(tm) Processor "},
182 {0x01, 0x05, 0x01, "Embedded AMD Opteron(tm) Processor "},
183 {0, 0, 0, NULL}
184};
185
186static const struct str_s String2_socket_C32[] = {
187 {0x00, 0x03, 0x00, " HE"},
188 {0x00, 0x03, 0x01, " EE"},
189 {0x00, 0x05, 0x00, " HE"},
190 {0x00, 0x05, 0x01, " EE"},
191 {0x01, 0x03, 0x01, "QS HE"},
192 {0x01, 0x03, 0x02, "LE HE"},
193 {0x01, 0x05, 0x01, "KX HE"},
194 {0x01, 0x05, 0x02, "GL EE"},
195 {0, 0, 0, NULL}
196};
Marc Jonesc1cbff22008-04-24 20:03:13 +0000197
Edward O'Callaghand6b452f2014-11-12 17:45:38 +1100198const char *unknown = "AMD Processor model unknown";
199const char *unknown2 = " type unknown";
200const char *sample = "AMD Engineering Sample";
201const char *thermal = "AMD Thermal Test Kit";
Marc Jonesc1cbff22008-04-24 20:03:13 +0000202
203
Stefan Reinauer8b547b12010-03-30 09:56:35 +0000204static int strcpymax(char *dst, const char *src, int buflen)
205{
Marc Jonesc1cbff22008-04-24 20:03:13 +0000206 int i;
207 for (i = 0; i < buflen && src[i]; i++)
208 dst[i] = src[i];
209 if (i >= buflen)
210 i--;
211 dst[i] = 0;
212 return i;
213}
214
Timothy Pearson730a0432015-10-16 13:51:51 -0500215#define NAME_STRING_MAXLEN 48
Marc Jonesc1cbff22008-04-24 20:03:13 +0000216
217int init_processor_name(void)
218{
Marc Jonesc1cbff22008-04-24 20:03:13 +0000219 msr_t msr;
Timothy Pearson730a0432015-10-16 13:51:51 -0500220 ssize_t i;
221 char program_string[NAME_STRING_MAXLEN];
222 u32 *p_program_string = (u32 *)program_string;
223 uint8_t fam15h = 0;
224 uint32_t family;
Marc Jonesc1cbff22008-04-24 20:03:13 +0000225
Timothy Pearson730a0432015-10-16 13:51:51 -0500226 family = cpuid_eax(0x80000001);
227 family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
Marc Jonesc1cbff22008-04-24 20:03:13 +0000228
Timothy Pearson730a0432015-10-16 13:51:51 -0500229 if (family >= 0x6f)
230 /* Family 15h or later */
231 fam15h = 1;
Marc Jonesc1cbff22008-04-24 20:03:13 +0000232
233 /* null the string */
234 memset(program_string, 0, sizeof(program_string));
235
Timothy Pearson730a0432015-10-16 13:51:51 -0500236 if (fam15h) {
237 /* Family 15h or later */
238 uint32_t dword;
Elyes HAOUASd2d8a312018-02-08 13:38:21 +0100239 struct device *cpu_fn5_dev = dev_find_slot(0, PCI_DEVFN(0x18, 5));
Timothy Pearson730a0432015-10-16 13:51:51 -0500240 pci_write_config32(cpu_fn5_dev, 0x194, 0);
241 dword = pci_read_config32(cpu_fn5_dev, 0x198);
242 if (dword == 0) {
243 strcpymax(program_string, sample, sizeof(program_string));
244 } else {
245 /* Assemble the string from PCI configuration register contents */
246 for (i = 0; i < 12; i++) {
247 pci_write_config32(cpu_fn5_dev, 0x194, i);
248 p_program_string[i] = pci_read_config32(cpu_fn5_dev, 0x198);
249 }
Marc Jonesc1cbff22008-04-24 20:03:13 +0000250
Timothy Pearson730a0432015-10-16 13:51:51 -0500251 /* Correctly place the null terminator */
252 for (i = (NAME_STRING_MAXLEN - 2); i > 0; i--) {
253 if (program_string[i] != 0x20)
254 break;
255 }
256 program_string[i + 1] = 0;
Marc Jonesc1cbff22008-04-24 20:03:13 +0000257 }
Timothy Pearson730a0432015-10-16 13:51:51 -0500258 } else {
259 /* variable names taken from fam10 revision guide for clarity */
260 u32 BrandId; /* CPUID Fn8000_0001_EBX */
261 u8 String1; /* BrandID[14:11] */
262 u8 String2; /* BrandID[3:0] */
263 u8 Model; /* BrandID[10:4] */
264 u8 Pg; /* BrandID[15] */
265 u8 PkgTyp; /* BrandID[31:28] */
266 u8 NC; /* CPUID Fn8000_0008_ECX */
267 const char *processor_name_string = unknown;
268 int j = 0, str2_checkNC = 1;
269 const struct str_s *str, *str2;
Marc Jonesc1cbff22008-04-24 20:03:13 +0000270
Timothy Pearson730a0432015-10-16 13:51:51 -0500271 /* Find out which CPU brand it is */
272 BrandId = cpuid_ebx(0x80000001);
273 String1 = (u8)((BrandId >> 11) & 0x0F);
274 String2 = (u8)((BrandId >> 0) & 0x0F);
275 Model = (u8)((BrandId >> 4) & 0x7F);
276 Pg = (u8)((BrandId >> 15) & 0x01);
277 PkgTyp = (u8)((BrandId >> 28) & 0x0F);
278 NC = (u8)(cpuid_ecx(0x80000008) & 0xFF);
Marc Jonesc1cbff22008-04-24 20:03:13 +0000279
Timothy Pearson730a0432015-10-16 13:51:51 -0500280 if (!Model) {
281 processor_name_string = Pg ? thermal : sample;
282 goto done;
Marc Jonesc1cbff22008-04-24 20:03:13 +0000283 }
Timothy Pearson730a0432015-10-16 13:51:51 -0500284
285 switch (PkgTyp) {
286 case 0: /* F1207 */
287 str = String1_socket_F;
288 str2 = String2_socket_F;
289 str2_checkNC = 0;
290 break;
291 case 1: /* AM2 */
292 str = String1_socket_AM2;
293 str2 = String2_socket_AM2;
294 break;
295 case 3: /* G34 */
296 str = String1_socket_G34;
297 str2 = String2_socket_G34;
298 str2_checkNC = 0;
299 break;
300 case 5: /* C32 */
301 str = String1_socket_C32;
302 str2 = String2_socket_C32;
303 break;
304 default:
305 goto done;
306 }
307
308 /* String1 */
309 for (i = 0; str[i].value; i++) {
310 if ((str[i].Pg == Pg) &&
311 (str[i].NC == NC) &&
312 (str[i].String == String1)) {
313 processor_name_string = str[i].value;
314 break;
315 }
316 }
317
318 if (!str[i].value)
319 goto done;
320
321 j = strcpymax(program_string, processor_name_string,
322 sizeof(program_string));
323
324 /* Translate Model from 01-99 to ASCII and put it on the end.
325 * Numbers less than 10 should include a leading zero, e.g., 09.*/
326 if (Model < 100 && j < sizeof(program_string) - 2) {
327 program_string[j++] = (Model / 10) + '0';
328 program_string[j++] = (Model % 10) + '0';
329 }
330
331 processor_name_string = unknown2;
332
333 /* String 2 */
Elyes HAOUAScbe7464c2016-08-23 21:07:28 +0200334 for (i = 0; str2[i].value; i++) {
Timothy Pearson730a0432015-10-16 13:51:51 -0500335 if ((str2[i].Pg == Pg) &&
336 ((str2[i].NC == NC) || !str2_checkNC) &&
337 (str2[i].String == String2)) {
338 processor_name_string = str2[i].value;
339 break;
340 }
341 }
342
Martin Rothe35db2c2016-03-30 13:30:12 -0600343done:
Timothy Pearson730a0432015-10-16 13:51:51 -0500344 strcpymax(&program_string[j], processor_name_string,
345 sizeof(program_string) - j);
Marc Jonesc1cbff22008-04-24 20:03:13 +0000346 }
347
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000348 printk(BIOS_DEBUG, "CPU model: %s\n", program_string);
Marc Jonesc1cbff22008-04-24 20:03:13 +0000349
350 for (i = 0; i < 6; i++) {
351 msr.lo = p_program_string[(2 * i) + 0];
352 msr.hi = p_program_string[(2 * i) + 1];
353 wrmsr_amd(0xC0010030 + i, msr);
354 }
355
356 return 0;
357}