This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / i386 / kernel / cpu / cpufreq / cpufreq-nforce2.c
1 /*
2  * (C) 2004  Sebastian Witt <se.witt@gmx.net>
3  *
4  *  Licensed under the terms of the GNU GPL License version 2.
5  *  Based upon reverse engineered information
6  *
7  *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/moduleparam.h>
13 #include <linux/init.h>
14 #include <linux/cpufreq.h>
15 #include <linux/pci.h>
16 #include <linux/delay.h>
17
18 #define NFORCE2_XTAL 25
19 #define NFORCE2_BOOTFSB 0x48
20 #define NFORCE2_PLLENABLE 0xa8
21 #define NFORCE2_PLLREG 0xa4
22 #define NFORCE2_PLLADR 0xa0
23 #define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div)
24
25 #define NFORCE2_MIN_FSB 50
26 #define NFORCE2_SAFE_DISTANCE 50
27
28 /* Delay in ms between FSB changes */
29 //#define NFORCE2_DELAY 10
30
31 /* nforce2_chipset:
32  * FSB is changed using the chipset
33  */
34 static struct pci_dev *nforce2_chipset_dev;
35
36 /* fid:
37  * multiplier * 10
38  */
39 static int fid = 0;
40
41 /* min_fsb, max_fsb:
42  * minimum and maximum FSB (= FSB at boot time) 
43  */
44 static int min_fsb = 0;
45 static int max_fsb = 0;
46
47 MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
48 MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver");
49 MODULE_LICENSE("GPL");
50
51 module_param(fid, int, 0444);
52 module_param(min_fsb, int, 0444);
53
54 MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
55 MODULE_PARM_DESC(min_fsb,
56                  "Minimum FSB to use, if not defined: current FSB - 50");
57
58 /* DEBUG
59  *   Define it if you want verbose debug output, e.g. for bug reporting
60  */
61 //#define NFORCE2_DEBUG
62
63 #ifdef NFORCE2_DEBUG
64 #define dprintk(msg...) printk(msg)
65 #else
66 #define dprintk(msg...) do { } while(0)
67 #endif
68
69 /*
70  * nforce2_calc_fsb - calculate FSB
71  * @pll: PLL value
72  * 
73  *   Calculates FSB from PLL value
74  */
75 static int nforce2_calc_fsb(int pll)
76 {
77         unsigned char mul, div;
78
79         mul = (pll >> 8) & 0xff;
80         div = pll & 0xff;
81
82         if (div > 0)
83                 return NFORCE2_XTAL * mul / div;
84
85         return 0;
86 }
87
88 /*
89  * nforce2_calc_pll - calculate PLL value
90  * @fsb: FSB
91  * 
92  *   Calculate PLL value for given FSB
93  */
94 static int nforce2_calc_pll(unsigned int fsb)
95 {
96         unsigned char xmul, xdiv;
97         unsigned char mul = 0, div = 0;
98         int tried = 0;
99
100         /* Try to calculate multiplier and divider up to 4 times */
101         while (((mul == 0) || (div == 0)) && (tried <= 3)) {
102                 for (xdiv = 1; xdiv <= 0x80; xdiv++)
103                         for (xmul = 1; xmul <= 0xfe; xmul++)
104                                 if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) ==
105                                     fsb + tried) {
106                                         mul = xmul;
107                                         div = xdiv;
108                                 }
109                 tried++;
110         }
111
112         if ((mul == 0) || (div == 0))
113                 return -1;
114
115         return NFORCE2_PLL(mul, div);
116 }
117
118 /*
119  * nforce2_write_pll - write PLL value to chipset
120  * @pll: PLL value
121  * 
122  *   Writes new FSB PLL value to chipset
123  */
124 static void nforce2_write_pll(int pll)
125 {
126         int temp;
127
128         /* Set the pll addr. to 0x00 */
129         temp = 0x00;
130         pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLADR, temp);
131
132         /* Now write the value in all 64 registers */
133         for (temp = 0; temp <= 0x3f; temp++) {
134                 pci_write_config_dword(nforce2_chipset_dev, 
135                                        NFORCE2_PLLREG, pll);
136         }
137
138         return;
139 }
140
141 /*
142  * nforce2_fsb_read - Read FSB
143  *
144  *   Read FSB from chipset
145  *   If bootfsb != 0, return FSB at boot-time
146  */
147 static unsigned int nforce2_fsb_read(int bootfsb)
148 {
149         struct pci_dev *nforce2_sub5;
150         u32 fsb, temp = 0;
151
152         
153         /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
154         nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
155                                       0x01EF,
156                                       PCI_ANY_ID,
157                                       PCI_ANY_ID,
158                                       NULL);
159         
160         if (!nforce2_sub5)
161                 return 0;
162
163         pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb);
164         fsb /= 1000000;
165         
166         /* Check if PLL register is already set */
167         pci_read_config_byte(nforce2_chipset_dev, 
168                              NFORCE2_PLLENABLE, (u8 *)&temp);
169         
170         if(bootfsb || !temp)
171                 return fsb;
172                 
173         /* Use PLL register FSB value */
174         pci_read_config_dword(nforce2_chipset_dev, 
175                               NFORCE2_PLLREG, &temp);
176         fsb = nforce2_calc_fsb(temp);
177
178         return fsb;
179 }
180
181 /*
182  * nforce2_set_fsb - set new FSB
183  * @fsb: New FSB
184  * 
185  *   Sets new FSB
186  */
187 static int nforce2_set_fsb(unsigned int fsb)
188 {
189         u32 pll, temp = 0;
190         unsigned int tfsb;
191         int diff;
192
193         if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
194                 printk(KERN_ERR "cpufreq: FSB %d is out of range!\n", fsb);
195                 return -EINVAL;
196         }
197         
198         tfsb = nforce2_fsb_read(0);
199         if (!tfsb) {
200                 printk(KERN_ERR "cpufreq: Error while reading the FSB\n");
201                 return -EINVAL;
202         }
203
204         /* First write? Then set actual value */
205         pci_read_config_byte(nforce2_chipset_dev, 
206                              NFORCE2_PLLENABLE, (u8 *)&temp);
207         if (!temp) {
208                 pll = nforce2_calc_pll(tfsb);
209
210                 if (pll < 0)
211                         return -EINVAL;
212
213                 nforce2_write_pll(pll);
214         }
215
216         /* Enable write access */
217         temp = 0x01;
218         pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8)temp);
219
220         diff = tfsb - fsb;
221
222         if (!diff)
223                 return 0;
224
225         while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) {
226                 if (diff < 0)
227                         tfsb++;
228                 else
229                         tfsb--;
230
231                 /* Calculate the PLL reg. value */
232                 if ((pll = nforce2_calc_pll(tfsb)) == -1)
233                         return -EINVAL;
234                 
235                 nforce2_write_pll(pll);
236 #ifdef NFORCE2_DELAY
237                 mdelay(NFORCE2_DELAY);
238 #endif
239         }
240
241         temp = 0x40;
242         pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLADR, (u8)temp);
243
244         return 0;
245 }
246
247 /**
248  * nforce2_get - get the CPU frequency
249  * @cpu: CPU number
250  * 
251  * Returns the CPU frequency
252  */
253 static unsigned int nforce2_get(unsigned int cpu)
254 {
255         if (cpu)
256                 return 0;
257         return nforce2_fsb_read(0) * fid * 100;
258 }
259
260 /**
261  * nforce2_target - set a new CPUFreq policy
262  * @policy: new policy
263  * @target_freq: the target frequency
264  * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
265  *
266  * Sets a new CPUFreq policy.
267  */
268 static int nforce2_target(struct cpufreq_policy *policy,
269                           unsigned int target_freq, unsigned int relation)
270 {
271 //        unsigned long         flags;
272         struct cpufreq_freqs freqs;
273         unsigned int target_fsb;
274
275         if ((target_freq > policy->max) || (target_freq < policy->min))
276                 return -EINVAL;
277
278         target_fsb = target_freq / (fid * 100);
279
280         freqs.old = nforce2_get(policy->cpu);
281         freqs.new = target_fsb * fid * 100;
282         freqs.cpu = 0;          /* Only one CPU on nForce2 plattforms */
283
284         if (freqs.old == freqs.new)
285                 return 0;
286
287         dprintk(KERN_INFO "cpufreq: Old CPU frequency %d kHz, new %d kHz\n",
288                freqs.old, freqs.new);
289
290         cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
291
292         /* Disable IRQs */
293         //local_irq_save(flags);
294
295         if (nforce2_set_fsb(target_fsb) < 0)
296                 printk(KERN_ERR "cpufreq: Changing FSB to %d failed\n",
297                        target_fsb);
298         else
299                 dprintk(KERN_INFO "cpufreq: Changed FSB successfully to %d\n",
300                        target_fsb);
301
302         /* Enable IRQs */
303         //local_irq_restore(flags);
304
305         cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
306
307         return 0;
308 }
309
310 /**
311  * nforce2_verify - verifies a new CPUFreq policy
312  * @policy: new policy
313  */
314 static int nforce2_verify(struct cpufreq_policy *policy)
315 {
316         unsigned int fsb_pol_max;
317
318         fsb_pol_max = policy->max / (fid * 100);
319
320         if (policy->min < (fsb_pol_max * fid * 100))
321                 policy->max = (fsb_pol_max + 1) * fid * 100;
322
323         cpufreq_verify_within_limits(policy,
324                                      policy->cpuinfo.min_freq,
325                                      policy->cpuinfo.max_freq);
326         return 0;
327 }
328
329 static int nforce2_cpu_init(struct cpufreq_policy *policy)
330 {
331         unsigned int fsb;
332         unsigned int rfid;
333
334         /* capability check */
335         if (policy->cpu != 0)
336                 return -ENODEV;
337
338         /* Get current FSB */
339         fsb = nforce2_fsb_read(0);
340
341         if (!fsb)
342                 return -EIO;
343
344         /* FIX: Get FID from CPU */
345         if (!fid) {
346                 if (!cpu_khz) {
347                         printk(KERN_WARNING
348                                "cpufreq: cpu_khz not set, can't calculate multiplier!\n");
349                         return -ENODEV;
350                 }
351
352                 fid = cpu_khz / (fsb * 100);
353                 rfid = fid % 5;
354
355                 if (rfid) {
356                         if (rfid > 2)
357                                 fid += 5 - rfid;
358                         else
359                                 fid -= rfid;
360                 }
361         }
362
363         printk(KERN_INFO "cpufreq: FSB currently at %i MHz, FID %d.%d\n", fsb,
364                fid / 10, fid % 10);
365         
366         /* Set maximum FSB to FSB at boot time */
367         max_fsb = nforce2_fsb_read(1);
368         
369         if(!max_fsb)
370                 return -EIO;
371
372         if (!min_fsb)
373                 min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE;
374
375         if (min_fsb < NFORCE2_MIN_FSB)
376                 min_fsb = NFORCE2_MIN_FSB;
377
378         /* cpuinfo and default policy values */
379         policy->cpuinfo.min_freq = min_fsb * fid * 100;
380         policy->cpuinfo.max_freq = max_fsb * fid * 100;
381         policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
382         policy->cur = nforce2_get(policy->cpu);
383         policy->min = policy->cpuinfo.min_freq;
384         policy->max = policy->cpuinfo.max_freq;
385         policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
386
387         return 0;
388 }
389
390 static int nforce2_cpu_exit(struct cpufreq_policy *policy)
391 {
392         return 0;
393 }
394
395 static struct cpufreq_driver nforce2_driver = {
396         .name = "nforce2",
397         .verify = nforce2_verify,
398         .target = nforce2_target,
399         .get = nforce2_get,
400         .init = nforce2_cpu_init,
401         .exit = nforce2_cpu_exit,
402         .owner = THIS_MODULE,
403 };
404
405 /**
406  * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
407  *
408  * Detects nForce2 A2 and C1 stepping
409  * 
410  */
411 static unsigned int nforce2_detect_chipset(void)
412 {
413         u8 revision;
414
415         nforce2_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
416                                              PCI_DEVICE_ID_NVIDIA_NFORCE2,
417                                              PCI_ANY_ID,
418                                              PCI_ANY_ID,
419                                              NULL);
420
421         if (nforce2_chipset_dev == NULL)
422                 return -ENODEV;
423
424         pci_read_config_byte(nforce2_chipset_dev, PCI_REVISION_ID, &revision);
425
426         printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n",
427                revision);
428         printk(KERN_INFO
429                "cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n");
430
431         return 0;
432 }
433
434 /**
435  * nforce2_init - initializes the nForce2 CPUFreq driver
436  *
437  * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported
438  * devices, -EINVAL on problems during initiatization, and zero on
439  * success.
440  */
441 static int __init nforce2_init(void)
442 {
443         /* TODO: do we need to detect the processor? */
444
445         /* detect chipset */
446         if (nforce2_detect_chipset()) {
447                 printk(KERN_ERR "cpufreq: No nForce2 chipset.\n");
448                 return -ENODEV;
449         }
450
451         return cpufreq_register_driver(&nforce2_driver);
452 }
453
454 /**
455  * nforce2_exit - unregisters cpufreq module
456  *
457  *   Unregisters nForce2 FSB change support.
458  */
459 static void __exit nforce2_exit(void)
460 {
461         cpufreq_unregister_driver(&nforce2_driver);
462 }
463
464 module_init(nforce2_init);
465 module_exit(nforce2_exit);
466