/* * 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); }
/* * 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; }