root/drivers/cpufreq/cpufreq-nforce2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nforce2_calc_fsb
  2. nforce2_calc_pll
  3. nforce2_write_pll
  4. nforce2_fsb_read
  5. nforce2_set_fsb
  6. nforce2_get
  7. nforce2_target
  8. nforce2_verify
  9. nforce2_cpu_init
  10. nforce2_cpu_exit
  11. nforce2_detect_chipset
  12. nforce2_init
  13. nforce2_exit

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

/* [<][>][^][v][top][bottom][index][help] */