Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db44aaf3 authored by Rafa Bilski's avatar Rafa Bilski Committed by Dave Jones
Browse files

[CPUFREQ] Longhaul - Add voltage scaling to driver



Rename option "dont_scale_voltage" to "scale_voltage" because
don't will be default.
Use "pos" for calculating voltage. In this way driver don't need
to know mV value or low level value. Simply min U is one pos and
max U is second pos. All pos between these two are used.
Assume that min U is for min f and max U for max f. For frequency
between min and max calculate pos based on difference between
current frequency and min f.
Values in mobile VRM table changed to values from
C3-M datasheet.

Signed-off-by: default avatarRafa³ Bilski <rafalbilski@interia.pl>
Signed-off-by: default avatarDave Jones <davej@redhat.com>
parent 23e735bc
Loading
Loading
Loading
Loading
+56 −41
Original line number Diff line number Diff line
@@ -53,19 +53,26 @@
#define	CPU_NEHEMIAH	5

static int cpu_model;
static unsigned int numscales=16, numvscales;
static unsigned int numscales=16;
static unsigned int fsb;
static int minvid, maxvid;

static struct mV_pos *vrm_mV_table;
static unsigned char *mV_vrm_table;
struct f_msr {
	unsigned char vrm;
};
static struct f_msr f_msr_table[32];

static unsigned int highest_speed, lowest_speed; /* kHz */
static unsigned int minmult, maxmult;
static int can_scale_voltage;
static int vrmrev;
static struct acpi_processor *pr = NULL;
static struct acpi_processor_cx *cx = NULL;
static int port22_en = 0;
static int port22_en;

/* Module parameters */
static int dont_scale_voltage;
static int ignore_latency = 0;
static int scale_voltage;
static int ignore_latency;

#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)

@@ -73,7 +80,6 @@ static int ignore_latency = 0;
/* Clock ratios multiplied by 10 */
static int clock_ratio[32];
static int eblcr_table[32];
static int voltage_table[32];
static unsigned int highest_speed, lowest_speed; /* kHz */
static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table;
@@ -163,6 +169,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
	longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
	longhaul.bits.EnableSoftBusRatio = 1;

	if (can_scale_voltage) {
		longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm;
		longhaul.bits.EnableSoftVID = 1;
	}

	/* Sync to timer tick */
	safe_halt();
	/* Change frequency on next halt or sleep */
@@ -454,52 +465,56 @@ static int __init longhaul_get_ranges(void)
static void __init longhaul_setup_voltagescaling(void)
{
	union msr_longhaul longhaul;
	struct mV_pos minvid, maxvid;
	unsigned int j, speed, pos, kHz_step, numvscales;

	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);

	if (!(longhaul.bits.RevisionID & 1))
	if (!(longhaul.bits.RevisionID & 1)) {
		printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n");
		return;
	}

	minvid = longhaul.bits.MinimumVID;
	maxvid = longhaul.bits.MaximumVID;
	vrmrev = longhaul.bits.VRMRev;
	if (!longhaul.bits.VRMRev) {
		printk (KERN_INFO PFX "VRM 8.5\n");
		vrm_mV_table = &vrm85_mV[0];
		mV_vrm_table = &mV_vrm85[0];
	} else {
		printk (KERN_INFO PFX "Mobile VRM\n");
		vrm_mV_table = &mobilevrm_mV[0];
		mV_vrm_table = &mV_mobilevrm[0];
	}

	minvid = vrm_mV_table[longhaul.bits.MinimumVID];
	maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
	numvscales = maxvid.pos - minvid.pos + 1;
	kHz_step = (highest_speed - lowest_speed) / numvscales;

	if (minvid == 0 || maxvid == 0) {
	if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
		printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
					"Voltage scaling disabled.\n",
					minvid/1000, minvid%1000, maxvid/1000, maxvid%1000);
					minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);
		return;
	}

	if (minvid == maxvid) {
	if (minvid.mV == maxvid.mV) {
		printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "
				"both %d.%03d. Voltage scaling disabled\n",
				maxvid/1000, maxvid%1000);
				maxvid.mV/1000, maxvid.mV%1000);
		return;
	}

	if (vrmrev==0) {
		dprintk ("VRM 8.5\n");
		memcpy (voltage_table, vrm85scales, sizeof(voltage_table));
		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;
	} else {
		dprintk ("Mobile VRM\n");
		memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table));
		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5;
	}
	printk(KERN_INFO PFX "Max VID=%d.%03d  Min VID=%d.%03d, %d possible voltage scales\n",
		maxvid.mV/1000, maxvid.mV%1000,
		minvid.mV/1000, minvid.mV%1000,
		numvscales);
	
	/* Current voltage isn't readable at first, so we need to
	   set it to a known value. The spec says to use maxvid */
	longhaul.bits.RevisionKey = longhaul.bits.RevisionID;	/* FIXME: This is bad. */
	longhaul.bits.EnableSoftVID = 1;
	longhaul.bits.SoftVID = maxvid;
	wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);

	minvid = voltage_table[minvid];
	maxvid = voltage_table[maxvid];

	dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",
		maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);
	j = 0;
	while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
		speed = longhaul_table[j].frequency;
		pos = (speed - lowest_speed) / kHz_step + minvid.pos;
		f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos];
		j++;
	}

	can_scale_voltage = 1;
}
@@ -685,7 +700,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
		return ret;

	if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) &&
		 (dont_scale_voltage==0))
		 (scale_voltage != 0))
		longhaul_setup_voltagescaling();

	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
