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