2 * This file is part of the coreboot project.
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
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.
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.
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
20 #include <console/console.h>
21 #include <cpu/x86/msr.h>
22 #include <cpu/amd/mtrr.h>
23 #include <device/device.h>
24 #include <device/pci.h>
26 #include <cpu/x86/msr.h>
27 #include <cpu/x86/pae.h>
28 #include <pc80/mc146818rtc.h>
29 #include <cpu/x86/lapic.h>
31 #include "../../../northbridge/amd/amdfam10/amdfam10.h"
33 #include <cpu/amd/model_10xxx_rev.h>
35 #include <cpu/x86/cache.h>
36 #include <cpu/x86/mtrr.h>
37 #include <cpu/x86/mem.h>
39 #include <cpu/amd/quadcore.h>
41 #include <cpu/amd/model_10xxx_msr.h>
42 #include <cpu/amd/amdfam10_sysconf.h>
44 extern device_t get_node_pci(u32 nodeid, u32 fn);
46 #include "fidvid_common.c"
48 #define PSTATES_DEBUG 0
52 static void inline dump_msr_pstates(u32 nodes)
57 printk_debug("P%d:", j);
58 for(i=0;i<nodes;i++) {
59 printk_debug(" [%08x %08x] ", sysconf.msr_pstate[i*5+j].hi, sysconf.msr_pstate[i*5+j].lo);
67 static void inline dump_p(const char *p_c, u32 nodes, u32 *p)
73 for(i=0;i<nodes;i++) {
74 printk_debug(" %d ", p[i]);
82 //according the pstate and make it work conformed to mixed conf system
83 static u32 get_pwrvalue(u32 val)
87 case 0: times = 1000; break;
88 case 1: times = 100; break;
89 case 2: times = 10; break;
95 return (val & 0xff) * times;
100 static u32 get_powerstep(u32 val)
103 if(val<4) {time = (4 - val)*100;}
104 else if(val<8) { time = (9+4-val)*10;}
105 else { time = (10+8-val) * 5; }
112 static u32 get_plllocktime(u32 val)
121 case 4: time = 8; break;
122 case 5: time = 16; break;
131 static void disable_pstate(u32 nodes, u32 *p)
135 for(i=0;i<nodes; i++) {
136 sysconf.msr_pstate[i*5+p[i]].hi &= ~(1<<(63-32));
141 static void match_pstate(u32 nodes, u32 *p)
144 u32 corecof_min, pwrvalue_max, pwrval_max;
146 enable = (sysconf.msr_pstate[0*5+p[0]].hi >> 31);
148 disable_pstate(nodes, p);
151 corecof_min = ((sysconf.msr_pstate[0*5+p[0]].lo & 0x3f) + 0x10)>>((sysconf.msr_pstate[0*5+p[0]].lo>>6) & 7);
152 pwrval_max = sysconf.msr_pstate[0*5+p[0]].hi & 0x3ff;
153 pwrvalue_max = get_pwrvalue(pwrval_max);
155 for(i=1; i<nodes; i++) {
156 enable = (sysconf.msr_pstate[0*5+p[i]].hi >> 31);
158 disable_pstate(nodes, p);
162 u32 coredid = ((sysconf.msr_pstate[i*5+p[i]].lo>>6) & 7);
163 u32 corecof = ((sysconf.msr_pstate[i*5+p[i]].lo & 0x3f) + 0x10)>>coredid;
164 if(corecof<corecof_min) corecof_min = corecof;
165 u32 pwrval, pwrvalue;
166 pwrval = sysconf.msr_pstate[i*5+p[i]].hi & 0x3ff;
167 pwrvalue = get_pwrvalue(pwrval);
168 if(pwrvalue>pwrvalue_max) {
169 pwrvalue_max = pwrvalue;
174 for(i=0; i<nodes; i++) {
175 u32 coredid = ((sysconf.msr_pstate[i*5+p[i]].lo>>6) & 7);
176 u32 corefid = (corecof_min<<coredid);
177 while(corefid<0x10) {
179 corefid = (corecof_min<<coredid);
181 sysconf.msr_pstate[i*5+p[i]].lo &= ~(0x1ff);
182 sysconf.msr_pstate[i*5+p[i]].lo |= (corefid - 0x10) | (coredid << 6);
183 sysconf.msr_pstate[i*5+p[i]].hi &= ~(0x3ff);
184 sysconf.msr_pstate[i*5+p[i]].hi |= pwrval_max;
189 static void match_pstates(u32 nodes, u32 *p, u32 *px)
193 u32 p_int[NODE_NUMS];
197 for(i=0;i<nodes; i++) {
201 for(i=0;i<nodes; i++) {
202 if(px[i]<=(p[i]+jj)) {
208 for(i=0; i<nodes; i++) {
209 p_int[i] = px[i] - jj;
211 match_pstate(nodes, p_int);
212 dump_p("P int\n", nodes, p_int);
216 for(i=0;i<nodes; i++) {
217 for(j=p[i]+1; j<p_int[i]; j++) {
218 sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
227 void prep_pstates_all(void)
229 device_t f3_dev[NODE_NUMS], f4_dev[NODE_NUMS];
231 u32 p_htc[NODE_NUMS];
232 u32 p_lowest[NODE_NUMS];
234 u32 lowest_htc_equal = 0;
236 u32 nodes = sysconf.nodes;
244 for(i=0;i<nodes; i++) { // get the value from F4x1F0:E0 or we can get that msr in CAR stage...
245 f3_dev[i] = get_node_pci(i, 3);
246 f4_dev[i] = get_node_pci(i, 4);
249 for(i=0;i<nodes; i++) { // get the value from F4x1F0:E0 or we can get that msr in CAR stage...
250 val = pci_read_config32(f4_dev[i], 0x1f4);
252 nbvid1 = (val>>7) & 0x3f;
254 val = pci_read_config32(f4_dev[i], 0x1e0 + (j<<2));
255 nbdid = ((val>>16) & 1);
256 sysconf.msr_pstate[i*5+j].lo = (val & 0xffff) | (nbdid<<22) | ((nbdid?nbvid1:nbvid0)<<25);
257 sysconf.msr_pstate[i*5+j].hi = (((val>>17) & 0x3ff) << (32-32)) | (((val>>27) & 1)<<(63-32));
261 dump_msr_pstates(nodes);
263 sysconf.needs_update_pstate_msrs = 0; // normal case for all sockets are installed same conf CPU
265 for(i=1; (i<nodes) && (!sysconf.needs_update_pstate_msrs); i++) {
267 if((sysconf.msr_pstate[i*5+j].lo != sysconf.msr_pstate[0*5+j].lo) || (sysconf.msr_pstate[i*5+j].hi != sysconf.msr_pstate[0*5+j].hi)) {
268 sysconf.needs_update_pstate_msrs = 1;
274 if(sysconf.needs_update_pstate_msrs) {
276 // update msr_pstate for mixed conf
279 /* Match P0 cpu cof for all cpu cores to the lowest P0 cpu cof value in the coherent fabric, and match P0 power for all cpu cores to the highest P0 power value */
280 for(i=0;i<nodes; i++) p[i] = 0;
281 match_pstate(nodes, p);
282 dump_p("P0\n", nodes, p);
283 dump_msr_pstates(nodes);
287 for(i=0;i<nodes; i++) {
288 val = pci_read_config32(f3_dev[i], 0xe8); //htc cap
289 if(!(val & (1<<10))) {
295 val = pci_read_config32(f3_dev[i], 0x64);
296 p_htc[i] = (((val>>28) & 7));
299 pci_write_config32(f3_dev[i], 0x64, val);
300 val = pci_read_config32(f3_dev[i], 0x68); //stc
303 pci_write_config32(f3_dev[i], 0x68, val);
309 match_pstate(nodes, p_htc);
311 dump_p("P_htc\n", nodes, p_htc);
312 dump_msr_pstates(nodes);
316 for(i=0;i<nodes; i++) {
319 if(sysconf.msr_pstate[i*5+j].hi & (1<<(63-32))) {
324 val = pci_read_config32(f3_dev[i], 0xdc);
325 if(p_lowest[i]>((val>>8) & 7)) {
327 val |= (p_lowest[i])<<8;
328 pci_write_config32(f3_dev[i], 0xdc, val);
331 p_lowest[i] = (val>>8) & 7;
335 for(i=0;i<nodes; i++) {
336 if(p_lowest[i]==p_htc[i]){
337 lowest_htc_equal = 1;
342 if(lowest_htc_equal) {
343 for(i=0;i<nodes; i++) {
345 val = pci_read_config32(f3_dev[i], 0xdc);
348 pci_write_config32(f3_dev[i], 0xdc, val);
349 for(j=p_htc[i]+1; j<5; j++) {
350 sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
354 match_pstate(nodes, p_lowest);
355 for(i=0; i<nodes; i++) {
356 for(j=p_lowest[i]+1; j<5; j++) {
357 sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
363 dump_p("Px\n", nodes, p_lowest);
364 dump_msr_pstates(nodes);
369 match_pstates(nodes, p, p_htc);
371 dump_msr_pstates(nodes);
374 match_pstates(nodes, p_htc, p_lowest);
376 match_pstates(nodes, p, p_lowest);
379 dump_msr_pstates(nodes);
383 // fill data into p_state
384 for(i=0; i<nodes; i++) {
385 sysconf.p_state_num = 0;
386 u32 corefid_equal = 1;
388 corefid = (sysconf.msr_pstate[i*5+0].lo & 0x3f);
391 msr_pstate = &(sysconf.msr_pstate[i*5+j]);
392 if(!(msr_pstate->hi & (1<<(63-32)) )) continue;
393 if((msr_pstate->lo & 0x3f) != corefid) {
399 struct p_state_t *p_state;
401 msr_pstate = &sysconf.msr_pstate[i*5+j];
402 if(!(msr_pstate->hi & (1<<(63-32)) )) continue;
403 p_state = &sysconf.p_state[i*5+sysconf.p_state_num];
404 u32 coredid = ((msr_pstate->lo>>6) & 7);
405 u32 corecof = ((msr_pstate->lo & 0x3f) + 0x10)>>coredid;
406 p_state->corefreq = corecof;
408 u32 pwrval, pwrvalue;
409 pwrval = msr_pstate->hi & 0x3ff;
410 pwrvalue = get_pwrvalue(pwrval);
411 p_state->power = pwrvalue;
414 val = pci_read_config32(f3_dev[i], 0xd4);
415 lat = 15 * (get_powerstep((val>>24)& 0xf)+get_powerstep((val>>20)& 0xf)) /1000;
417 val = pci_read_config32(f3_dev[i], 0xa0);
418 lat += get_plllocktime((val >> 11 ) & 7);
420 p_state->transition_lat = lat;
421 p_state->busmaster_lat = lat;
423 p_state->control = j;
426 sysconf.p_state_num++;
428 // don't need look at other nodes
429 if(!sysconf.p_state_num) break;
434 //it will update pstates info from ram into MSR
435 void init_pstates(device_t dev, u32 nodeid, u32 coreid)
440 if(sysconf.needs_update_pstate_msrs) {
441 for(j=0; j < 5; j++) {
442 wrmsr(0xC0010064 + j, sysconf.msr_pstate[nodeid * 5 + j]);
446 /* Set TSC Freq Select: TSC increments at the rate of the core P-state 0 */
447 msr = rdmsr(0xC0010015);
449 wrmsr(0xC0010015, msr);
451 // Enter the state P0
452 //FIXME I don't think that this works correctly. May depend on early fid/vid setup.
453 if(sysconf.p_state_num)
454 set_core_nb_max_pstate_after_other_warm_reset(nodeid, coreid);