Beispiel #1
0
/*
 * Find the maximum frequency that results in dynamic and leakage current that
 * is less than the regulator current limit.
 * temp_C - valid or -EINVAL
 * power_mW - valid or -1 (infinite) or -EINVAL
 */
static unsigned int edp_calculate_maxf(
				struct tegra_edp_cpu_leakage_params *params,
				int temp_C, int power_mW,
				int iddq_mA,
				int n_cores_idx)
{
	unsigned int voltage_mV, freq_KHz = 0;
	unsigned int cur_effective = regulator_cur - edp_reg_override_mA;
	int f, i, j, k, r = 0;
	s64 leakage_mA, dyn_mA, leakage_calc_step;
	s64 leakage_mW, dyn_mW;

	for (f = freq_voltage_lut_size - 1; f >= 0; f--) {
		freq_KHz = freq_voltage_lut[f].freq / 1000;
		voltage_mV = freq_voltage_lut[f].voltage_mV;

		/* Constrain Volt-Temp. Eg. at Tj >= 70C, no VDD_CPU > 1.24V */
		if (temp_C > params->volt_temp_cap.temperature &&
		    voltage_mV > params->volt_temp_cap.voltage_limit_mV)
			continue;

		/* Calculate leakage current */
		leakage_mA = 0;
		for (i = 0; i <= 3; i++) {
			for (j = 0; j <= 3; j++) {
				for (k = 0; k <= 3; k++) {
					leakage_calc_step =
						params->leakage_consts_ijk
						[i][j][k] * edp_pow(iddq_mA, i);
					/* Convert (mA)^i to (A)^i */
					leakage_calc_step =
						div64_s64(leakage_calc_step,
							  edp_pow(1000, i));
					leakage_calc_step *=
						edp_pow(voltage_mV, j);
					/* Convert (mV)^j to (V)^j */
					leakage_calc_step =
						div64_s64(leakage_calc_step,
							  edp_pow(1000, j));
					leakage_calc_step *=
						edp_pow(temp_C, k);
					/* Convert (C)^k to (scaled_C)^k */
					leakage_calc_step =
						div64_s64(leakage_calc_step,
						edp_pow(params->temp_scaled,
							k));
					/* leakage_consts_ijk was scaled */
					leakage_calc_step =
						div64_s64(leakage_calc_step,
							  params->ijk_scaled);
					leakage_mA += leakage_calc_step;
				}
			}
		}

		/* if specified, set floor for leakage current */
		if (params->leakage_min && leakage_mA <= params->leakage_min)
			leakage_mA = params->leakage_min;

		/* leakage cannot be negative => leakage model has error */
		if (leakage_mA <= 0) {
			pr_err("VDD_CPU EDP failed: IDDQ too high (%d mA)\n",
			       iddq_mA);
			r = -EINVAL;
			goto end;
		}

		leakage_mA *= params->leakage_consts_n[n_cores_idx];

		/* leakage_const_n was scaled */
		leakage_mA = div64_s64(leakage_mA, params->consts_scaled);

		/* Calculate dynamic current */
		dyn_mA = voltage_mV * freq_KHz / 1000;
		/* Convert mV to V */
		dyn_mA = div64_s64(dyn_mA, 1000);
		dyn_mA *= params->dyn_consts_n[n_cores_idx];
		/* dyn_const_n was scaled */
		dyn_mA = div64_s64(dyn_mA, params->dyn_scaled);

		if (power_mW != -1) {
			leakage_mW = leakage_mA * voltage_mV;
			dyn_mW = dyn_mA * voltage_mV;
			if (div64_s64(leakage_mW + dyn_mW, 1000) <= power_mW)
				goto end;
		} else if ((leakage_mA + dyn_mA) <= cur_effective) {
			goto end;
		}
		freq_KHz = 0;
	}

 end:
	if (r != 0)
		return r;

	return edp_apply_fixed_limits(freq_KHz, params,
					cur_effective, temp_C, n_cores_idx);
}
Beispiel #2
0
/*
 * Find the maximum frequency that results in dynamic and leakage current that
 * is less than the regulator current limit.
 * temp_C - valid or -EINVAL
 * power_mW - valid or -1 (infinite) or -EINVAL
 */
static unsigned int edp_calculate_maxf(
				struct tegra_edp_cpu_leakage_params *params,
				int temp_C, int power_mW,
				int iddq_mA,
				int n_cores_idx)
{
	unsigned int voltage_mV, freq_KHz;
	unsigned int cur_effective = regulator_cur - edp_reg_override_mA;
	int f, i, j, k;
	s64 leakage_mA, dyn_mA, leakage_calc_step;
	s64 leakage_mW, dyn_mW;

	for (f = freq_voltage_lut_size - 1; f >= 0; f--) {
		freq_KHz = freq_voltage_lut[f].freq / 1000;
		voltage_mV = freq_voltage_lut[f].voltage_mV;

		/* Constrain Volt-Temp. Eg. at Tj >= 70C, no VDD_CPU > 1.24V */
		if (temp_C > params->volt_temp_cap.temperature &&
		    voltage_mV > params->volt_temp_cap.voltage_limit_mV)
			continue;

		/* Calculate leakage current */
		leakage_mA = 0;
		for (i = 0; i <= 3; i++) {
			for (j = 0; j <= 3; j++) {
				for (k = 0; k <= 3; k++) {
					leakage_calc_step =
						params->leakage_consts_ijk
						[i][j][k] * edp_pow(iddq_mA, i);
					/* Convert (mA)^i to (A)^i */
					leakage_calc_step =
						div64_s64(leakage_calc_step,
							  edp_pow(1000, i));
					leakage_calc_step *=
						edp_pow(voltage_mV, j);
					/* Convert (mV)^i to (V)^i */
					leakage_calc_step =
						div64_s64(leakage_calc_step,
							  edp_pow(1000, j));
					leakage_calc_step *=
						edp_pow(temp_C, k);
					/* leakage_consts_ijk was X 100,000 */
					leakage_calc_step =
						div64_s64(leakage_calc_step,
							  100000);
					leakage_mA += leakage_calc_step;
				}
			}
		}
		/* leakage cannot be negative => leakage model has error */
		if (leakage_mA <= 0) {
			pr_err("VDD_CPU EDP failed: IDDQ too high (%d mA)\n",
			       iddq_mA);
			return -EINVAL;
		}

		leakage_mA *= params->leakage_consts_n[n_cores_idx];
		/* leakage_const_n was pre-multiplied by 1,000,000 */
		leakage_mA = div64_s64(leakage_mA, 1000000);

		/* Calculate dynamic current */
		dyn_mA = voltage_mV * freq_KHz / 1000;
		/* Convert mV to V */
		dyn_mA = div64_s64(dyn_mA, 1000);
		dyn_mA *= params->dyn_consts_n[n_cores_idx];
		/* dyn_const_n was pre-multiplied by 1,000,000 */
		dyn_mA = div64_s64(dyn_mA, 1000000);

		if (power_mW != -1) {
			leakage_mW = leakage_mA * voltage_mV;
			dyn_mW = dyn_mA * voltage_mV;
			if (div64_s64(leakage_mW + dyn_mW, 1000) <= power_mW)
				return freq_KHz;
		} else if ((leakage_mA + dyn_mA) <= cur_effective) {
			return freq_KHz;
		}
	}
	return -EINVAL;
}