Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);