📄 longhaul.c
字号:
/* * $Id: longhaul.c,v 1.83 2003/01/02 22:16:26 db Exp $ * * (C) 2001 Dave Jones. <davej@suse.de> * (C) 2002 Padraig Brady. <padraig@antefacto.com> * * Licensed under the terms of the GNU GPL License version 2. * Based upon datasheets & sample CPUs kindly provided by VIA. * * VIA have currently 3 different versions of Longhaul. * * +---------------------+----------+---------------------------------+ * | Marketing name | Codename | longhaul version / features. | * +---------------------+----------+---------------------------------+ * | Samuel/CyrixIII | C5A | v1 : multipliers only | * | Samuel2/C3 | C3E/C5B | v1 : multiplier only | * | Ezra | C5C | v2 : multipliers & voltage | * | Ezra-T | C5M/C5N | v3 : multipliers, voltage & FSB | * +---------------------+----------+---------------------------------+ * * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* */#include <linux/kernel.h>#include <linux/module.h> #include <linux/init.h>#include <linux/cpufreq.h>#include <linux/slab.h>#include <linux/string.h>#include <asm/msr.h>#include <asm/timex.h>#include <asm/io.h>#define DEBUG#ifdef DEBUG#define dprintk(msg...) printk(msg)#else#define dprintk(msg...) do { } while(0);#endifstatic int numscales=16, numvscales;static int minvid, maxvid;static int can_scale_voltage;static int can_scale_fsb;static int vrmrev;/* Module parameters */static int dont_scale_voltage;static int dont_scale_fsb;static int current_fsb;#define __hlt() __asm__ __volatile__("hlt": : :"memory")/* * Clock ratio tables. * The eblcr ones specify the ratio read from the CPU. * The clock_ratio ones specify what to write to the CPU. *//* VIA C3 Samuel 1 & Samuel 2 (stepping 0)*/static int __initdata longhaul1_clock_ratio[16] = { -1, /* 0000 -> RESERVED */ 30, /* 0001 -> 3.0x */ 40, /* 0010 -> 4.0x */ -1, /* 0011 -> RESERVED */ -1, /* 0100 -> RESERVED */ 35, /* 0101 -> 3.5x */ 45, /* 0110 -> 4.5x */ 55, /* 0111 -> 5.5x */ 60, /* 1000 -> 6.0x */ 70, /* 1001 -> 7.0x */ 80, /* 1010 -> 8.0x */ 50, /* 1011 -> 5.0x */ 65, /* 1100 -> 6.5x */ 75, /* 1101 -> 7.5x */ -1, /* 1110 -> RESERVED */ -1, /* 1111 -> RESERVED */};static int __initdata samuel1_eblcr[16] = { 50, /* 0000 -> RESERVED */ 30, /* 0001 -> 3.0x */ 40, /* 0010 -> 4.0x */ -1, /* 0011 -> RESERVED */ 55, /* 0100 -> 5.5x */ 35, /* 0101 -> 3.5x */ 45, /* 0110 -> 4.5x */ -1, /* 0111 -> RESERVED */ -1, /* 1000 -> RESERVED */ 70, /* 1001 -> 7.0x */ 80, /* 1010 -> 8.0x */ 60, /* 1011 -> 6.0x */ -1, /* 1100 -> RESERVED */ 75, /* 1101 -> 7.5x */ -1, /* 1110 -> RESERVED */ 65, /* 1111 -> 6.5x */};/* VIA C3 Samuel2 Stepping 1->15 & VIA C3 Ezra */static int __initdata longhaul2_clock_ratio[16] = { 100, /* 0000 -> 10.0x */ 30, /* 0001 -> 3.0x */ 40, /* 0010 -> 4.0x */ 90, /* 0011 -> 9.0x */ 95, /* 0100 -> 9.5x */ 35, /* 0101 -> 3.5x */ 45, /* 0110 -> 4.5x */ 55, /* 0111 -> 5.5x */ 60, /* 1000 -> 6.0x */ 70, /* 1001 -> 7.0x */ 80, /* 1010 -> 8.0x */ 50, /* 1011 -> 5.0x */ 65, /* 1100 -> 6.5x */ 75, /* 1101 -> 7.5x */ 85, /* 1110 -> 8.5x */ 120, /* 1111 -> 12.0x */};static int __initdata samuel2_eblcr[16] = { 50, /* 0000 -> 5.0x */ 30, /* 0001 -> 3.0x */ 40, /* 0010 -> 4.0x */ 100, /* 0011 -> 10.0x */ 55, /* 0100 -> 5.5x */ 35, /* 0101 -> 3.5x */ 45, /* 0110 -> 4.5x */ 110, /* 0111 -> 11.0x */ 90, /* 1000 -> 9.0x */ 70, /* 1001 -> 7.0x */ 80, /* 1010 -> 8.0x */ 60, /* 1011 -> 6.0x */ 120, /* 1100 -> 12.0x */ 75, /* 1101 -> 7.5x */ 130, /* 1110 -> 13.0x */ 65, /* 1111 -> 6.5x */};static int __initdata ezra_eblcr[16] = { 50, /* 0000 -> 5.0x */ 30, /* 0001 -> 3.0x */ 40, /* 0010 -> 4.0x */ 100, /* 0011 -> 10.0x */ 55, /* 0100 -> 5.5x */ 35, /* 0101 -> 3.5x */ 45, /* 0110 -> 4.5x */ 95, /* 0111 -> 9.5x */ 90, /* 1000 -> 9.0x */ 70, /* 1001 -> 7.0x */ 80, /* 1010 -> 8.0x */ 60, /* 1011 -> 6.0x */ 120, /* 1100 -> 12.0x */ 75, /* 1101 -> 7.5x */ 85, /* 1110 -> 8.5x */ 65, /* 1111 -> 6.5x */};/* VIA C5M. */static int __initdata longhaul3_clock_ratio[32] = { 100, /* 0000 -> 10.0x */ 30, /* 0001 -> 3.0x */ 40, /* 0010 -> 4.0x */ 90, /* 0011 -> 9.0x */ 95, /* 0100 -> 9.5x */ 35, /* 0101 -> 3.5x */ 45, /* 0110 -> 4.5x */ 55, /* 0111 -> 5.5x */ 60, /* 1000 -> 6.0x */ 70, /* 1001 -> 7.0x */ 80, /* 1010 -> 8.0x */ 50, /* 1011 -> 5.0x */ 65, /* 1100 -> 6.5x */ 75, /* 1101 -> 7.5x */ 85, /* 1110 -> 8.5x */ 120, /* 1111 -> 12.0x */ -1, /* 0000 -> RESERVED (10.0x) */ 110, /* 0001 -> 11.0x */ 120, /* 0010 -> 12.0x */ -1, /* 0011 -> RESERVED (9.0x)*/ 105, /* 0100 -> 10.5x */ 115, /* 0101 -> 11.5x */ 125, /* 0110 -> 12.5x */ 135, /* 0111 -> 13.5x */ 140, /* 1000 -> 14.0x */ 150, /* 1001 -> 15.0x */ 160, /* 1010 -> 16.0x */ 130, /* 1011 -> 13.0x */ 145, /* 1100 -> 14.5x */ 155, /* 1101 -> 15.5x */ -1, /* 1110 -> RESERVED (13.0x) */ -1, /* 1111 -> RESERVED (12.0x) */};static int __initdata c5m_eblcr[32] = { 50, /* 0000 -> 5.0x */ 30, /* 0001 -> 3.0x */ 40, /* 0010 -> 4.0x */ 100, /* 0011 -> 10.0x */ 55, /* 0100 -> 5.5x */ 35, /* 0101 -> 3.5x */ 45, /* 0110 -> 4.5x */ 95, /* 0111 -> 9.5x */ 90, /* 1000 -> 9.0x */ 70, /* 1001 -> 7.0x */ 80, /* 1010 -> 8.0x */ 60, /* 1011 -> 6.0x */ 120, /* 1100 -> 12.0x */ 75, /* 1101 -> 7.5x */ 85, /* 1110 -> 8.5x */ 65, /* 1111 -> 6.5x */ -1, /* 0000 -> RESERVED (9.0x) */ 110, /* 0001 -> 11.0x */ 120, /* 0010 -> 12.0x */ -1, /* 0011 -> RESERVED (10.0x)*/ 135, /* 0100 -> 13.5x */ 115, /* 0101 -> 11.5x */ 125, /* 0110 -> 12.5x */ 105, /* 0111 -> 10.5x */ 130, /* 1000 -> 13.0x */ 150, /* 1001 -> 15.0x */ 160, /* 1010 -> 16.0x */ 140, /* 1011 -> 14.0x */ -1, /* 1100 -> RESERVED (12.0x) */ 155, /* 1101 -> 15.5x */ -1, /* 1110 -> RESERVED (13.0x) */ 145, /* 1111 -> 14.5x */};/* fsb values as defined in CPU */static unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 };/* fsb values to favour low fsb speed (lower power) */static unsigned int power_fsb_table[] = { 66, 100, 133, -1 };/* fsb values to favour high fsb speed (for e.g. if lowering CPU freq because of heat, but want to maintain highest performance possible) */static unsigned int perf_fsb_table[] = { 133, 100, 66, -1 };static unsigned int *fsb_search_table;/* Voltage scales. Div by 1000 to get actual voltage. */static int __initdata vrm85scales[32] = { 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700, 1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300, 1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725, 1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325,};static int __initdata mobilevrmscales[32] = { 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 1600, 1550, 1500, 1450, 1500, 1350, 1300, -1, 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975, 950, 925, -1,};/* Clock ratios multiplied by 10 */static int clock_ratio[32];static int eblcr_table[32];static int voltage_table[32];static int highest_speed, lowest_speed; /* kHz */static int longhaul; /* version. */static struct cpufreq_driver *longhaul_driver;static int longhaul_get_cpu_fsb (void){ unsigned long invalue=0,lo, hi; if (current_fsb == 0) { rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); invalue = (lo & (1<<18|1<<19)) >>18; return eblcr_fsb_table[invalue]; } else { return current_fsb; }}static int longhaul_get_cpu_mult (void){ unsigned long invalue=0,lo, hi; rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; if (longhaul==3) { if (lo & (1<<27)) invalue+=16; } return eblcr_table[invalue];}/** * longhaul_set_cpu_frequency() * @clock_ratio_index : index of clock_ratio[] for new frequency * @newfsb: the new FSB * * Sets a new clock ratio, and -if applicable- a new Front Side Bus */static void longhaul_setstate (unsigned int clock_ratio_index, unsigned int newfsb){ unsigned long lo, hi; unsigned int bits; int revkey; int vidindex, i; struct cpufreq_freqs freqs; if (!newfsb || (clock_ratio[clock_ratio_index] == -1)) return; if ((!can_scale_fsb) && (newfsb != current_fsb)) return; if (((clock_ratio[clock_ratio_index] * newfsb * 100) > highest_speed) || ((clock_ratio[clock_ratio_index] * newfsb * 100) < lowest_speed)) return; freqs.old = longhaul_get_cpu_mult() * longhaul_get_cpu_fsb() * 100; freqs.new = clock_ratio[clock_ratio_index] * newfsb * 100; freqs.cpu = 0; /* longhaul.c is UP only driver */ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); dprintk (KERN_INFO "longhaul: New FSB:%d Mult(x10):%d\n", newfsb, clock_ratio[clock_ratio_index]); bits = clock_ratio_index; /* "bits" contains the bitpattern of the new multiplier. we now need to transform it to the desired format. */ switch (longhaul) { case 1: rdmsr (MSR_VIA_BCR2, lo, hi); revkey = (lo & 0xf)<<4; /* Rev key. */ lo &= ~(1<<23|1<<24|1<<25|1<<26); lo |= (1<<19); /* Enable software clock multiplier */ lo |= (bits<<23); /* desired multiplier */ lo |= revkey; wrmsr (MSR_VIA_BCR2, lo, hi); __hlt(); /* Disable software clock multiplier */ rdmsr (MSR_VIA_BCR2, lo, hi); lo &= ~(1<<19); lo |= revkey; wrmsr (MSR_VIA_BCR2, lo, hi); break; case 2: rdmsr (MSR_VIA_LONGHAUL, lo, hi); revkey = (lo & 0xf)<<4; /* Rev key. */ lo &= 0xfff0bf0f; /* reset [19:16,14](bus ratio) and [7:4](rev key) to 0 */ lo |= (bits<<16); lo |= (1<<8); /* EnableSoftBusRatio */ lo |= revkey; if (can_scale_voltage) { if (can_scale_fsb==1) { dprintk (KERN_INFO "longhaul: Voltage scaling + FSB scaling not done yet.\n"); goto bad_voltage; } else { /* PB: TODO fix this up */ vidindex = (((highest_speed-lowest_speed) / (newfsb/2)) - ((highest_speed-((clock_ratio[clock_ratio_index] * newfsb * 100)/1000)) / (newfsb/2))); } for (i=0;i<32;i++) { dprintk (KERN_INFO "VID hunting. Looking for %d, found %d\n", minvid+(vidindex*25), voltage_table[i]); if (voltage_table[i]==(minvid + (vidindex * 25))) break; } if (i==32) goto bad_voltage; dprintk (KERN_INFO "longhaul: Desired vid index=%d\n", i);#if 0 lo &= 0xfe0fffff;/* reset [24:20](voltage) to 0 */ lo |= (i<<20); /* set voltage */ lo |= (1<<9); /* EnableSoftVID */#endif }bad_voltage: wrmsr (MSR_VIA_LONGHAUL, lo, hi); __hlt(); rdmsr (MSR_VIA_LONGHAUL, lo, hi); lo &= ~(1<<8); if (can_scale_voltage) lo &= ~(1<<9); lo |= revkey; wrmsr (MSR_VIA_LONGHAUL, lo, hi); break; case 3: rdmsr (MSR_VIA_LONGHAUL, lo, hi); revkey = (lo & 0xf)<<4; /* Rev key. */ lo &= 0xfff0bf0f; /* reset longhaul[19:16,14] to 0 */ lo |= (bits<<16); lo |= (1<<8); /* EnableSoftBusRatio */ lo |= revkey; /* Set FSB */ if (can_scale_fsb==1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -