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