regulator: cpr3-regulator: adjust voltage limits based upon aging results
Adjust the floor, ceiling, and open-loop voltages for each corner of each CPR3 regulator based upon aging measurements. This allows the fixed open-loop voltage adjustment to be reduced since it no longer has to account for the maximum possible aging adjustment. This in turn leads to more situations where LDO mode may be used for the HMSS CPR3 regulators since the LDO must always operate at the open-loop voltage. Change-Id: Iaca0ed4b51f258656b5c44dc58f7361814ca3af7 CRs-Fixed: 949622 Signed-off-by: David Collins <collinsd@codeaurora.org>
This commit is contained in:
parent
70dcea8217
commit
5cf7daa23d
4 changed files with 116 additions and 9 deletions
|
@ -517,6 +517,21 @@ Platform independent properties:
|
|||
regardless of the fuse combination and speed bin found
|
||||
on a given chip.
|
||||
|
||||
- qcom,allow-aging-open-loop-voltage-adjustment
|
||||
Usage: optional
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: A list of integers which specifies if CPR aging adjustment
|
||||
should be applied to open-loop voltages for each fuse
|
||||
combination. Note that aging adjustment must be allowed via
|
||||
qcom,allow-aging-voltage-adjustment in order for this
|
||||
property to have an effect.
|
||||
Supported per-combo element values:
|
||||
0 - do not perform CPR aging adjustment
|
||||
1 - perform CPR aging adjustment
|
||||
|
||||
The list must meet the same size requirements as those
|
||||
specified for qcom,allow-aging-voltage-adjustment above.
|
||||
|
||||
- qcom,cpr-aging-max-voltage-adjustment
|
||||
Usage: required if qcom,allow-aging-voltage-adjustment is specified
|
||||
Value type: <prop-encoded-array>
|
||||
|
|
|
@ -3505,7 +3505,8 @@ cleanup:
|
|||
}
|
||||
|
||||
/**
|
||||
* cpr3_regulator_readjust_quotients() - readjust the target quotients for the
|
||||
* cpr3_regulator_readjust_volt_and_quot() - readjust the target quotients as
|
||||
* well as the floor, ceiling, and open-loop voltages for the
|
||||
* regulator by removing the old adjustment and adding the new one
|
||||
* @vreg: Pointer to the CPR3 regulator
|
||||
* @old_adjust_volt: Old aging adjustment voltage in microvolts
|
||||
|
@ -3513,12 +3514,14 @@ cleanup:
|
|||
*
|
||||
* Also reset the cached closed loop voltage (last_volt) to equal the open-loop
|
||||
* voltage for each corner.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static void cpr3_regulator_readjust_quotients(struct cpr3_regulator *vreg,
|
||||
static void cpr3_regulator_readjust_volt_and_quot(struct cpr3_regulator *vreg,
|
||||
int old_adjust_volt, int new_adjust_volt)
|
||||
{
|
||||
unsigned long long temp;
|
||||
int i, j, old_volt, new_volt;
|
||||
int i, j, old_volt, new_volt, rounded_volt;
|
||||
|
||||
if (!vreg->aging_allowed)
|
||||
return;
|
||||
|
@ -3548,14 +3551,34 @@ static void cpr3_regulator_readjust_quotients(struct cpr3_regulator *vreg,
|
|||
old_volt);
|
||||
}
|
||||
}
|
||||
|
||||
rounded_volt = CPR3_ROUND(new_volt,
|
||||
vreg->thread->ctrl->step_volt);
|
||||
|
||||
if (!vreg->aging_allow_open_loop_adj)
|
||||
rounded_volt = 0;
|
||||
|
||||
vreg->corner[i].ceiling_volt
|
||||
= vreg->corner[i].unaged_ceiling_volt + rounded_volt;
|
||||
vreg->corner[i].ceiling_volt = min(vreg->corner[i].ceiling_volt,
|
||||
vreg->corner[i].abs_ceiling_volt);
|
||||
vreg->corner[i].floor_volt
|
||||
= vreg->corner[i].unaged_floor_volt + rounded_volt;
|
||||
vreg->corner[i].floor_volt = min(vreg->corner[i].floor_volt,
|
||||
vreg->corner[i].ceiling_volt);
|
||||
vreg->corner[i].open_loop_volt
|
||||
= vreg->corner[i].unaged_open_loop_volt + rounded_volt;
|
||||
vreg->corner[i].open_loop_volt
|
||||
= min(vreg->corner[i].open_loop_volt,
|
||||
vreg->corner[i].ceiling_volt);
|
||||
|
||||
vreg->corner[i].last_volt = vreg->corner[i].open_loop_volt;
|
||||
|
||||
cpr3_debug(vreg, "corner %d: applying %d uV closed-loop voltage margin adjustment\n",
|
||||
i, new_volt);
|
||||
cpr3_debug(vreg, "corner %d: applying %d uV closed-loop and %d uV open-loop voltage margin adjustment\n",
|
||||
i, new_volt, rounded_volt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* cpr3_regulator_set_aging_ref_adjustment() - adjust target quotients for the
|
||||
* regulators managed by this CPR controller to account for aging
|
||||
|
@ -3574,7 +3597,7 @@ static void cpr3_regulator_set_aging_ref_adjustment(
|
|||
|
||||
for (i = 0; i < ctrl->thread_count; i++) {
|
||||
for (j = 0; j < ctrl->thread[i].vreg_count; j++) {
|
||||
cpr3_regulator_readjust_quotients(
|
||||
cpr3_regulator_readjust_volt_and_quot(
|
||||
&ctrl->thread[i].vreg[j],
|
||||
ctrl->aging_ref_adjust_volt,
|
||||
ref_adjust_volt);
|
||||
|
@ -5586,10 +5609,13 @@ static int cpr3_regulator_init_ctrl_data(struct cpr3_controller *ctrl)
|
|||
static int cpr3_regulator_init_vreg_data(struct cpr3_regulator *vreg)
|
||||
{
|
||||
int i, j;
|
||||
bool init_aging;
|
||||
|
||||
vreg->current_corner = CPR3_REGULATOR_CORNER_INVALID;
|
||||
vreg->last_closed_loop_corner = CPR3_REGULATOR_CORNER_INVALID;
|
||||
|
||||
init_aging = vreg->aging_allowed && vreg->thread->ctrl->aging_required;
|
||||
|
||||
for (i = 0; i < vreg->corner_count; i++) {
|
||||
vreg->corner[i].last_volt = vreg->corner[i].open_loop_volt;
|
||||
vreg->corner[i].irq_en = CPR3_IRQ_UP | CPR3_IRQ_DOWN;
|
||||
|
@ -5599,6 +5625,33 @@ static int cpr3_regulator_init_vreg_data(struct cpr3_regulator *vreg)
|
|||
if (vreg->corner[i].target_quot[j] == 0)
|
||||
vreg->corner[i].ro_mask |= BIT(j);
|
||||
}
|
||||
|
||||
if (init_aging) {
|
||||
vreg->corner[i].unaged_floor_volt
|
||||
= vreg->corner[i].floor_volt;
|
||||
vreg->corner[i].unaged_ceiling_volt
|
||||
= vreg->corner[i].ceiling_volt;
|
||||
vreg->corner[i].unaged_open_loop_volt
|
||||
= vreg->corner[i].open_loop_volt;
|
||||
}
|
||||
|
||||
if (vreg->aging_allowed) {
|
||||
if (vreg->corner[i].unaged_floor_volt <= 0) {
|
||||
cpr3_err(vreg, "invalid unaged_floor_volt[%d] = %d\n",
|
||||
i, vreg->corner[i].unaged_floor_volt);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (vreg->corner[i].unaged_ceiling_volt <= 0) {
|
||||
cpr3_err(vreg, "invalid unaged_ceiling_volt[%d] = %d\n",
|
||||
i, vreg->corner[i].unaged_ceiling_volt);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (vreg->corner[i].unaged_open_loop_volt <= 0) {
|
||||
cpr3_err(vreg, "invalid unaged_open_loop_volt[%d] = %d\n",
|
||||
i, vreg->corner[i].unaged_open_loop_volt);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vreg->aging_allowed && vreg->corner[vreg->aging_corner].ceiling_volt
|
||||
|
|
|
@ -100,6 +100,16 @@ struct cpr4_sdelta {
|
|||
* microvolts
|
||||
* @last_volt: Last known settled CPR closed-loop voltage which is used
|
||||
* when switching to a new corner
|
||||
* @abs_ceiling_volt: The absolute CPR closed-loop ceiling voltage in
|
||||
* microvolts. This is used to limit the ceiling_volt
|
||||
* value when it is increased as a result of aging
|
||||
* adjustment.
|
||||
* @unaged_floor_volt: The CPR closed-loop floor voltage in microvolts before
|
||||
* any aging adjustment is performed
|
||||
* @unaged_ceiling_volt: The CPR closed-loop ceiling voltage in microvolts
|
||||
* before any aging adjustment is performed
|
||||
* @unaged_open_loop_volt: The CPR open-loop voltage (i.e. initial voltage) in
|
||||
* microvolts before any aging adjusment is performed
|
||||
* @system_volt: The system-supply voltage in microvolts or corners or
|
||||
* levels
|
||||
* @mem_acc_volt: The mem-acc-supply voltage in corners
|
||||
|
@ -136,7 +146,11 @@ struct cpr4_sdelta {
|
|||
*
|
||||
* The value of last_volt is initialized inside of the cpr3_regulator_register()
|
||||
* call with the open_loop_volt value. It can later be updated to the settled
|
||||
* VDD supply voltage.
|
||||
* VDD supply voltage. The values for unaged_floor_volt, unaged_ceiling_volt,
|
||||
* and unaged_open_loop_volt are initialized inside of cpr3_regulator_register()
|
||||
* if ctrl->aging_required == true. These three values must be pre-initialized
|
||||
* if cpr3_regulator_register() is called with ctrl->aging_required == false and
|
||||
* ctrl->aging_succeeded == true.
|
||||
*
|
||||
* The values of ro_mask and irq_en are initialized inside of the
|
||||
* cpr3_regulator_register() call.
|
||||
|
@ -146,6 +160,10 @@ struct cpr3_corner {
|
|||
int ceiling_volt;
|
||||
int open_loop_volt;
|
||||
int last_volt;
|
||||
int abs_ceiling_volt;
|
||||
int unaged_floor_volt;
|
||||
int unaged_ceiling_volt;
|
||||
int unaged_open_loop_volt;
|
||||
int system_volt;
|
||||
int mem_acc_volt;
|
||||
u32 proc_freq;
|
||||
|
@ -277,6 +295,13 @@ struct cprh_corner_band {
|
|||
* @aging_allowed: Boolean defining if CPR aging adjustments are allowed
|
||||
* for this CPR3 regulator given the fuse combo of the
|
||||
* device
|
||||
* @aging_allow_open_loop_adj: Boolean defining if the open-loop voltage of each
|
||||
* corner of this regulator should be adjusted as a result
|
||||
* of an aging measurement. This flag can be set to false
|
||||
* when the open-loop voltage adjustments have been
|
||||
* specified such that they include the maximum possible
|
||||
* aging adjustment. This flag is only used if
|
||||
* aging_allowed == true.
|
||||
* @aging_corner: The corner that should be configured for this regulator
|
||||
* when an aging measurement is performed.
|
||||
* @aging_max_adjust_volt: The maximum aging voltage margin in microvolts that
|
||||
|
@ -342,6 +367,7 @@ struct cpr3_regulator {
|
|||
bool vreg_enabled;
|
||||
|
||||
bool aging_allowed;
|
||||
bool aging_allow_open_loop_adj;
|
||||
int aging_corner;
|
||||
int aging_max_adjust_volt;
|
||||
|
||||
|
|
|
@ -695,9 +695,11 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
|
|||
1, temp);
|
||||
if (rc)
|
||||
goto free_temp;
|
||||
for (i = 0; i < vreg->corner_count; i++)
|
||||
for (i = 0; i < vreg->corner_count; i++) {
|
||||
vreg->corner[i].ceiling_volt
|
||||
= CPR3_ROUND(temp[i], ctrl->step_volt);
|
||||
vreg->corner[i].abs_ceiling_volt = vreg->corner[i].ceiling_volt;
|
||||
}
|
||||
|
||||
rc = cpr3_parse_corner_array_property(vreg, "qcom,cpr-voltage-floor",
|
||||
1, temp);
|
||||
|
@ -807,6 +809,17 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
|
|||
vreg->aging_allowed = aging_allowed;
|
||||
}
|
||||
|
||||
if (of_find_property(vreg->of_node,
|
||||
"qcom,allow-aging-open-loop-voltage-adjustment", NULL)) {
|
||||
rc = cpr3_parse_array_property(vreg,
|
||||
"qcom,allow-aging-open-loop-voltage-adjustment",
|
||||
1, &aging_allowed);
|
||||
if (rc)
|
||||
goto free_temp;
|
||||
|
||||
vreg->aging_allow_open_loop_adj = aging_allowed;
|
||||
}
|
||||
|
||||
if (vreg->aging_allowed) {
|
||||
if (ctrl->aging_ref_volt <= 0) {
|
||||
cpr3_err(ctrl, "qcom,cpr-aging-ref-voltage must be specified\n");
|
||||
|
|
Loading…
Add table
Reference in a new issue