@@ -773,8 +788,8 @@ static void __exit longhaul_exit(void)
	kfree(longhaul_table);
}

module_param (dont_scale_voltage, int, 0644);
MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor");
module_param (scale_voltage, int, 0644);
MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
module_param(ignore_latency, int, 0644);
MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test");

+38 −10
Original line number Diff line number Diff line
@@ -450,17 +450,45 @@ static int __initdata nehemiah_c_eblcr[32] = {
 * Voltage scales. Div/Mod by 1000 to get actual voltage.
 * Which scale to use depends on the VRM type in use.
 */
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,

struct mV_pos {
	unsigned short mV;
	unsigned short pos;
};

static struct mV_pos __initdata vrm85_mV[32] = {
	{1250, 8},	{1200, 6},	{1150, 4},	{1100, 2},
	{1050, 0},	{1800, 30},	{1750, 28},	{1700, 26},
	{1650, 24},	{1600, 22},	{1550, 20},	{1500, 18},
	{1450, 16},	{1400, 14},	{1350, 12},	{1300, 10},
	{1275, 9},	{1225, 7},	{1175, 5},	{1125, 3},
	{1075, 1},	{1825, 31},	{1775, 29},	{1725, 27},
	{1675, 25},	{1625, 23},	{1575, 21},	{1525, 19},
	{1475, 17},	{1425, 15},	{1375, 13},	{1325, 11}
};

static unsigned char __initdata mV_vrm85[32] = {
	0x04,	0x14,	0x03,	0x13,	0x02,	0x12,	0x01,	0x11,
	0x00,	0x10,	0x0f,	0x1f,	0x0e,	0x1e,	0x0d,	0x1d,
	0x0c,	0x1c,	0x0b,	0x1b,	0x0a,	0x1a,	0x09,	0x19,
	0x08,	0x18,	0x07,	0x17,	0x06,	0x16,	0x05,	0x15
};

static struct mV_pos __initdata mobilevrm_mV[32] = {
	{1750, 31},	{1700, 30},	{1650, 29},	{1600, 28},
	{1550, 27},	{1500, 26},	{1450, 25},	{1400, 24},
	{1350, 23},	{1300, 22},	{1250, 21},	{1200, 20},
	{1150, 19},	{1100, 18},	{1050, 17},	{1000, 16},
	{975, 15},	{950, 14},	{925, 13},	{900, 12},
	{875, 11},	{850, 10},	{825, 9},	{800, 8},
	{775, 7},	{750, 6},	{725, 5},	{700, 4},
	{675, 3},	{650, 2},	{625, 1},	{600, 0}
};

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,
static unsigned char __initdata mV_mobilevrm[32] = {
	0x1f,	0x1e,	0x1d,	0x1c,	0x1b,	0x1a,	0x19,	0x18,
	0x17,	0x16,	0x15,	0x14,	0x13,	0x12,	0x11,	0x10,
	0x0f,	0x0e,	0x0d,	0x0c,	0x0b,	0x0a,	0x09,	0x08,
	0x07,	0x06,	0x05,	0x04,	0x03,	0x02,	0x01,	0x00
};