Find matching settings for each CPUs FID, VID, and P-state registers and initialize...
[coreboot.git] / src / cpu / amd / model_10xxx / fidvid_common.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007 Advanced Micro Devices, Inc.
5  *
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.
9  *
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.
14  *
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
18  */
19
20
21 #include <cpu/x86/tsc.h>
22
23
24 static u32 get_vstime(u32 nodeid, u32 slam)
25 {
26         u32 val;
27         u32 v;
28         device_t dev;
29
30 #if defined(__ROMCC__)
31         dev = NODE_PCI(nodeid, 3);
32 #else
33         dev = get_node_pci(nodeid, 3);
34 #endif
35
36         val = pci_read_config32(dev, 0xd8);
37
38         val >>= slam?0:4;
39         val &= 7;
40
41         switch (val) {
42         case 4: v = 60; break;
43         case 5: v = 100; break;
44         case 6: v = 200; break;
45         case 7: v = 500; break;
46         default:
47                 v = (val+1)*10; // in us
48         }
49
50         return v;
51 }
52
53 static void udelay_tsc(u32 us)
54 {
55         /* Use TSC to delay because it is fixed, ie. it will not changed with p-states.
56          * Also, We use the APIC TIMER register is to hold flags for AP init.
57          */
58         u32 dword;
59         tsc_t tsc, tsc1, tscd;
60         u32 d =  0x00000200; //800Mhz or 200Mhz or 1.6G or get the NBFID at first
61         u32 dn = 0x1000000/2; // howmany us need to use hi
62
63         tscd.hi = us/dn;
64         tscd.lo = (us - tscd.hi * dn) * d;
65
66         tsc1 = rdtsc();
67         dword = tsc1.lo + tscd.lo;
68         if((dword<tsc1.lo) || (dword<tscd.lo)) {
69                 tsc1.hi++;
70         }
71         tsc1.lo = dword;
72         tsc1.hi+= tscd.hi;
73
74         do {
75                 tsc = rdtsc();
76         } while ((tsc.hi>tsc1.hi) || ((tsc.hi==tsc1.hi) && (tsc.lo>tsc1.lo)));
77
78 }
79
80 #ifdef __ROMCC__
81 void udelay(u32 usecs)
82 {
83         udelay_tsc(usecs);
84 }
85 #endif
86
87 static u32 set_vid(u32 newvid, u32 bit_offset, u32 nodeid, u32 coreid)
88 {
89         u32 val;
90         msr_t msr;
91         u32 curvid;
92         u32 slam;
93         u32 delay;
94         u32 count = 3;
95         device_t dev;
96
97         msr = rdmsr(0xc0010071);//status
98         curvid = (msr.lo >> bit_offset) & 0x7f; // seven bits
99
100         if(newvid == curvid) return curvid;
101
102 #if defined(__ROMCC__)
103         dev = NODE_PCI(nodeid, 3);
104 #else
105         dev = get_node_pci(nodeid, 3);
106 #endif
107
108         val = pci_read_config32(dev, 0xa0);
109
110         slam = (val >> 29) & 1;
111         delay = get_vstime(nodeid, slam);
112
113         if(!slam) {
114                 if(curvid>newvid) {
115                         count = (curvid - newvid) * 2;
116                 } else {
117                         count = (newvid - curvid) * 2;
118                 }
119         }
120
121         while(count-->0) {
122                 if(slam) {
123                         curvid = newvid;
124                 }
125                 else { //ramp
126                         if(curvid>newvid) {
127                                 curvid--;
128                         } else {
129                                 curvid++;
130                         }
131                 }
132
133                 msr = rdmsr(0xc0010070); //control
134                 msr.lo &= ~(0x7f<<bit_offset);
135                 msr.lo |= (curvid<<bit_offset);
136                 wrmsr(0xc0010070, msr); // how about all copys, APIC or PCI conf space?
137
138                 udelay_tsc(delay);
139
140                 msr = rdmsr(0xc0010071);//status
141                 curvid = (msr.lo >> bit_offset) & 0x7f; // seven bits
142
143                 if(curvid == newvid) break;
144
145         }
146
147         return curvid;
148 }
149
150
151 static u32 set_nb_vid(u32 newvid, u32 nodeid, u32 coreid)
152 {
153         return set_vid(newvid, 25, nodeid, coreid);
154 }
155
156
157 static u32 set_core_vid(u32 newvid, u32 nodeid, u32 coreid)
158 {
159         return set_vid(newvid, 9, nodeid, coreid);
160 }
161
162
163 static unsigned set_cof(u32 val, u32 mask, u32 nodeid, u32 coreid)
164 {
165         msr_t msr;
166         int count = 3;
167
168         val &= mask;
169
170         // FIXME: What is count for? Why 3 times? What about node and core id?
171         while(count-- > 0) {
172
173                 msr = rdmsr(0xc0010071);
174                 msr.lo &= mask;
175                 if(msr.lo == val) break;
176
177                 msr = rdmsr(0xc0010070);
178                 msr.lo &= ~(mask);
179                 msr.lo |= val;
180                 wrmsr(0xc0010070, msr);
181         }
182
183         return msr.lo;
184 }
185
186 static u32 set_core_cof(u32 fid, u32 did, u32 nodeid, u32 coreid)
187 {
188         u32 val;
189         u32 mask;
190
191         mask = (7<<6) | 0x3f;
192         val = ((did & 7)<<6) | (fid & 0x3f);
193
194         return set_cof(val, mask, nodeid, coreid);
195
196 }
197
198
199 static u32 set_nb_cof(u32 did, u32 nodeid, u32 coreid) // fid need warmreset
200 {
201         u32 val;
202         u32 mask;
203
204         mask = 1<<22;
205         val = (did & 1)<<22;
206
207         return set_cof(val, mask, nodeid, coreid);
208
209 }
210
211
212 /* set vid and cof for core and nb after warm reset is not started by BIOS */
213 static void set_core_nb_max_pstate_after_other_warm_reset(u32 nodeid, u32 coreid) // P0
214 {
215         msr_t msr;
216         u32 val;
217         u32 vid;
218         u32 mask;
219         u32 did;
220         device_t dev;
221
222         msr = rdmsr(0xc0010064);
223
224 #if defined(__ROMCC__)
225         dev = NODE_PCI(nodeid, 3);
226 #else
227         dev = get_node_pci(nodeid, 3);
228 #endif
229
230         val = pci_read_config32(dev, 0xa0);
231         if((val>>8) & 1) { // PVI
232                 vid = (msr.lo >> 25) & 0x7f;
233         } else { //SVI
234                 vid = (msr.lo >> 9) & 0x7f;
235         }
236         set_core_vid(vid, nodeid, coreid);
237
238         mask = (0x7<<6) | 0x3f;
239         val = msr.lo & mask;
240         set_cof(val, mask, nodeid, coreid);
241
242         //set nb cof and vid
243         did = (msr.lo >> 22) & 1;
244         vid = (msr.lo >> 25) & 0x7f;
245         if(did) {
246                  set_nb_cof(did, nodeid, coreid);
247                 set_nb_vid(vid, nodeid, coreid);
248         } else {
249                 set_nb_vid(vid, nodeid, coreid);
250                  set_nb_cof(did, nodeid, coreid);
251         }
252
253         //set the p state
254         msr.hi = 0;
255         msr.lo = 0;
256         wrmsr(0xc0010062, msr);
257
258 }
259
260
261 /* set vid and cof for core and nb after warm reset is not started by BIOS */
262 static void  set_core_nb_min_pstate_after_other_warm_reset(u32 nodeid, u32 coreid) // Px
263 {
264         msr_t msr;
265         u32 val;
266         u32 vid;
267         u32 mask;
268         u32 did;
269         u32 pstate;
270         device_t dev;
271
272 #if defined(__ROMCC__)
273         dev = NODE_PCI(nodeid, 3);
274 #else
275         dev = get_node_pci(nodeid, 3);
276 #endif
277
278
279         val = pci_read_config32(dev, 0xdc); //PstateMaxVal
280
281         pstate = (val >> 8) & 0x7;
282
283         msr = rdmsr(0xc0010064 + pstate);
284
285         mask = (7<<6) | 0x3f;
286         val = msr.lo & mask;
287         set_cof(val, mask, nodeid, coreid);
288
289         val = pci_read_config32(dev, 0xa0);
290         if((val>>8) & 1) { // PVI
291                  vid = (msr.lo>>25) & 0x7f;
292         } else { //SVI
293                  vid = (msr.lo>>9) & 0x7f;
294         }
295         set_core_vid(vid, nodeid, coreid);
296
297         //set nb cof and vid
298         did = (msr.lo >> 22) & 1;
299         vid = (msr.lo >> 25) & 0x7f;
300         if(did) {
301                 set_nb_cof(did, nodeid, coreid);
302                 set_nb_vid(vid, nodeid, coreid);
303         } else {
304                 set_nb_vid(vid, nodeid, coreid);
305                 set_nb_cof(did, nodeid, coreid);
306         }
307
308         //set the p state
309         msr.hi = 0;
310         msr.lo = pstate;
311         wrmsr(0xc0010062, msr);
312 }