static void longhaul_setup_voltagescaling()

in longhaul.c [528:616]


static void longhaul_setup_voltagescaling(void)
{
	struct cpufreq_frequency_table *freq_pos;
	union msr_longhaul longhaul;
	struct mV_pos minvid, maxvid, vid;
	unsigned int j, speed, pos, kHz_step, numvscales;
	int min_vid_speed;

	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
	if (!(longhaul.bits.RevisionID & 1)) {
		pr_info("Voltage scaling not supported by CPU\n");
		return;
	}

	if (!longhaul.bits.VRMRev) {
		pr_info("VRM 8.5\n");
		vrm_mV_table = &vrm85_mV[0];
		mV_vrm_table = &mV_vrm85[0];
	} else {
		pr_info("Mobile VRM\n");
		if (cpu_model < CPU_NEHEMIAH)
			return;
		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];

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

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

	/* How many voltage steps*/
	numvscales = maxvid.pos - minvid.pos + 1;
	pr_info("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);

	/* Calculate max frequency at min voltage */
	j = longhaul.bits.MinMHzBR;
	if (longhaul.bits.MinMHzBR4)
		j += 16;
	min_vid_speed = eblcr[j];
	if (min_vid_speed == -1)
		return;
	switch (longhaul.bits.MinMHzFSB) {
	case 0:
		min_vid_speed *= 13333;
		break;
	case 1:
		min_vid_speed *= 10000;
		break;
	case 3:
		min_vid_speed *= 6666;
		break;
	default:
		return;
	}
	if (min_vid_speed >= highest_speed)
		return;
	/* Calculate kHz for one voltage step */
	kHz_step = (highest_speed - min_vid_speed) / numvscales;

	cpufreq_for_each_entry_idx(freq_pos, longhaul_table, j) {
		speed = freq_pos->frequency;
		if (speed > min_vid_speed)
			pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
		else
			pos = minvid.pos;
		freq_pos->driver_data |= mV_vrm_table[pos] << 8;
		vid = vrm_mV_table[mV_vrm_table[pos]];
		pr_info("f: %d kHz, index: %d, vid: %d mV\n",
			speed, j, vid.mV);
	}

	can_scale_voltage = 1;
	pr_info("Voltage scaling enabled\n");
}