e35b5fc543819898e7543dc8926263896a71adce
[coreboot.git] / src / cpu / amd / model_fxx / fidvid.c
1 #if K8_SET_FIDVID == 1
2
3 #define K8_SET_FIDVID_DEBUG 0
4
5 #define K8_SET_FIDVID_ONE_BY_ONE 1
6
7 #define K8_SET_FIDVID_STORE_AP_APICID_AT_FIRST 1
8
9 #ifndef SB_VFSMAF 
10 #define SB_VFSMAF 1
11 #endif
12
13 #define FX_SUPPORT 1
14
15 static inline void print_debug_fv(const char *str, unsigned val)
16 {
17 #if K8_SET_FIDVID_DEBUG == 1
18         #if CONFIG_USE_PRINTK_IN_CAR
19                 printk_debug("%s%x\r\n", str, val);
20         #else
21                 print_debug(str); print_debug_hex32(val); print_debug("\r\n");
22         #endif
23 #endif
24 }
25
26 static inline void print_debug_fv_8(const char *str, unsigned val)
27 {
28 #if K8_SET_FIDVID_DEBUG == 1
29         #if CONFIG_USE_PRINTK_IN_CAR
30                 printk_debug("%s%02x\r\n", str, val);
31         #else
32                 print_debug(str); print_debug_hex8(val); print_debug("\r\n");
33         #endif
34 #endif
35 }
36
37 static inline void print_debug_fv_64(const char *str, unsigned val, unsigned val2)
38 {
39 #if K8_SET_FIDVID_DEBUG == 1
40         #if CONFIG_USE_PRINTK_IN_CAR
41                 printk_debug("%s%x%x\r\n", str, val, val2);
42         #else
43                 print_debug(str); print_debug_hex32(val); print_debug_hex32(val2); print_debug("\r\n");
44         #endif
45 #endif
46 }
47
48
49 static void enable_fid_change(void)
50 {
51         uint32_t dword;
52         unsigned nodes;
53         int i;
54
55         nodes = ((pci_read_config32(PCI_DEV(0, 0x18, 0), 0x60)>>4) & 7) + 1;
56
57         for(i=0; i<nodes; i++) {
58                 dword = pci_read_config32(PCI_DEV(0, 0x18+i, 3), 0xd8);
59                 dword &= 0x8ff00000;
60                 dword |= (2<<28) | (0x02710);
61                 pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0xd8, dword);
62
63                 dword = 0x04e2a707;
64                 pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0xd4, dword);
65
66                 dword = pci_read_config32(PCI_DEV(0, 0x18+i, 2), 0x94);
67                 dword |= (1<<14);// disable the DRAM interface at first, it will be enabled by raminit again
68                 pci_write_config32(PCI_DEV(0, 0x18+i, 2), 0x94, dword);
69
70                 dword = 0x23070700; //enable FID/VID change
71 //              dword = 0x00070000; //enable FID/VID change
72                 pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0x80, dword);
73
74                 dword = 0x00132113;
75                 pci_write_config32(PCI_DEV(0, 0x18+i, 3), 0x84, dword);
76
77         }
78 }
79
80 #if K8_SET_FIDVID_ONE_BY_ONE == 0
81 static unsigned set_fidvid_without_init(unsigned fidvid)
82 {
83
84         msr_t msr;
85         uint32_t vid;
86         uint32_t fid;
87
88         fid = (fidvid >> 8) & 0x3f;
89         vid = (fidvid >> 16) & 0x3f;
90
91         // set new FID/VID
92         msr.hi = 1;
93         msr.lo = (vid<<8) | fid;
94         wrmsr(0xc0010041, msr);
95         return fidvid;
96 }
97 #endif
98
99 static unsigned set_fidvid(unsigned apicid, unsigned fidvid, int showmessage)
100 {
101         //for (cur, new) there is one <1600MHz x8 to find out next_fid 
102         static const uint8_t next_fid_a[] = {
103         /* x4  x5  x6  x7  x8  x9 x10 x11 x12 x13 x14 x15 */ // 0:x4, 2:x5....BASE=4, MIN=4, MAX=25, INC=2 result = (xX-BASE)*INC
104 /* x4 */    0,  9,  9,  8,  9,  9,  9,  9,  9,  9,  9,  9,
105 /* x5 */    9,  0, 11, 11,  9,  9, 10, 11, 11, 11, 11, 11, 
106 /* x6 */   11, 11,  0, 13, 11, 11, 11, 11, 12, 13, 13, 13,
107 /* x7 */   13, 13, 13,  0, 13, 13, 13, 13, 13, 13, 14, 15,
108 /* x8 */    4,  9,  9,  9,  0,  9,  9,  9,  9,  9,  9,  9,
109 /* x9 */    4,  5, 10, 10,  8,  0,  0,  0,  0,  0,  0,  0, 
110 /*x10 */    9,  5, 11, 11,  9,  0,  0,  0,  0,  0,  0,  0, 
111 /*x11 */   10,  5,  6, 12, 10,  0,  0,  0,  0,  0,  0,  0,
112 /*x12 */   11, 11,  6, 13, 11,  0,  0,  0,  0,  0,  0,  0,
113 /*x13 */   12, 12,  6,  7, 12,  0,  0,  0,  0,  0,  0,  0,
114 /*x14 */   13, 13, 13,  7, 13,  0,  0,  0,  0,  0,  0,  0,
115 /*x15 */   14, 14, 14,  7, 14,  0,  0,  0,  0,  0,  0,  0, 
116         };
117
118         msr_t msr;
119         uint32_t vid;
120         uint32_t fid;
121         uint32_t vid_max;
122         uint32_t fid_max;
123         uint32_t vid_cur;
124         uint32_t fid_cur;
125         unsigned apicidx;
126
127         int steps;
128         int loop;
129
130         apicidx = lapicid();
131
132         if(apicid!=apicidx) {
133 #if CONFIG_USE_PRINTK_IN_CAR    
134                 printk_err("wrong apicid, we want change %x, but it is %x\r\n", apicid, apicidx);
135 #else
136                 print_err("wrong apicid, we want change "); print_err_hex8(apicid); print_err(" but it is "); print_err_hex8(apicidx); print_err("\r\n");
137 #endif
138                 return fidvid;  
139         }
140
141         fid = (fidvid >> 8) & 0x3f;
142         vid = (fidvid >> 16) & 0x3f;
143
144         msr = rdmsr(0xc0010042);
145
146         vid_cur = msr.hi & 0x3f;
147         fid_cur = msr.lo & 0x3f;
148
149         if((vid_cur==vid) && (fid_cur==fid)) return fidvid; 
150
151         vid_max = (msr.hi>>(48-32)) & 0x3f;
152         fid_max = ((msr.lo>>16) & 0x3f); //max fid
153 #if FX_SUPPORT
154         if(fid_max>=((25-4)*2)) { // FX max fid is 5G
155                 fid_max = ((msr.lo>>8) & 0x3f) + 5*2; // max FID is min fid + 1G
156                 if(fid_max >= ((25-4)*2)) {
157                         fid_max = (10-4)*2; // hard set to 2G
158                 }
159         }
160 #endif
161
162         //set vid to max
163         msr.hi = 1;
164         msr.lo = (vid_max<<8) | (fid_cur);
165 #if SB_VFSMAF == 1
166         msr.lo |= (1<<16); // init changes
167 #endif
168         wrmsr(0xc0010041, msr);
169 #if SB_VFSMAF == 0
170         ldtstop_sb();
171 #endif
172         
173
174         for(loop=0;loop<100000;loop++){
175                 msr = rdmsr(0xc0010042);
176                 if(!(msr.lo & (1<<31))) break;
177         }
178         vid_cur = msr.hi & 0x3f;
179
180         steps = 8; //??
181         while((fid_cur!=fid) && (steps-->0)) {
182                 uint32_t fid_temp;      
183                 if((fid_cur > (8-4)*2) && (fid> (8-4)*2)) {
184                         if(fid_cur<fid) {
185                                 fid_temp = fid_cur + 2;
186                         } else {
187                                 fid_temp = fid_cur - 2;
188                         }
189                 }
190                 else { //there is one < 8, So we need to lookup the table to find the fid_cur
191                         int temp;
192                         temp = next_fid_a[(fid_cur/2)*12+(fid/2)];
193                         if(temp <= 0) break;
194                         fid_temp = (temp-4) * 2;
195                 }
196                 if(fid_temp>fid_max) break;
197
198                 fid_cur = fid_temp;
199
200                 //set target fid
201                 msr.hi = (100000/5);
202                 msr.lo = (vid_cur<<8) | fid_cur;
203 #if SB_VFSMAF == 1
204                 msr.lo |= (1<<16); // init changes
205 #endif
206                 wrmsr(0xc0010041, msr);
207 #if SB_VFSMAF == 0
208                 ldtstop_sb();
209 #endif
210
211
212 #if K8_SET_FIDVID_DEBUG == 1
213                 if(showmessage) {
214                         print_debug_fv_8("\tapicid in set_fidvid = ", apicid);
215                         print_debug_fv_64("ctrl msr fid, vid ", msr.hi, msr.lo); 
216                 }
217 #endif
218
219                 for(loop=0;loop<100000;loop++){
220                         msr = rdmsr(0xc0010042);
221                         if(!(msr.lo & (1<<31))) break;
222                 }
223                 fid_cur = msr.lo & 0x3f;
224
225 #if K8_SET_FIDVID_DEBUG == 1
226                 if(showmessage) {       
227                         print_debug_fv_64("status msr fid, vid ", msr.hi, msr.lo);
228                 }
229 #endif
230         }
231
232         //set vid to final 
233         msr.hi = 1;
234         msr.lo = (vid<<8) | (fid_cur);
235 #if SB_VFSMAF == 1
236         msr.lo |= (1<<16); // init changes
237 #endif
238         wrmsr(0xc0010041, msr);
239 #if SB_VFSMAF == 0
240         ldtstop_sb();
241 #endif
242
243         for(loop=0;loop<100000;loop++){
244                 msr = rdmsr(0xc0010042);
245                 if(!(msr.lo & (1<<31))) break;
246         }
247         vid_cur = msr.hi & 0x3f;
248
249         fidvid = (vid_cur<< 16) | (fid_cur<<8);
250
251         if(showmessage) {
252                 if(vid!=vid_cur) {
253                         print_err("set vid failed for apicid ="); print_err_hex8(apicidx);  print_err("\r\n");
254                 }
255                 if(fid!=fid_cur) {
256                         print_err("set fid failed for apicid ="); print_err_hex8(apicidx); print_err("\r\n");
257                 }
258         }
259
260         return fidvid;
261
262 }
263
264 static void init_fidvid_ap(unsigned bsp_apicid, unsigned apicid)
265 {
266
267         uint32_t send;
268         uint32_t readback = 0;
269         unsigned timeout = 1;
270         msr_t msr;
271         uint32_t vid_cur;
272         uint32_t fid_cur;
273         uint32_t fid_max;
274         int loop;
275
276         msr =  rdmsr(0xc0010042);
277         fid_max = ((msr.lo>>16) & 0x3f); //max fid
278 #if FX_SUPPORT
279         if(fid_max>=((25-4)*2)) { // FX max fid is 5G
280                 fid_max = ((msr.lo>>8) & 0x3f) + 5*2; // max FID is min fid + 1G
281                 if(fid_max >= ((25-4)*2)) {
282                         fid_max = (10-4)*2; // hard set to 2G
283                 }
284         }
285 #endif
286         send = fid_max<<8;
287
288         send |= ((msr.hi>>(48-32)) & 0x3f) << 16; //max vid
289         send |= (apicid<<24); // ap apicid
290
291 #if K8_SET_FIDVID_ONE_BY_ONE == 1
292         vid_cur = msr.hi & 0x3f;
293         fid_cur = msr.lo & 0x3f;
294
295         // set to current
296         msr.hi = 1;
297         msr.lo = (vid_cur<<8) | (fid_cur);
298         wrmsr(0xc0010041, msr);
299 #endif
300
301         timeout = wait_cpu_state(bsp_apicid, 1);
302         if(timeout) {
303                 print_initcpu8("fidvid_ap_stage1: time out while reading from BSP on ", apicid);
304         }
305         //send signal to BSP about this AP max fid and vid
306         lapic_write(LAPIC_MSG_REG, send | 1); //AP at state 1 that sent our fid and vid
307
308 //      wait_cpu_state(bsp_apicid, 2);// don't need we can use apicid directly  
309         loop = 1000000;
310         while(--loop>0) {
311                 //remote read BSP signal that include vid and fid that need to set
312                 if(lapic_remote_read(bsp_apicid, LAPIC_MSG_REG, &readback)!=0) continue;
313                 if(((readback>>24) & 0xff) == apicid) break; // it is this cpu turn
314         }
315
316         if(loop>0) {
317         #if K8_SET_FIDVID_ONE_BY_ONE == 1
318                 readback = set_fidvid(apicid, readback & 0xffff00, 1); // this AP
319         #else
320                 readback = set_fidvid_without_init(readback & 0xffff00); // this AP
321         #endif
322                 //send signal to BSP that this AP fid/vid is set // allow to change state2 is together with apicid
323                 send = (apicid<<24) | (readback & 0x00ffff00); // AP at state that We set the requested fid/vid
324         } else {
325                 print_initcpu8("fidvid_ap_stage2: time out while reading from BSP on ", apicid);
326         }
327
328         lapic_write(LAPIC_MSG_REG, send | 2);
329
330         timeout = wait_cpu_state(bsp_apicid, 3);
331         if(timeout) {
332                 print_initcpu8("fidvid_ap_stage3: time out while reading from BSP on ", apicid);
333         }
334 }
335
336 static unsigned calc_common_fidvid(unsigned fidvid, unsigned fidvidx)
337 {
338         /* FIXME: need to check the change path to verify if it is reachable when common fid is small than 1.6G */      
339         if((fidvid & 0xff00)<=(fidvidx & 0xff00)) {
340                 return fidvid;
341         }
342         else {
343                 return fidvidx;
344         }
345
346
347 struct fidvid_st {
348         unsigned common_fidvid;
349 };
350
351 static void init_fidvid_bsp_stage1(unsigned ap_apicid, void *gp ) 
352 {               
353                 unsigned readback = 0;
354                 unsigned timeout = 1;
355
356                 struct fidvid_st *fvp = gp;
357                 int loop;
358                 
359                 print_debug_fv("state 1: ap_apicid=", ap_apicid);
360
361                 loop = 1000000;
362                 while(--loop > 0) {
363                       if(lapic_remote_read(ap_apicid, LAPIC_MSG_REG, &readback)!=0) continue;
364                       if((readback & 0xff) == 1) {
365                                 timeout = 0;
366                                 break; //target ap is in stage 1 
367                       }
368                 }
369                 if(timeout) {
370                         print_initcpu8("fidvid_bsp_stage1: time out while reading from ap ", ap_apicid);
371                         return;
372                 }
373
374                 print_debug_fv("\treadback=", readback);
375
376                 fvp->common_fidvid = calc_common_fidvid(fvp->common_fidvid, readback & 0xffff00);
377
378                 print_debug_fv("\tcommon_fidvid=", fvp->common_fidvid);
379
380 }
381 static void init_fidvid_bsp_stage2(unsigned ap_apicid, void *gp)
382 {
383                 unsigned readback = 0;
384                 unsigned timeout = 1;
385
386                 struct fidvid_st *fvp = gp;
387                 int loop;
388
389                 print_debug_fv("state 2: ap_apicid=", ap_apicid);
390
391                 lapic_write(LAPIC_MSG_REG, fvp->common_fidvid | (ap_apicid<<24) | 2); // all set to state2
392                 
393                 loop = 1000000; 
394                 while(--loop > 0) {
395                         if(lapic_remote_read(ap_apicid, LAPIC_MSG_REG, &readback)!=0) continue;
396                         if((readback & 0xff) == 2) { 
397                                 timeout = 0;
398                                 break; // target ap is stage 2, and it'd FID has beed set
399                         }
400                 }
401
402                 if(timeout) {
403                         print_initcpu8("fidvid_bsp_stage2: time out while reading from ap ", ap_apicid);
404                         return;
405                 }
406
407                 print_debug_fv("\treadback=", readback);
408 }
409
410 #if K8_SET_FIDVID_STORE_AP_APICID_AT_FIRST == 1
411 struct ap_apicid_st {
412         unsigned num;
413         unsigned apicid[16]; // 8 way dual core need 16
414         /* FIXME: 32 node quad core, may need 128 */
415 };
416
417 static void store_ap_apicid(unsigned ap_apicid, void *gp)
418 {
419         struct ap_apicid_st *p = gp;
420         
421         p->apicid[p->num++] = ap_apicid;
422
423 }
424 #endif
425
426 static void init_fidvid_bsp(unsigned bsp_apicid) 
427 {
428         uint32_t vid_max;
429         uint32_t fid_max;
430
431         struct fidvid_st fv;
432
433 #if K8_SET_FIDVID_STORE_AP_APICID_AT_FIRST == 1
434         struct ap_apicid_st ap_apicidx;
435         unsigned i;
436 #endif
437
438         
439         msr_t msr;
440         msr =  rdmsr(0xc0010042);
441         fid_max = ((msr.lo>>16) & 0x3f); //max fid
442 #if FX_SUPPORT == 1
443         if(fid_max>=((25-4)*2)) { // FX max fid is 5G
444                 fid_max = ((msr.lo>>8) & 0x3f) + 5*2; // max FID is min fid + 1G        
445                 if(fid_max >= ((25-4)*2)) {
446                         fid_max = (10-4)*2; // hard set to 2G
447                 }
448         }
449 #endif
450         vid_max = ((msr.hi>>(48-32)) & 0x3f); //max vid
451         fv.common_fidvid = (fid_max<<8)|(vid_max<<16);
452
453
454         // for all APs (We know the APIC ID of all APs even the APIC ID is lifted)
455         // remote read from AP about max fid/vid
456
457         //let all ap trains to state 1
458         lapic_write(LAPIC_MSG_REG,  (bsp_apicid<<24) | 1);  
459
460         // calculate the common max fid/vid that could be used for all APs and BSP
461 #if K8_SET_FIDVID_STORE_AP_APICID_AT_FIRST == 1
462         ap_apicidx.num = 0;
463         
464         for_each_ap(bsp_apicid, K8_SET_FIDVID_CORE0_ONLY, store_ap_apicid, &ap_apicidx);
465
466         for(i=0;i<ap_apicidx.num;i++) {
467                 init_fidvid_bsp_stage1(ap_apicidx.apicid[i], &fv);
468         }
469 #else
470         for_each_ap(bsp_apicid, K8_SET_FIDVID_CORE0_ONLY, init_fidvid_bsp_stage1, &fv);
471 #endif
472
473
474 #if 0
475         unsigned fid, vid;
476         // Can we use max only? So we can only set fid in one around, otherwise we need to set that to max after raminit
477         // set fid vid to DQS training required
478         fid = (fv.common_fidvid >> 8)  & 0x3f;
479         vid = (fv.common_fidvid >> 16) & 0x3f;
480
481         if(fid>(10-4)*2) {
482                 fid = (10-4)*2; //x10 
483         }
484
485         if(vid>=0x1f) {
486                 vid+= 4; //unit is 12.5mV
487         } else {
488                 vid+= 2; //unit is 25mV
489         }
490
491         fv.common_fidvid = (fid<<8) | (vid<<16);
492
493         print_debug_fv("common_fidvid=", fv.common_fidvid);
494
495 #endif
496
497 #if K8_SET_FIDVID_ONE_BY_ONE == 1 
498         // set BSP fid and vid
499         print_debug_fv("bsp apicid=", bsp_apicid);
500         fv.common_fidvid = set_fidvid(bsp_apicid, fv.common_fidvid, 1);
501         print_debug_fv("common_fidvid=", fv.common_fidvid);
502
503 #endif
504
505         //for all APs ( We know the APIC ID of all AP even the APIC ID is lifted)
506         // send signal to the AP it could change it's fid/vid
507         // remote read singnal from AP that AP is done
508
509         fv.common_fidvid &= 0xffff00;
510
511         //set state 2 allow is in init_fidvid_bsp_stage2
512 #if K8_SET_FIDVID_STORE_AP_APICID_AT_FIRST == 1
513         for(i=0;i<ap_apicidx.num;i++) {
514                 init_fidvid_bsp_stage2(ap_apicidx.apicid[i], &fv);
515         }
516 #else
517         for_each_ap(bsp_apicid, K8_SET_FIDVID_CORE0_ONLY, init_fidvid_bsp_stage2, &fv);
518 #endif
519
520 #if K8_SET_FIDVID_ONE_BY_ONE == 0
521         // set BSP fid and vid
522         print_debug_fv("bsp apicid=", bsp_apicid);
523         fv.common_fidvid = set_fidvid(bsp_apicid, fv.common_fidvid, 1);
524         print_debug_fv("common_fidvid=", fv.common_fidvid);
525
526 #endif
527
528         lapic_write(LAPIC_MSG_REG, fv.common_fidvid | (bsp_apicid<<24) | 3); // clear the state
529
530         //here  wait a while, so last ap could read pack, and stop it, don't call init_timer too early or just don't use init_timer
531
532 }
533
534 #endif