--- arch/i386/kernel/cpu/cpufreq/powernow-k7.c 2005-07-24 15:37:33.000000000 +0300 +++ arch/i386/kernel/cpu/cpufreq/powernow-k7.c 2005-07-24 15:30:12.000000000 +0300 @@ -85,21 +85,55 @@ 150, 225, 160, 165, 170, 180, -1, -1, }; +//------------>>--------------- +/* translation table for even multiplier to fid */ +static int even_multiplier[20]= { + 16, 18, 4, 6, 8, 10, 12, 14, // 3, 4, 5, 6, 7 ,8 , 9, 10 + 0, 2, 20, 22, 24, 26, 28, 29, // 11, 12, 13, 14, 15, 16, 17, 18 + 17, 19, 23, 25, // 19, 20, 21, 22 +}; + +/* translation table for odd multiplier to fid*/ +static int odd_multiplier[9]={ + 5, 7, 9, 11, 12, 13, 1, 3, // 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5 + 21, // 13.5 +}; + +//--------------<<------------- + /* This parameter is used in order to force ACPI instead of legacy method for * configuration purpose. */ static int acpi_force; +//----------------->>------------ +/* This parameters can be used to manually overwrite the tables */ +static int overwrite_table=1; +#define MAX_PST 10 +static int multiplier[MAX_PST]= { 30, 60, 80, 90, 100, 120, 130, 140, 180, 200,}; +static int voltage[MAX_PST]= { 1200, 1300, 1350, 1400, 1450, 1450, 1450, 1450, 1450, 1450,}; +//static int voltage[MAX_PST]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; +static int switch_latency=200; +static int max_voltage_overwrite; +static int max_voltage_overwrite_value=1600; +static int max_multiplier_overwrite=1; +static int max_multiplier_overwrite_value=220; +static int do_not_change_vid=1; +//------------------<<------------ + static struct cpufreq_frequency_table *powernow_table; static unsigned int can_scale_bus; static unsigned int can_scale_vid; static unsigned int minimum_speed=-1; static unsigned int maximum_speed; -static unsigned int number_scales; +static unsigned int number_scales=10; static unsigned int fsb; -static unsigned int latency; +//----------------->>------------ +static unsigned int latency=200; +//------------------<<------------ +//static unsigned int latency; static char have_a0; #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k7", msg) @@ -232,7 +266,7 @@ union msr_fidvidctl fidvidctl; rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); - if (fidvidctl.bits.VID != vid) { + if ((fidvidctl.bits.VID != vid)&&(do_not_change_vid=0)) { fidvidctl.bits.SGTC = latency; fidvidctl.bits.VID = vid; fidvidctl.bits.FIDC = 0; @@ -414,6 +448,153 @@ } #endif +//-------------->>---------------- +static int powernow_manual_settings(union msr_fidvidstatus *fidvidstatus) +{ + int i,k, validentry; + unsigned int max_multiplier, max_voltage; + unsigned int speed, cm; + u8 vid, fid; + static struct cpufreq_frequency_table *powernow_table_tmp; + if (switch_latency > 0) { + if (switch_latency < 100) { + printk (KERN_INFO PFX "Settling time passed as %d microseconds." + "Should be at least 100. Correcting.\n", switch_latency); + switch_latency = 100; + } + latency = switch_latency; + } else { + latency = 200; + } + printk (KERN_INFO PFX "Settling Time: %d microseconds.\n", latency); + + /* get number of specified multipliers */ + for (i=0; i< MAX_PST; i++) { + if (multiplier[i] == 0) { + number_scales=i; + break; + } + } + + /* get maximum values */ + max_multiplier = fid_codes[fidvidstatus->bits.MFID]; + max_voltage = mobile_vid_table[fidvidstatus->bits.MVID]; + printk(KERN_INFO PFX "Max multiplayer:%d. Max voltage:%d\n",max_multiplier,max_voltage); + /* Overwrite Max Voltage- extreamly DANGEROUS !!!*/ + if (max_voltage_overwrite) + { + max_voltage = max_voltage_overwrite_value; + printk(KERN_INFO PFX "Max voltage overwrited to:%d\n",max_voltage); + } + /* Overwrite Max multiplier DANGEROUS !!! */ + if (max_multiplier_overwrite) + { + max_multiplier = max_multiplier_overwrite_value; + printk(KERN_INFO PFX "Max multiplayer overwrited to:%d\n",max_multiplier); + + } + /* allocate memory */ + printk(KERN_INFO PFX "number_scales:%d\n",i, number_scales); + powernow_table=kmalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); + if (!powernow_table){ + printk(KERN_INFO PFX "Ne6to se sgabi\n"); + return -ENOMEM; + } + memset(powernow_table,0,(sizeof(struct cpufreq_frequency_table)*(number_scales+1))); + k=0; + printk(KERN_INFO PFX "number_scales:%d\n",i, number_scales); + for(i=0; i< number_scales; i++) + { + validentry = 0; + if (multiplier[i] != 0) { + printk(KERN_INFO PFX "multipliers:%d - %d\n",i,multiplier[i]); + /* fix multiplier */ + if (multiplier[i] < 30) + multiplier[i]=multiplier[i] * 10; + + if (multiplier[i] < max_multiplier) { + cm = (multiplier[i]/10); + /* check if odd or even muliplier */ + if (multiplier[i]%10) { + /* odd multiplier */ + if (cm == 16) { + /* hardcoded because 14.5 and 15.5 fids not possible */ + fid = 27; + validentry = 1; + //fid= odd_multiplier[cm-5]; + //validentry = 1; + }else if ((cm > 4) && (cm < 14)) { + fid= odd_multiplier[cm-5]; + validentry = 1; + } + } else { + /* even_multiplier */ + if ((cm < 23) && (cm > 2)) { + fid = even_multiplier[cm-3]; + validentry=1; + } + } + } + } + + if (validentry) { + /* if no voltage specified use CPU default */ + if (voltage[i] == 0) + voltage[i] = max_voltage; + printk(KERN_INFO PFX "Voltage:%d - %d\n",i,voltage[i]); + /* we do not allow higher voltages than the CPU's maximum + 925 mV is the minimum */ + if ((voltage[i] <= max_voltage) && (voltage[i] >= 925)) { + if (voltage[i] >= 1300) { + vid = 40 - (voltage[i]/50); + } else { + vid = 67 - (voltage[i]/25); + } + /* calculate speed */ + speed = fsb * fid_codes[fid] / 10; + powernow_table[k].frequency = speed; + powernow_table[k].index=fid; /*lower 8 bits*/ + powernow_table[k].index|= (vid << 8); /*upper 8 bits*/ + + if (speed < minimum_speed) + minimum_speed = speed; + if (speed > maximum_speed) + maximum_speed = speed; + + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); + dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, mobile_vid_table[vid]%1000); + printk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); + printk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, mobile_vid_table[vid]%1000); + k++; + } + } else { + // invalid entry + printk (KERN_INFO PFX "Entry %d is invalid\n", i+1); + } + } + + if (k < number_scales) { + /* some entrys were invalid need to realloc table */ + number_scales = k; + powernow_table_tmp = kmalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); + if (!powernow_table_tmp) { + kfree(powernow_table); + return -ENOMEM; + } + memcpy(powernow_table_tmp,powernow_table,(sizeof(struct cpufreq_frequency_table) * (number_scales + 1))); + kfree(powernow_table); + powernow_table=powernow_table_tmp; + } + + + /* Terminate frequency list */ + powernow_table[number_scales].frequency = CPUFREQ_TABLE_END; + powernow_table[number_scales].index = 0; + + return 0; +} +//---------------------<<------------------ + static int powernow_decode_bios (int maxfid, int startvid) { struct psb_s *psb; @@ -620,7 +801,12 @@ printk(KERN_INFO PFX "SGTC: %d\n", latency); } } - + //--------------->>-------------------------- + if (overwrite_table){ + printk(KERN_INFO PFX "Overwriting PST table with manual settings\n"); + result = powernow_manual_settings(&fidvidstatus); + } + //---------------<<-------------------------- if (result) return result; @@ -685,7 +871,16 @@ module_param(acpi_force, int, 0444); MODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); - +//------------------>>--------------------- +module_param(overwrite_table,int,0444); +MODULE_PARM_DESC(overwrite_table, "overwrite table with manually settings"); +module_param_array(multiplier, int, MAX_PST, 0444); +MODULE_PARM_DESC(multiplier, "Specifiy up to 10 multipliers, multiply them by 10: 5->50, 5.5->55"); +module_param_array(voltage, int, MAX_PST, 0444); +MODULE_PARM_DESC(voltage, "Specify voltages in respect to the given multipliers, specify them in mV: 1.275V -> 1275"); +module_param(switch_latency, int, 0444); +MODULE_PARM_DESC(switch_latency, "Set state transition latency in microseconds (default 200us)"); +//--------------------<<------------------- MODULE_AUTHOR ("Dave Jones "); MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); MODULE_LICENSE ("GPL");