Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * (C) 2004-2006  Sebastian Witt <se.witt@gmx.net>
0004  *
0005  *  Based upon reverse engineered information
0006  *
0007  *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
0008  */
0009 
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/moduleparam.h>
0015 #include <linux/init.h>
0016 #include <linux/cpufreq.h>
0017 #include <linux/pci.h>
0018 #include <linux/delay.h>
0019 
0020 #define NFORCE2_XTAL 25
0021 #define NFORCE2_BOOTFSB 0x48
0022 #define NFORCE2_PLLENABLE 0xa8
0023 #define NFORCE2_PLLREG 0xa4
0024 #define NFORCE2_PLLADR 0xa0
0025 #define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div)
0026 
0027 #define NFORCE2_MIN_FSB 50
0028 #define NFORCE2_SAFE_DISTANCE 50
0029 
0030 /* Delay in ms between FSB changes */
0031 /* #define NFORCE2_DELAY 10 */
0032 
0033 /*
0034  * nforce2_chipset:
0035  * FSB is changed using the chipset
0036  */
0037 static struct pci_dev *nforce2_dev;
0038 
0039 /* fid:
0040  * multiplier * 10
0041  */
0042 static int fid;
0043 
0044 /* min_fsb, max_fsb:
0045  * minimum and maximum FSB (= FSB at boot time)
0046  */
0047 static int min_fsb;
0048 static int max_fsb;
0049 
0050 MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
0051 MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver");
0052 MODULE_LICENSE("GPL");
0053 
0054 module_param(fid, int, 0444);
0055 module_param(min_fsb, int, 0444);
0056 
0057 MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
0058 MODULE_PARM_DESC(min_fsb,
0059         "Minimum FSB to use, if not defined: current FSB - 50");
0060 
0061 /**
0062  * nforce2_calc_fsb - calculate FSB
0063  * @pll: PLL value
0064  *
0065  *   Calculates FSB from PLL value
0066  */
0067 static int nforce2_calc_fsb(int pll)
0068 {
0069     unsigned char mul, div;
0070 
0071     mul = (pll >> 8) & 0xff;
0072     div = pll & 0xff;
0073 
0074     if (div > 0)
0075         return NFORCE2_XTAL * mul / div;
0076 
0077     return 0;
0078 }
0079 
0080 /**
0081  * nforce2_calc_pll - calculate PLL value
0082  * @fsb: FSB
0083  *
0084  *   Calculate PLL value for given FSB
0085  */
0086 static int nforce2_calc_pll(unsigned int fsb)
0087 {
0088     unsigned char xmul, xdiv;
0089     unsigned char mul = 0, div = 0;
0090     int tried = 0;
0091 
0092     /* Try to calculate multiplier and divider up to 4 times */
0093     while (((mul == 0) || (div == 0)) && (tried <= 3)) {
0094         for (xdiv = 2; xdiv <= 0x80; xdiv++)
0095             for (xmul = 1; xmul <= 0xfe; xmul++)
0096                 if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) ==
0097                     fsb + tried) {
0098                     mul = xmul;
0099                     div = xdiv;
0100                 }
0101         tried++;
0102     }
0103 
0104     if ((mul == 0) || (div == 0))
0105         return -1;
0106 
0107     return NFORCE2_PLL(mul, div);
0108 }
0109 
0110 /**
0111  * nforce2_write_pll - write PLL value to chipset
0112  * @pll: PLL value
0113  *
0114  *   Writes new FSB PLL value to chipset
0115  */
0116 static void nforce2_write_pll(int pll)
0117 {
0118     int temp;
0119 
0120     /* Set the pll addr. to 0x00 */
0121     pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0);
0122 
0123     /* Now write the value in all 64 registers */
0124     for (temp = 0; temp <= 0x3f; temp++)
0125         pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll);
0126 }
0127 
0128 /**
0129  * nforce2_fsb_read - Read FSB
0130  *
0131  *   Read FSB from chipset
0132  *   If bootfsb != 0, return FSB at boot-time
0133  */
0134 static unsigned int nforce2_fsb_read(int bootfsb)
0135 {
0136     struct pci_dev *nforce2_sub5;
0137     u32 fsb, temp = 0;
0138 
0139     /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
0140     nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, 0x01EF,
0141                 PCI_ANY_ID, PCI_ANY_ID, NULL);
0142     if (!nforce2_sub5)
0143         return 0;
0144 
0145     pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb);
0146     fsb /= 1000000;
0147 
0148     /* Check if PLL register is already set */
0149     pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
0150 
0151     if (bootfsb || !temp)
0152         return fsb;
0153 
0154     /* Use PLL register FSB value */
0155     pci_read_config_dword(nforce2_dev, NFORCE2_PLLREG, &temp);
0156     fsb = nforce2_calc_fsb(temp);
0157 
0158     return fsb;
0159 }
0160 
0161 /**
0162  * nforce2_set_fsb - set new FSB
0163  * @fsb: New FSB
0164  *
0165  *   Sets new FSB
0166  */
0167 static int nforce2_set_fsb(unsigned int fsb)
0168 {
0169     u32 temp = 0;
0170     unsigned int tfsb;
0171     int diff;
0172     int pll = 0;
0173 
0174     if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
0175         pr_err("FSB %d is out of range!\n", fsb);
0176         return -EINVAL;
0177     }
0178 
0179     tfsb = nforce2_fsb_read(0);
0180     if (!tfsb) {
0181         pr_err("Error while reading the FSB\n");
0182         return -EINVAL;
0183     }
0184 
0185     /* First write? Then set actual value */
0186     pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
0187     if (!temp) {
0188         pll = nforce2_calc_pll(tfsb);
0189 
0190         if (pll < 0)
0191             return -EINVAL;
0192 
0193         nforce2_write_pll(pll);
0194     }
0195 
0196     /* Enable write access */
0197     temp = 0x01;
0198     pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp);
0199 
0200     diff = tfsb - fsb;
0201 
0202     if (!diff)
0203         return 0;
0204 
0205     while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) {
0206         if (diff < 0)
0207             tfsb++;
0208         else
0209             tfsb--;
0210 
0211         /* Calculate the PLL reg. value */
0212         pll = nforce2_calc_pll(tfsb);
0213         if (pll == -1)
0214             return -EINVAL;
0215 
0216         nforce2_write_pll(pll);
0217 #ifdef NFORCE2_DELAY
0218         mdelay(NFORCE2_DELAY);
0219 #endif
0220     }
0221 
0222     temp = 0x40;
0223     pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp);
0224 
0225     return 0;
0226 }
0227 
0228 /**
0229  * nforce2_get - get the CPU frequency
0230  * @cpu: CPU number
0231  *
0232  * Returns the CPU frequency
0233  */
0234 static unsigned int nforce2_get(unsigned int cpu)
0235 {
0236     if (cpu)
0237         return 0;
0238     return nforce2_fsb_read(0) * fid * 100;
0239 }
0240 
0241 /**
0242  * nforce2_target - set a new CPUFreq policy
0243  * @policy: new policy
0244  * @target_freq: the target frequency
0245  * @relation: how that frequency relates to achieved frequency
0246  *  (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
0247  *
0248  * Sets a new CPUFreq policy.
0249  */
0250 static int nforce2_target(struct cpufreq_policy *policy,
0251               unsigned int target_freq, unsigned int relation)
0252 {
0253 /*        unsigned long         flags; */
0254     struct cpufreq_freqs freqs;
0255     unsigned int target_fsb;
0256 
0257     if ((target_freq > policy->max) || (target_freq < policy->min))
0258         return -EINVAL;
0259 
0260     target_fsb = target_freq / (fid * 100);
0261 
0262     freqs.old = nforce2_get(policy->cpu);
0263     freqs.new = target_fsb * fid * 100;
0264 
0265     if (freqs.old == freqs.new)
0266         return 0;
0267 
0268     pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
0269            freqs.old, freqs.new);
0270 
0271     cpufreq_freq_transition_begin(policy, &freqs);
0272 
0273     /* Disable IRQs */
0274     /* local_irq_save(flags); */
0275 
0276     if (nforce2_set_fsb(target_fsb) < 0)
0277         pr_err("Changing FSB to %d failed\n", target_fsb);
0278     else
0279         pr_debug("Changed FSB successfully to %d\n",
0280             target_fsb);
0281 
0282     /* Enable IRQs */
0283     /* local_irq_restore(flags); */
0284 
0285     cpufreq_freq_transition_end(policy, &freqs, 0);
0286 
0287     return 0;
0288 }
0289 
0290 /**
0291  * nforce2_verify - verifies a new CPUFreq policy
0292  * @policy: new policy
0293  */
0294 static int nforce2_verify(struct cpufreq_policy_data *policy)
0295 {
0296     unsigned int fsb_pol_max;
0297 
0298     fsb_pol_max = policy->max / (fid * 100);
0299 
0300     if (policy->min < (fsb_pol_max * fid * 100))
0301         policy->max = (fsb_pol_max + 1) * fid * 100;
0302 
0303     cpufreq_verify_within_cpu_limits(policy);
0304     return 0;
0305 }
0306 
0307 static int nforce2_cpu_init(struct cpufreq_policy *policy)
0308 {
0309     unsigned int fsb;
0310     unsigned int rfid;
0311 
0312     /* capability check */
0313     if (policy->cpu != 0)
0314         return -ENODEV;
0315 
0316     /* Get current FSB */
0317     fsb = nforce2_fsb_read(0);
0318 
0319     if (!fsb)
0320         return -EIO;
0321 
0322     /* FIX: Get FID from CPU */
0323     if (!fid) {
0324         if (!cpu_khz) {
0325             pr_warn("cpu_khz not set, can't calculate multiplier!\n");
0326             return -ENODEV;
0327         }
0328 
0329         fid = cpu_khz / (fsb * 100);
0330         rfid = fid % 5;
0331 
0332         if (rfid) {
0333             if (rfid > 2)
0334                 fid += 5 - rfid;
0335             else
0336                 fid -= rfid;
0337         }
0338     }
0339 
0340     pr_info("FSB currently at %i MHz, FID %d.%d\n",
0341         fsb, fid / 10, fid % 10);
0342 
0343     /* Set maximum FSB to FSB at boot time */
0344     max_fsb = nforce2_fsb_read(1);
0345 
0346     if (!max_fsb)
0347         return -EIO;
0348 
0349     if (!min_fsb)
0350         min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE;
0351 
0352     if (min_fsb < NFORCE2_MIN_FSB)
0353         min_fsb = NFORCE2_MIN_FSB;
0354 
0355     /* cpuinfo and default policy values */
0356     policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
0357     policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
0358 
0359     return 0;
0360 }
0361 
0362 static int nforce2_cpu_exit(struct cpufreq_policy *policy)
0363 {
0364     return 0;
0365 }
0366 
0367 static struct cpufreq_driver nforce2_driver = {
0368     .name = "nforce2",
0369     .flags = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
0370     .verify = nforce2_verify,
0371     .target = nforce2_target,
0372     .get = nforce2_get,
0373     .init = nforce2_cpu_init,
0374     .exit = nforce2_cpu_exit,
0375 };
0376 
0377 #ifdef MODULE
0378 static const struct pci_device_id nforce2_ids[] = {
0379     { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
0380     {}
0381 };
0382 MODULE_DEVICE_TABLE(pci, nforce2_ids);
0383 #endif
0384 
0385 /**
0386  * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
0387  *
0388  * Detects nForce2 A2 and C1 stepping
0389  *
0390  */
0391 static int nforce2_detect_chipset(void)
0392 {
0393     nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
0394                     PCI_DEVICE_ID_NVIDIA_NFORCE2,
0395                     PCI_ANY_ID, PCI_ANY_ID, NULL);
0396 
0397     if (nforce2_dev == NULL)
0398         return -ENODEV;
0399 
0400     pr_info("Detected nForce2 chipset revision %X\n",
0401         nforce2_dev->revision);
0402     pr_info("FSB changing is maybe unstable and can lead to crashes and data loss\n");
0403 
0404     return 0;
0405 }
0406 
0407 /**
0408  * nforce2_init - initializes the nForce2 CPUFreq driver
0409  *
0410  * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported
0411  * devices, -EINVAL on problems during initialization, and zero on
0412  * success.
0413  */
0414 static int __init nforce2_init(void)
0415 {
0416     /* TODO: do we need to detect the processor? */
0417 
0418     /* detect chipset */
0419     if (nforce2_detect_chipset()) {
0420         pr_info("No nForce2 chipset\n");
0421         return -ENODEV;
0422     }
0423 
0424     return cpufreq_register_driver(&nforce2_driver);
0425 }
0426 
0427 /**
0428  * nforce2_exit - unregisters cpufreq module
0429  *
0430  *   Unregisters nForce2 FSB change support.
0431  */
0432 static void __exit nforce2_exit(void)
0433 {
0434     cpufreq_unregister_driver(&nforce2_driver);
0435 }
0436 
0437 module_init(nforce2_init);
0438 module_exit(nforce2_exit);