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