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